use chrono::{DateTime, Utc};
use cortex_core::{
revalidate_temporal_authority, KeyLifecycleState, PolicyContribution, PolicyDecision,
PolicyOutcome, TemporalAuthorityEvidence, TemporalAuthorityReport, TrustTier,
};
use rusqlite::{params, OptionalExtension, Row};
use crate::{Pool, StoreError, StoreResult};
pub const KEY_STATE_ATTESTED_BY_OPERATOR_RULE_ID: &str = "authority.key_state.attested_by_operator";
pub const KEY_STATE_TRUST_TIER_GATE_RULE_ID: &str = "authority.key_state.trust_tier_gate";
pub const PRINCIPAL_STATE_ATTESTED_BY_OPERATOR_RULE_ID: &str =
"authority.principal_state.attested_by_operator";
pub const PRINCIPAL_STATE_TRUST_TIER_GATE_RULE_ID: &str =
"authority.principal_state.trust_tier_gate";
pub const PRINCIPAL_STATE_TIER_PROMOTION_ATTESTATION_RULE_ID: &str =
"authority.principal_state.tier_promotion_attestation";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyTimelineRecord {
pub key_id: String,
pub principal_id: String,
pub state: KeyLifecycleState,
pub effective_at: DateTime<Utc>,
pub reason: Option<String>,
pub audit_ref: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PrincipalTimelineRecord {
pub principal_id: String,
pub trust_tier: TrustTier,
pub effective_at: DateTime<Utc>,
pub trust_review_due_at: Option<DateTime<Utc>>,
pub removed_at: Option<DateTime<Utc>>,
pub audit_ref: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TemporalAuthorityQuery {
pub key_id: String,
pub event_time: DateTime<Utc>,
pub now: DateTime<Utc>,
pub minimum_trust_tier: TrustTier,
}
#[derive(Debug)]
pub struct AuthorityRepo<'a> {
pool: &'a Pool,
}
impl<'a> AuthorityRepo<'a> {
#[must_use]
pub const fn new(pool: &'a Pool) -> Self {
Self { pool }
}
pub fn append_key_state(
&self,
record: &KeyTimelineRecord,
policy: &PolicyDecision,
) -> StoreResult<()> {
require_policy_final_outcome(policy, "authority.key_state")?;
require_contributor_rule(policy, KEY_STATE_ATTESTED_BY_OPERATOR_RULE_ID)?;
require_contributor_rule(policy, KEY_STATE_TRUST_TIER_GATE_RULE_ID)?;
require_attestation_not_break_glassed(
policy,
KEY_STATE_ATTESTED_BY_OPERATOR_RULE_ID,
"authority.key_state",
)?;
if matches!(record.state, KeyLifecycleState::Active) {
self.reject_active_key_for_undertrust_principal(record)?;
}
self.pool.execute(
"INSERT INTO authority_key_timeline (
key_id, principal_id, state, effective_at, reason, audit_ref
) VALUES (?1, ?2, ?3, ?4, ?5, ?6);",
params![
record.key_id,
record.principal_id,
key_state_wire(record.state),
record.effective_at.to_rfc3339(),
record.reason,
record.audit_ref,
],
)?;
Ok(())
}
pub fn append_principal_state(
&self,
record: &PrincipalTimelineRecord,
policy: &PolicyDecision,
) -> StoreResult<()> {
require_policy_final_outcome(policy, "authority.principal_state")?;
require_contributor_rule(policy, PRINCIPAL_STATE_ATTESTED_BY_OPERATOR_RULE_ID)?;
require_contributor_rule(policy, PRINCIPAL_STATE_TRUST_TIER_GATE_RULE_ID)?;
require_contributor_rule(policy, PRINCIPAL_STATE_TIER_PROMOTION_ATTESTATION_RULE_ID)?;
require_attestation_not_break_glassed(
policy,
PRINCIPAL_STATE_ATTESTED_BY_OPERATOR_RULE_ID,
"authority.principal_state",
)?;
require_attestation_not_break_glassed(
policy,
PRINCIPAL_STATE_TIER_PROMOTION_ATTESTATION_RULE_ID,
"authority.principal_state",
)?;
self.pool.execute(
"INSERT INTO authority_principal_timeline (
principal_id, trust_tier, effective_at, trust_review_due_at, removed_at, audit_ref
) VALUES (?1, ?2, ?3, ?4, ?5, ?6);",
params![
record.principal_id,
trust_tier_wire(record.trust_tier),
record.effective_at.to_rfc3339(),
record.trust_review_due_at.map(|value| value.to_rfc3339()),
record.removed_at.map(|value| value.to_rfc3339()),
record.audit_ref,
],
)?;
Ok(())
}
fn reject_active_key_for_undertrust_principal(
&self,
record: &KeyTimelineRecord,
) -> StoreResult<()> {
let current_trust = self.principal_state_at(&record.principal_id, record.effective_at)?;
match current_trust {
Some(state) if state.trust_tier < TrustTier::Verified => {
Err(StoreError::Validation(format!(
"authority.key_state preflight: refuse to activate key `{}` for principal `{}` while current trust tier `{:?}` is below `Verified`",
record.key_id, record.principal_id, state.trust_tier,
)))
}
None => Err(StoreError::Validation(format!(
"authority.key_state preflight: refuse to activate key `{}` for principal `{}` without a current trust tier row",
record.key_id, record.principal_id,
))),
Some(_) => Ok(()),
}
}
pub fn revalidate(
&self,
query: &TemporalAuthorityQuery,
) -> StoreResult<TemporalAuthorityReport> {
let key_at_event = self.key_state_at(&query.key_id, query.event_time)?;
let current_key_state = self.key_state_at(&query.key_id, query.now)?;
let key_activated_at = self.key_state_effective_at(
&query.key_id,
KeyLifecycleState::Active,
query.event_time,
)?;
let key_retired_at =
self.key_state_effective_at(&query.key_id, KeyLifecycleState::Retired, query.now)?;
let key_revoked_at =
self.key_state_effective_at(&query.key_id, KeyLifecycleState::Revoked, query.now)?;
let principal_id = key_at_event
.as_ref()
.or(current_key_state.as_ref())
.map(|record| record.principal_id.clone());
let trust_at_event = match principal_id.as_deref() {
Some(principal_id) => self.principal_state_at(principal_id, query.event_time)?,
None => None,
};
let current_trust = match principal_id.as_deref() {
Some(principal_id) => self.principal_state_at(principal_id, query.now)?,
None => None,
};
Ok(revalidate_temporal_authority(TemporalAuthorityEvidence {
key_id: query.key_id.clone(),
principal_id,
event_time: query.event_time,
now: query.now,
key_activated_at,
key_retired_at,
key_revoked_at,
trust_tier_at_event_time: trust_at_event.as_ref().map(|record| record.trust_tier),
current_trust_tier: current_trust.as_ref().map(|record| record.trust_tier),
current_trust_tier_effective_at: current_trust
.as_ref()
.map(|record| record.effective_at),
minimum_trust_tier: query.minimum_trust_tier,
principal_removed_at: current_trust.as_ref().and_then(|record| record.removed_at),
trust_review_due_at: current_trust
.as_ref()
.and_then(|record| record.trust_review_due_at),
}))
}
fn key_state_at(
&self,
key_id: &str,
at: DateTime<Utc>,
) -> StoreResult<Option<KeyTimelineRecord>> {
let row = self
.pool
.query_row(
"SELECT key_id, principal_id, state, effective_at, reason, audit_ref
FROM authority_key_timeline
WHERE key_id = ?1 AND effective_at <= ?2
ORDER BY effective_at DESC, state DESC
LIMIT 1;",
params![key_id, at.to_rfc3339()],
key_timeline_row,
)
.optional()?;
row.map(TryInto::try_into).transpose()
}
fn key_state_effective_at(
&self,
key_id: &str,
state: KeyLifecycleState,
at: DateTime<Utc>,
) -> StoreResult<Option<DateTime<Utc>>> {
let value = self
.pool
.query_row(
"SELECT effective_at
FROM authority_key_timeline
WHERE key_id = ?1 AND state = ?2 AND effective_at <= ?3
ORDER BY effective_at DESC
LIMIT 1;",
params![key_id, key_state_wire(state), at.to_rfc3339()],
|row| row.get::<_, String>(0),
)
.optional()?;
value.as_deref().map(parse_utc).transpose()
}
fn principal_state_at(
&self,
principal_id: &str,
at: DateTime<Utc>,
) -> StoreResult<Option<PrincipalTimelineRecord>> {
let row = self
.pool
.query_row(
"SELECT principal_id, trust_tier, effective_at, trust_review_due_at, removed_at, audit_ref
FROM authority_principal_timeline
WHERE principal_id = ?1 AND effective_at <= ?2
ORDER BY effective_at DESC
LIMIT 1;",
params![principal_id, at.to_rfc3339()],
principal_timeline_row,
)
.optional()?;
row.map(TryInto::try_into).transpose()
}
}
#[derive(Debug)]
struct KeyTimelineRow {
key_id: String,
principal_id: String,
state: String,
effective_at: String,
reason: Option<String>,
audit_ref: Option<String>,
}
fn key_timeline_row(row: &Row<'_>) -> rusqlite::Result<KeyTimelineRow> {
Ok(KeyTimelineRow {
key_id: row.get(0)?,
principal_id: row.get(1)?,
state: row.get(2)?,
effective_at: row.get(3)?,
reason: row.get(4)?,
audit_ref: row.get(5)?,
})
}
impl TryFrom<KeyTimelineRow> for KeyTimelineRecord {
type Error = StoreError;
fn try_from(row: KeyTimelineRow) -> StoreResult<Self> {
Ok(Self {
key_id: row.key_id,
principal_id: row.principal_id,
state: parse_key_state(&row.state)?,
effective_at: parse_utc(&row.effective_at)?,
reason: row.reason,
audit_ref: row.audit_ref,
})
}
}
#[derive(Debug)]
struct PrincipalTimelineRow {
principal_id: String,
trust_tier: String,
effective_at: String,
trust_review_due_at: Option<String>,
removed_at: Option<String>,
audit_ref: Option<String>,
}
fn principal_timeline_row(row: &Row<'_>) -> rusqlite::Result<PrincipalTimelineRow> {
Ok(PrincipalTimelineRow {
principal_id: row.get(0)?,
trust_tier: row.get(1)?,
effective_at: row.get(2)?,
trust_review_due_at: row.get(3)?,
removed_at: row.get(4)?,
audit_ref: row.get(5)?,
})
}
impl TryFrom<PrincipalTimelineRow> for PrincipalTimelineRecord {
type Error = StoreError;
fn try_from(row: PrincipalTimelineRow) -> StoreResult<Self> {
Ok(Self {
principal_id: row.principal_id,
trust_tier: parse_trust_tier(&row.trust_tier)?,
effective_at: parse_utc(&row.effective_at)?,
trust_review_due_at: row
.trust_review_due_at
.as_deref()
.map(parse_utc)
.transpose()?,
removed_at: row.removed_at.as_deref().map(parse_utc).transpose()?,
audit_ref: row.audit_ref,
})
}
}
fn require_policy_final_outcome(policy: &PolicyDecision, surface: &str) -> StoreResult<()> {
match policy.final_outcome {
PolicyOutcome::Allow | PolicyOutcome::Warn | PolicyOutcome::BreakGlass => Ok(()),
PolicyOutcome::Quarantine | PolicyOutcome::Reject => Err(StoreError::Validation(format!(
"{surface} preflight: composed policy outcome {:?} blocks authority-root mutation",
policy.final_outcome,
))),
}
}
fn require_contributor_rule(policy: &PolicyDecision, rule_id: &str) -> StoreResult<()> {
let contains_rule = policy
.contributing
.iter()
.chain(policy.discarded.iter())
.any(|contribution| contribution.rule_id.as_str() == rule_id);
if contains_rule {
Ok(())
} else {
Err(StoreError::Validation(format!(
"policy decision missing required contributor `{rule_id}`; caller skipped ADR 0026 composition",
)))
}
}
fn require_attestation_not_break_glassed(
policy: &PolicyDecision,
rule_id: &str,
surface: &str,
) -> StoreResult<()> {
let attestation = policy
.contributing
.iter()
.chain(policy.discarded.iter())
.find(|contribution| contribution.rule_id.as_str() == rule_id)
.ok_or_else(|| {
StoreError::Validation(format!(
"{surface} preflight: required attestation contributor `{rule_id}` is absent from the policy decision",
))
})?;
if attestation.outcome == PolicyOutcome::Allow {
Ok(())
} else {
Err(StoreError::Validation(format!(
"{surface} preflight: attestation contributor `{rule_id}` returned {:?}; ADR 0026 §4 forbids BreakGlass substituting for attestation",
attestation.outcome,
)))
}
}
#[must_use]
pub fn key_state_policy_decision_test_allow() -> PolicyDecision {
use cortex_core::compose_policy_outcomes;
compose_policy_outcomes(
vec![
PolicyContribution::new(
KEY_STATE_ATTESTED_BY_OPERATOR_RULE_ID,
PolicyOutcome::Allow,
"test fixture: operator attestation present",
)
.expect("static test contribution is valid"),
PolicyContribution::new(
KEY_STATE_TRUST_TIER_GATE_RULE_ID,
PolicyOutcome::Allow,
"test fixture: trust tier gate satisfied",
)
.expect("static test contribution is valid"),
],
None,
)
}
#[must_use]
pub fn principal_state_policy_decision_test_allow() -> PolicyDecision {
use cortex_core::compose_policy_outcomes;
compose_policy_outcomes(
vec![
PolicyContribution::new(
PRINCIPAL_STATE_ATTESTED_BY_OPERATOR_RULE_ID,
PolicyOutcome::Allow,
"test fixture: operator attestation present",
)
.expect("static test contribution is valid"),
PolicyContribution::new(
PRINCIPAL_STATE_TRUST_TIER_GATE_RULE_ID,
PolicyOutcome::Allow,
"test fixture: trust tier gate satisfied",
)
.expect("static test contribution is valid"),
PolicyContribution::new(
PRINCIPAL_STATE_TIER_PROMOTION_ATTESTATION_RULE_ID,
PolicyOutcome::Allow,
"test fixture: tier promotion attestation present",
)
.expect("static test contribution is valid"),
],
None,
)
}
fn parse_utc(value: &str) -> StoreResult<DateTime<Utc>> {
Ok(DateTime::parse_from_rfc3339(value)?.with_timezone(&Utc))
}
fn key_state_wire(state: KeyLifecycleState) -> &'static str {
match state {
KeyLifecycleState::Active => "active",
KeyLifecycleState::Retired => "retired",
KeyLifecycleState::Revoked => "revoked",
}
}
fn parse_key_state(value: &str) -> StoreResult<KeyLifecycleState> {
match value {
"active" => Ok(KeyLifecycleState::Active),
"retired" => Ok(KeyLifecycleState::Retired),
"revoked" => Ok(KeyLifecycleState::Revoked),
other => Err(StoreError::Validation(format!(
"unknown key lifecycle state `{other}`"
))),
}
}
fn trust_tier_wire(tier: TrustTier) -> &'static str {
match tier {
TrustTier::Untrusted => "untrusted",
TrustTier::Observed => "observed",
TrustTier::Verified => "verified",
TrustTier::Operator => "operator",
}
}
fn parse_trust_tier(value: &str) -> StoreResult<TrustTier> {
match value {
"untrusted" => Ok(TrustTier::Untrusted),
"observed" => Ok(TrustTier::Observed),
"verified" => Ok(TrustTier::Verified),
"operator" => Ok(TrustTier::Operator),
other => Err(StoreError::Validation(format!(
"unknown trust tier `{other}`"
))),
}
}