Skip to main content

pedant_types/
attestation.rs

1use serde::{Deserialize, Serialize};
2
3use crate::CapabilityProfile;
4
5/// How deeply the source was analyzed, affecting finding accuracy.
6#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash)]
7#[serde(rename_all = "snake_case")]
8pub enum AnalysisTier {
9    /// Pattern-based detection on unresolved syntax trees.
10    Syntactic,
11    /// Type-resolved analysis via rust-analyzer.
12    Semantic,
13    /// Full inter-procedural data-flow tracking.
14    DataFlow,
15}
16
17/// How complete capability extraction was for a hashed source set.
18#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Default)]
19pub struct AnalysisCompleteness {
20    /// Number of reachable files whose capabilities were analyzed successfully.
21    pub analyzed_files: usize,
22    /// Number of reachable files that were hashed but skipped for capability analysis.
23    pub skipped_files: usize,
24    /// Relative paths of hashed files that could not be analyzed.
25    #[serde(default, skip_serializing_if = "<[Box<str>]>::is_empty")]
26    pub skipped_paths: Box<[Box<str>]>,
27    /// Per-file analysis failures for hashed files that were skipped.
28    #[serde(default, skip_serializing_if = "<[SkippedAnalysis]>::is_empty")]
29    pub skipped_details: Box<[SkippedAnalysis]>,
30}
31
32impl AnalysisCompleteness {
33    /// Returns true when capability extraction succeeded for all hashed files.
34    pub fn is_complete(&self) -> bool {
35        self.skipped_files == 0
36    }
37}
38
39/// A hashed file that capability analysis skipped, with the cause.
40#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
41pub struct SkippedAnalysis {
42    /// Relative path of the hashed file.
43    pub path: Box<str>,
44    /// Human-readable reason the file could not be analyzed.
45    pub error: Box<str>,
46}
47
48/// Signed attestation binding a source hash to its capability profile.
49#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
50pub struct AttestationContent {
51    /// Schema version for forward compatibility (e.g., `"0.1.0"`).
52    pub spec_version: Box<str>,
53    /// SHA-256 digest of the concatenated source files.
54    pub source_hash: Box<str>,
55    /// Crate name from `Cargo.toml`.
56    pub crate_name: Box<str>,
57    /// Crate version from `Cargo.toml`.
58    pub crate_version: Box<str>,
59    /// How deeply the source was analyzed.
60    pub analysis_tier: AnalysisTier,
61    /// UTC seconds since Unix epoch.
62    pub timestamp: u64,
63    /// Whether capability analysis covered all hashed files.
64    #[serde(default, skip_serializing_if = "Option::is_none")]
65    pub analysis_completeness: Option<AnalysisCompleteness>,
66    /// Declared `package.rust-version` from the dependency's `Cargo.toml`,
67    /// when available. Populated for Cargo supply-chain attestations only.
68    #[serde(default, skip_serializing_if = "Option::is_none")]
69    pub rust_version: Option<Box<str>>,
70    /// Capability findings from the analysis.
71    pub profile: CapabilityProfile,
72}