delegated 0.2.2

Minimal fail-closed capability-token evaluation core
Documentation
//! Wire models, trusted operation context, decisions, and audit events.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::fmt::{Display, Formatter};

/// A fail-closed validation or evaluation failure.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Violation {
    /// Stable pipeline stage at which evaluation stopped.
    pub stage: &'static str,
    /// Operator-facing reason for denial.
    pub reason: String,
}

impl Violation {
    /// Creates a violation for a stable stage and explanatory reason.
    pub fn new(stage: &'static str, reason: impl Into<String>) -> Self {
        Self {
            stage,
            reason: reason.into(),
        }
    }
}

impl Display for Violation {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}: {}", self.stage, self.reason)
    }
}

impl Error for Violation {}

/// A bearer capability issued by a configured, trusted issuer.
///
/// Every authorization-relevant field is covered by `signature`. The issuer key is
/// resolved from host configuration; no key material supplied by the caller is trusted.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct DelegationToken {
    /// Wire-format version; currently `0.2`.
    pub spec_version: String,
    /// Object discriminator; currently `DelegatedCapability`.
    pub kind: String,
    /// Issuer-scoped identifier used for revocation.
    pub token_id: String,
    /// Issuer identifier used with `key_id` to resolve a trusted key.
    pub issuer: String,
    /// Agent identity asserted by the issuer.
    pub agent_id: String,
    /// Delegating principal identity asserted by the issuer.
    pub delegator_id: String,
    /// Services or trust domains permitted to accept the capability.
    pub audience: Vec<String>,
    /// Exact host-defined action identifiers authorized by the capability.
    pub allowed_actions: Vec<String>,
    /// Optional exact host-defined resource identifiers.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub allowed_resources: Option<Vec<String>>,
    /// Optional upper bound on trusted host-supplied delegation depth.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_delegation_depth: Option<u16>,
    /// Capability activation time.
    pub issued_at: DateTime<Utc>,
    /// Capability expiry time.
    pub expires_at: DateTime<Utc>,
    /// Issuer-unique replay nonce consumed on the first successful evaluation.
    pub nonce: String,
    /// Identifier of the trusted issuer key that signs this token.
    pub key_id: String,
    /// Signature algorithm; only `Ed25519` is accepted.
    pub signature_alg: String,
    /// Base64url-no-pad Ed25519 signature over the canonical unsigned token.
    pub signature: String,
}

/// The untrusted wire wrapper. It intentionally does not contain action, audience,
/// resource, or policy context; those values must come from the host operation.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RequestEnvelope {
    /// Wire-format version; currently `0.2`.
    pub spec_version: String,
    /// Object discriminator; currently `DelegatedRequest`.
    pub kind: String,
    /// Optional caller correlation identifier; it has no authorization effect.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub request_id: Option<String>,
    /// Issuer-signed bearer capability presented for evaluation.
    pub delegation_token: DelegationToken,
}

/// Authorization facts derived by the host from the operation that will actually run.
/// Never construct this from fields in the request envelope.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OperationContext {
    /// Host-defined audience of the component that will execute the operation.
    pub audience: String,
    /// Host-derived action that will actually execute.
    pub action: String,
    /// Optional host-derived resource that will actually be accessed.
    pub resource: Option<String>,
    /// Optional delegation depth maintained by trusted host infrastructure.
    pub delegation_depth: Option<u16>,
}

impl OperationContext {
    /// Creates trusted operation context for an audience and action.
    pub fn new(audience: impl Into<String>, action: impl Into<String>) -> Self {
        Self {
            audience: audience.into(),
            action: action.into(),
            resource: None,
            delegation_depth: None,
        }
    }

    /// Adds the exact resource that the host intends to access.
    pub fn with_resource(mut self, resource: impl Into<String>) -> Self {
        self.resource = Some(resource.into());
        self
    }

    /// Adds delegation depth maintained by trusted host infrastructure.
    pub fn with_delegation_depth(mut self, depth: u16) -> Self {
        self.delegation_depth = Some(depth);
        self
    }
}

/// Final allow or deny result returned by evaluation.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Decision {
    /// Whether the operation may execute.
    pub allowed: bool,
    /// Stable pipeline stage that produced the result.
    pub stage: String,
    /// Human-readable explanation suitable for logs and operator diagnostics.
    pub reason: String,
}

impl Decision {
    /// Creates an allow decision.
    pub fn allow(stage: impl Into<String>, reason: impl Into<String>) -> Self {
        Self {
            allowed: true,
            stage: stage.into(),
            reason: reason.into(),
        }
    }

    /// Creates a deny decision.
    pub fn deny(stage: impl Into<String>, reason: impl Into<String>) -> Self {
        Self {
            allowed: false,
            stage: stage.into(),
            reason: reason.into(),
        }
    }
}

/// Structured record of one authorization decision.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuditEvent {
    /// Host-supplied evaluation timestamp.
    pub occurred_at: DateTime<Utc>,
    /// Whether the operation was authorized.
    pub allowed: bool,
    /// Stable evaluation stage that produced the decision.
    pub stage: String,
    /// Human-readable decision reason.
    pub reason: String,
    /// False means identity fields were copied from untrusted input for diagnostics only.
    pub claims_verified: bool,
    /// Optional untrusted request correlation identifier.
    pub request_id: Option<String>,
    /// Token identifier, or untrusted diagnostic input when `claims_verified` is false.
    pub token_id: Option<String>,
    /// Issuer identifier, or untrusted diagnostic input when `claims_verified` is false.
    pub issuer: Option<String>,
    /// Agent identifier, or untrusted diagnostic input when `claims_verified` is false.
    pub agent_id: Option<String>,
    /// Delegator identifier, or untrusted diagnostic input when `claims_verified` is false.
    pub delegator_id: Option<String>,
    /// Trusted host audience evaluated for this decision.
    pub audience: String,
    /// Trusted host action evaluated for this decision.
    pub action: String,
    /// Trusted host resource evaluated for this decision.
    pub resource: Option<String>,
}