Skip to main content

clawft_kernel/licence/
gate.rs

1//! The run gate (ADR-106 section 4, step 7): bytes are installed or run only
2//! with BOTH a valid grant for this mesh and an operator hash approval whose
3//! sha256 set covers the binary. A grant alone never makes bytes runnable,
4//! and the grant key cannot sign an approval. Not wired into placement yet
5//! (phase 3); exported and tested here.
6
7use super::{ApprovalStore, CheckoutGrantStore};
8
9/// What is about to be installed or run.
10#[derive(Debug, Clone, Copy)]
11pub struct RunRequest<'a> {
12    /// Cog id.
13    pub cog_id: &'a str,
14    /// Cog version.
15    pub version: &'a str,
16    /// sha256 of the binary, lower-case hex, computed from the bytes.
17    pub sha256: &'a str,
18    /// BLAKE3 of the binary, lower-case hex, computed from the bytes (never
19    /// copied from a grant: the revocation check is made on this value).
20    pub blake3: &'a str,
21}
22
23/// Why the gate refused.
24#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
25pub enum RunDenied {
26    /// No valid grant for this mesh lists a binary with exactly this
27    /// (sha256, blake3) pair.
28    #[error("no valid checkout grant covers this binary")]
29    NoValidGrant,
30    /// No operator approval for this cog version covers this sha256.
31    #[error("no operator approval covers this binary")]
32    NoApproval,
33    /// The binary's BLAKE3 is revoked (this also withdraws its approval).
34    #[error("the binary's hash is revoked")]
35    HashRevoked,
36}
37
38/// Evidence for the run, for provenance.
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct RunPermit {
41    /// The covering grant's id.
42    pub grant_id: String,
43    /// The covering approval's content key.
44    pub approval_id: String,
45    /// The binary's BLAKE3, lower-case hex.
46    pub blake3: String,
47}
48
49/// May `req` be installed or run? Needs a valid grant and a covering approval,
50/// and the binary's `ArtifactHash` must not be revoked.
51pub fn may_run(
52    grants: &CheckoutGrantStore,
53    approvals: &ApprovalStore,
54    req: &RunRequest<'_>,
55) -> Result<RunPermit, RunDenied> {
56    let (grant, art) = grants
57        .valid_grant_for_artifact(req.cog_id, req.version, req.sha256, req.blake3)
58        .ok_or(RunDenied::NoValidGrant)?;
59    if grants.is_hash_revoked(req.blake3) {
60        return Err(RunDenied::HashRevoked);
61    }
62    let approval_id = approvals
63        .covering(req.cog_id, req.version, req.sha256)
64        .ok_or(RunDenied::NoApproval)?;
65    Ok(RunPermit { grant_id: grant.grant_id, approval_id, blake3: art.blake3 })
66}