Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 54 additions & 35 deletions cli/tools/publish/provenance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self, AnyError> {
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 {
Expand All @@ -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
),
},
},
}
})
}
}

Expand All @@ -236,13 +252,13 @@ struct ProvenanceAttestation {
}

impl ProvenanceAttestation {
pub fn new_github_actions(subjects: Vec<Subject>) -> Self {
Self {
pub fn new_github_actions(subjects: Vec<Subject>) -> Result<Self, AnyError> {
Ok(Self {
_type: INTOTO_STATEMENT_TYPE,
subject: subjects,
predicate_type: SLSA_PREDICATE_TYPE,
predicate: Predicate::new_github_actions(),
}
predicate: Predicate::new_github_actions()?,
})
}
}

Expand Down Expand Up @@ -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?;
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
)
}
}
Expand All @@ -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,
Expand Down
Loading