Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
f517c3e
feat(tinysecurity-module): add native-security-tests feature
senamakel Oct 23, 2026
89a5373
feat(native_test_resolver): add deterministic fixture resolver for na…
senamakel Oct 23, 2026
ce27627
Merge remote-tracking branch 'origin/main' into epic-7328-continue
senamakel Oct 23, 2026
de7fd53
refactor(tinysecurity-module): route egress checks through a resolver…
senamakel Oct 23, 2026
d61b9c0
refactor(native-test-resolver): simplify fallback and tidy tests
senamakel Oct 23, 2026
04f9c09
fix(tinysecurity-module): gate native test resolver on debug builds
senamakel Oct 23, 2026
c326322
test(native): cover mixed-case host key resolution
senamakel Oct 23, 2026
57d11dd
fix(tinysecurity-module): reject duplicate fixture hostnames
senamakel Oct 23, 2026
27d99de
test(tinysecurity-module): return result from mixed-case host key test
senamakel Oct 23, 2026
5ed1d42
Document the native DNS test fixture
senamakel Oct 23, 2026
e2e4a87
test(native): cover duplicate host keys in invalid fixture inputs
senamakel Oct 23, 2026
9e43459
fix(tinysecurity-module): reject duplicate hostnames in dns fixtures
senamakel Oct 23, 2026
467ed1e
style: reorder imports in native test resolver
senamakel Oct 23, 2026
d2d217e
test(tinysecurity-module): cover fixture resolver bounds and failure …
senamakel Oct 23, 2026
51f9ee6
refactor(native-test-resolver): extract fixture parsing into a testab…
senamakel Oct 23, 2026
ed63e62
test(native): return result from resolver rejection test
senamakel Oct 23, 2026
d8707a0
test: tolerate Windows coverage overhead in cipher fixtures
senamakel Oct 23, 2026
c18b56f
test: let cipher replay assertions observe module rejection
senamakel Oct 23, 2026
0867aa0
feat(native_handles): add register_scope for live registries
senamakel Oct 23, 2026
1d91ba6
test(crypto): cover scope registration generation checks
senamakel Oct 23, 2026
59ab3d1
fix(tinysecurity-crypto): reject stale scope registrations
senamakel Oct 23, 2026
7994e67
feat(bus): add runtime secret scope registration method
senamakel Oct 23, 2026
4cf86e8
feat(approval): add scope_snapshot accessor for live registrations
senamakel Oct 23, 2026
bef5153
feat(module): support dynamic secret registrations
senamakel Oct 23, 2026
b81f2ca
feat(secret): add dynamic secret scope registration and retirement
senamakel Oct 23, 2026
6694582
feat(module): register secret scopes and retire them with approval sc…
senamakel Oct 23, 2026
1e3896e
refactor(adapter_secret): simplify secret state iteration and borrows
senamakel Oct 23, 2026
5c8eb2e
test(adapter): cover secret scope registration and retirement
senamakel Oct 23, 2026
439fca3
test(adapter-secret): cover mode 22 denial in master resolution test
senamakel Oct 23, 2026
521a9b6
test(adapter-secret): cover runtime secret registration approval scope
senamakel Oct 23, 2026
3d4a58e
test(adapter-secret): simplify mode 22 assertion and fix signature fo…
senamakel Oct 23, 2026
fce7bf3
test(adapter-secret): add trace output to runtime secret exercise
senamakel Oct 23, 2026
a432d47
test(adapter-secret): register approval scope through proxy in runtim…
senamakel Oct 23, 2026
5402803
test(adapter-secret): use hex ids in secret scope fixtures
senamakel Oct 23, 2026
316aa9a
fix(secret): check dynamic registrations before re-registering
senamakel Oct 23, 2026
88c41f4
test(bus): update contract version expectations to 1.29
senamakel Oct 23, 2026
fff0b2a
test(adapter-secret): reformat assertion for readability
senamakel Oct 23, 2026
3456127
test(adapter-secret): cast registration counts to usize
senamakel Oct 23, 2026
37fb952
docs: add runtime secret scopes contract for 1.29
senamakel Oct 23, 2026
4144fad
docs: document runtime secret scopes contract 1.29
senamakel Oct 23, 2026
6fe5572
test(adapter-secret): cover scope replacement and secret re-registration
senamakel Oct 23, 2026
685b4a7
chore(bus): reorder method name entries
senamakel Oct 23, 2026
4de953e
test(crypto): cover scope replacement fencing old reservations
senamakel Oct 23, 2026
b3dee49
feat(native_handles): add replace_scope to update a live scope's policy
senamakel Oct 23, 2026
9788ae1
fix(secret): guard approval scope with rwlock and refresh on change
senamakel Oct 23, 2026
826b48b
fix(module): refresh approval scope after replacing it
senamakel Oct 23, 2026
84299f1
style: reformat adapter_secret for rustfmt compliance
senamakel Oct 23, 2026
1a6b62e
test(adapter-secret): cover re-registration with a reused policy ref
senamakel Oct 23, 2026
2f98856
fix(native_handles): reject operations on deactivated scopes
senamakel Oct 23, 2026
f0a7354
test(crypto): cover revoked scope re-registration and replacement
senamakel Oct 23, 2026
48ce317
test(crypto): reformat revoked scope assertions
senamakel Oct 23, 2026
8c7ec6e
docs(specs): document tombstoning of revoked runtime secret ids
senamakel Oct 23, 2026
4653dbf
refactor(crypto): take registration by reference in replace_scope
senamakel Oct 23, 2026
e507098
fix(tinysecurity-crypto): correct borrows in native handle registry
senamakel Oct 23, 2026
469a801
fix(tinysecurity-crypto): correct registration reference in scope checks
senamakel Oct 23, 2026
4bf677c
chore(adapter): note async bus interface in secret scope registration
senamakel Oct 23, 2026
e7347bc
refactor(adapter_secret): simplify scope retention predicate
senamakel Oct 23, 2026
0e3d8fd
fix(adapter): serialize secret scope lifecycle operations
senamakel Oct 23, 2026
c6fc837
fix(tinysecurity-module): retire approval scopes after engine updates
senamakel Oct 23, 2026
0a2badb
fix(tinysecurity-module): retire approval scope before replacing or r…
senamakel Oct 23, 2026
802648b
refactor(adapter): move secret scope lifecycle lock to a static
senamakel Oct 23, 2026
74fbe99
fix(tinysecurity-module): retire approval scope after engine call
senamakel Oct 23, 2026
aeeb66c
fix(adapter): serialize secret scope registration with lifecycle lock
senamakel Oct 23, 2026
9968f23
fix(adapter): serialize scope registration and retirement
senamakel Oct 23, 2026
3eb7e6a
style: reformat approval scope code and tests
senamakel Oct 23, 2026
88f5c4f
test(policy): cover host skill scan verdicts and denial precedence
senamakel Oct 23, 2026
dae1135
feat(bus): add skill scan verdict check to policy contract
senamakel Oct 23, 2026
f205ed7
fix(approval): treat skill scan checks as non-external
senamakel Oct 23, 2026
f6256bb
test(policy): import SkillScanVerdict in engine tests
senamakel Oct 23, 2026
9a950f5
test(tinysecurity-policy): rename loop variable in skill scan verdict…
senamakel Oct 23, 2026
fecf3bc
feat(policy): bind skill scan approvals to bundle digest
senamakel Oct 23, 2026
893ef9c
docs: document host skill-scan contract 1.29
senamakel Oct 23, 2026
5c4abe5
test(approval): cover skill scan warn and block verdicts
senamakel Oct 23, 2026
b8be187
test(approval): assert denied lifecycle state instead of error
senamakel Oct 23, 2026
d2d1187
test(approval): narrow skill scan test to human approval path
senamakel Oct 23, 2026
5599b28
docs: expand skill-scan contract 1.29 spec
senamakel Oct 23, 2026
a5fdecc
test(approval): cover skill scan block under auto-approve scope
senamakel Oct 23, 2026
09fdf07
fix(approval): require human approval for blocked and warned skill scans
senamakel Oct 23, 2026
2237f3b
test(adapter-host): cover host skill scan verdicts before run_workflow
senamakel Oct 23, 2026
758a779
refactor(approval): extract blocked skill scan check and flatten cond…
senamakel Oct 23, 2026
e94c723
test(policy): cover skill scan pass without effect check
senamakel Oct 23, 2026
4adef47
fix(policy): stop treating skill scan checks as host tool calls
senamakel Oct 23, 2026
2f85664
docs: clarify skill scan is supplemental and additive for 1.28 hosts
senamakel Oct 23, 2026
8dfbb39
test(policy): simplify contract version test setup
senamakel Oct 23, 2026
7721860
test(adapter-host-tool): cover skill scan checks in admission-only de…
senamakel Oct 23, 2026
d9d2590
fix(adapter): treat skill scans as admission-only checks
senamakel Oct 23, 2026
24ef88e
style: reformat admission_only check for readability
senamakel Oct 23, 2026
0e8e631
docs(tinysecurity-module): clarify admission_only doc comment
senamakel Oct 23, 2026
e7f1b32
test: isolate process-owned confidential fixtures in child processes
senamakel Oct 23, 2026
fe5bf95
test(adapter-secret): cover static registration and conflicting backend
senamakel Oct 23, 2026
4af2af2
style: format runtime registration coverage tests
senamakel Oct 23, 2026
10453d7
fix(secret): refresh cipher audit policy on scope replacement
senamakel Oct 23, 2026
44499c4
chore(tinysecurity-module): gate audit_policy_ref behind cfg(test)
senamakel Oct 23, 2026
e71c68c
test(adapter): serialize secret scope tests with a shared lock
senamakel Oct 23, 2026
ca5b4d0
test(adapter): isolate process-global secret scope tests
senamakel Oct 23, 2026
5227651
test(adapter-secret): drop redundant lock and inline result type
senamakel Oct 23, 2026
6ddd02a
fix(module): pass secret cipher state into approval scope refresh
senamakel Oct 23, 2026
57cc91c
test: remove process isolation helper from secret adapter tests
senamakel Oct 23, 2026
d57aafa
Merge branch 'skill-scan-risk-7328' into runtime-secret-scopes-129
senamakel Oct 23, 2026
f391368
test(secret): cover orphaned pending scope cleanup
senamakel Oct 23, 2026
6458de1
fix(secret): prune orphaned pending scope calls
senamakel Oct 23, 2026
068bb33
Merge pull request #47 from tinyhumansai/runtime-secret-scopes-129
senamakel Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
# Example of a credential a live/network-gated test would need. Tests that
# require one must skip cleanly when it is unset.
# EXAMPLE_API_KEY=replace-me

# Debug-only native egress fixture input (enable `native-security-tests`). Each
# host lookup consumes the next address; malformed or exhausted sequences deny.
# TINYSECURITY_TEST_DNS_SEQUENCE={"rebind.test":["8.8.8.8","127.0.0.1"]}
3 changes: 3 additions & 0 deletions MODULE.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ Full details: [paired-device lifecycle specification](docs/specs/device-pairing-
## Browser destination authorization (contract 1.28)
Full details: [browser dial specification](docs/specs/browser-dial-contract-1.28.md).

## Host skill-scan decisions (contract 1.29)
Full details: [host skill-scan specification](docs/specs/skill-scan-contract-1.29.md).

## Confidential injected master resolution
Full details: [`Confidential injected master resolution`](docs/module-crypto.md#confidential-injected-master-resolution).

Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ when a lease expires or policy generation changes. Sensitive and local-only
privacy modes deny this uninspectable traffic; TinyComputer remains responsible
for enforcing the proxy and dialing the approved socket. See the
[browser-dial contract specification](docs/specs/browser-dial-contract-1.28.md).
Contract 1.29 adds the host-only `RegisterSecretScope2` member for adding a
secret resolver bound to an already-live approval scope, without reinitializing
the process-global secret registry. Approval-scope replacement or retirement
revokes the associated secret handles and runtime registrations; see the
[runtime secret-scope specification](docs/specs/runtime-secret-scopes-contract-1.29.md).

Contract 1.29 adds `Check::SkillScan` so the trusted host can submit the scan
verdict and exact bundle digest before an installed skill runs. `Block` is a
content denial, `Warn` enters the host's approval flow, and `Pass` leaves the
remaining policy checks authoritative. See the
[host skill-scan specification](docs/specs/skill-scan-contract-1.29.md).

Contract 1.6 supplies `Audit2`, `EvaluateAudited2` and `CheckAudited2` with
authenticated exact audit callbacks and a bounded [native journal](crates/tinysecurity-audit/README.md).
Expand Down
16 changes: 15 additions & 1 deletion crates/tinysecurity-approval/src/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ pub(crate) fn native_safe_call(request: &EvaluateRequest) -> Result<String> {
}
Ok(safe_call)
}

fn contains_blocked_skill_scan(checks: &[Check]) -> bool {
checks.iter().any(|check| {
matches!(
check,
Check::SkillScan {
verdict: tinysecurity_bus::SkillScanVerdict::Block,
..
}
)
})
}

pub(crate) fn original(
reg: &ApprovalScope2,
request: &EvaluateRequest,
Expand All @@ -113,6 +126,7 @@ pub(crate) fn original(
|| request.call.arguments_json.len() > 32768
|| request.call.checks.is_empty()
|| request.call.checks.len() > 128
|| contains_blocked_skill_scan(&request.call.checks)
|| (reg.ceiling == AccessTier::Read && request.caller.tier != AccessTier::Read)
|| (reg.ceiling == AccessTier::Write && request.caller.tier == AccessTier::Full)
|| request
Expand All @@ -137,7 +151,7 @@ pub(crate) fn original(
args.sort_all_objects();
let canonical = serde_json::to_string(&args).map_err(|_| Error::Invalid)?;
let external = request.call.checks.iter().any(|check| match check {
Check::LocalDiagnostic {} => false,
Check::LocalDiagnostic {} | Check::SkillScan { .. } => false,
Check::Path { write, .. } => *write,
Check::HostAction {
external_effect, ..
Expand Down
18 changes: 18 additions & 0 deletions crates/tinysecurity-approval/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,17 @@ impl Engine {
now: u64,
native: bool,
) -> Result<(Option<ApprovalRow2>, bool)> {
let scan_warning = request.request.call.checks.iter().any(|check| {
matches!(
check,
Check::SkillScan {
verdict: tinysecurity_bus::SkillScanVerdict::Warn,
..
}
)
});
let human_only = native
|| scan_warning
|| matches!(
request.request.call.tool.as_str(),
"sandbox_host_network" | "device_crypto"
Expand Down Expand Up @@ -1172,6 +1182,14 @@ impl Engine {
let entry = self.entry(id)?;
Ok(self.registered(&entry))
}
/// Return the current trusted scope snapshot for one live registration.
/// This is used by sibling module adapters that must bind a secondary
/// capability to the approval engine's canonical subject and generation.
/// # Errors
/// Rejects unknown registrations or poisoned approval state.
pub fn scope_snapshot(&self, id: &str) -> Result<ApprovalScope2> {
self.registration(id)
}
fn validate_scope(scope: &ApprovalScope2) -> Result<()> {
if scope.scope_id.len() != 32
|| !scope.scope_id.bytes().all(|b| b.is_ascii_hexdigit())
Expand Down
27 changes: 27 additions & 0 deletions crates/tinysecurity-approval/src/engine_scopes_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,33 @@ async fn host_tool_marker_is_an_external_effect_that_cron_cannot_reach() -> Resu
Ok(())
}

#[tokio::test]
async fn skill_scan_warning_enters_human_approval() -> Result<()> {
let (_, owner) = owner()?;
let mut auto_approve = register(7);
auto_approve.scope.auto_approve_all = true;
auto_approve.grants = grants(&["run_workflow"], &[]);
owner.register_scope(auto_approve).await?;

let mut warning = begin_for(7, "run_workflow", None, Origin::Operator);
warning.request.call.checks = vec![Check::SkillScan {
verdict: tinysecurity_bus::SkillScanVerdict::Warn,
bundle_sha256: "a".repeat(64),
}];
let pending = owner.begin(warning).await?;
assert_eq!(pending.state, ApprovalLifecycle2::Pending);
assert!(!pending.external_effect);

let mut blocked = begin_for(7, "run_workflow", None, Origin::Operator);
blocked.request.caller.call_id = "blocked-call".into();
blocked.request.call.checks = vec![Check::SkillScan {
verdict: tinysecurity_bus::SkillScanVerdict::Block,
bundle_sha256: "b".repeat(64),
}];
assert_eq!(owner.begin(blocked).await.err(), Some(Error::Denied));
Ok(())
}

#[tokio::test]
async fn host_action_and_shell_checks_bind_with_their_own_external_effect() -> Result<()> {
let (_, owner) = owner()?;
Expand Down
2 changes: 1 addition & 1 deletion crates/tinysecurity-bus/src/device_frame_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,5 @@ fn frame_operations_redact_both_payloads_without_changing_open_wire_shape()
#[test]
fn frame_member_name_is_stable_and_contract_version_is_bumped() {
assert_eq!(crate::names::methods::DEVICE_FRAME2, "DeviceFrame2");
assert_eq!(crate::CONTRACT_VERSION, (1, 28));
assert_eq!(crate::CONTRACT_VERSION, (1, 29));
}
2 changes: 1 addition & 1 deletion crates/tinysecurity-bus/src/device_pairing_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn refresh_and_close_are_distinct_transient_session_operations() {

#[test]
fn pairing_contract_is_versioned_after_the_frame_contract() {
assert_eq!(CONTRACT_VERSION, (1, 28));
assert_eq!(CONTRACT_VERSION, (1, 29));
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion crates/tinysecurity-bus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub use scoped_policy::*;
pub use tool_trust::*;
pub mod names;
/// Current wire vocabulary version, independent of the artifact version.
pub const CONTRACT_VERSION: (u32, u32) = (1, 28);
pub const CONTRACT_VERSION: (u32, u32) = (1, 29);
/// Whether a remote module's advertised version supplies this host's vocabulary.
///
/// `version` is the provider version received by the host, not a host requirement
Expand Down
3 changes: 3 additions & 0 deletions crates/tinysecurity-bus/src/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ pub mod methods {
pub const REPLACE_APPROVAL_SCOPE2: &str = "ReplaceApprovalScope2";
/// Retire a scope so later calls under it deny (contract 1.17).
pub const RETIRE_APPROVAL_SCOPE2: &str = "RetireApprovalScope2";
/// Register a secret resolver for an already-live approval scope (contract 1.29).
pub const REGISTER_SECRET_SCOPE2: &str = "RegisterSecretScope2";
/// Evaluate member.
pub const EVALUATE: &str = "Evaluate";
/// Check member.
Expand Down Expand Up @@ -249,6 +251,7 @@ pub const METHODS: &[&str] = &[
methods::LIST_TOOL_TRUST2,
methods::IMPORT_TRUST_SOURCE2,
methods::REGISTER_APPROVAL_SCOPE2,
methods::REGISTER_SECRET_SCOPE2,
methods::REPLACE_APPROVAL_SCOPE2,
methods::RETIRE_APPROVAL_SCOPE2,
methods::REGISTER_SANDBOX_SCOPE2,
Expand Down
25 changes: 25 additions & 0 deletions crates/tinysecurity-bus/src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ pub struct ToolCall {
/// Never forward checks supplied by a model, tool client or remote caller.
pub checks: Vec<Check>,
}

/// Host-computed verdict from scanning a skill before execution (contract 1.29).
/// The host must scan the exact installed document and resources it will expose;
/// this value is a trusted host assertion, never a model-supplied claim. It is
/// supplemental to the host-effect check and cannot authorize a tool call alone.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SkillScanVerdict {
/// No findings require action.
Pass,
/// Findings require the existing host approval flow before execution.
Warn,
/// The scan found content that must not execute.
Block,
}

/// A check of a concrete operation. The bootstrap has no URL authorization.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
Expand Down Expand Up @@ -141,6 +157,15 @@ pub enum Check {
#[serde(default, skip_serializing_if = "Option::is_none")]
command_policy: Option<CommandPolicyId>,
},
/// A trusted host's scan result for the exact skill bundle being executed
/// (contract 1.29). `Warn` requires host approval; `Block` is a hard denial.
SkillScan {
/// Result computed by the host scanner.
verdict: SkillScanVerdict,
/// Lowercase SHA-256 of the exact document and resources the host will
/// expose during this run. The approval binding includes this value.
bundle_sha256: String,
},
/// An effect not supported by this engine.
Unknown {
/// Content-free descriptor.
Expand Down
25 changes: 25 additions & 0 deletions crates/tinysecurity-bus/src/policy_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,31 @@ fn host_shell_has_a_stable_strict_wire_form() -> TestResult {
Ok(())
}

#[test]
fn skill_scan_has_stable_verdict_wire_forms() -> TestResult {
for (verdict, wire) in [
(SkillScanVerdict::Pass, "pass"),
(SkillScanVerdict::Warn, "warn"),
(SkillScanVerdict::Block, "block"),
] {
let check = Check::SkillScan {
verdict,
bundle_sha256: "a".repeat(64),
};
let value = serde_json::to_value(&check)?;
assert_eq!(
value,
serde_json::json!({
"kind":"skill_scan",
"verdict":wire,
"bundle_sha256":"a".repeat(64),
})
);
assert_eq!(serde_json::from_value::<Check>(value)?, check);
}
Ok(())
}

#[test]
fn new_denial_reasons_have_stable_wire_forms_and_old_ones_are_unchanged() -> TestResult {
for (reason, wire) in [
Expand Down
16 changes: 16 additions & 0 deletions crates/tinysecurity-bus/src/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ pub struct SecretRegistration2 {
/// At most three compatible read-only historical entries.
pub legacy: Vec<SecretSourceBinding2>,
}
/// Host-only runtime registration for a secret scope whose approval scope is live.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RegisterSecretScopeRequest2 {
/// Immutable secret registration; the module resolves the approval scope itself.
pub registration: SecretRegistration2,
}
/// Safe confirmation of one active secret registration.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SecretScopeReceipt2 {
/// Opaque registration identity supplied by the trusted host.
pub registration_id: String,
/// Whether the registration is currently active.
pub active: bool,
}
/// Bounded retention and reservation ceilings, matching the internal registry.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
Expand Down
35 changes: 35 additions & 0 deletions crates/tinysecurity-bus/src/secret_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,38 @@ fn caller_authority_overrides_and_plaintext_response_fields_are_rejected()
);
Ok(())
}

#[test]
fn runtime_secret_scope_registration_only_accepts_the_trusted_descriptor()
-> Result<(), Box<dyn std::error::Error>> {
let request = RegisterSecretScopeRequest2 {
registration: SecretRegistration2 {
registration_id: "a".repeat(32),
approval_scope_id: "b".repeat(32),
origin: Origin::Operator,
purpose: MasterPurpose2::ConfigUserMaster,
target: SecretBinding2 {
backend_id: "c".repeat(32),
slot: MasterSlotKind2::User,
},
legacy: vec![],
},
};
let value = serde_json::to_value(&request)?;
assert_eq!(
serde_json::from_value::<RegisterSecretScopeRequest2>(value.clone())?,
request
);
let mut forged = value;
forged["subject"] = serde_json::json!({ "user": "caller" });
assert!(serde_json::from_value::<RegisterSecretScopeRequest2>(forged).is_err());
let receipt = SecretScopeReceipt2 {
registration_id: "a".repeat(32),
active: true,
};
assert_eq!(
serde_json::from_value::<SecretScopeReceipt2>(serde_json::to_value(receipt.clone())?)?,
receipt
);
Ok(())
}
11 changes: 6 additions & 5 deletions crates/tinysecurity-bus/tests/scoped_wire.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Registered subject policy wire shapes and the 1.28 compatibility boundary.
//! Registered subject policy wire shapes and the 1.29 compatibility boundary.
use serde_json::json;
use tinysecurity_bus::*;

Expand Down Expand Up @@ -79,6 +79,7 @@ fn new_members_are_advertised_and_named_by_contract_constants() {
names::methods::AUTHORIZE_BROWSER_DIAL,
names::methods::CONSUME_BROWSER_DIAL,
names::methods::VALIDATE_BROWSER_DIAL,
names::methods::REGISTER_SECRET_SCOPE2,
] {
assert!(names::METHODS.contains(&name), "{name}");
}
Expand All @@ -87,10 +88,10 @@ fn new_members_are_advertised_and_named_by_contract_constants() {

#[test]
fn contract_bump_is_additive_for_older_hosts_and_modules() {
assert_eq!(CONTRACT_VERSION, (1, 28));
// A host built against 1.28 accepts this module and newer minors, not a 1.27 module.
assert!(is_compatible((1, 28)));
assert!(!is_compatible((1, 27)));
assert_eq!(CONTRACT_VERSION, (1, 29));
// A host built against 1.29 accepts this module and newer minors, not a 1.28 module.
assert!(is_compatible((1, 29)));
assert!(!is_compatible((1, 28)));
assert!(!is_compatible((1, 26)));
assert!(!is_compatible((1, 25)));
assert!(!is_compatible((1, 24)));
Expand Down
2 changes: 1 addition & 1 deletion crates/tinysecurity-bus/tests/wire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ fn redactor_init_is_additive_and_secrets_never_enter_public_info()
serde_json::to_value(&config)?["redactor"]["secrets"][0],
"literal-private"
);
assert_eq!(CONTRACT_VERSION, (1, 28));
assert_eq!(CONTRACT_VERSION, (1, 29));
for (mode, wire) in [
(RedactMode::Text, "text"),
(RedactMode::StructuredArguments, "structured_arguments"),
Expand Down
Loading
Loading