diff --git a/.changeset/24239-public-form-grant-skill.md b/.changeset/24239-public-form-grant-skill.md new file mode 100644 index 00000000000..7e013eb9660 --- /dev/null +++ b/.changeset/24239-public-form-grant-skill.md @@ -0,0 +1,9 @@ +--- +'@objectstack/skills': patch +--- + +docs(skills): `objectstack-api` states that a public form's submit is authorized by the form's own `publicFormGrant`, and that the `guest_portal` name on the submit context admits nothing and needs no permission set (#24239) + +Clause-②: no + +`skills/objectstack-api/SKILL.md` described the anonymous form endpoints as running under a synthetic `{ permissions: ['guest_portal'], anonymous: true }` execution context and named nothing else, so an author reading it inferred that a `guest_portal` permission set authorizes the submit and declared one, or concluded that the form falls open without one. Neither is true: the submit is authorized by the form's own declaration (ADR-0056 Option A) — the route hands the engine a `publicFormGrant` scoped to the form's target object, which admits the create and the read-back of the row it made and nothing else, decided before any permission set resolves. The `guest_portal` name on the context admits nothing; where a deployment registers a set under it, that set only feeds the grant's result masker. The passage now says so, matching `content/docs/ui/public-data-collection.mdx` and the `registerFormEndpoints` docstring in `@objectstack/rest`. Text only; nothing an author writes changes, and the form routes' behaviour is unchanged. diff --git a/skills/objectstack-api/SKILL.md b/skills/objectstack-api/SKILL.md index 2d55cd4fa2f..74567684b73 100644 --- a/skills/objectstack-api/SKILL.md +++ b/skills/objectstack-api/SKILL.md @@ -84,9 +84,11 @@ GET /api/v1/forms/:slug # returns form spec + restricted objectSchema POST /api/v1/forms/:slug/submit # whitelist-filtered INSERT, no auth header ``` -These bypass `enforceAuth`, run under a synthetic -`{ permissions: ['guest_portal'], anonymous: true }` execution context, and -are intended for Web-to-Lead / Web-to-Case style flows. The framework +These bypass `enforceAuth` (Web-to-Lead / Web-to-Case flows). The form's own +declaration authorizes the submit: a `publicFormGrant` on its target object +(create and read-back of its new row, nothing else), decided before any permission +set resolves. The submit context's `guest_portal` name admits nothing and needs +no set; a set so named only feeds the grant's result masker. The framework strips fields outside the form's `sections[].fields[]` list; a `beforeInsert` hook on the target object should stamp safe defaults (`status='new'`, `lead_source='web'`, …) and `delete` privileged keys