Repository navigation
cover owner revocation of policy roots - #364
Conversation
Tests on SQLite and PostgreSQL through the production app: the space owner's wallet (did:pkh, SIWE) and a did:key space owner revoke an agent-signed policy root over the generic route, with the cascade to admitted sessions, re-shared children, challenge and mint, and the status routes; a revoke control naming the space's delegations and the encryption network revokes it, a space-only control cannot; an unrelated key, another agent of the wallet and the recipient are refused on both routes; the JSON route keeps its signer and enforcer rules. Adds a shared Policy/v3 test harness and documents the client rule.
|
Review at head 93b3cb3 (artifacts-1423-review-n3b). Details are in the TC-1423 Linear comment. Verified: One change requested: no test covers the generic route refusing a delegatee on a policy root. Removing the delegatee exclusion in for root in [&first.policy.policy_root_cid, &first.policy.enforcement_root_cid] {
let (status, body) = h.post_revoke(h.enforcer.revoke(root)?).await;
assert_eq!((status, body.as_str()), (Status::Forbidden, "Unauthorized Revoker"));
}
assert_root_live(&h, &first).await?;Minor: the generic-refusal assertions accept |
- The enforcer, the delegatee of the enforcement root, is refused on the generic route on both roots (403 Unauthorized Revoker). - Generic refusals pin 403 Unauthorized Revoker; the hook-ticket refusal is pinned before (Unauthorized Action) and after the revoke (delegation-ancestor-revoked). - The shared harness drops helpers no test uses, and its dead-code allow. - Docs: policy sessions can't mint hook tickets, so the hook-stream bound doesn't apply; the released parser's 300-second freshness limit (TC-1450).
|
APPROVE: see TC-1423 |
# Conflicts: # CHANGELOG.md
Linear: TC-1423 (N3b: owner revocation of policy roots, design §15, v3.3)
This PR adds tests and the client rule only; node behaviour does not change. It covers who can revoke a Policy/v3 root, over which route, and what happens after a revoke. Every revoker other than the root's own signer uses the generic
POST /revoke. The JSONRootRevocation/v1route stays limited to the root's signer and the enforcer, as today.Changes
tinycloud-node-server/src/policy_v3/root_revocation_tests.rs: tests O-1 to O-7. Each runs on SQLite and on PostgreSQL through the production app (app_with_control).tinycloud-node-server/src/policy_v3/test_harness.rs: a shared Policy/v3 test harness, trimmed to what these tests use. It provides did:key and did:pkh principals, owner grants, policy registration, v4 sessions, reads, decrypt, re-share, generic and JSON revocation, delegation status, status routes and hook tickets. record owner authority for policy registrations #358 has its own copy of this harness inline; once both have merged, the copy can be replaced with an import of this module.docs/policy-root-revocation.md: who may revoke, on which route, the client rule, and how to confirm a revocation.Tests
the_space_owner_wallet_revokes_an_agent_signed_rootroot-revoked; decrypt gets the core 401delegation-ancestor-revoked(see note); challenge and mint are refused;/delegation/statuson the root showsrevoked;GET /policy/v3/statusgivesstate: revokedover anactivecheckpoint; the renewal POST gives 409root-revoked. A policy session cannot hold a hook ticket, so there is no stream to close; the ticket is refused before the revoke (401Unauthorized Action) and after it (401delegation-ancestor-revoked). The ≤300 s hook-stream bound after a JSON-route revoke therefore does not apply to policy roots.a_key_space_owner_revokes_over_the_generic_route_onlyroot-revocation-issuer-invalidand the root stays live. The same owner over generic UCAN gets 200 and the O-1 cascade.others_cannot_revoke_a_policy_rootUnauthorized Revoker), and the root stays active.a_revoke_control_naming_the_network_revokes_a_policy_root<applications>/delegationplus the content network: generic revoke gives 200 and the cascade. The same control without the network row gets 403Unauthorized Revoker, and the root stays live.the_json_route_keeps_its_signer_and_enforcer_rulesUnauthorized Revokeron both roots; this is the delegatee exclusion, and removing it fails this test on both backends. On the JSON route, the enforcer on the policy root gets 403. The enforcer on the enforcement root gets 200, withstate == checkpoint.state == revoked. The signer (A) on its policy root gets 200, withstate == checkpoint.state.Finding (pre-existing, not changed here): after a generic root revoke,
POST /encryption/networks/<id>/decryptreturns401 delegation-ancestor-revoked: ancestor=<root cid> invoked=<session cid>, not 403root-revoked. The decrypt route runs coreverify_authbefore the policy gate (routes/encryption.rs:151-172). The CIDs in the body are the recipient's own session and the root from its envelope. The test pins this behaviour.Bases (the same tests at each ref)
989078c)1338d4f)467093c, this PR's base)So only O-6 depends on N4'. The rest pins existing behaviour (design §15a: "already meets the ruling"). On #353 and 1.21.0, the two failures are
a_revoke_control_naming_the_network_revokes_a_policy_rooton sqlite and postgres.Stack and merge order
tc-1423/n4-typed-revoke-scope(fix(TC-1423): typed scope for revoke controls #356, which contains fix(TC-1436): tighten revocation authorization #353) at467093c.### Changesheading with every bullet.main.Review delta (head 185b798)
(403, "Unauthorized Revoker").#![allow(dead_code)]removed.party_may_actlets the delegatee revoke): O-7 fails on SQLite and PG, 8 passed and 2 failed.Verification (head 185b798)
cargo test -p tinycloud-node --lib root_revocation_testswith PostgreSQL: 10 passed, 0 failed.cargo clippy -p tinycloud-node --all-targets -- -D warnings: clean.cargo fmt --all -- --check: clean.