diff --git a/cli/tools/publish/provenance.rs b/cli/tools/publish/provenance.rs index 6319f3de8c1a70..1952f8604b2d4c 100644 --- a/cli/tools/publish/provenance.rs +++ b/cli/tools/publish/provenance.rs @@ -159,20 +159,48 @@ struct Predicate { } impl Predicate { - pub fn new_github_actions() -> Self { - let repo = - std::env::var("GITHUB_REPOSITORY").expect("GITHUB_REPOSITORY not set"); - let rel_ref = std::env::var("GITHUB_WORKFLOW_REF") - .unwrap_or_default() - .replace(&format!("{}/", &repo), ""); - - let delimn = rel_ref.find('@').unwrap(); + pub fn new_github_actions() -> Result { + let repo = std::env::var("GITHUB_REPOSITORY").map_err(|_| { + anyhow::anyhow!("GITHUB_REPOSITORY environment variable is not set") + })?; + let workflow_ref_raw = + std::env::var("GITHUB_WORKFLOW_REF").map_err(|_| { + anyhow::anyhow!("GITHUB_WORKFLOW_REF environment variable is not set") + })?; + let rel_ref = workflow_ref_raw.replace(&format!("{}/", &repo), ""); + + let delimn = rel_ref.find('@').ok_or_else(|| { + anyhow::anyhow!( + "GITHUB_WORKFLOW_REF does not contain '@' separator: {}", + rel_ref + ) + })?; let (workflow_path, mut workflow_ref) = rel_ref.split_at(delimn); workflow_ref = &workflow_ref[1..]; - let server_url = std::env::var("GITHUB_SERVER_URL").unwrap(); + let server_url = std::env::var("GITHUB_SERVER_URL").map_err(|_| { + anyhow::anyhow!("GITHUB_SERVER_URL environment variable is not set") + })?; + + let github_ref = std::env::var("GITHUB_REF").map_err(|_| { + anyhow::anyhow!("GITHUB_REF environment variable is not set") + })?; + let github_sha = std::env::var("GITHUB_SHA").map_err(|_| { + anyhow::anyhow!("GITHUB_SHA environment variable is not set") + })?; + let runner_environment = + std::env::var("RUNNER_ENVIRONMENT").map_err(|_| { + anyhow::anyhow!("RUNNER_ENVIRONMENT environment variable is not set") + })?; + let github_run_id = std::env::var("GITHUB_RUN_ID").map_err(|_| { + anyhow::anyhow!("GITHUB_RUN_ID environment variable is not set") + })?; + let github_run_attempt = + std::env::var("GITHUB_RUN_ATTEMPT").map_err(|_| { + anyhow::anyhow!("GITHUB_RUN_ATTEMPT environment variable is not set") + })?; - Self { + Ok(Self { build_definition: BuildDefinition { build_type: GITHUB_BUILD_TYPE, external_parameters: ExternalParameters { @@ -192,36 +220,24 @@ impl Predicate { }, }, resolved_dependencies: [ResourceDescriptor { - uri: format!( - "git+{}/{}@{}", - server_url, - &repo, - std::env::var("GITHUB_REF").unwrap() - ), + uri: format!("git+{}/{}@{}", server_url, &repo, github_ref), digest: Some(GhaResourceDigest { - git_commit: std::env::var("GITHUB_SHA").unwrap(), + git_commit: github_sha, }), }], }, run_details: RunDetails { builder: Builder { - id: format!( - "{}/{}", - &GITHUB_BUILDER_ID_PREFIX, - std::env::var("RUNNER_ENVIRONMENT").unwrap() - ), + id: format!("{}/{}", &GITHUB_BUILDER_ID_PREFIX, runner_environment), }, metadata: Metadata { invocation_id: format!( "{}/{}/actions/runs/{}/attempts/{}", - server_url, - repo, - std::env::var("GITHUB_RUN_ID").unwrap(), - std::env::var("GITHUB_RUN_ATTEMPT").unwrap() + server_url, repo, github_run_id, github_run_attempt ), }, }, - } + }) } } @@ -236,13 +252,13 @@ struct ProvenanceAttestation { } impl ProvenanceAttestation { - pub fn new_github_actions(subjects: Vec) -> Self { - Self { + pub fn new_github_actions(subjects: Vec) -> Result { + Ok(Self { _type: INTOTO_STATEMENT_TYPE, subject: subjects, predicate_type: SLSA_PREDICATE_TYPE, - predicate: Predicate::new_github_actions(), - } + predicate: Predicate::new_github_actions()?, + }) } } @@ -309,7 +325,7 @@ pub async fn generate_provenance( ); }; - let slsa = ProvenanceAttestation::new_github_actions(subjects); + let slsa = ProvenanceAttestation::new_github_actions(subjects)?; let attestation = serde_json::to_string(&slsa)?; let bundle = attest(http_client, &attestation, INTOTO_PAYLOAD_TYPE).await?; @@ -343,7 +359,9 @@ pub async fn attest( testify(http_client, &content, &key_material.certificate).await?; // First log entry is the one we're interested in - let (_, log_entry) = transparency_logs.iter().next().unwrap(); + let (_, log_entry) = transparency_logs.iter().next().ok_or_else(|| { + anyhow::anyhow!("No transparency log entries returned from Rekor") + })?; let bundle = ProvenanceBundle { media_type: "application/vnd.in-toto+json", @@ -731,7 +749,7 @@ mod tests { env::set_var("RUNNER_ENVIRONMENT", "github-hosted"); env::set_var( "GITHUB_WORKFLOW_REF", - "littledivy/deno_sdl2@refs/tags/sdl2@0.0.1", + "littledivy/deno_sdl2/.github/workflows/publish.yml@refs/tags/sdl2@0.0.1", ) } } @@ -742,7 +760,8 @@ mod tests { sha256: "yourmom".to_string(), }, }; - let slsa = ProvenanceAttestation::new_github_actions(vec![subject]); + let slsa = + ProvenanceAttestation::new_github_actions(vec![subject]).unwrap(); assert_eq!( slsa.subject.len(), 1,