#![allow(clippy::pedantic, clippy::nursery, missing_docs)]
use serde_json::json;
use super::*;
fn spec(name: &str) -> ToolSpec {
ToolSpec::new(name, "d", json!({}))
}
fn profile(origin: ToolOrigin) -> ToolProfile {
ToolProfile {
origin,
read_only: false,
destructive: false,
open_world: false,
}
}
const fn set(caps: &[Capability]) -> CapabilitySet {
let mut s = CapabilitySet::EMPTY;
let mut i = 0;
while i < caps.len() {
s = s.with(caps[i]);
i += 1;
}
s
}
#[test]
fn set_algebra_is_sound() {
let a = set(&[Capability::LocalRead, Capability::ArbitraryEgress]);
let b = set(&[Capability::ArbitraryEgress, Capability::MutateExternal]);
assert!(a.contains(Capability::LocalRead));
assert!(!a.contains(Capability::MutateExternal));
assert_eq!(
a.union(b),
set(&[
Capability::LocalRead,
Capability::ArbitraryEgress,
Capability::MutateExternal
])
);
assert_eq!(a.intersection(b), set(&[Capability::ArbitraryEgress]));
assert_eq!(a.difference(b), set(&[Capability::LocalRead]));
assert!(set(&[Capability::LocalRead]).is_subset_of(a));
assert!(!a.is_subset_of(b));
assert!(CapabilitySet::EMPTY.is_empty());
assert!(CapabilitySet::EMPTY.is_subset_of(CapabilitySet::EMPTY));
for c in Capability::ALL {
assert!(
CapabilitySet::all().contains(c),
"{} missing from all()",
c.as_str()
);
}
let rebuilt: CapabilitySet = a.iter().collect();
assert_eq!(rebuilt, a);
}
#[test]
fn names_round_trip_and_unknown_names_grant_nothing() {
for c in Capability::ALL {
assert_eq!(Capability::from_name(c.as_str()), Some(c), "{}", c.as_str());
}
assert_eq!(Capability::from_name("egress"), None);
assert_eq!(Capability::from_name(""), None);
let (parsed, unknown) =
CapabilitySet::from_names(["arbitrary-egress", "definitely-not-a-capability", ""]);
assert_eq!(parsed, set(&[Capability::ArbitraryEgress]));
assert_eq!(
unknown,
vec!["definitely-not-a-capability".to_owned(), String::new()]
);
let all_names = CapabilitySet::all().names();
let (reparsed, unknown) = CapabilitySet::from_names(all_names);
assert_eq!(reparsed, CapabilitySet::all());
assert!(unknown.is_empty());
}
#[test]
fn required_capabilities_maps_annotations_and_provenance() {
let local_read = ToolProfile {
read_only: true,
..profile(ToolOrigin::LocalSandbox)
};
assert_eq!(
required_capabilities(local_read),
set(&[Capability::LocalRead])
);
let local_write = ToolProfile {
destructive: true,
..profile(ToolOrigin::LocalSandbox)
};
assert_eq!(
required_capabilities(local_write),
set(&[Capability::LocalRead, Capability::LocalWrite])
);
let web = ToolProfile {
read_only: true,
open_world: true,
..profile(ToolOrigin::Fetcher)
};
assert_eq!(
required_capabilities(web),
set(&[Capability::ArbitraryEgress])
);
let paid = ToolProfile {
destructive: true,
open_world: true,
..profile(ToolOrigin::Fetcher)
};
assert_eq!(
required_capabilities(paid),
set(&[Capability::ArbitraryEgress, Capability::MutateExternal])
);
let registered_read = ToolProfile {
read_only: true,
..profile(ToolOrigin::RegisteredConnector)
};
assert_eq!(
required_capabilities(registered_read),
set(&[Capability::FixedConnectorRead])
);
let registered_open_read = ToolProfile {
read_only: true,
open_world: true,
..profile(ToolOrigin::RegisteredConnector)
};
assert_eq!(
required_capabilities(registered_open_read),
set(&[Capability::FixedConnectorRead])
);
let registered_mutating = profile(ToolOrigin::RegisteredConnector);
assert_eq!(
required_capabilities(registered_mutating),
set(&[Capability::FixedConnectorRead, Capability::MutateExternal])
);
let registered_destructive_read = ToolProfile {
read_only: true,
destructive: true,
..profile(ToolOrigin::RegisteredConnector)
};
assert_eq!(
required_capabilities(registered_destructive_read),
set(&[Capability::FixedConnectorRead, Capability::MutateExternal])
);
let first_party_read = ToolProfile {
read_only: true,
..profile(ToolOrigin::FirstParty)
};
assert_eq!(
required_capabilities(first_party_read),
set(&[Capability::FixedConnectorRead])
);
let unknown = ToolProfile {
read_only: true, ..profile(ToolOrigin::Unknown)
};
assert_eq!(required_capabilities(unknown), CapabilitySet::all());
}
#[test]
fn profile_reads_spec_annotations() {
let s = spec("t").read_only().open_world();
let p = ToolProfile::for_spec(&s, ToolOrigin::RegisteredConnector);
assert!(p.read_only && p.open_world && !p.destructive);
assert_eq!(p.origin, ToolOrigin::RegisteredConnector);
}
#[test]
fn self_declared_hints_never_earn_taint_immunity() {
let self_declared = ToolProfile {
read_only: true,
..profile(ToolOrigin::Unknown)
};
let required = required_capabilities(self_declared);
assert!(required.contains(Capability::ArbitraryEgress));
assert!(required.contains(Capability::MutateExternal));
let granted = granted_capabilities(GrantPolicy::default(), TaintState::Tainted);
assert!(!required.is_subset_of(granted));
}
#[test]
fn taint_revokes_egress_and_external_mutation() {
let policy = GrantPolicy::default();
let clean = granted_capabilities(policy, TaintState::Clean);
assert_eq!(clean, CapabilitySet::all());
let tainted = granted_capabilities(policy, TaintState::Tainted);
assert!(!tainted.contains(Capability::ArbitraryEgress));
assert!(!tainted.contains(Capability::MutateExternal));
assert!(tainted.contains(Capability::LocalRead));
assert!(tainted.contains(Capability::LocalWrite));
assert!(tainted.contains(Capability::FixedConnectorRead));
}
#[test]
fn grants_are_monotonic_under_every_fixed_policy() {
let all_sets = || {
(0..32u8).map(|bits| {
Capability::ALL
.into_iter()
.enumerate()
.filter(|(i, _)| bits & (1 << i) != 0)
.map(|(_, c)| c)
.collect::<CapabilitySet>()
})
};
for base in all_sets() {
let policy = GrantPolicy { base };
let clean = granted_capabilities(policy, TaintState::Clean);
let tainted = granted_capabilities(policy, TaintState::Tainted);
assert!(
tainted.is_subset_of(clean),
"taint added a capability under base={:?}",
base.names()
);
assert!(
tainted.is_subset_of(base),
"granted escaped the base policy under base={:?}",
base.names()
);
}
}
#[test]
fn veto_takes_precedence_over_everything() {
let policy = CallPolicy {
veto: Some("path escapes the workspace".to_owned()),
requires_human: true,
sandbox_escalation: true,
transform: ArgTransform::Rewrite("{}".to_owned()),
};
let out = decide(
CapabilitySet::all(),
CapabilitySet::EMPTY,
&policy,
"shell_exec",
);
assert_eq!(
out,
GateOutcome::Deny("path escapes the workspace".to_owned())
);
}
#[test]
fn missing_capabilities_escalate_with_the_missing_set() {
let required = set(&[Capability::ArbitraryEgress]);
let granted = granted_capabilities(GrantPolicy::default(), TaintState::Tainted);
let out = decide(required, granted, &CallPolicy::default(), "web_fetch");
let GateOutcome::Escalate { reason, missing } = out else {
panic!("expected escalate, got {out:?}");
};
assert_eq!(missing, set(&[Capability::ArbitraryEgress]));
assert!(
reason.contains("web_fetch"),
"reason names the tool: {reason}"
);
assert!(!reason.is_empty());
}
#[test]
fn policy_gate_escalates_with_empty_missing_set_and_empty_reason() {
let policy = CallPolicy {
requires_human: true,
..CallPolicy::default()
};
let out = decide(
set(&[Capability::LocalRead]),
CapabilitySet::all(),
&policy,
"shell_exec",
);
assert_eq!(
out,
GateOutcome::Escalate {
reason: String::new(),
missing: CapabilitySet::EMPTY
}
);
let policy = CallPolicy {
sandbox_escalation: true,
..CallPolicy::default()
};
let out = decide(
set(&[Capability::LocalWrite]),
CapabilitySet::all(),
&policy,
"file_write",
);
assert!(matches!(out, GateOutcome::Escalate { missing, .. } if missing.is_empty()));
}
#[test]
fn allowed_calls_honor_the_argument_transform() {
let granted = CapabilitySet::all();
let required = set(&[Capability::LocalRead]);
let out = decide(required, granted, &CallPolicy::default(), "file_read");
assert_eq!(out, GateOutcome::Allow);
let rewrite = CallPolicy {
transform: ArgTransform::Rewrite(r#"{"path":"safe.txt"}"#.to_owned()),
..CallPolicy::default()
};
assert_eq!(
decide(required, granted, &rewrite, "file_read"),
GateOutcome::Modify(r#"{"path":"safe.txt"}"#.to_owned())
);
let inject = CallPolicy {
transform: ArgTransform::InjectContext("note".to_owned()),
..CallPolicy::default()
};
assert_eq!(
decide(required, granted, &inject, "file_read"),
GateOutcome::InjectContext("note".to_owned())
);
let out = decide(
CapabilitySet::all(),
granted.difference(TAINT_REVOKED),
&rewrite,
"t",
);
assert!(matches!(out, GateOutcome::Escalate { .. }));
}
#[test]
fn decision_table_is_exhaustive_over_required_and_granted() {
let all_sets = || {
(0..32u8).map(|bits| {
Capability::ALL
.into_iter()
.enumerate()
.filter(|(i, _)| bits & (1 << i) != 0)
.map(|(_, c)| c)
.collect::<CapabilitySet>()
})
};
for required in all_sets() {
for granted in all_sets() {
let out = decide(required, granted, &CallPolicy::default(), "t");
if required.is_subset_of(granted) {
assert_eq!(
out,
GateOutcome::Allow,
"required={:?} granted={:?}",
required.names(),
granted.names()
);
} else {
let GateOutcome::Escalate { missing, .. } = out else {
panic!(
"expected escalate for required={:?} granted={:?}",
required.names(),
granted.names()
);
};
assert_eq!(missing, required.difference(granted));
assert!(!missing.is_empty());
}
}
}
}
#[test]
fn behavior_changing_rows_are_pinned() {
let tainted_grants = granted_capabilities(GrantPolicy::default(), TaintState::Tainted);
let mutating = required_capabilities(profile(ToolOrigin::RegisteredConnector));
let out = decide(
mutating,
tainted_grants,
&CallPolicy::default(),
"send_message",
);
assert!(
matches!(out, GateOutcome::Escalate { ref missing, .. } if missing.contains(Capability::MutateExternal)),
"got {out:?}"
);
let read = required_capabilities(ToolProfile {
read_only: true,
..profile(ToolOrigin::RegisteredConnector)
});
assert_eq!(
decide(read, tainted_grants, &CallPolicy::default(), "service_list"),
GateOutcome::Allow
);
}
#[test]
fn engine_is_uniform_over_the_taxonomy() {
for c in Capability::ALL {
let single = CapabilitySet::of(c);
let out = decide(single, CapabilitySet::EMPTY, &CallPolicy::default(), "t");
assert!(
matches!(out, GateOutcome::Escalate { missing, .. } if missing == single),
"{}",
c.as_str()
);
assert_eq!(
decide(single, single, &CallPolicy::default(), "t"),
GateOutcome::Allow,
"{}",
c.as_str()
);
}
}
#[test]
fn redeclaration_only_ever_grows_the_required_set() {
let origins = [
ToolOrigin::LocalSandbox,
ToolOrigin::Fetcher,
ToolOrigin::FirstParty,
ToolOrigin::RegisteredConnector,
ToolOrigin::Unknown,
];
let bools = [false, true];
let mut profiles = Vec::new();
for origin in origins {
for read_only in bools {
for destructive in bools {
for open_world in bools {
profiles.push(ToolProfile {
origin,
read_only,
destructive,
open_world,
});
}
}
}
}
for &old in &profiles {
for &new in &profiles {
let clamped = monotonic_redeclaration(old, new);
let before = required_capabilities(old);
let after = required_capabilities(clamped);
assert!(
before.is_subset_of(after),
"re-declaration shrank requirements: old={old:?} new={new:?} clamped={clamped:?}"
);
assert!(
!old.open_world || clamped.open_world,
"open-world never downgrades to closed-world"
);
assert!(
old.read_only || !clamped.read_only,
"a tool never gains read-only at runtime"
);
}
}
let old = ToolProfile {
read_only: true,
..profile(ToolOrigin::RegisteredConnector)
};
let new = ToolProfile {
destructive: true,
..profile(ToolOrigin::RegisteredConnector)
};
let clamped = monotonic_redeclaration(old, new);
assert!(required_capabilities(clamped).contains(Capability::MutateExternal));
}
#[test]
fn grant_access_is_never_granted_by_any_input() {
assert!(!Capability::ALL.contains(&Capability::GrantAccess));
assert!(!CapabilitySet::all().contains(Capability::GrantAccess));
for policy in [
GrantPolicy::default(),
GrantPolicy {
base: CapabilitySet::EMPTY,
},
] {
for taint in [TaintState::Clean, TaintState::Tainted] {
assert!(
!granted_capabilities(policy, taint).contains(Capability::GrantAccess),
"grant-access must never be granted (policy={policy:?}, taint={taint:?})"
);
}
}
assert_eq!(Capability::from_name("grant-access"), None);
let (parsed, unknown) = CapabilitySet::from_names(["grant-access"]);
assert!(parsed.is_empty(), "grant-access parses to nothing");
assert_eq!(unknown, vec!["grant-access".to_owned()]);
}
#[test]
fn access_grant_always_escalates_in_every_state() {
let required = required_capabilities(ToolProfile {
read_only: false,
destructive: true,
open_world: true,
..profile(ToolOrigin::AccessGrant)
});
assert!(
required.contains(Capability::GrantAccess),
"an access-grant tool requires the never-granted marker"
);
for policy in [
GrantPolicy::default(),
GrantPolicy {
base: CapabilitySet::EMPTY,
},
] {
for taint in [TaintState::Clean, TaintState::Tainted] {
let granted = granted_capabilities(policy, taint);
let out = decide(required, granted, &CallPolicy::default(), "invite");
assert_ne!(out, GateOutcome::Allow, "policy={policy:?} taint={taint:?}");
let GateOutcome::Escalate { reason, missing } = out else {
panic!("expected escalate for policy={policy:?} taint={taint:?}");
};
assert!(
missing.contains(Capability::GrantAccess),
"the shortfall names the access-grant marker"
);
assert!(reason.contains("invite"), "reason names the tool: {reason}");
}
}
}
#[test]
fn revoke_access_is_never_granted_by_any_input() {
assert!(!Capability::ALL.contains(&Capability::RevokeAccess));
assert!(!CapabilitySet::all().contains(Capability::RevokeAccess));
for policy in [
GrantPolicy::default(),
GrantPolicy {
base: CapabilitySet::EMPTY,
},
] {
for taint in [TaintState::Clean, TaintState::Tainted] {
assert!(
!granted_capabilities(policy, taint).contains(Capability::RevokeAccess),
"revoke-access must never be granted (policy={policy:?}, taint={taint:?})"
);
}
}
assert_eq!(Capability::from_name("revoke-access"), None);
let (parsed, unknown) = CapabilitySet::from_names(["revoke-access"]);
assert!(parsed.is_empty(), "revoke-access parses to nothing");
assert_eq!(unknown, vec!["revoke-access".to_owned()]);
}
#[test]
fn revoke_access_always_escalates_in_every_state() {
let required = required_capabilities(ToolProfile {
read_only: false,
destructive: true,
open_world: false,
..profile(ToolOrigin::AccessRevoke)
});
assert!(
required.contains(Capability::RevokeAccess),
"an access-revoke tool requires the never-granted marker"
);
for policy in [
GrantPolicy::default(),
GrantPolicy {
base: CapabilitySet::EMPTY,
},
] {
for taint in [TaintState::Clean, TaintState::Tainted] {
let granted = granted_capabilities(policy, taint);
let out = decide(required, granted, &CallPolicy::default(), "revoke");
assert_ne!(out, GateOutcome::Allow, "policy={policy:?} taint={taint:?}");
let GateOutcome::Escalate { reason, missing } = out else {
panic!("expected escalate for policy={policy:?} taint={taint:?}");
};
assert!(
missing.contains(Capability::RevokeAccess),
"the shortfall names the revoke-access marker"
);
assert!(reason.contains("revoke"), "reason names the tool: {reason}");
}
}
}
#[test]
fn manage_admin_is_never_granted_by_any_input() {
assert!(!Capability::ALL.contains(&Capability::ManageAdmin));
assert!(!CapabilitySet::all().contains(Capability::ManageAdmin));
for policy in [
GrantPolicy::default(),
GrantPolicy {
base: CapabilitySet::EMPTY,
},
] {
for taint in [TaintState::Clean, TaintState::Tainted] {
assert!(
!granted_capabilities(policy, taint).contains(Capability::ManageAdmin),
"manage-admin must never be granted (policy={policy:?}, taint={taint:?})"
);
}
}
assert_eq!(Capability::from_name("manage-admin"), None);
let (parsed, unknown) = CapabilitySet::from_names(["manage-admin"]);
assert!(parsed.is_empty(), "manage-admin parses to nothing");
assert_eq!(unknown, vec!["manage-admin".to_owned()]);
}
#[test]
fn manage_admin_always_escalates_in_every_state() {
let required = required_capabilities(ToolProfile {
read_only: false,
destructive: true,
open_world: false,
..profile(ToolOrigin::AdminManage)
});
assert!(
required.contains(Capability::ManageAdmin),
"an admin-manage tool requires the never-granted marker"
);
for policy in [
GrantPolicy::default(),
GrantPolicy {
base: CapabilitySet::EMPTY,
},
] {
for taint in [TaintState::Clean, TaintState::Tainted] {
let granted = granted_capabilities(policy, taint);
let out = decide(required, granted, &CallPolicy::default(), "demote");
assert_ne!(out, GateOutcome::Allow, "policy={policy:?} taint={taint:?}");
let GateOutcome::Escalate { reason, missing } = out else {
panic!("expected escalate for policy={policy:?} taint={taint:?}");
};
assert!(
missing.contains(Capability::ManageAdmin),
"the shortfall names the manage-admin marker"
);
assert!(reason.contains("demote"), "reason names the tool: {reason}");
}
}
}
#[test]
fn escalation_reason_is_plain_language_on_every_shape() {
let shapes = [
set(&[Capability::ArbitraryEgress]),
set(&[Capability::MutateExternal]),
set(&[Capability::ArbitraryEgress, Capability::MutateExternal]),
set(&[Capability::LocalWrite]),
set(&[Capability::GrantAccess]),
];
for missing in shapes {
let reason = escalation_reason("my_tool", missing);
assert!(reason.contains("my_tool"), "{reason}");
for banned in [
"capability",
"trifecta",
"egress",
"exfiltrat",
"taint",
"please",
"sorry",
"unfortunately",
] {
assert!(
!reason.to_lowercase().contains(banned),
"banned word {banned:?} in {reason:?}"
);
}
}
assert_eq!(GateOutcome::Allow.label(), "allow");
assert_eq!(
GateOutcome::Escalate {
reason: String::new(),
missing: CapabilitySet::EMPTY
}
.label(),
"escalate"
);
assert_eq!(GateOutcome::Deny(String::new()).label(), "deny");
assert_eq!(GateOutcome::Modify(String::new()).label(), "modify");
assert_eq!(
GateOutcome::InjectContext(String::new()).label(),
"inject_context"
);
}
#[test]
fn requirement_name_round_trips_through_from_name() {
for req in Requirement::ALL {
assert_eq!(Requirement::from_name(req.as_str()), Some(req));
}
assert_eq!(Requirement::from_name("no-such-requirement"), None);
}
#[test]
fn requirement_names_are_unique() {
let mut names: Vec<&str> = Requirement::ALL.iter().map(|r| r.as_str()).collect();
let before = names.len();
names.sort_unstable();
names.dedup();
assert_eq!(
names.len(),
before,
"every Requirement must have a distinct wire name"
);
}
#[test]
fn deployment_capabilities_default_is_nothing_viable() {
let caps = DeploymentCapabilities::default();
for req in Requirement::ALL {
assert!(
!caps.is_viable(req),
"{req:?} must not be viable by default"
);
}
assert!(caps.viable_names().is_empty());
}
#[test]
fn deployment_capabilities_viable_names_round_trips_through_from_names() {
let caps = DeploymentCapabilities {
mail_relay: true,
wallet_link_ceremony: false,
email_magic_link_ceremony: true,
payments_proxy: false,
};
let names = caps.viable_names();
assert_eq!(names, vec!["mail-relay", "ceremony-page:email-magic-link"]);
assert_eq!(DeploymentCapabilities::from_names(names), caps);
}
#[test]
fn deployment_capabilities_from_names_ignores_unknown_entries() {
let caps = DeploymentCapabilities::from_names(["mail-relay", "not-a-real-requirement"]);
assert!(caps.mail_relay);
assert!(!caps.payments_proxy);
}
#[test]
fn all_viable_is_true_only_when_every_requirement_is_met() {
let caps = DeploymentCapabilities {
mail_relay: true,
payments_proxy: false,
..DeploymentCapabilities::default()
};
assert!(
caps.all_viable(&[]),
"an empty requirement list is always viable"
);
assert!(caps.all_viable(&[Requirement::MailRelay]));
assert!(!caps.all_viable(&[Requirement::MailRelay, Requirement::PaymentsProxy]));
assert!(!caps.all_viable(&[Requirement::PaymentsProxy]));
}