You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit be50633
Browse filesBrowse the repository at this point in the historyBrowse files
docs(adr),refactor(plugin-security): restate the ADR text that names C3-retired security machinery; delete the unreachable audience-anchor binding gate (#23412)
Fixes#23403
Clause-②: no
Restates the ADR text that still names security machinery C3 (#15204)
has retired, and deletes one gate that has been unreachable since stage
8. A sub-card of #22975. It cites 7a's deletions (#23368) as done, so
the seat lands it after 7a.
## 维护者速读(草稿)
### 改了什么
- 修订五份 ADR(0138、0094、0126、0131、0103)中仍在描述已退役安全机制的文字,让每一处都与 main 当前行为一致。
- 删除一个已经不可能被触发的安全检查(「受众锚点绑定闸门」),连同它的调用点和 3 个测试用例,共删约 120
行代码;并修正其他包里仍把它当作「在运行」来描述的注释。
- ADR-0138 执行对照表里「锚点绑定层级」一行的状态,从 `enforced` 改为「`everyone` 已执行;`guest`
待后续 F4」。这是状态更正,不是新的决定。
### 为什么改
- 阶段 8 下线了 `sys_position_permission_set` 表。这个闸门只检查对这张表的写入,此后再也不会执行,但 ADR
仍写着「由它负责拦截」,读者会误以为这层防护还在起作用。
- 对 `everyone` 锚点,同样的高权限检查实际在「确认建议」和「重新推导」两处执行,ADR 现在如实写明。对
`guest`,目前没有任何入口能绑定权限集,ADR 也写明了这一点。
### 风险与代价(含回滚)
- 运行行为没有任何变化:被删的闸门自阶段 8 起就没被调用过,删掉的也不是对外导出。
- ADR 改动只是更正描述,不改变任何决定。
- 回滚:revert 本 PR 即可,没有数据迁移。
### 席位意见
### 你要做的
审阅后批准合并(Tier H:改动了受管路径 `docs/adr/**`)。
## What this changes
**Code: `@objectstack/plugin-security`, patch.**
- `SecurityPlugin.assertAudienceAnchorBindingGate` is deleted, with its
call in the security middleware and its three cases in
`security-plugin.test.ts`. The two imports only it used
(`describeAnchorForbiddenBits`, `AnchorBindingContext`) go too.
- The gate returned on anything but a write to
`sys_position_permission_set`. Stage 8 (#23222) unregistered that
object, so no write has reached the gate since.
- The anchor tier itself is unchanged and still applied where a binding
is made:
- `confirmAudienceBindingSuggestion` and the `everyone` derivation
(`readAcceptedEveryoneSets`), both in `suggested-audience-bindings.ts`;
- for `guest`, no door binds a set.
- Not an entry export. The changeset is
`.changeset/23403-audience-anchor-binding-gate-retired.md`.
**ADRs.** Each item was checked first against `a581c57eae` (#23362),
which recorded stage 8's retirement.
- **ADR-0138:**
- **:171** drops the anchor to the deleted gate. It now says the `guest`
tier has no caller on `main` until item 5's bind door.
- **Item 4 (:371)** says where the predicate runs today: `everyone` on
confirm and on every derivation; `guest` by the bind door when built.
- **Item 5's re-read note (:395)** and **the conformance row (:578)**
are restated the same way. The row now reads "enforced for `everyone`;
`guest`: follow-up F4".
- `a581c57eae` did not touch this ADR.
- **ADR-0094:** `a581c57eae` already restated the TL;DR, D1–D4 and the
addendum. Three lines still pointed at the module as living:
- the RETIRED banner's "stays in the tree until stage 7a deletes it";
- the unit-case citation of `permission-set-projection.test.ts`;
- the Implementation line.
All three now record the deletion by stage 7a (#23368).
- **ADR-0126:** "Three real mechanisms" gains a path note: stage 8
retired the `sys_permission_set` row whose `active` column carried the
row state, and stage 7a deleted the module. This follows the ADR's
existing path-note convention, and the path is kept as the record of
what the section measured.
- **ADR-0131:** both lists are dated evidence (re-verified at
`2514d49f3`), so they are annotated rather than rewritten.
- The Consumers line (:59) gains a note: the five bootstrap seeders went
with stages 6a and 6b, and `permission-set-projection.ts` with 7a.
- The framework code list (:993) gains a note naming the four deleted
seeder files and the projection.
- **ADR-0103 (:52):** the provenance note said
`assertSystemRowWriteGate` guards `sys_sharing_rule`, `sys_position` and
`sys_capability`. Measured on `main`, its map (`SYSTEM_ROW_PROVENANCE`)
holds `sys_position` and `sys_capability` only. `sys_sharing_rule` is
deliberately ungated: plugin-sharing's provenance hook
(`sharing-rule-provenance.ts`) stamps an edited row `customized`
instead. And since stage 8 unregistered both objects, no write reaches
that gate. The note now says this.
## Acceptance notes
- **Out of scope, found:** `assertSystemRowWriteGate` is unreachable for
the same reason as the deleted gate, since its two objects are
unregistered. It stays here because this card names only the anchor
gate; it belongs with 8-post's residue or its own card.
- **Prose left for 8-post's comment sweep:** two comments still describe
the deleted gate:
- the `declared-capability-context.ts` docblock ("all three runtime
consumers", "the gate the engine middleware re-enforces on the insert");
- `examples/app-showcase/src/security/permission-sets.ts:360`.
- `plugin-sharing/CHANGELOG.md` names the gate as history and is not
edited.
- **Comments that described the gate as live, now restated** (comments
and one note string only, no code):
- the preview docblocks in `security-plugin.ts` (about `:6151`) and
`objectql/src/engine.ts` (about `:5518`);
- the engine's referential-integrity docblock (about `:8859`) and its
sandbox gate list (about `:20842`);
- `integrity/dangling-reference-audit.ts` (about `:375`), and the same
phrase in two test comments
(`engine-lookup-referential-integrity.test.ts`,
`dangling-reference-audit.test.ts`);
- `lint/src/validate-security-posture.ts` (about `:37`);
- the `position-active` row's `note` in
`qa/dogfood/test/authz-conformance.matrix.ts` (prose: no test reads
`note`).
## Verification
On `64c2e41049` (`main` `dac99c2277`'s successor merged once, at
`bd13bf7808`, to sit on 7a; not re-merged since):
- `check:adr-symbol-anchors` and `check:adr-links`: exit 0.
- Typecheck of `plugin-security`, `objectql`, `lint` and the dogfood
package: exit 0.
- `authz-conformance.test.ts` (the matrix row changed): 61/61.
- On `bd13bf7808`, before this round's comment-only changes:
- `plugin-security` suite: 185/185 files, 3,773 passed;
- `check:scripts-symbol-anchors` and
`check:spec-docblock-symbol-anchors`: exit 0.
- On `59761d4a71`: the derived gate sweep, 74 derived, 74 run, all exit
0, with `--ran` reconciling at 0 NOT-MEASURED and 0 UNRUN.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01287UbjvrigpWwNfGDmdwpS)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
refactor(plugin-security): the audience-anchor binding gate on `sys_position_permission_set` is deleted
6
+
7
+
Clause-②: no
8
+
9
+
`SecurityPlugin`'s private engine-middleware gate that refused binding a high-privilege permission set to the `everyone` or `guest` position guarded writes to `sys_position_permission_set` only. C3 stage 8 (#23222) unregistered that object, so no write has reached the gate since. The gate, its call in the middleware and its three unit cases are removed.
10
+
11
+
No behaviour changes, and nothing exported changes. The anchor tier itself (`describeAnchorForbiddenBits` from `@objectstack/spec/security`) still applies wherever a binding is made: when an `everyone` suggestion is confirmed (`confirmAudienceBindingSuggestion`), and on every derivation of the `everyone` anchor. No door binds a set to `guest`.
> **RETIRED 2026-10-13 (#15204 stage 8, `66949b7729`, by execution of [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D2/D3/D13).**
17
17
> The `sys_permission_set` row object is no longer registered, and the machinery that kept it a
18
18
> projection — the write-through (D3), the `permission` projector (D2) and the boot reconcile and
19
-
> backfill (D4) — is unwired; its module stays in the tree until #15204 stage 7a deletes it. D1
19
+
> backfill (D4) — is unwired, and #15204 stage 7a (#23368) deleted its module (`permission-set-projection.ts`, with the seed-name lookup and the refusal sink). D1
20
20
> stands. Read the rest of this summary, D2–D4 and the Consequences in the past tense.
21
21
22
22
A permission-set **definition** (label, description, the six facet groups, `adminScope`,
@@ -184,9 +184,10 @@ is `managed_by:'admin'` while its definition ships as a platform artifact, and i
184
184
data-door edit is **refused** — the record's provenance column was never what the gate
185
185
read. The mirror case is `twodoors_pkgset`, whose row is `managed_by:'package'` while its
186
186
definition lives in `sys_metadata` (that materialization is pinned in the same file);
187
-
that an edit of such a row still **lands**is pinned as a unit case in
187
+
that an edit of such a row still **lands**was pinned as a unit case in
definition write** (`packages/plugins/plugin-security/src/permission-set-projection.ts`, #4669; *Path note, 2026-10: #15204 stage 8 retired the `sys_permission_set` row whose `active` column carried that row state, and stage 7a (#23368) deleted the module; the path is kept as the record of what this section measured*).
@@ -575,7 +581,7 @@ that card lands; no row is declared without an enforcer.
575
581
| no `system` flow behind an anonymous flow door | D2b | the publish path, in both directions | card E2 |
576
582
| the guest's grants, and deny-all when none | D3 | the anonymous branch of `resolveAuthzContext`| card E1 |
577
583
| no door binds a set to `guest` until the bind door is built | D3 item 5 (amended) | the anchors' seal (`NOT_OVERRIDABLE`; the package door's built-in names) and `confirmAudienceBindingSuggestion`'s refusal of a `guest` row | enforced; the door is follow-up F4 |
578
-
| the anchor binding tier | ADR-0090 D9; D3 |`describeAnchorForbiddenBits`, through `assertAudienceAnchorBindingGate`| enforced |
584
+
| the anchor binding tier | ADR-0090 D9; D3 |`describeAnchorForbiddenBits`: for `everyone` through `confirmAudienceBindingSuggestion` and `readAcceptedEveryoneSets`; for `guest`, through the bind door when it is built (no door binds a set to `guest`, the row above) | enforced for `everyone`; `guest`: follow-up F4|
579
585
| no delegated binding of an anchor | ADR-0090 D12 |`ANCHOR_POSITIONS`| enforced |
580
586
| the guest's organization | D4 | the guest entry's organization step, with `resolveSystemWriteOrganization`'s predicate | card E1 |
581
587
| the form doors' organization | D4, clarification (1) |`anonymousFormIntakeUnavailability`; the engine's write derivation | enforced |
0 commit comments