use std::path::PathBuf;
use antigen_macros::presents;
use serde::{Deserialize, Serialize};
use crate::scan::Immunity;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "status", rename_all = "snake_case")]
pub enum WitnessStatus {
Resolved {
location: PathBuf,
witness_kind: WitnessKind,
},
External {
tool_hint: String,
},
Ambiguous {
candidates: Vec<PathBuf>,
},
NotFound {
reason: String,
},
Missing,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum WitnessKind {
Test,
IgnoredTest,
Proptest,
Function,
PhantomType {
proof_type: String,
type_params: Vec<String>,
constructor: Option<String>,
},
SubstrateWitness {
kind: antigen_attestation::RatificationKind,
},
CrossCrateWitness,
}
#[presents(ParallelStateTrackersDiverge)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "snake_case")]
pub enum WitnessTier {
None = 0,
Reachability = 1,
Execution = 2,
FormalProof = 4,
}
#[presents(DeclaredCapabilityWithNoProductionPath)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub enum AuditHint {
NoneApplicable,
FunctionResolves,
TestAttributePresentNotInvoked,
TestAttributePresentIgnoreSkipped,
ProptestPresentNotInvoked,
ExternalToolPrefixRecognized,
ExternalToolInvoked,
PhantomTypeShapeRecognized,
PhantomTypeConstructionValidated,
AmbiguousResolution,
FabricatedPathPrefix,
InheritedPresentationNotReAttested,
DescendedFromFingerprintDivergence,
DisciplineSidecarMissing,
DisciplineSidecarSchemaInvalid,
DisciplinePredicateFailed,
DisciplinePredicateDeferred,
DisciplineSubstrateStale,
DisciplineSubstrateDeltaChainNearCap,
DisciplinePredicatePassedViaDeltaChain,
DisciplinePredicatePassedSubstrateCurrent,
ToleranceVibesGrade,
ToleranceSidecarMissing,
TolerancePredicateFailed,
TolerancePredicatePassedSubstrateCurrent,
DisciplineSidecarKindMismatchExpectedImmunityGotTolerance,
ToleranceSidecarKindMismatchExpectedToleranceGotImmunity,
DisciplineImmunityToleranceContradiction,
AnergyActive,
AnergyCostimulationNotArrived,
AnergyStale,
ImmunosuppressActive,
ImmunosuppressExpired,
ImmunosuppressDurationCapExceeded,
PoxpartyActive,
PoxpartyOutcomePending,
PoxpartyOutcomeRecorded,
PoxpartyOutsideIsolation,
OrientActive,
OrientPendingActionRequired,
DeferredDefenseHintSuppressedWithoutRationale,
UnpinnedDependency,
UnpinnedTransitiveDependency,
UnattestedDependencyInclusion,
DependencyUpgradeWithoutDiffReview,
MaintainerChangeWithoutReattestation,
MaintainerChangeDetectedAfterCargoUpdate,
SuddenDependencyExpansion,
UnsandboxedBuildScript,
UnsandboxedProcMacro,
PostInstallScriptInDependency,
ContentHashMismatch,
ContentHashNoAttestation,
DepAttestWithoutReviewableArtifact,
CratesIoMetadataQueryFailed,
DepAttestationStale,
AutoDependencyChainWithoutPinning,
ContentHashSidecarMalformed,
MalformedRequiresPredicate,
DiagnosticModalityInsufficient,
DiagnosticModalitiesClassCollapsed,
DiagnosticModalitiesEmpty,
DiagnosticMinIndependentZero,
IggMinReattestationsZero,
ClonalFixedSeedDetected,
ClonalIterationsBelowThreshold,
IggIdentityCollapseWarning,
IggSpanTooShort,
IggReattestationsInsufficient,
CrossreactiveFingerprintUnresolved,
PolyclonalInsufficientLineages,
AdccSingleMechanismOnly,
ItchNoticedNotAnchored,
RecurrenceThresholdReachedNoAction,
RecurrenceAnchorNoItchPrecondition,
CrystallizeWithoutAntigen,
ChronicSignalUnmanaged,
ChronicSignalPastReviewDate,
ChronicSinceNotADate,
SaturateNoAnchor,
StrandNoAnchors,
MucosalBoundaryUndefended,
MucosalKindMismatch,
MucosalRationaleInsufficient,
MucosalDisciplineDelegateTargetMissing,
MucosalDisciplineDelegateTargetNotMucosal,
MucosalDisciplineDelegateTargetKindMismatch,
MucosalDisciplineDelegateTargetAmbiguous,
MucosalTolerantRationaleInsufficient,
MucosalTolerantPastReviewDate,
MucosalTolerantAcceptsEmpty,
MucosalTolerantWithoutReviewer,
AntigenCategoryDefaultedImplicitFunctional,
AntigenCategoryClaimInconsistentWithPredicateType,
AntigenCategoryHybridIncompleteEvidence,
AntigenWitnessShapeMismatchForSilenceNoWitness,
AntigenWitnessShapeMismatchForSilenceWrongTier,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImmunityAudit {
pub immunity: Immunity,
pub witness_status: WitnessStatus,
pub witness_tier: WitnessTier,
pub audit_hint: AuditHint,
#[serde(default = "default_evidence_kind")]
pub evidence_kind: antigen_attestation::EvidenceKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub signature_strength: Option<antigen_attestation::SignatureStrength>,
#[serde(default)]
pub compound_evidence: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub evaluated_predicate: Option<String>,
#[serde(default)]
pub code_witness_sidecar_ignored: bool,
#[serde(default)]
pub leaf_outcomes: Vec<antigen_attestation::LeafOutcome>,
}
const fn default_evidence_kind() -> antigen_attestation::EvidenceKind {
antigen_attestation::EvidenceKind::None
}
impl ImmunityAudit {
#[must_use]
pub const fn has_witness(&self) -> bool {
!matches!(self.witness_tier, WitnessTier::None)
}
#[must_use]
pub fn meets_tier(&self, minimum: WitnessTier) -> bool {
self.witness_tier >= minimum
}
#[must_use]
pub fn is_well_formed(&self) -> bool {
self.meets_tier(WitnessTier::Execution)
}
}
impl WitnessTier {
#[must_use]
pub const fn from_status(status: &WitnessStatus) -> Self {
match status {
WitnessStatus::Missing
| WitnessStatus::NotFound { .. }
| WitnessStatus::Ambiguous { .. } => Self::None,
WitnessStatus::External { .. } => Self::Reachability,
WitnessStatus::Resolved { witness_kind, .. } => match witness_kind {
WitnessKind::Test
| WitnessKind::IgnoredTest
| WitnessKind::Proptest
| WitnessKind::Function => Self::Reachability,
WitnessKind::PhantomType { .. } => Self::FormalProof,
WitnessKind::SubstrateWitness { .. } | WitnessKind::CrossCrateWitness => {
Self::Reachability
},
},
}
}
}
#[must_use]
pub const fn evidence_kind_from_status(
status: &WitnessStatus,
) -> antigen_attestation::EvidenceKind {
match status {
WitnessStatus::Missing
| WitnessStatus::NotFound { .. }
| WitnessStatus::Ambiguous { .. } => antigen_attestation::EvidenceKind::None,
WitnessStatus::External { .. } => antigen_attestation::EvidenceKind::Behavioral,
WitnessStatus::Resolved { witness_kind, .. } => match witness_kind {
WitnessKind::Test
| WitnessKind::IgnoredTest
| WitnessKind::Proptest
| WitnessKind::Function => antigen_attestation::EvidenceKind::Behavioral,
WitnessKind::PhantomType { .. } => antigen_attestation::EvidenceKind::TypeSystemProof,
WitnessKind::SubstrateWitness { .. } | WitnessKind::CrossCrateWitness => {
antigen_attestation::EvidenceKind::SubstrateState
},
},
}
}
impl AuditHint {
#[must_use]
pub const fn from_status(status: &WitnessStatus) -> Self {
match status {
WitnessStatus::Missing | WitnessStatus::NotFound { .. } => Self::NoneApplicable,
WitnessStatus::Ambiguous { .. } => Self::AmbiguousResolution,
WitnessStatus::External { .. } => Self::ExternalToolPrefixRecognized,
WitnessStatus::Resolved { witness_kind, .. } => match witness_kind {
WitnessKind::Test => Self::TestAttributePresentNotInvoked,
WitnessKind::IgnoredTest => Self::TestAttributePresentIgnoreSkipped,
WitnessKind::Proptest => Self::ProptestPresentNotInvoked,
WitnessKind::Function => Self::FunctionResolves,
WitnessKind::PhantomType { .. } => Self::PhantomTypeShapeRecognized,
WitnessKind::SubstrateWitness { .. } | WitnessKind::CrossCrateWitness => {
Self::ExternalToolPrefixRecognized
},
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InheritedUnaddressed {
pub presentation: crate::scan::Presentation,
pub audit_hint: AuditHint,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AuditReport {
pub audits: Vec<ImmunityAudit>,
pub resolved_count: usize,
pub external_count: usize,
pub ambiguous_count: usize,
pub broken_count: usize,
pub missing_count: usize,
#[serde(default)]
pub inherited_unaddressed: Vec<InheritedUnaddressed>,
#[serde(default)]
pub presentation_verdicts: Vec<PresentationVerdict>,
}
impl AuditReport {
#[must_use]
pub fn all_valid(&self) -> bool {
self.audits.iter().all(ImmunityAudit::is_well_formed)
}
#[must_use]
pub fn all_meet_tier(&self, minimum: WitnessTier) -> bool {
self.audits.iter().all(|a| a.meets_tier(minimum))
}
#[must_use]
pub fn problematic_audits(&self) -> Vec<&ImmunityAudit> {
self.audits.iter().filter(|a| !a.is_well_formed()).collect()
}
#[must_use]
pub fn undefended_verdicts(&self) -> Vec<&PresentationVerdict> {
self.presentation_verdicts
.iter()
.filter(|v| matches!(v.verdict, ImmuneVerdict::Undefended))
.collect()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "verdict", rename_all = "kebab-case")]
pub enum ImmuneVerdict {
Defended {
tier: WitnessTier,
},
Undefended,
SubstrateGap,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum WorkVerdict {
Pending,
Fulfilled,
Overdue,
OutOfFrame,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FrameState {
None,
Within,
Past,
Unparseable,
}
impl FrameState {
#[must_use]
pub fn classify(frame: Option<&str>, today: chrono::NaiveDate) -> Self {
frame.map_or(Self::None, |s| {
match chrono::NaiveDate::parse_from_str(s.trim(), "%Y-%m-%d") {
Ok(d) if d >= today => Self::Within,
Ok(_) => Self::Past,
Err(_) => Self::Unparseable,
}
})
}
}
impl WorkVerdict {
#[must_use]
pub const fn project(satisfied: bool, evaluable: bool, frame: FrameState) -> Self {
if !evaluable {
return Self::OutOfFrame;
}
if satisfied {
return Self::Fulfilled;
}
match frame {
FrameState::Past => Self::Overdue,
FrameState::Within | FrameState::None => Self::Pending,
FrameState::Unparseable => Self::OutOfFrame,
}
}
#[must_use]
pub const fn is_loud(self) -> bool {
matches!(self, Self::Overdue)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PresentationVerdict {
pub presentation: crate::scan::Presentation,
pub antigen_type: String,
pub verdict: ImmuneVerdict,
#[serde(default)]
pub defended_by: Vec<String>,
}
pub const CLONAL_ITERATIONS_DEFAULT_FLOOR: u64 = 100;
pub const IGG_HISTORICAL_SPAN_DEFAULT_FLOOR: u64 = 30;