feat(#11): live-policy auth + 6 companion admin RPCs + Token.revokedAt #13

Merged
padreug merged 3 commits from issue-11-live-policy-auth into dev 2026-05-30 15:25:16 +00:00

3 commits

Author SHA1 Message Date
49091f722f feat(admin): companion RPCs for live policy + token revocation (#11)
Some checks failed
Docker image / build-and-push-image (push) Has been cancelled
Six new admin-RPC handlers that complement the live-policy auth
rewrite. Each follows the canonical create_new_policy.ts pattern
(single JSON-stringified param, kind-24134 response, one prisma
mutation, no per-call ACL — validateRequestFromAdmin gates them
via the admin-npub allowlist).

Policy-level mutations propagate to every KeyUser bound to the
policy at the next sign-time check (the point of #11):

  add_policy_rule    { policyId, rule: {method, kind?, maxUsageCount?} }
  remove_policy_rule { ruleId }
  update_policy      { policyId, patch: {name?, expiresAt?} }

Per-KeyUser override mutations (override layer):

  add_signing_condition    { keyUserId, condition: {method, kind?, allowed} }
  remove_signing_condition { conditionId }

Surgical token revocation without nuking the KeyUser:

  revoke_token { tokenId }

The 'all' kind literal is honored as a wildcard in add_policy_rule
for parity with the SigningCondition override-layer convention.

Param shapes ratified by webapp in
#11 (comment).

refs: #11
2026-05-30 13:27:28 +02:00
35826ab695 feat(acl): live-policy auth in checkIfPubkeyAllowed (#11)
Shifts sign-time authorization from materialized SigningCondition
snapshots (frozen at token-bind time) to a layered model:

  1. fetch KeyUser; missing → undefined
  2. KeyUser.revokedAt set → false
  3. SigningCondition override layer (explicit reject, per-(method,
     kind) grant/deny) → return matching row's allowed value
  4. live policy join: KeyUser → Token (revokedAt IS NULL) →
     Policy → PolicyRule. Match on method + kind (exact /
     'all' / NULL defensive) → true
  5. else → undefined (caller may still prompt admin)

Backwards-compatible. The existing applyToken fan-out of
SigningCondition rows continues to populate step 3 for legacy
auth, so already-bound users keep working with no behavior change.
New users will still go through that fan-out until the follow-up
trim (#12). The key win: PolicyRule mutations via the upcoming
companion RPCs (add_policy_rule / remove_policy_rule / etc.)
propagate live to every KeyUser bound to that policy, rather than
requiring per-user backfill RPCs that don't exist.

Algorithm ratified by webapp in
#11 (comment).

refs: #11
2026-05-30 13:25:48 +02:00
eb6c86a4d1 chore(schema): add Token.revokedAt for surgical token revocation (#11)
Pre-requisite for the live-policy auth rewrite in #11. The new
revoke_token admin RPC needs a way to mark a single Token as
revoked without nuking the whole KeyUser (revoke_user) or
conflating with future expiry cleanup (deletedAt).

Nullable DateTime — existing rows default to NULL (active), no
data migration needed.

refs: #11
2026-05-30 13:24:14 +02:00