use crate::machines::mob_machine as mob_dsl;
use meerkat_contracts::wire::supervisor_bridge::BridgeRejectionCause;
use meerkat_contracts::wire::{WireControlScope, WireGrantRecord, WireScopeDeniedDetail};
use meerkat_core::auth::PrincipalId;
use meerkat_core::types::SessionId;
use std::collections::BTreeSet;
pub use crate::machines::mob_machine::ControlScope;
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum MobControlPrincipal {
Owner,
External(PrincipalId),
Unresolved,
}
impl MobControlPrincipal {
#[must_use]
pub fn from_owner_bridge_session(
session: &SessionId,
state: &mob_dsl::MobMachineState,
) -> Option<Self> {
let owner = state.owner_bridge_session_id.as_ref()?;
(owner == &mob_dsl::SessionId::from_domain(session)).then_some(Self::Owner)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeDenial {
pub required: ControlScope,
pub presented: BTreeSet<ControlScope>,
}
impl ScopeDenial {
#[must_use]
pub fn required_name(&self) -> &'static str {
self.required.name()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[must_use]
pub struct ResolvedControlPolicy {
kind: ResolvedControlPolicyKind,
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum ResolvedControlPolicyKind {
OwnerFull,
Granted(BTreeSet<ControlScope>),
}
impl ResolvedControlPolicy {
pub fn resolve(
principal: &MobControlPrincipal,
state: &mob_dsl::MobMachineState,
now_ms: u64,
) -> Self {
let kind = match principal {
MobControlPrincipal::Owner => ResolvedControlPolicyKind::OwnerFull,
MobControlPrincipal::External(id) => {
let key = machine_principal(id);
match state.operator_grant_scopes.get(&key) {
None => ResolvedControlPolicyKind::Granted(BTreeSet::new()),
Some(scopes) => match state.operator_grant_expiries.get(&key) {
Some(None) => ResolvedControlPolicyKind::Granted(scopes.clone()),
Some(Some(expires_at_ms)) if now_ms < *expires_at_ms => {
ResolvedControlPolicyKind::Granted(scopes.clone())
}
Some(Some(_)) => ResolvedControlPolicyKind::Granted(BTreeSet::new()),
None => ResolvedControlPolicyKind::Granted(BTreeSet::new()),
},
}
}
MobControlPrincipal::Unresolved => ResolvedControlPolicyKind::Granted(BTreeSet::new()),
};
Self { kind }
}
pub fn require(&self, scope: ControlScope) -> Result<(), ScopeDenial> {
match &self.kind {
ResolvedControlPolicyKind::OwnerFull => Ok(()),
ResolvedControlPolicyKind::Granted(set) => {
if set.contains(&scope) {
Ok(())
} else {
Err(ScopeDenial {
required: scope,
presented: set.clone(),
})
}
}
}
}
#[must_use]
pub fn permits(&self, scope: ControlScope) -> bool {
match &self.kind {
ResolvedControlPolicyKind::OwnerFull => true,
ResolvedControlPolicyKind::Granted(set) => set.contains(&scope),
}
}
#[must_use]
pub fn is_owner_full(&self) -> bool {
matches!(self.kind, ResolvedControlPolicyKind::OwnerFull)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OperatorGrant {
pub principal: String,
pub scopes: BTreeSet<ControlScope>,
pub expires_at_ms: Option<u64>,
}
impl OperatorGrant {
#[must_use]
pub fn to_wire(&self) -> WireGrantRecord {
WireGrantRecord {
principal: self.principal.clone(),
scopes: self
.scopes
.iter()
.copied()
.map(ControlScope::to_wire)
.collect(),
expires_at_ms: self.expires_at_ms,
}
}
}
impl ControlScope {
#[must_use]
pub fn to_wire(self) -> WireControlScope {
match self {
Self::List => WireControlScope::List,
Self::ReadHistory => WireControlScope::ReadHistory,
Self::SubscribeEvents => WireControlScope::SubscribeEvents,
Self::SendCommand => WireControlScope::SendCommand,
Self::Cancel => WireControlScope::Cancel,
Self::Retire => WireControlScope::Retire,
Self::WireTopology => WireControlScope::WireTopology,
Self::Live => WireControlScope::Live,
Self::AdminHost => WireControlScope::AdminHost,
Self::AdminGrants => WireControlScope::AdminGrants,
}
}
#[must_use]
pub fn name(self) -> &'static str {
match self {
Self::List => "list",
Self::ReadHistory => "read_history",
Self::SubscribeEvents => "subscribe_events",
Self::SendCommand => "send_command",
Self::Cancel => "cancel",
Self::Retire => "retire",
Self::WireTopology => "wire_topology",
Self::Live => "live",
Self::AdminHost => "admin_host",
Self::AdminGrants => "admin_grants",
}
}
}
impl From<WireControlScope> for ControlScope {
fn from(scope: WireControlScope) -> Self {
match scope {
WireControlScope::List => Self::List,
WireControlScope::ReadHistory => Self::ReadHistory,
WireControlScope::SubscribeEvents => Self::SubscribeEvents,
WireControlScope::SendCommand => Self::SendCommand,
WireControlScope::Cancel => Self::Cancel,
WireControlScope::Retire => Self::Retire,
WireControlScope::WireTopology => Self::WireTopology,
WireControlScope::Live => Self::Live,
WireControlScope::AdminHost => Self::AdminHost,
WireControlScope::AdminGrants => Self::AdminGrants,
}
}
}
impl From<&ScopeDenial> for BridgeRejectionCause {
fn from(denial: &ScopeDenial) -> Self {
Self::ScopeDenied {
required: denial.required.to_wire(),
presented: denial
.presented
.iter()
.copied()
.map(ControlScope::to_wire)
.collect(),
}
}
}
impl From<&ScopeDenial> for WireScopeDeniedDetail {
fn from(denial: &ScopeDenial) -> Self {
Self {
required: denial.required.to_wire(),
presented: denial
.presented
.iter()
.copied()
.map(ControlScope::to_wire)
.collect(),
}
}
}
pub(crate) fn machine_principal(id: &PrincipalId) -> mob_dsl::PrincipalId {
mob_dsl::PrincipalId::from(id.as_str())
}
#[derive(Debug, Clone)]
pub struct CommandAuthority {
lane: CommandAuthorityLane,
member_operator_execution_fence: Option<MemberOperatorExecutionFence>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct MemberOperatorExecutionFence {
pub(crate) agent_identity: String,
pub(crate) host_id: String,
pub(crate) host_binding_generation: u64,
pub(crate) requester_member_session_id: String,
pub(crate) generation: u64,
pub(crate) fence_token: u64,
}
#[derive(Debug, Clone)]
enum CommandAuthorityLane {
Principal(MobControlPrincipal),
AgentLane,
Internal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommandAuthorityKind {
Principal,
AgentLane,
Internal,
}
impl CommandAuthority {
#[must_use]
pub fn principal(principal: MobControlPrincipal) -> Self {
Self {
lane: CommandAuthorityLane::Principal(principal),
member_operator_execution_fence: None,
}
}
#[must_use]
pub(crate) fn carried_principal(&self) -> Option<&MobControlPrincipal> {
match &self.lane {
CommandAuthorityLane::Principal(principal) => Some(principal),
CommandAuthorityLane::AgentLane | CommandAuthorityLane::Internal => None,
}
}
#[must_use]
pub(crate) fn agent_lane() -> Self {
Self {
lane: CommandAuthorityLane::AgentLane,
member_operator_execution_fence: None,
}
}
#[must_use]
pub(crate) fn remote_member_operator(fence: MemberOperatorExecutionFence) -> Self {
Self {
lane: CommandAuthorityLane::AgentLane,
member_operator_execution_fence: Some(fence),
}
}
#[must_use]
pub(crate) fn internal() -> Self {
Self {
lane: CommandAuthorityLane::Internal,
member_operator_execution_fence: None,
}
}
pub(crate) fn member_operator_execution_fence(&self) -> Option<&MemberOperatorExecutionFence> {
self.member_operator_execution_fence.as_ref()
}
#[must_use]
pub fn kind(&self) -> CommandAuthorityKind {
match &self.lane {
CommandAuthorityLane::Principal(_) => CommandAuthorityKind::Principal,
CommandAuthorityLane::AgentLane => CommandAuthorityKind::AgentLane,
CommandAuthorityLane::Internal => CommandAuthorityKind::Internal,
}
}
#[must_use]
pub(crate) fn control_principal(&self) -> Option<&MobControlPrincipal> {
match &self.lane {
CommandAuthorityLane::Principal(principal) => Some(principal),
CommandAuthorityLane::AgentLane | CommandAuthorityLane::Internal => None,
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod tests {
use super::*;
const ALL_SCOPES: [ControlScope; 10] = [
ControlScope::List,
ControlScope::ReadHistory,
ControlScope::SubscribeEvents,
ControlScope::SendCommand,
ControlScope::Cancel,
ControlScope::Retire,
ControlScope::WireTopology,
ControlScope::Live,
ControlScope::AdminHost,
ControlScope::AdminGrants,
];
const ALL_WIRE_SCOPES: [WireControlScope; 10] = [
WireControlScope::List,
WireControlScope::ReadHistory,
WireControlScope::SubscribeEvents,
WireControlScope::SendCommand,
WireControlScope::Cancel,
WireControlScope::Retire,
WireControlScope::WireTopology,
WireControlScope::Live,
WireControlScope::AdminHost,
WireControlScope::AdminGrants,
];
fn external(id: &str) -> MobControlPrincipal {
MobControlPrincipal::External(PrincipalId::new(id).expect("valid principal id"))
}
fn granted_state(
principal: &str,
scopes: &[ControlScope],
expires_at_ms: Option<u64>,
) -> mob_dsl::MobMachineState {
let mut authority = mob_dsl::MobMachineAuthority::new();
mob_dsl::MobMachineMutator::apply(
&mut authority,
mob_dsl::MobMachineInput::GrantOperatorScopes {
principal: mob_dsl::PrincipalId::from(principal),
scopes: scopes.iter().copied().collect(),
expires_at_ms,
},
)
.expect("grant accepted");
authority.state().clone()
}
#[test]
fn owner_is_full_and_ignores_grant_rows() {
let state = granted_state("console:someone", &[ControlScope::List], Some(1));
let policy = ResolvedControlPolicy::resolve(&MobControlPrincipal::Owner, &state, u64::MAX);
assert!(policy.is_owner_full());
for scope in ALL_SCOPES {
assert!(policy.permits(scope));
policy.require(scope).expect("owner passes every scope");
}
}
#[test]
fn unresolved_and_ungranted_principals_resolve_to_empty() {
let state = granted_state("console:granted", &[ControlScope::List], None);
for principal in [
external("console:stranger"),
MobControlPrincipal::Unresolved,
] {
let policy = ResolvedControlPolicy::resolve(&principal, &state, 0);
assert!(!policy.is_owner_full());
for scope in ALL_SCOPES {
assert!(!policy.permits(scope));
let denial = policy
.require(scope)
.expect_err("empty effective set denies every scope");
assert_eq!(denial.required, scope);
assert!(
denial.presented.is_empty(),
"denial must present the empty set"
);
}
}
}
#[test]
fn each_scope_grants_exactly_itself() {
for granted in ALL_SCOPES {
let state = granted_state("console:one", &[granted], None);
let policy = ResolvedControlPolicy::resolve(&external("console:one"), &state, 0);
assert!(policy.permits(granted));
policy.require(granted).expect("granted scope passes");
for other in ALL_SCOPES {
if other == granted {
continue;
}
let denial = policy
.require(other)
.expect_err("non-granted scope must deny");
assert_eq!(denial.required, other);
assert_eq!(
denial.presented,
BTreeSet::from([granted]),
"presented must be the caller's own effective set"
);
}
}
}
#[test]
fn semantic_scope_pairs_stay_distinct() {
let pairs: &[(&[ControlScope], ControlScope)] = &[
(&[ControlScope::SendCommand], ControlScope::ReadHistory),
(&[ControlScope::SubscribeEvents], ControlScope::Cancel),
(&[ControlScope::WireTopology], ControlScope::SendCommand),
(&[ControlScope::AdminHost], ControlScope::AdminGrants),
(&[ControlScope::AdminGrants], ControlScope::AdminHost),
];
for (granted, denied) in pairs {
let state = granted_state("console:pair", granted, None);
let policy = ResolvedControlPolicy::resolve(&external("console:pair"), &state, 0);
for scope in *granted {
assert!(policy.permits(*scope));
}
let denial = policy.require(*denied).expect_err("pair scope must deny");
assert_eq!(denial.required, *denied);
}
}
#[test]
fn expiry_is_inclusive_at_the_deadline_and_presents_empty() {
let state = granted_state("console:exp", &[ControlScope::List], Some(1_000));
let principal = external("console:exp");
let live = ResolvedControlPolicy::resolve(&principal, &state, 999);
assert!(live.permits(ControlScope::List));
for now_ms in [1_000, 1_001, u64::MAX] {
let expired = ResolvedControlPolicy::resolve(&principal, &state, now_ms);
assert!(!expired.permits(ControlScope::List));
let denial = expired
.require(ControlScope::List)
.expect_err("expired grant denies");
assert!(
denial.presented.is_empty(),
"expired presents the empty set (indistinguishable from never-granted)"
);
}
let unexpiring = granted_state("console:exp", &[ControlScope::List], None);
let policy = ResolvedControlPolicy::resolve(&principal, &unexpiring, u64::MAX);
assert!(
policy.permits(ControlScope::List),
"None expiry never expires"
);
}
#[test]
fn desynced_expiry_row_fails_closed_to_empty() {
let mut state = granted_state("console:desync", &[ControlScope::List], None);
state
.operator_grant_expiries
.remove(&mob_dsl::PrincipalId::from("console:desync"));
let policy = ResolvedControlPolicy::resolve(&external("console:desync"), &state, 0);
for scope in ALL_SCOPES {
assert!(!policy.permits(scope));
}
let denial = policy
.require(ControlScope::List)
.expect_err("desynced row denies");
assert!(denial.presented.is_empty());
}
#[test]
fn live_scope_is_generic_and_distinct() {
let live_state = granted_state("console:live", &[ControlScope::Live], None);
let live = ResolvedControlPolicy::resolve(&external("console:live"), &live_state, 0);
live.require(ControlScope::Live)
.expect("Live-granted principal passes require(Live)");
let non_live_state = granted_state(
"console:live",
&[ControlScope::SendCommand, ControlScope::SubscribeEvents],
None,
);
let non_live =
ResolvedControlPolicy::resolve(&external("console:live"), &non_live_state, 0);
let denial = non_live
.require(ControlScope::Live)
.expect_err("SendCommand+SubscribeEvents does not confer Live");
assert_eq!(denial.required, ControlScope::Live);
assert_eq!(denial.required_name(), "live");
}
#[test]
fn scope_vocabulary_is_ten_variants_with_total_wire_round_trip() {
for scope in ALL_SCOPES {
assert_eq!(ControlScope::from(scope.to_wire()), scope);
}
for wire in ALL_WIRE_SCOPES {
assert_eq!(ControlScope::from(wire).to_wire(), wire);
}
let names: BTreeSet<&'static str> = ALL_SCOPES.iter().map(|scope| scope.name()).collect();
assert_eq!(names.len(), 10);
assert!(!names.contains("approve"));
assert!(!names.contains("rewrite_transcript"));
}
#[test]
fn from_owner_bridge_session_matches_only_the_owner_fact() {
let owner_session = SessionId::new();
let other_session = SessionId::new();
let mut authority = mob_dsl::MobMachineAuthority::new();
mob_dsl::MobMachineMutator::apply(
&mut authority,
mob_dsl::MobMachineInput::BindOwnerBridgeSession {
bridge_session_id: mob_dsl::SessionId::from_domain(&owner_session),
destroy_on_owner_archive: false,
implicit_delegation_mob: false,
},
)
.expect("owner bind accepted");
let bound_state = authority.state().clone();
assert_eq!(
MobControlPrincipal::from_owner_bridge_session(&owner_session, &bound_state),
Some(MobControlPrincipal::Owner)
);
assert_eq!(
MobControlPrincipal::from_owner_bridge_session(&other_session, &bound_state),
None,
"a non-owner session derives NO principal (agent lane), not Unresolved"
);
let unbound_state = mob_dsl::MobMachineAuthority::new().state().clone();
assert_eq!(
MobControlPrincipal::from_owner_bridge_session(&owner_session, &unbound_state),
None,
"an unset owner fact derives no principal"
);
}
#[test]
fn scope_denial_converts_to_both_wire_carriers_deterministically() {
let denial = ScopeDenial {
required: ControlScope::AdminGrants,
presented: BTreeSet::from([ControlScope::SendCommand, ControlScope::List]),
};
let cause = BridgeRejectionCause::from(&denial);
assert_eq!(
cause,
BridgeRejectionCause::ScopeDenied {
required: WireControlScope::AdminGrants,
presented: vec![WireControlScope::List, WireControlScope::SendCommand],
}
);
let detail = WireScopeDeniedDetail::from(&denial);
assert_eq!(detail.required, WireControlScope::AdminGrants);
assert_eq!(
detail.presented,
vec![WireControlScope::List, WireControlScope::SendCommand]
);
}
#[test]
fn operator_grant_projects_raw_wire_records() {
let grant = OperatorGrant {
principal: "console:luka".to_string(),
scopes: BTreeSet::from([ControlScope::ReadHistory, ControlScope::List]),
expires_at_ms: Some(5),
};
let wire = grant.to_wire();
assert_eq!(wire.principal, "console:luka");
assert_eq!(
wire.scopes,
vec![WireControlScope::List, WireControlScope::ReadHistory]
);
assert_eq!(
wire.expires_at_ms,
Some(5),
"expiry rides verbatim — the projection never evaluates it"
);
}
}