use super::*;
use crate::registry_core::declaration::PluginSource;
use std::fmt;
#[derive(Clone, Debug)]
pub struct PluginArtifact {
pub registration: crate::RegistrationInfo,
pub bytes: Vec<u8>,
pub key_fingerprint: Option<String>,
}
#[derive(Clone, Debug)]
pub struct VerifiedPluginArtifact {
registration: crate::RegistrationInfo,
bytes: Vec<u8>,
assurance: PluginAssurance,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum PluginAssurance {
Digest,
Signature,
}
impl VerifiedPluginArtifact {
pub const fn registration(&self) -> crate::RegistrationInfo {
self.registration
}
pub fn bytes(&self) -> &[u8] {
&self.bytes
}
pub const fn assurance(&self) -> PluginAssurance {
self.assurance
}
pub fn into_parts(self) -> (crate::RegistrationInfo, Vec<u8>) {
(self.registration, self.bytes)
}
}
impl PluginArtifact {
pub fn verify_artifact(
self,
policy: PluginTrustPolicy,
) -> Result<VerifiedPluginArtifact, PluginTrustError> {
let manifest = self
.registration
.plugin
.ok_or(PluginTrustError::MissingManifest)?;
policy.verify(manifest, &self.bytes, self.key_fingerprint.as_deref())?;
Ok(VerifiedPluginArtifact {
registration: self.registration,
bytes: self.bytes,
assurance: PluginAssurance::Digest,
})
}
pub fn verify_signed(
self,
policy: PluginTrustPolicy,
verifier: &impl PluginSignatureVerifier,
) -> Result<VerifiedPluginArtifact, PluginTrustError> {
let manifest = self
.registration
.plugin
.ok_or(PluginTrustError::MissingManifest)?;
if manifest.source != PluginSource::Official {
return Err(PluginTrustError::SignatureLaneRequired);
}
policy.verify_with(
manifest,
&self.registration,
&self.bytes,
self.key_fingerprint.as_deref(),
verifier,
)?;
Ok(VerifiedPluginArtifact {
registration: self.registration,
bytes: self.bytes,
assurance: PluginAssurance::Signature,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PluginDecision {
Accepted,
Rejected(PluginRejectReason),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PluginRejectReason {
FrameworkMismatch,
SourceDisabled,
InvalidDigest,
MissingSignature,
LockMismatch,
}
impl fmt::Display for PluginRejectReason {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::FrameworkMismatch => "framework mismatch",
Self::SourceDisabled => "plugin source disabled",
Self::InvalidDigest => "checksum is not a SHA-256 digest",
Self::MissingSignature => "official plugin signature is missing",
Self::LockMismatch => "official lock record mismatch",
})
}
}
pub(super) fn is_sha256(value: &str) -> bool {
let value = value.strip_prefix("sha256:").unwrap_or(value);
value.len() == 64 && value.bytes().all(|byte| byte.is_ascii_hexdigit())
}
#[cfg(test)]
#[path = "artifact_tests.rs"]
mod artifact_tests;