sigstore_verification/verifiers/
github.rs

1use crate::Result;
2use crate::bundle::ParsedBundle;
3use crate::verifiers::{Policy, VerificationResult, Verifier};
4use async_trait::async_trait;
5use log::debug;
6use std::path::Path;
7
8/// GitHub Actions attestation verifier
9/// Specializes in verifying GitHub-generated attestations with workflow identity
10pub struct GitHubVerifier {
11    /// Expected repository (e.g., "owner/repo")
12    pub repository: Option<String>,
13    /// Expected workflow path (e.g., ".github/workflows/release.yml")
14    pub workflow: Option<String>,
15}
16
17impl GitHubVerifier {
18    pub fn new() -> Self {
19        Self {
20            repository: None,
21            workflow: None,
22        }
23    }
24
25    pub fn with_repository(mut self, repo: impl Into<String>) -> Self {
26        self.repository = Some(repo.into());
27        self
28    }
29
30    pub fn with_workflow(mut self, workflow: impl Into<String>) -> Self {
31        self.workflow = Some(workflow.into());
32        self
33    }
34}
35
36impl Default for GitHubVerifier {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42#[async_trait]
43impl Verifier for GitHubVerifier {
44    async fn verify(
45        &self,
46        bundle: &ParsedBundle,
47        artifact_path: &Path,
48        policy: &Policy,
49    ) -> Result<VerificationResult> {
50        debug!(
51            "Starting GitHub attestation verification for {:?}",
52            artifact_path
53        );
54
55        // Use the workflow from policy if not set on verifier
56        let expected_workflow = policy
57            .signer_workflow
58            .as_deref()
59            .or(self.workflow.as_deref());
60
61        // Reuse existing GitHub verification logic
62        let attestations = vec![crate::api::Attestation {
63            bundle: Some(serde_json::from_slice(&bundle.payload)?),
64            bundle_url: None,
65        }];
66
67        crate::verify::verify_attestations(&attestations, artifact_path, expected_workflow).await?;
68
69        // Extract certificate info for the result
70        let cert_info = if let Some(cert) = &bundle.certificate {
71            Some(crate::verify::verify_certificate(cert)?)
72        } else {
73            None
74        };
75
76        Ok(VerificationResult {
77            success: true,
78            slsa_level: Some(3), // GitHub Actions attestations are SLSA L3
79            certificate_identity: cert_info.as_ref().and_then(|ci| ci.repository.clone()),
80            builder_identity: cert_info.as_ref().and_then(|ci| ci.workflow_ref.clone()),
81            messages: vec![
82                "GitHub attestation verification successful".to_string(),
83                format!("Workflow: {}", expected_workflow.unwrap_or("any")),
84            ],
85        })
86    }
87
88    fn verifier_type(&self) -> &'static str {
89        "GitHub"
90    }
91}