From fb4cd616b6adacd8439493080fb3c19262c4e10f Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 08:55:23 +0000 Subject: [PATCH 1/9] refactor(approval): share the scope row cap across grant paths The 960-row scope cap was duplicated in the tool, flow-trust and import-trust grant modules. It now lives in one place, with a smaller value under test so filling a scope to its limit takes a handful of grants, and a test pins the production value. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- crates/tinysecurity-approval/src/engine.rs | 11 +++++++++++ crates/tinysecurity-approval/src/engine_flow_trust.rs | 5 +---- .../tinysecurity-approval/src/engine_import_trust.rs | 3 +-- crates/tinysecurity-approval/src/engine_tool_trust.rs | 3 +-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/tinysecurity-approval/src/engine.rs b/crates/tinysecurity-approval/src/engine.rs index 459c97a1..633e8cab 100644 --- a/crates/tinysecurity-approval/src/engine.rs +++ b/crates/tinysecurity-approval/src/engine.rs @@ -2133,6 +2133,17 @@ fn reusable_grant<'a>( }) } +/// Rows a scope may hold before a new tool, flow or import grant is refused: +/// below the 1024 the module's load contract accepts, so ordinary approvals keep +/// a margin. Shared by the tool, flow-trust and import-trust grant paths. +pub(crate) const PRODUCTION_MAX_SCOPE_ROWS: usize = 960; + +/// The cap the engine enforces. Unit tests run against a small cap so filling a +/// scope to its limit takes a handful of grants rather than 960; the refusal +/// logic under test is the same comparison either way, and the production value +/// is pinned by `engine::tests::the_production_scope_row_cap_is_960`. +pub(crate) const MAX_SCOPE_ROWS: usize = if cfg!(test) { 8 } else { PRODUCTION_MAX_SCOPE_ROWS }; + #[path = "engine_flow_trust.rs"] mod flow_trust; #[path = "engine_import_trust.rs"] diff --git a/crates/tinysecurity-approval/src/engine_flow_trust.rs b/crates/tinysecurity-approval/src/engine_flow_trust.rs index 74ba8c97..deab963f 100644 --- a/crates/tinysecurity-approval/src/engine_flow_trust.rs +++ b/crates/tinysecurity-approval/src/engine_flow_trust.rs @@ -20,9 +20,6 @@ use tinysecurity_bus::{ const ATTRIBUTION: &str = "flow-trust-grant"; pub(super) const IMPORT_ATTRIBUTION: &str = "flow-trust-import"; -/// Rows a scope may hold before a new grant is refused, below the 1024 the module's -/// load contract accepts so ordinary approvals keep a margin. -const MAX_SCOPE_ROWS: usize = 960; /// Digest of the exact `(flow, tool)` pair, domain-separated from every call digest. pub(super) fn trust_key(flow_id: &str, tool: &str) -> String { @@ -134,7 +131,7 @@ impl Engine { } // Revoked and expired grants still occupy durable rows. Reissuing them would // append another row and eventually exceed the module's load bound. - if rows.len() >= MAX_SCOPE_ROWS { + if rows.len() >= super::MAX_SCOPE_ROWS { return Err(Error::Unavailable); } let redactor = self.redactor()?; diff --git a/crates/tinysecurity-approval/src/engine_import_trust.rs b/crates/tinysecurity-approval/src/engine_import_trust.rs index f2cd4670..478781ac 100644 --- a/crates/tinysecurity-approval/src/engine_import_trust.rs +++ b/crates/tinysecurity-approval/src/engine_import_trust.rs @@ -12,7 +12,6 @@ use tinysecurity_bus::{ ImportTrustSourceRequest2, TOOL_TRUST_LIFETIME_MS2, }; -const MAX_SCOPE_ROWS: usize = 960; struct ImportPlan { attribution: &'static str, @@ -215,7 +214,7 @@ impl Engine { request_id: existing.request_id.clone(), }); } - if rows.len() >= MAX_SCOPE_ROWS { + if rows.len() >= super::MAX_SCOPE_ROWS { return Err(Error::Unavailable); } let now = self.now()?; diff --git a/crates/tinysecurity-approval/src/engine_tool_trust.rs b/crates/tinysecurity-approval/src/engine_tool_trust.rs index f2bef415..cdfa1104 100644 --- a/crates/tinysecurity-approval/src/engine_tool_trust.rs +++ b/crates/tinysecurity-approval/src/engine_tool_trust.rs @@ -14,7 +14,6 @@ use tinysecurity_bus::{ const ATTRIBUTION: &str = "tool-trust-grant"; pub(super) const IMPORT_ATTRIBUTION: &str = "tool-trust-import"; -const MAX_SCOPE_ROWS: usize = 960; /// Digest of an exact tool name, disjoint from call and flow trust bindings. pub(super) fn trust_key(tool: &str) -> String { @@ -121,7 +120,7 @@ impl Engine { } // Revoked and expired grants still occupy durable rows. Reissuing them would // append another row and eventually exceed the module's load bound. - if rows.len() >= MAX_SCOPE_ROWS { + if rows.len() >= super::MAX_SCOPE_ROWS { return Err(Error::Unavailable); } let redactor = self.redactor()?; From 8cf1f2fd074877fe95c0f41ede67b8d881be8bd2 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 08:55:35 +0000 Subject: [PATCH 2/9] test(approval): derive scope row cap from engine constant Replace the hard-coded 960 row limit in the engine gap tests with a CAP constant sourced from engine::MAX_SCOPE_ROWS, so the tests track the real cap instead of silently drifting if it changes. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- .../src/engine_gaps_tests.rs | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/crates/tinysecurity-approval/src/engine_gaps_tests.rs b/crates/tinysecurity-approval/src/engine_gaps_tests.rs index b793c448..bb1efe3f 100644 --- a/crates/tinysecurity-approval/src/engine_gaps_tests.rs +++ b/crates/tinysecurity-approval/src/engine_gaps_tests.rs @@ -1589,30 +1589,33 @@ async fn a_flow_identity_may_be_as_long_as_a_callers_but_a_tool_name_keeps_its_b Ok(()) } +/// The scope row cap the engine enforces in unit tests, as a grant counter. +const CAP: u64 = crate::engine::MAX_SCOPE_ROWS as u64; + #[tokio::test] async fn a_full_scope_takes_no_new_flow_trust_but_still_answers_for_a_live_one() -> Result<()> { let (_, owner) = owner()?; owner.register_scope(register(7)).await?; - for n in 0..960u64 { + for n in 0..CAP { owner .grant_flow_tool(grant(7, &format!("flow-{n}"), "shell", n + 1)) .await?; } assert_eq!( owner - .grant_flow_tool(grant(7, "one-more", "shell", 961)) + .grant_flow_tool(grant(7, "one-more", "shell", CAP + 1)) .await .err(), Some(Error::Unavailable) ); let again = owner - .grant_flow_tool(grant(7, "flow-0", "shell", 962)) + .grant_flow_tool(grant(7, "flow-0", "shell", CAP + 2)) .await?; assert_eq!(again.outcome, FlowTrustOutcome2::Unchanged); // The scope still loads. assert_eq!( owner.list_flow_trust(listing(7, None)).await?.entries.len(), - 960 + crate::engine::MAX_SCOPE_ROWS ); Ok(()) } @@ -1621,33 +1624,33 @@ async fn a_full_scope_takes_no_new_flow_trust_but_still_answers_for_a_live_one() async fn a_revoked_pair_cannot_cross_the_scope_row_cap_when_regranted() -> Result<()> { let (fixture, owner) = owner()?; owner.register_scope(register(7)).await?; - for n in 0..960u64 { + for n in 0..CAP { owner .grant_flow_tool(grant(7, &format!("flow-{n}"), "shell", n + 1)) .await?; } assert_eq!( fixture.rows.lock().map_err(|_| Error::Unavailable)?.len(), - 960 + crate::engine::MAX_SCOPE_ROWS ); let revoked = owner - .revoke_flow_tool(revoke(7, "flow-0", "shell", 961)) + .revoke_flow_tool(revoke(7, "flow-0", "shell", CAP + 1)) .await?; assert_eq!(revoked.outcome, FlowTrustOutcome2::Revoked); assert_eq!( fixture.rows.lock().map_err(|_| Error::Unavailable)?.len(), - 960 + crate::engine::MAX_SCOPE_ROWS ); assert_eq!( owner - .grant_flow_tool(grant(7, "flow-0", "shell", 962)) + .grant_flow_tool(grant(7, "flow-0", "shell", CAP + 2)) .await .err(), Some(Error::Unavailable) ); assert_eq!( fixture.rows.lock().map_err(|_| Error::Unavailable)?.len(), - 960 + crate::engine::MAX_SCOPE_ROWS ); Ok(()) } @@ -1656,28 +1659,28 @@ async fn a_revoked_pair_cannot_cross_the_scope_row_cap_when_regranted() -> Resul async fn a_revoked_tool_cannot_cross_the_scope_row_cap_when_regranted() -> Result<()> { let (fixture, owner) = owner()?; owner.register_scope(register(7)).await?; - for n in 0..960u64 { + for n in 0..CAP { owner .grant_tool(tool_grant(7, &format!("tool-{n}"), n + 1)) .await?; } assert_eq!( fixture.rows.lock().map_err(|_| Error::Unavailable)?.len(), - 960 + crate::engine::MAX_SCOPE_ROWS ); - let revoked = owner.revoke_tool(tool_revoke(7, "tool-0", 961)).await?; + let revoked = owner.revoke_tool(tool_revoke(7, "tool-0", CAP + 1)).await?; assert_eq!(revoked.outcome, ToolTrustOutcome2::Revoked); assert_eq!( fixture.rows.lock().map_err(|_| Error::Unavailable)?.len(), - 960 + crate::engine::MAX_SCOPE_ROWS ); assert_eq!( - owner.grant_tool(tool_grant(7, "tool-0", 962)).await.err(), + owner.grant_tool(tool_grant(7, "tool-0", CAP + 2)).await.err(), Some(Error::Unavailable) ); assert_eq!( fixture.rows.lock().map_err(|_| Error::Unavailable)?.len(), - 960 + crate::engine::MAX_SCOPE_ROWS ); Ok(()) } From c1c2448fcc7ee0f66668c779520ca098835357b8 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 08:55:45 +0000 Subject: [PATCH 3/9] test(approval): pin the production scope row cap to 960 Add a test asserting that the production scope row limit stays at 960 and remains below the 1024 rows the scope load contract accepts, since unit tests only exercise the smaller test cap and would not catch a drift in the production value. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- crates/tinysecurity-approval/src/engine_tests.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/tinysecurity-approval/src/engine_tests.rs b/crates/tinysecurity-approval/src/engine_tests.rs index 5a2cbed6..0f1f00a8 100644 --- a/crates/tinysecurity-approval/src/engine_tests.rs +++ b/crates/tinysecurity-approval/src/engine_tests.rs @@ -2532,3 +2532,13 @@ async fn app_io_rows_cannot_supply_reusable_or_flow_authority() -> Result<()> { } #[path = "engine_scopes_tests.rs"] mod engine_scopes_tests; + +#[test] +fn the_production_scope_row_cap_is_960() { + // Unit tests enforce a small cap (`MAX_SCOPE_ROWS`) so the cap tests stay + // fast; this pins the value every non-test build enforces, and keeps it below + // the 1024 rows the module's scope load contract accepts. + assert_eq!(crate::engine::PRODUCTION_MAX_SCOPE_ROWS, 960); + assert!(crate::engine::PRODUCTION_MAX_SCOPE_ROWS < 1024); + assert!(crate::engine::MAX_SCOPE_ROWS < crate::engine::PRODUCTION_MAX_SCOPE_ROWS); +} From d51351b5d33005be500fe4a0f5e9436c30b800c7 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 08:56:14 +0000 Subject: [PATCH 4/9] refactor(approval): move scope row cap bounds to compile-time assertions The upper bound on the production scope row cap and its relationship to the test cap are now checked by const assertions next to the constants instead of at runtime in a unit test, so a violation fails the build rather than a single test. The test keeps pinning the production value at 960. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- crates/tinysecurity-approval/src/engine.rs | 2 ++ crates/tinysecurity-approval/src/engine_tests.rs | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/tinysecurity-approval/src/engine.rs b/crates/tinysecurity-approval/src/engine.rs index 633e8cab..8aa50e06 100644 --- a/crates/tinysecurity-approval/src/engine.rs +++ b/crates/tinysecurity-approval/src/engine.rs @@ -2143,6 +2143,8 @@ pub(crate) const PRODUCTION_MAX_SCOPE_ROWS: usize = 960; /// logic under test is the same comparison either way, and the production value /// is pinned by `engine::tests::the_production_scope_row_cap_is_960`. pub(crate) const MAX_SCOPE_ROWS: usize = if cfg!(test) { 8 } else { PRODUCTION_MAX_SCOPE_ROWS }; +const _: () = assert!(PRODUCTION_MAX_SCOPE_ROWS < 1024); +const _: () = assert!(MAX_SCOPE_ROWS <= PRODUCTION_MAX_SCOPE_ROWS); #[path = "engine_flow_trust.rs"] mod flow_trust; diff --git a/crates/tinysecurity-approval/src/engine_tests.rs b/crates/tinysecurity-approval/src/engine_tests.rs index 0f1f00a8..acc254f4 100644 --- a/crates/tinysecurity-approval/src/engine_tests.rs +++ b/crates/tinysecurity-approval/src/engine_tests.rs @@ -2536,9 +2536,7 @@ mod engine_scopes_tests; #[test] fn the_production_scope_row_cap_is_960() { // Unit tests enforce a small cap (`MAX_SCOPE_ROWS`) so the cap tests stay - // fast; this pins the value every non-test build enforces, and keeps it below - // the 1024 rows the module's scope load contract accepts. + // fast; this pins the value every non-test build enforces. The bound against + // the 1024-row load contract is a compile-time assertion beside the constant. assert_eq!(crate::engine::PRODUCTION_MAX_SCOPE_ROWS, 960); - assert!(crate::engine::PRODUCTION_MAX_SCOPE_ROWS < 1024); - assert!(crate::engine::MAX_SCOPE_ROWS < crate::engine::PRODUCTION_MAX_SCOPE_ROWS); } From 73ac32f1924ccb2f1f52c7391e6bc95323a10386 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 08:56:34 +0000 Subject: [PATCH 5/9] perf(build): optimize crypto dependencies in dev and test profiles Debug and test builds now compile the crypto crates at opt-level 3 so Argon2id key derivation no longer takes seconds per call under coverage instrumentation. Only third-party crypto crates are optimized, leaving the workspace's own debug assertions and coverage counters intact. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- Cargo.toml | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 4b32a343..cab68911 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -141,6 +141,54 @@ must_use_candidate = "warn" broken_intra_doc_links = "warn" private_intra_doc_links = "warn" +# Debug and test builds (which `cargo test` and `cargo llvm-cov` inherit) run the +# crypto dependencies optimized. Unoptimized Argon2id at the production 64 MiB / 3 +# passes takes seconds per derivation, and every password round-trip test pays it, +# several times over under coverage instrumentation. Only these third-party crates +# are optimized, so the workspace's own code keeps full debug assertions and its +# coverage counters; what each test checks is unchanged. +[profile.dev.package.argon2] +opt-level = 3 + +[profile.dev.package.blake2] +opt-level = 3 + +[profile.dev.package.aes] +opt-level = 3 + +[profile.dev.package."aes-gcm"] +opt-level = 3 + +[profile.dev.package.ghash] +opt-level = 3 + +[profile.dev.package.polyval] +opt-level = 3 + +[profile.dev.package.chacha20] +opt-level = 3 + +[profile.dev.package.chacha20poly1305] +opt-level = 3 + +[profile.dev.package.poly1305] +opt-level = 3 + +[profile.dev.package.sha2] +opt-level = 3 + +[profile.dev.package.hmac] +opt-level = 3 + +[profile.dev.package.hkdf] +opt-level = 3 + +[profile.dev.package."curve25519-dalek"] +opt-level = 3 + +[profile.dev.package."x25519-dalek"] +opt-level = 3 + [profile.release] # Cross-crate optimization and smaller, faster binaries for release builds. lto = "thin" From a6ddeecb1b2fb10cc88212a0ff3d4e2518a09a3c Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 08:56:59 +0000 Subject: [PATCH 6/9] build: optimize zeroize in dev profile Raise the optimization level for the zeroize crate in dev builds so its zeroing routines run at full speed during development, matching the existing per-package overrides for other crypto dependencies. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index cab68911..0b85407f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -189,6 +189,9 @@ opt-level = 3 [profile.dev.package."x25519-dalek"] opt-level = 3 +[profile.dev.package.zeroize] +opt-level = 3 + [profile.release] # Cross-crate optimization and smaller, faster binaries for release builds. lto = "thin" From 4c1be779e2ba035cc6b0feb7750e4a2ecbb80971 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 08:58:27 +0000 Subject: [PATCH 7/9] test(approval_callbacks): shrink runtime scope cap under test Unit tests now fill the approval store client to its limit using a small test-only cap instead of the production 65,536, so the bound check runs in a handful of admits rather than tens of thousands. A new test pins the bus constant's contract value, and a compile-time assertion keeps the test cap from ever exceeding it. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- .../tinysecurity-module/src/approval_callbacks.rs | 14 +++++++++++++- .../src/approval_callbacks_tests.rs | 9 ++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/tinysecurity-module/src/approval_callbacks.rs b/crates/tinysecurity-module/src/approval_callbacks.rs index 8ce36918..0a71a020 100644 --- a/crates/tinysecurity-module/src/approval_callbacks.rs +++ b/crates/tinysecurity-module/src/approval_callbacks.rs @@ -10,6 +10,18 @@ use tinysecurity_bus::{ AuditConfig2, AuditEvent2, AuditKind2, AuditSinkRequest2, AuditSinkResponse2, HumanDecisionReceipt2, SubjectScope, VerifyHumanRequest2, callback_names2, }; + +/// Runtime subjects one store client may hold: the engine's own scope cap +/// (`MAX_APPROVAL_SCOPES2`). Unit tests use a small cap so filling the client to +/// its limit takes a handful of admits rather than 65,535; the refusal is the same +/// comparison either way. Non-test builds use the bus constant directly, and +/// `tests::the_bus_approval_scope_cap_is_65536` pins its contract value. +pub(crate) const MAX_RUNTIME_SCOPES: usize = if cfg!(test) { + 16 +} else { + tinysecurity_bus::MAX_APPROVAL_SCOPES2 +}; +const _: () = assert!(MAX_RUNTIME_SCOPES <= tinysecurity_bus::MAX_APPROVAL_SCOPES2); /// Captured registered callback identity; no model-provided destination or scope. pub(crate) struct ApprovalStoreClient { connection: tinybus::Connection, @@ -82,7 +94,7 @@ impl ApprovalStoreClient { fn admit(&self, handle: SubjectScope) -> Result<()> { let mut scopes = self.scopes.write().map_err(|_| Error::Unavailable)?; if !scopes.contains(&handle) { - if scopes.len() >= tinysecurity_bus::MAX_APPROVAL_SCOPES2 { + if scopes.len() >= MAX_RUNTIME_SCOPES { return Err(Error::Unavailable); } scopes.push(handle); diff --git a/crates/tinysecurity-module/src/approval_callbacks_tests.rs b/crates/tinysecurity-module/src/approval_callbacks_tests.rs index 6ca995db..d560e88e 100644 --- a/crates/tinysecurity-module/src/approval_callbacks_tests.rs +++ b/crates/tinysecurity-module/src/approval_callbacks_tests.rs @@ -979,7 +979,7 @@ async fn store_client_admits_releases_and_bounds_runtime_subjects() client.release(&handle)?; assert!(client.scope(&handle).is_err()); // Filling to the cap refuses the next new subject, and re-admitting a held one stays fine. - for n in 0..(tinysecurity_bus::MAX_APPROVAL_SCOPES2 - 1) { + for n in 0..(super::MAX_RUNTIME_SCOPES - 1) { client.admit(tinysecurity::approval::scope_handle(&SubjectScope { user: format!("u{n}"), workspace: "w".into(), @@ -1116,3 +1116,10 @@ async fn released_subjects_keep_their_stream_only_for_the_retention_window_and_p broker.abort(); Ok(()) } + +#[test] +fn the_bus_approval_scope_cap_is_65536() { + // Unit tests enforce a small `MAX_RUNTIME_SCOPES`; every other build uses + // `MAX_APPROVAL_SCOPES2` itself, whose contract value this pins. + assert_eq!(tinysecurity_bus::MAX_APPROVAL_SCOPES2, 65_536); +} From 8d042cdac3d32740556b3b4b723aa822cbbbd59e Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 09:00:43 +0000 Subject: [PATCH 8/9] refactor(approval): make pending creation memo cap test-configurable The hard-coded 1024-entry cap on the creation retry memo is now a named constant that shrinks to 16 under cfg(test), mirroring the existing scope-row cap so tests can fill the memo without thousands of iterations. A compile-time assertion keeps the test cap at or below the production value, and a new test pins the production cap at 1024. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- crates/tinysecurity-approval/src/engine.rs | 11 ++++++++++- crates/tinysecurity-approval/src/engine_tests.rs | 11 +++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/tinysecurity-approval/src/engine.rs b/crates/tinysecurity-approval/src/engine.rs index 8aa50e06..630a2c6a 100644 --- a/crates/tinysecurity-approval/src/engine.rs +++ b/crates/tinysecurity-approval/src/engine.rs @@ -824,7 +824,7 @@ impl Engine { if native && intents.len() >= 32 && !intents.contains_key(&row.binding.call_sha256) { return Err(Error::Unavailable); } - if !creations.contains_key(&row.binding.call_sha256) && creations.len() >= 1024 { + if !creations.contains_key(&row.binding.call_sha256) && creations.len() >= MAX_PENDING_CREATIONS { return Err(Error::Unavailable); } let row = creations @@ -2138,6 +2138,15 @@ fn reusable_grant<'a>( /// a margin. Shared by the tool, flow-trust and import-trust grant paths. pub(crate) const PRODUCTION_MAX_SCOPE_ROWS: usize = 960; +/// Pending creations the retry memo holds before a new call identity is refused. +pub(crate) const PRODUCTION_MAX_PENDING_CREATIONS: usize = 1024; + +/// The memo cap the engine enforces; small in unit tests for the same reason as +/// `MAX_SCOPE_ROWS`. Pinned by `engine::tests::the_production_creation_memo_cap_is_1024`. +pub(crate) const MAX_PENDING_CREATIONS: usize = + if cfg!(test) { 16 } else { PRODUCTION_MAX_PENDING_CREATIONS }; +const _: () = assert!(MAX_PENDING_CREATIONS <= PRODUCTION_MAX_PENDING_CREATIONS); + /// The cap the engine enforces. Unit tests run against a small cap so filling a /// scope to its limit takes a handful of grants rather than 960; the refusal /// logic under test is the same comparison either way, and the production value diff --git a/crates/tinysecurity-approval/src/engine_tests.rs b/crates/tinysecurity-approval/src/engine_tests.rs index acc254f4..cb258c82 100644 --- a/crates/tinysecurity-approval/src/engine_tests.rs +++ b/crates/tinysecurity-approval/src/engine_tests.rs @@ -1046,7 +1046,7 @@ async fn completed_executions_do_not_exhaust_the_creation_retry_window() -> Resu Arc::new(TestClock::default()), Redactor::new(&RedactorConfig::default()).map_err(|_| Error::Invalid)?, )?; - for index in 0..1026 { + for index in 0..crate::engine::MAX_PENDING_CREATIONS + 2 { let mut input = request(); input.request.caller.call_id = format!("completed-{index}"); let row = owner.begin(input.clone()).await?; @@ -1139,7 +1139,7 @@ async fn indeterminate_creation_identities_survive_capacity_pressure_and_retry() let f = Arc::new(Fixture::default()); let owner = engine(f.clone(), Arc::new(TestClock::default()))?; f.fail.store(1, Ordering::SeqCst); - for index in 0..1024 { + for index in 0..crate::engine::MAX_PENDING_CREATIONS { let mut input = request(); input.request.caller.call_id = format!("unacknowledged-{index}"); assert!(owner.begin(input).await.is_err()); @@ -2540,3 +2540,10 @@ fn the_production_scope_row_cap_is_960() { // the 1024-row load contract is a compile-time assertion beside the constant. assert_eq!(crate::engine::PRODUCTION_MAX_SCOPE_ROWS, 960); } + +#[test] +fn the_production_creation_memo_cap_is_1024() { + // Unit tests enforce a small `MAX_PENDING_CREATIONS`; this pins the value every + // non-test build enforces. + assert_eq!(crate::engine::PRODUCTION_MAX_PENDING_CREATIONS, 1024); +} From 1d8f0b2ddffd7733a9aee24f882cc56b0cf86831 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 12 Nov 2026 09:02:18 +0000 Subject: [PATCH 9/9] style(tinysecurity-approval): reformat engine sources with rustfmt Reformatted the approval engine and its gap tests to satisfy rustfmt, wrapping long conditionals and method chains and dropping stray blank lines. No behaviour changes. Auto-committed-on: cuttlefish Co-authored-by: Medulla --- crates/tinysecurity-approval/src/engine.rs | 17 +++++++++++++---- .../src/engine_flow_trust.rs | 1 - .../src/engine_gaps_tests.rs | 5 ++++- .../src/engine_import_trust.rs | 1 - 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/tinysecurity-approval/src/engine.rs b/crates/tinysecurity-approval/src/engine.rs index 630a2c6a..7f396618 100644 --- a/crates/tinysecurity-approval/src/engine.rs +++ b/crates/tinysecurity-approval/src/engine.rs @@ -824,7 +824,9 @@ impl Engine { if native && intents.len() >= 32 && !intents.contains_key(&row.binding.call_sha256) { return Err(Error::Unavailable); } - if !creations.contains_key(&row.binding.call_sha256) && creations.len() >= MAX_PENDING_CREATIONS { + if !creations.contains_key(&row.binding.call_sha256) + && creations.len() >= MAX_PENDING_CREATIONS + { return Err(Error::Unavailable); } let row = creations @@ -2143,15 +2145,22 @@ pub(crate) const PRODUCTION_MAX_PENDING_CREATIONS: usize = 1024; /// The memo cap the engine enforces; small in unit tests for the same reason as /// `MAX_SCOPE_ROWS`. Pinned by `engine::tests::the_production_creation_memo_cap_is_1024`. -pub(crate) const MAX_PENDING_CREATIONS: usize = - if cfg!(test) { 16 } else { PRODUCTION_MAX_PENDING_CREATIONS }; +pub(crate) const MAX_PENDING_CREATIONS: usize = if cfg!(test) { + 16 +} else { + PRODUCTION_MAX_PENDING_CREATIONS +}; const _: () = assert!(MAX_PENDING_CREATIONS <= PRODUCTION_MAX_PENDING_CREATIONS); /// The cap the engine enforces. Unit tests run against a small cap so filling a /// scope to its limit takes a handful of grants rather than 960; the refusal /// logic under test is the same comparison either way, and the production value /// is pinned by `engine::tests::the_production_scope_row_cap_is_960`. -pub(crate) const MAX_SCOPE_ROWS: usize = if cfg!(test) { 8 } else { PRODUCTION_MAX_SCOPE_ROWS }; +pub(crate) const MAX_SCOPE_ROWS: usize = if cfg!(test) { + 8 +} else { + PRODUCTION_MAX_SCOPE_ROWS +}; const _: () = assert!(PRODUCTION_MAX_SCOPE_ROWS < 1024); const _: () = assert!(MAX_SCOPE_ROWS <= PRODUCTION_MAX_SCOPE_ROWS); diff --git a/crates/tinysecurity-approval/src/engine_flow_trust.rs b/crates/tinysecurity-approval/src/engine_flow_trust.rs index deab963f..ee0c5337 100644 --- a/crates/tinysecurity-approval/src/engine_flow_trust.rs +++ b/crates/tinysecurity-approval/src/engine_flow_trust.rs @@ -20,7 +20,6 @@ use tinysecurity_bus::{ const ATTRIBUTION: &str = "flow-trust-grant"; pub(super) const IMPORT_ATTRIBUTION: &str = "flow-trust-import"; - /// Digest of the exact `(flow, tool)` pair, domain-separated from every call digest. pub(super) fn trust_key(flow_id: &str, tool: &str) -> String { let mut bytes = Vec::with_capacity(flow_id.len() + tool.len() + 8); diff --git a/crates/tinysecurity-approval/src/engine_gaps_tests.rs b/crates/tinysecurity-approval/src/engine_gaps_tests.rs index bb1efe3f..a1395803 100644 --- a/crates/tinysecurity-approval/src/engine_gaps_tests.rs +++ b/crates/tinysecurity-approval/src/engine_gaps_tests.rs @@ -1675,7 +1675,10 @@ async fn a_revoked_tool_cannot_cross_the_scope_row_cap_when_regranted() -> Resul crate::engine::MAX_SCOPE_ROWS ); assert_eq!( - owner.grant_tool(tool_grant(7, "tool-0", CAP + 2)).await.err(), + owner + .grant_tool(tool_grant(7, "tool-0", CAP + 2)) + .await + .err(), Some(Error::Unavailable) ); assert_eq!( diff --git a/crates/tinysecurity-approval/src/engine_import_trust.rs b/crates/tinysecurity-approval/src/engine_import_trust.rs index 478781ac..81b2e371 100644 --- a/crates/tinysecurity-approval/src/engine_import_trust.rs +++ b/crates/tinysecurity-approval/src/engine_import_trust.rs @@ -12,7 +12,6 @@ use tinysecurity_bus::{ ImportTrustSourceRequest2, TOOL_TRUST_LIFETIME_MS2, }; - struct ImportPlan { attribution: &'static str, choice: ApprovalChoice2,