Skip to content

Allow policy registration under a space-owner register grant - #399

Draft
samgbafa wants to merge 20 commits into
skgbafa/tc-1423-n3-owner-authority-livenessfrom
skgbafa/tc-1718-c2-register-grant-n3
Draft

samgbafa wants to merge 20 commits into
skgbafa/tc-1423-n3-owner-authority-livenessfrom
skgbafa/tc-1718-c2-register-grant-n3

Conversation

@samgbafa

@samgbafa samgbafa commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Policy registration accepts a space-owner register grant as an authorization fallback. No database migration. Stacked on #362.

What the new right allows

tinycloud.policy/register on <space>/policy/<digest> lets its holder register a policy root whose template digest equals <digest>. The template digest is SHA-256 over the domain xyz.tinycloud.policy/RegisterTemplate/v1\0 followed by the JCS encoding of the policy with policyId, createdAt, expiresAt and signature removed.

The fallback runs only when ordinary owner authority selection fails. Owners with ordinary authority take the existing path.

Who can grant it

Only the space owner, as delegator, to the policy owner. The grant must be a root delegation with no parents. Core /delegate requires the space owner as issuer for this ability, and refuses any delegation with parents that carries a tinycloud.policy/* ability (policy-register-grant-must-be-parentless; the check runs after main's key-delete refusal and before the parent-based authorization).

Properties

  • Exact-digest. A grant names one template. Changing any field outside the excluded set needs a new grant.
  • Revocable. A revoked grant does not authorize.
  • Bounded to the space owner's own space. The grant is valid only in [nbf, exp). A root that expires after the grant is refused (policy-root-outlives-register-grant) in both modes.
  • No migration. Classifier version 3 carries register_grant in memory only. Rollback is the previous image with no database step.

Tests

owner_authority_tests.rs, on SQLite and on PostgreSQL (CI-only): a register grant authorizes the owner for its template; a grant on another template digest does not; a revoked grant does not; a root that outlives the grant is refused in both modes; the authority ends with the grant; re-classification against a remaining grant (background and backfill); a delegation with parents carrying a tinycloud.policy/* ability is refused. child_policy_grant_is_refused_before_parent_check (core, models/delegation.rs) pins the policy code for a child delegation that has no other violation.

The closure check of rule 4 (closure == {D}) is a second line behind the core rule above: no stored delegation with parents can carry the register ability, so no test reaches it without writing rows directly.

Verification

At this head, on SQLite: cargo fmt --all -- --check; cargo clippy --workspace --all-targets and cargo clippy -p tinycloud-core --features duckdb --all-targets, both with RUSTFLAGS=-Dwarnings; node scripts/gen-capabilities.mjs --check (the capability registry files are regenerated); and every test binary of tinycloud-core, tinycloud-node and tinycloud-auth pass, except the three startup_identity cases (the host has a dstack socket, so the node binary refuses to create an identity) and the three account_alias_tests, which time out when other jobs share the host and pass when the tinycloud-node lib tests run alone. PostgreSQL-backed tests run in CI.

Details: TC-1718

Naomi and others added 18 commits October 21, 2026 14:51
An owner with no ordinary authority over a space can be authorized by a parentless tinycloud.policy/register grant from the space owner, bound to the exact policy template digest (SHA-256 over JCS of the policy minus policyId, createdAt, expiresAt, signature). Classifier version 3; the grant is not persisted.

register_policy refuses roots that outlive the grant with policy-root-outlives-register-grant in both modes. Background classification maps such roots to unknown(OutlivesAuthority).

Details: TC-1718
A delegation carrying any tinycloud.policy/ ability must have no parents. Rejected with policy-register-grant-must-be-parentless so the register grant closure is exactly the grant itself.

Details: TC-1718
Registers the register ability in capabilities.json and regenerates the TypeScript and Rust outputs. gen-capabilities.mjs --check passes.

Details: TC-1718
Covers template binding, revocation, root lifetime refusal in both modes, reclassification and background backfill, parentless guard, and expiry ending authority. Runs on SQLite and Postgres.

Details: TC-1718
Adds the register-grant section to policy-owner-authority.md and a 1.21.8 CHANGELOG entry. No migration.

Details: TC-1718
…8-c2-register-grant-n3; neutral wording; check the decrypt request passes authorization before the revoke
@samgbafa

Copy link
Copy Markdown
Contributor Author

APPROVE: see TC-1718 (reviewed exact head e8b877a)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant