diff --git a/crates/runner-workflow-github-actions/src/context/credential.rs b/crates/runner-workflow-github-actions/src/context/credential.rs --- a/crates/runner-workflow-github-actions/src/context/credential.rs +++ b/crates/runner-workflow-github-actions/src/context/credential.rs @@ -1,58 +1,90 @@ -use syncode_runner_domain::{ - ControlVendor, IdentifierError, JobAssignment, SecretName, SecretValue, -}; -use syncode_runner_source::{RepositoryCredential, RepositoryUrl}; - -#[derive(Clone, Copy)] -enum CredentialSecret { - GiteaToken, - GithubToken, -} - -pub fn repository_credential( - assignment: &JobAssignment, - vendor: ControlVendor, - origin: RepositoryUrl, -) -> Result, IdentifierError> { - for candidate in CredentialSecret::for_vendor(vendor) { - if let Some(token) = secret(assignment, *candidate)? { - return Ok(Some(RepositoryCredential::new(origin, token.clone()))); - } - } - Ok(None) -} - -pub(crate) fn github_token( - assignment: &JobAssignment, -) -> Result, IdentifierError> { - secret(assignment, CredentialSecret::GithubToken) -} - -fn secret( - assignment: &JobAssignment, - candidate: CredentialSecret, -) -> Result, IdentifierError> { - let name = candidate.as_ref().parse::()?; - Ok(assignment.secrets.get(&name)) -} - -impl CredentialSecret { - const fn for_vendor(vendor: ControlVendor) -> &'static [Self] { - match vendor { - ControlVendor::SynCode | ControlVendor::Gitea | ControlVendor::Forgejo => { - &[Self::GiteaToken, Self::GithubToken] - } - ControlVendor::GitHub => &[Self::GithubToken], - ControlVendor::GitLab => &[], - } - } -} - -impl AsRef for CredentialSecret { - fn as_ref(&self) -> &str { - match self { - Self::GiteaToken => "GITEA_TOKEN", - Self::GithubToken => "GITHUB_TOKEN", - } - } -} +use syncode_runner_domain::{ + ControlVendor, IdentifierError, JobAssignment, SecretName, SecretValue, +}; +use syncode_runner_source::{RepositoryCredential, RepositoryUrl}; + +#[derive(Clone, Copy)] +enum CredentialSecret { + SyncodeRepository, + Gitea, + Github, +} + +pub fn repository_credential( + assignment: &JobAssignment, + vendor: ControlVendor, + origin: RepositoryUrl, +) -> Result, IdentifierError> { + for candidate in CredentialSecret::for_vendor(vendor) { + if let Some(token) = secret(assignment, *candidate)? { + return Ok(Some(RepositoryCredential::new(origin, token.clone()))); + } + } + Ok(None) +} + +pub(crate) fn github_token( + assignment: &JobAssignment, +) -> Result, IdentifierError> { + secret(assignment, CredentialSecret::Github) +} + +fn secret( + assignment: &JobAssignment, + candidate: CredentialSecret, +) -> Result, IdentifierError> { + let name = candidate.as_ref().parse::()?; + Ok(assignment.secrets.get(&name)) +} + +impl CredentialSecret { + const fn for_vendor(vendor: ControlVendor) -> &'static [Self] { + match vendor { + ControlVendor::SynCode => &[Self::SyncodeRepository, Self::Gitea, Self::Github], + ControlVendor::Gitea | ControlVendor::Forgejo => &[Self::Gitea, Self::Github], + ControlVendor::GitHub => &[Self::Github], + ControlVendor::GitLab => &[], + } + } +} + +impl AsRef for CredentialSecret { + fn as_ref(&self) -> &str { + match self { + Self::SyncodeRepository => "SYNCODE_REPOSITORY_TOKEN", + Self::Gitea => "GITEA_TOKEN", + Self::Github => "GITHUB_TOKEN", + } + } +} + +#[cfg(test)] +mod tests { + use syncode_runner_domain::ControlVendor; + + use super::CredentialSecret; + + #[test] + fn syncode_prefers_the_native_repository_token() { + let names = CredentialSecret::for_vendor(ControlVendor::SynCode) + .iter() + .map(AsRef::as_ref) + .collect::>(); + + assert_eq!( + names, + vec!["SYNCODE_REPOSITORY_TOKEN", "GITEA_TOKEN", "GITHUB_TOKEN"] + ); + } + + #[test] + fn forge_controls_do_not_request_syncode_credentials() { + for vendor in [ControlVendor::Gitea, ControlVendor::Forgejo] { + assert!( + CredentialSecret::for_vendor(vendor) + .iter() + .all(|candidate| candidate.as_ref() != "SYNCODE_REPOSITORY_TOKEN") + ); + } + } +}