feat(grid-agent): add portable control plane (#126)
Some checks failed
CI / rust-skia (Rust only) (push) Successful in 2m44s
CI / required (push) Failing after 2m43s

This commit is contained in:
2026-08-18 04:29:12 +00:00
parent 058ed10005
commit 962d17257d
16 changed files with 4023 additions and 31 deletions

View File

@@ -16,6 +16,7 @@ use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::error::Error;
use std::fmt;
use std::sync::{Arc, Mutex};
use std::time::{SystemTime, UNIX_EPOCH};
const MAX_POLICY_TOOLS: usize = 64;
const MAX_AUTHORIZED_AVATARS: usize = 1_024;
@@ -238,6 +239,16 @@ pub struct ResourceCost {
pub build_prims: u64,
}
/// Secret-free operator projection of one pending approval.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PendingApprovalMetadata {
pub id: ApprovalId,
pub principal: String,
pub tool: String,
pub expires_at: u64,
pub cost: ResourceCost,
}
impl ResourceCost {
#[must_use]
pub const fn one_call() -> Self {
@@ -514,6 +525,7 @@ pub enum PolicyFinalOutcome {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PolicyAuditRecord {
pub recorded_unix_millis: u64,
pub authorization_id: Option<u64>,
pub approval_id: Option<ApprovalId>,
pub origin: OriginClass,
@@ -581,6 +593,18 @@ impl PolicyAuditSink for MemoryPolicyAudit {
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct ApprovalId(u64);
impl ApprovalId {
#[must_use]
pub const fn from_raw(value: u64) -> Option<Self> {
if value == 0 { None } else { Some(Self(value)) }
}
#[must_use]
pub const fn get(self) -> u64 {
self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct SchedulerGrantId(u64);
@@ -588,6 +612,7 @@ pub struct SchedulerGrantId(u64);
enum ApprovalStatus {
Pending,
Granted,
Denied,
Consumed,
}
@@ -820,6 +845,31 @@ impl PolicyGateway {
PolicySnapshot(lock(&self.state).clone())
}
/// Returns bounded, content-free approval metadata for operator UIs.
#[must_use]
pub fn pending_approvals(&self, now: u64) -> Vec<PendingApprovalMetadata> {
lock(&self.state)
.approvals
.values()
.filter(|approval| {
approval.status == ApprovalStatus::Pending && approval.expires_at > now
})
.map(|approval| PendingApprovalMetadata {
id: approval.id,
principal: approval.principal.audit_label(),
tool: approval.tool.clone(),
expires_at: approval.expires_at,
cost: approval.cost,
})
.collect()
}
/// Current global budget use for a redacted control-plane projection.
#[must_use]
pub fn global_budget_usage(&self) -> ResourceCost {
lock(&self.state).global_used
}
#[cfg(test)]
pub(crate) fn pending_approval_count(&self) -> usize {
lock(&self.state)
@@ -1064,7 +1114,9 @@ impl PolicyGateway {
match approval.status {
ApprovalStatus::Pending => Some(PolicyReasonCode::ApprovalNotGranted),
ApprovalStatus::Granted => None,
ApprovalStatus::Consumed => Some(PolicyReasonCode::ApprovalReplayed),
ApprovalStatus::Denied | ApprovalStatus::Consumed => {
Some(PolicyReasonCode::ApprovalReplayed)
}
}
};
if let Some(reason) = reason {
@@ -1121,8 +1173,12 @@ impl PolicyGateway {
}
if state.approvals.len() == MAX_APPROVALS {
let removable = state.approvals.iter().find_map(|(id, approval)| {
(approval.expires_at <= now || approval.status == ApprovalStatus::Consumed)
.then_some(*id)
(approval.expires_at <= now
|| matches!(
approval.status,
ApprovalStatus::Denied | ApprovalStatus::Consumed
))
.then_some(*id)
});
let Some(removable) = removable else {
drop(state);
@@ -1323,6 +1379,40 @@ impl PolicyGateway {
Ok(PolicyReasonCode::Allowed)
}
pub fn deny_approval(
&self,
id: ApprovalId,
_operator: &AuthenticatedPrincipal,
now: u64,
) -> Result<PolicyReasonCode, PolicyError> {
let mut state = lock(&self.state);
let Some(approval) = state.approvals.get_mut(&id) else {
return Ok(PolicyReasonCode::ApprovalUnknown);
};
if approval.expires_at <= now {
return Ok(PolicyReasonCode::ApprovalExpired);
}
if approval.status != ApprovalStatus::Pending {
return Ok(PolicyReasonCode::ApprovalReplayed);
}
let audit = audit_record(
&approval.context,
approval.origin,
&approval.principal,
BoundedText::new("policy.tool", approval.tool.clone())?,
None,
Some(id),
PolicyDisposition::Denied,
PolicyReasonCode::ApprovalNotGranted,
approval.cost,
approval.arguments_hash,
PolicyFinalOutcome::Denied,
)?;
self.emit(audit)?;
approval.status = ApprovalStatus::Denied;
Ok(PolicyReasonCode::ApprovalNotGranted)
}
/// Consumes the originating authorization so it cannot be replayed to
/// create more than one scheduler grant.
#[allow(clippy::needless_pass_by_value)]
@@ -1621,6 +1711,11 @@ fn audit_record(
final_outcome: PolicyFinalOutcome,
) -> Result<PolicyAuditRecord, PolicyError> {
Ok(PolicyAuditRecord {
recorded_unix_millis: SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_or(0, |duration| {
u64::try_from(duration.as_millis()).unwrap_or(u64::MAX)
}),
authorization_id,
approval_id,
origin,