Repository navigation
Conversation
Tests first, on SQLite and PostgreSQL: revoking the owner's grant, an agent session (did:pkh wallet -> agent key), an ancestor or an alias-CID encoding ends already-admitted sessions across read, decrypt, re-shared children, challenge, mint, signed-KV mint and re-share admission with a fixed code; all-of grants; typed expiry codes; legacy registrations denied without authority unless escaped and never expiry-capped; hook streams closing after a grant is revoked or after repeated check errors; the 16-authority ticket cap. The delegated-session flow now expects the admitted session to stop when the owner's delegation is revoked.
Every policy use checks the recorded owner authority after the root checks: reads, decrypts and re-shared children of admitted sessions, re-share admission, signed-KV and hook-ticket mints, challenge, mint (and its locked recheck), S0 admission and delivery. A revoked delegation or ancestor (also under an alias CID) gives policy-owner-authority-revoked; a non-legacy bound authority past expiry policy-owner-authority-expired; no authority policy-owner-authority-unknown, unless legacy and policy_v3.legacy_unknown_allow. The mint's registration-time rescan runs only for escaped policies. Expired roots and sessions get typed codes. Hook tickets carry a policy session's closure (at most 16 IDs) and open streams re-check their authority, closing on a revocation or three failed checks; the chain check is two queries at any depth. What to check is cached once final; liveness never is.
…-cap' into skgbafa/tc-1423-n3-owner-authority-liveness # Conflicts: # CHANGELOG.md # tinycloud-node-server/src/policy_v3/owner_authority.rs
…-cap' into skgbafa/tc-1423-n3-owner-authority-liveness
The re-share fixture signs the child from the next whole second after the session starts (PostgreSQL keeps microseconds); it now waits for that second before importing, instead of racing it.
…-cap' into skgbafa/tc-1423-n3-owner-authority-liveness
Contributor
Author
|
Review at Verdict: changes requested (minor). No blocker. The check runs on every path that admits or serves a policy session: reads, decrypt, re-shared children, re-share admission, signed-KV and hook-ticket mints, challenge, mint plus the locked recheck, S0 admission, delivery, and the listing state. It is strict all-of and alias-aware; the escape flag is legacy-only and off by default; the codes are fixed strings. Run locally on SQLite and native PostgreSQL 14:
Requested:
Info:
Details: TC-1423. |
- Hook streams: after a failed authority check, the next check waits the interval; events are withheld meanwhile without querying, so a burst during a brief database error no longer closes a healthy stream. - First-use classification is single-flight per policy: concurrent uses share one computation, and a use arriving just after it reuses the in-memory result. - Tests: the revoked-stream test matches rocket's `event:write`, has a positive control and no idle re-check, so the pre-event re-check is what closes it; S0 re-import, delivery, the escape's legacy-only scope and the escaped mint's rescan each get a test; concurrent first uses count one classification. The policy flow tests box their future. - CHANGELOG: delivery keeps `delivery-authorization-invalid`. Docs note that `policy-owner-authority-expired` is not reached by stored rows.
Contributor
Author
|
APPROVE: see TC-1423 |
Contributor
Author
added 14 commits
October 23, 2026 22:44
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…ner-authority-liveness
…t-after-revoke check and the use-status check; neutral wording
This was referenced Oct 24, 2026
added 2 commits
October 24, 2026 10:51
Contributor
Author
|
APPROVE: see TC-1423 (reviewed exact head 3adcabd) |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linear: TC-1423 (part 3 of 3)
Every Policy/v3 use checks the owner authority that #358 recorded, after the existing root checks. A revoked owner delegation, or any revoked ancestor, ends the policies of already admitted sessions. Stacked on #360.
Changes
validate_owner_authority(policy_v3/owner_authority.rs) runs from:authorize_roots, which covers reads, decrypts and re-shared children of admitted sessions, re-share admission, signed-KV and hook-ticket mints, and challenge and mint;delivery-authorization-invalid;Outcomes:
bound*403 policy-owner-authority-revokedbound, not legacypolicy-owner-authority-expiredroot-authorityunknownpolicy-owner-authority-unknownLegacy (
backfill) rows are not expiry-checked.Legacy escape:
policy_v3.legacy_unknown_allow(default off). Legacyunknownrows get root-only checks plus the mint's registration-time rescan. Logged with a warning at boot, and per policy at most once an hour. Counted intinycloud_policy_owner_authority_unknown_allowed_total{reason}.Mint: the registration-time
owner_holds_capabilitiesrescan runs only for escaped policies; for the others the recorded authority covers it.Typed codes:
root-expired, at validation and at the status check. Other non-live roots giveroot-not-live.policy-session-expired; the signature is verified before the time window.Cache and cost:
OnceCellper policy that waiters await). The result is remembered before the entry is dropped, and a use that finds no entry checks memory under the same lock. No lock is held across an await. If the computing request is cancelled, a waiter takes over.Hooks (
routes/hooks.rs):403 hook-ticket-authority-too-large./hooks/eventsstreams re-check their authority before delivering an event, at most everyhooks.authority_recheck_seconds(5), and everyhooks.idle_authority_recheck_seconds(30) when idle.delegation_chains_unrevokedin coredb.rs, is one closure CTE plus one batched revocation query, whatever the depth.Listing:
ownerAuthorityStateshowsrevokedwhen a closure member is revoked andexpiredfor a non-legacyboundauthority past expiry.Metrics:
tinycloud_policy_owner_authority_denied_total{reason=revoked|expired|unknown}.Stack and merge order
skgbafa/tc-1423-n2-root-lifetime-cap(cap policy root lifetime and add authority mode #360). Allow policy registration under a space-owner register grant #399 stacks on this branch.Tests
owner_authority_tests.rs(SQLite; PostgreSQL in CI): revoking the owner's grant, an ancestor, or a grant stored under an alias CID ends admitted sessions (read, decrypt, re-shared child, challenge, mint, signed-KV mint, re-share admission) with a fixed opaque code; all-of grants; typed expiry codes; legacyunknownis denied unless escaped; legacy rows are not expiry-capped; the escape does not cover post-cutover rows; escaped mints check that the owner held the capability; an admitted session is not re-imported after a revoke; concurrent first uses share one classification; hook streams close after a revoke and after repeated check errors; a ticket carries at most 16 authority IDs; a PostgreSQL latency gate (ignored by default).policy_v3::tests::policy_owner_may_be_a_session_the_space_owner_delegated_to: once the space owner revokes the policy owner's delegation, the admitted session, a new challenge (403 policy-owner-authority-revoked), a mint with a challenge issued before the revoke (403 policy-owner-authority-revoked) and delivery are all refused.owner_authority.rs(in-memory SQLite, counted queries):steady_state_checks_cost_one_query_or_none;final_classifications_cost_the_request_path_nothing;background_classifications_are_limited_without_backing_off(three slots, then none; a use without a free slot is served and stores nothing; a later use stores);non_final_classifications_back_off(a result that could not be stored is reused for the back-off window, with no query and no new classification);unknown_legacy_classifications_are_denied_unless_allowed;expired_bound_authority_is_denied_except_legacy;a_panicking_classification_releases_its_claim.non_final_classifications_back_offandbackground_classifications_are_limited_without_backing_off.Harness::classify_on_usechecks the status of the use: 200 forbound,bound-uncappedandroot-authority, 403policy-owner-authority-unknownforunknown.Verification
At this head, on SQLite:
cargo fmt --all -- --check;cargo clippy --workspace --all-targetsandcargo clippy -p tinycloud-core --features duckdb --all-targets, both withRUSTFLAGS=-Dwarnings;node scripts/gen-capabilities.mjs --check; and every test binary oftinycloud-core,tinycloud-nodeandtinycloud-authpass, except the threestartup_identitycases (the host has a dstack socket, so the node binary refuses to create an identity) and a few timing-sensitive lib tests that time out when other jobs share the host and pass when thetinycloud-nodelib tests run alone. PostgreSQL-backed tests run in CI.Details: TC-1423