feat(security): ADR-0056 Option A — declaration-derived public-form authorization#2073
Merged
Conversation
…uthorization
Public form submit now derives a narrow `publicFormGrant: { object }` from the
form's declared target; the SecurityPlugin honors it as create + read-back on that
object ONLY (no userId, no deployment guest_portal, never the anonymous fall-open).
Lets public forms survive secure-by-default while staying least-privilege — the
prerequisite for the requireAuth default flip. Proven by form-self-auth dogfood
(3/3: target create allowed; cross-object + update/delete denied). No regression
(plugin-security 108, rest 121, full dogfood 98).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XVdnfUAx85amkerym26vdx
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 9 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
June 20, 2026 10:00
os-zhuang
added a commit
that referenced
this pull request
Jun 20, 2026
…ngs (#2075) The nine ADR-0056 PRs merged but updated only one doc line (the email-RLS note in #2054). This brings the hand-written security docs and the data authoring skill in line with what actually shipped and is dogfood-proven: - public-forms: public forms are now self-authorizing via a declaration- derived `publicFormGrant` (create + read-back on the form's target object). A `guest_portal` profile is no longer required — it is retained only for back-compat (hooks detecting a guest via falsy `ctx.user?.id`). (ADR-0056 Option A, #2073) - implementation-status + security guide: corrected the "anonymous traffic bypasses enforcement" posture (boot warning lands in D2; public forms no longer depend on the fall-open; the default-deny flip is release-gated); marked OWD/sharing-model enforcement, the sharing-rule evaluator, and the app-declarable default profile as live. - security guide: documented the `role_and_subordinates` sharing recipient (configurable role-hierarchy widening, D6). - permissions-matrix: `object.sharingModel` now accepts the canonical OWD vocabulary (`private`/`public_read`/`public_read_write`/ `controlled_by_parent`) alongside the legacy spellings (D1). - objectstack-data skill: corrected the RLS section to the enforced `rowLevelSecurity` policy shape (`using`/`check` + `current_user.*` placeholders, incl. the new `current_user.email`), and flagged the object-level CEL `rls` config as experimental (D8). Claude-Session: https://claude.ai/code/session_01XVdnfUAx85amkerym26vdx Co-authored-by: Claude <noreply@anthropic.com>
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.
What (ADR-0056 — Option A: declaration-derived public-form authorization)
Implements the recommended fix for the one blocker of the
requireAuthdefault flip: public forms.Today a public form submit relies on the anonymous fail-open (+ an optional, not-built-in
guest_portalprofile). Under secure-by-default that breaks. Option A makes the form self-authorizing from its declaration:publicFormGrant: { object }from the matched form's target object.create+ the immediate read-back on that object only, with nouserId, no deploymentguest_portal, and crucially not the anonymous fall-open.guest_portal/anonymousstay on the context for back-compat with guest-detection hooks.This lets public forms work under
requireAuthwithout any per-deployment config, scoped to exactly the declared object — and generalizes the platform principle "public access = declared + runtime-derived scoped grant" (the same shape share-links already use: validate → narrow grant, never a standing broad profile relied on by fail-open).Verification
form-self-authdogfood 3/3: create on the form target authorized (no userId / no guest_portal); cross-object create denied (narrow, not fall-open); update/delete denied. Regression:plugin-security108,rest121, full dogfood 98 — clean. Build 76/76.Relation to ADR-0056
This satisfies the
requireAuth-flip prerequisite documented in the D10 conformance matrix (#2071). With it, the only remaining step for the flip is the release-gated rollout (warn→enforce + migration note). Follow-on: update the matrix'srequireAuth-default-flipnote to point at this (both must be inmainfirst).🤖 Generated with Claude Code
Generated by Claude Code