provenance/src/error.rs
//! Why a piece of provenance was refused. Every variant carries one frozen
//! `holger-provenance-<n>` code; [`ProvenanceError::code`] is an exhaustive match,
//! so a new refusal without a code does not compile.
use holger_errcode as ec;
/// A refusal, with the reason in words.
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum ProvenanceError {
/// Nothing about these bytes was offered, and provenance is required.
#[error("no provenance about these bytes was offered: {0}")]
Missing(String),
/// The statement or signature names other bytes.
#[error("the attestation is about other bytes: {0}")]
SubjectMismatch(String),
/// A signature does not verify over the exact signed bytes.
#[error("the signature does not verify: {0}")]
SignatureInvalid(String),
/// The signer is not an allowed key and does not chain to the pinned root.
#[error("the signer is not trusted: {0}")]
SignerUntrusted(String),
/// The certificate's issuer and subject are not an allowed identity.
#[error("the signing identity is not allowed: {0}")]
IdentityMismatch(String),
/// The SLSA builder is not allowed.
#[error("the builder is not allowed: {0}")]
BuilderNotAllowed(String),
/// The SLSA build level is below the minimum.
#[error("the SLSA build level is too low: {0}")]
SlsaLevelTooLow(String),
/// The transparency-log entry does not verify.
#[error("the transparency-log entry does not verify: {0}")]
TlogUnverified(String),
/// The material cannot be read.
#[error("the attestation material cannot be read: {0}")]
Malformed(String),
/// The trust root is missing or does not verify.
#[error("the Sigstore trust root is not usable: {0}")]
TrustRoot(String),
/// The policy cannot mean what it says.
#[error("the provenance policy is not valid: {0}")]
PolicyInvalid(String),
/// The certificate was not valid when the log saw the signature.
#[error("the signing certificate was not valid at the signing time: {0}")]
CertExpired(String),
/// Nothing signed was offered, and a signature is required.
#[error("nothing signed about these bytes was offered: {0}")]
Unsigned(String),
}
impl ProvenanceError {
/// The frozen code for this refusal.
pub fn code(&self) -> &'static ec::ErrCode {
match self {
ProvenanceError::Missing(_) => &ec::PROVENANCE_MISSING,
ProvenanceError::SubjectMismatch(_) => &ec::PROVENANCE_SUBJECT_MISMATCH,
ProvenanceError::SignatureInvalid(_) => &ec::PROVENANCE_SIGNATURE_INVALID,
ProvenanceError::SignerUntrusted(_) => &ec::PROVENANCE_SIGNER_UNTRUSTED,
ProvenanceError::IdentityMismatch(_) => &ec::PROVENANCE_IDENTITY_MISMATCH,
ProvenanceError::BuilderNotAllowed(_) => &ec::PROVENANCE_BUILDER_NOT_ALLOWED,
ProvenanceError::SlsaLevelTooLow(_) => &ec::PROVENANCE_SLSA_LEVEL_TOO_LOW,
ProvenanceError::TlogUnverified(_) => &ec::PROVENANCE_TLOG_UNVERIFIED,
ProvenanceError::Malformed(_) => &ec::PROVENANCE_MALFORMED,
ProvenanceError::TrustRoot(_) => &ec::PROVENANCE_TRUST_ROOT,
ProvenanceError::PolicyInvalid(_) => &ec::PROVENANCE_POLICY_INVALID,
ProvenanceError::CertExpired(_) => &ec::PROVENANCE_CERT_EXPIRED,
ProvenanceError::Unsigned(_) => &ec::PROVENANCE_UNSIGNED,
}
}
/// `[holger-provenance-<n>] <sentence>`, the shape every Holger subsystem emits.
pub fn tagged(&self) -> String {
self.code().tag(self)
}
/// The bare wire code, `holger-provenance-<n>`.
pub fn code_str(&self) -> &'static str {
self.code().code
}
}
/// Shorthand.
pub type Result<T> = std::result::Result<T, ProvenanceError>;