Skip to content

fix(admin): per-request allowlist enforcement on the cookie path (revocation takes effect next request)#49

Merged
MartinMontero merged 1 commit into
mainfrom
claude/wcjbt-admin-revocation-enforcement
Jul 4, 2026
Merged

fix(admin): per-request allowlist enforcement on the cookie path (revocation takes effect next request)#49
MartinMontero merged 1 commit into
mainfrom
claude/wcjbt-admin-revocation-enforcement

Conversation

@MartinMontero

Copy link
Copy Markdown
Owner

What does this PR do?

Closes the one gap in per-request allowlist enforcement, so revocation (remove an identity → commit → deploy) takes effect on that identity's next request, per the governance model. This is the precondition hardening that lands BEFORE any real identities are committed.

Task B verdict (the read-only enforcement audit that prompted this)

Auth path Membership re-checked per request?
NIP-98 API client (whoami Path 2) PRESENTisAllowedNostrPubkey on every request (was already correct)
Browser cookie session (whoami Path 1) ABSENT — checked only at login/elevation; a live session survived de-listing until expiry (up to the 8h absolute bound)
Mid-session revocation test ABSENT — no coverage
ADMIN_SESSIONS contents identity only (subject, method, createdAt, lastSeen) — no membership/role snapshot to go stale, so a live re-check is the correct fix

Verdict: per-request enforcement ABSENT on the cookie path → smallest hardening + tests, this PR, merges before identities.

The fix

resolveAllowlistedAdmin() — the single per-request enforcement choke point for cookie-authenticated admin routes. It resolves the session (idle/absolute bounds, unchanged) and re-checks the identity against the current allowlist, destroying the session if the identity was de-listed. whoami's browser path routes through it; future privileged cookie routes (Phases 5/6) must too — never resolveAdminSessionId alone. Logout stays de-escalation-only (a revoked admin may still clear its own cookie).

Because a session stores no membership snapshot, revocation is a live lookup — no cache to invalidate. No behavior change for a still-allowlisted admin.

Tests

Two new mid-session revocation cases (Nostr + Bluesky): a live, in-bounds session whose identity is removed from the allowlist gets 401 on its next request and is destroyed (re-supplying the original allowlist can't resurrect it). verify:all green; enforce green; 289 tests, 0 fail.

Type of change

  • Enforcement engine / tooling · [x] Other — admin auth hardening

Required checks

  • npm run check · [x] npm run enforce · [x] npm test (289) · [x] npm run build

CI is pull_request-only; this draft is these commits' first CI run.

Deploy semantics

Merging IS a production deploy. It changes only the cookie-path enforcement (the allowlist is still committed-empty, so the live surface remains fails-closed-for-everyone). No new bindings, no schema change, no new deps.

Draft on purpose — do not mark ready-for-review, do not merge; merge is yours alone. This is the enforcement precondition; the identities PR (with the genesis role schema) is separate and fires only on your explicit identities: go.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LVPyHAtQ1cdK76RpFasafP


Generated by Claude Code

…evocation)

The NIP-98 API path already re-checked allowlist membership on every request,
but the browser COOKIE-session path (whoami) checked membership only at
login/elevation — so removing an identity from the committed allowlist would
not revoke a live browser session until it expired (up to the 8h absolute
bound). The governance model requires revocation (commit + deploy) to take
effect on the identity's NEXT request.

Add resolveAllowlistedAdmin(): the single per-request enforcement choke point
for cookie-authenticated admin routes. It resolves the session (idle/absolute
bounds, as before) AND re-checks the identity against the current allowlist,
DESTROYING the session if the identity has been de-listed. whoami's browser
path now routes through it; future privileged cookie routes (Phases 5/6) must
too — never resolveAdminSessionId alone. No stored membership/role snapshot to
go stale: ADMIN_SESSIONS holds identity only, so the check is always live.
Logout stays de-escalation-only (a revoked admin may still clear its cookie).

Tests: mid-session revocation for both methods — a live session whose identity
is removed from the allowlist gets 401 on its next request AND is destroyed
(the original allowlist can't resurrect it). Closes the gap that had no
coverage before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVPyHAtQ1cdK76RpFasafP
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
wecanjustbuildthings 1e7882d Jul 04 2026, 07:18 AM

@MartinMontero
MartinMontero marked this pull request as ready for review July 4, 2026 07:55
@MartinMontero
MartinMontero merged commit 6f84d51 into main Jul 4, 2026
14 checks passed
@MartinMontero
MartinMontero deleted the claude/wcjbt-admin-revocation-enforcement branch July 4, 2026 07:56
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.

2 participants