Skip to main content

deputy_core/
traits.rs

1use crate::error::Result;
2use crate::ids::{ArtifactRef, ContentHash, EcosystemId, Pin, SourceId};
3use crate::state::ScanVerdict;
4
5/// Which store a content-addressed artifact lives in. The dirty store is staging; the
6/// prod store is the trusted, append-only golden set (`docs/ARCHITECTURE.md` §4).
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum StoreKind {
9    Dirty,
10    Prod,
11}
12
13/// An acquirable dependency ecosystem. Cargo is the first implementor; npm/PyPI/Go follow
14/// without pipeline-core changes (`docs/PIPELINE.md` §0).
15///
16/// Method signatures are synchronous contracts; I/O-bound implementations may bridge to an
17/// async runtime internally. An implementor produces candidates for the **dirty** store
18/// only — it can never write to prod, and verification (hash/signature) is enforced by core
19/// callers, not by the implementor (`docs/THREAT_MODEL.md` ADV-6).
20pub trait DepEcosystem {
21    fn id(&self) -> EcosystemId;
22
23    /// Read the source's resolved, pinned dependency graph as [`Pin`]s — each an exact
24    /// name+version bound to its expected content hash. For Cargo these come straight from
25    /// `Cargo.lock` (`name`, `version`, `checksum`), so the pins are already tamper-evident.
26    /// Dependencies without a fetchable registry checksum (path/git/workspace members) are
27    /// omitted.
28    fn discover(&self, source: &SourceId) -> Result<Vec<Pin>>;
29
30    /// Download the artifact bytes for a pin. The bytes are untrusted until verified.
31    fn fetch(&self, pin: &Pin) -> Result<Vec<u8>>;
32
33    /// Verify downloaded bytes against the pin's expected hash. Errors on mismatch.
34    fn verify_integrity(&self, pin: &Pin, raw: &[u8]) -> Result<()>;
35}
36
37/// Content-addressed artifact storage. The address is the hash of the bytes (ecosystem is a
38/// higher-level annotation, not part of storage). Implementations seal every artifact at rest
39/// with AES-256-GCM under a per-artifact subkey (`docs/STORAGE.md` §2).
40pub trait ArtifactStore {
41    /// Store bytes and return their content address. Idempotent: storing the same bytes
42    /// twice yields the same `ContentHash` and is a no-op the second time.
43    fn put(&self, kind: StoreKind, raw: &[u8]) -> Result<ContentHash>;
44
45    /// Retrieve and decrypt previously stored bytes by content address.
46    fn get(&self, kind: StoreKind, hash: &ContentHash) -> Result<Vec<u8>>;
47
48    /// Whether the given store holds the artifact with this content address.
49    fn contains(&self, kind: StoreKind, hash: &ContentHash) -> Result<bool>;
50}
51
52/// Encrypted metadata: scan verdicts, promotion receipts, and graph annotations
53/// (`docs/STORAGE.md` §4).
54pub trait MetadataStore {
55    fn record_verdict(&self, artifact: &ArtifactRef, verdict: &ScanVerdict) -> Result<()>;
56    fn verdict(&self, artifact: &ArtifactRef) -> Result<Option<ScanVerdict>>;
57}