This repository was archived by the owner on Aug 17, 2026. It is now read-only.
feat(permissions): @Public() decorator + route-gating policy (prep for #47) - #52
Merged
Conversation
added 4 commits
May 2, 2026 22:24
Pins the metadata shape and `isPublicRoute()` reader for the guardrail decorator that lands the explicit-consent token for route gating (prep for Issue #47).
Adds the explicit-consent token an HTTP handler can carry to opt out of permission gating. Metadata-only — runtime gating still happens via the existing JWT middleware path-allowlist + CanGuard. The required `reason` argument forces an explanation at every decoration site so the future audit / CI gate (Issue #47) can surface why a route is public. The `isPublicRoute()` type-guard recognises only the literal boolean `true` so a JSON-roundtripped value cannot pose as consent.
Documents the rule that every HTTP handler is `@Can()`-gated, `@Public()`-consented, or path-allowlisted — with no fourth option. Issue #47 will enforce this at build time; this commit lands the written policy that tooling and humans can both reference.
Surfaces the route-gating policy in the agent workflow: - Decision flow at the top — pick @can() vs @public() vs allowlist before writing the route body - "When @public() is appropriate" checklist (health, OAS, anonymous webhooks with own HMAC, marketing pages) - Migration diff showing how to fix an unguarded handler either way - Test recipe for the @public() metadata using PUBLIC_ROUTE_METADATA_KEY + isPublicRoute() type-guard - Cross-link to project CLAUDE.md and Issue #47
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Summary
Lands the guardrails so AI agents (and humans) cannot ship unguarded
routes by accident:
@Public("<reason>")decorator atsrc/core/permissions/public.decorator.ts—required-reason argument forces explicit consent at the route site
CLAUDE.md"Route gating policy" — every route is gated,@Public(), or path-allowlisted; no fourth option.claude/skills/wiring-permissions.md— decision flow +when
@Public()is appropriate + migration diff + test recipeNot in this PR
This PR ships the prerequisites those rely on (the decorator + the
documented policy). Issue #47 then enforces it across all controllers
and adds the CI check.
Test plan
public.decorator.ts100% on lines/functions/statements/branches;core/permissions94.39% / 96.29% lines stays above the 90% gate), build🤖 Generated with Claude Code