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
feat(plugin-security): extend the packaged-permission-set lock to the restore leg of the write-through (#13409)
* feat(plugin-security): extend the packaged-permission-set lock to the restore leg of the write-through
The restore leg now consults assertPermissionSetNotPackageDeclared before
re-authoring a restored record's definition into metadata. A packaged (or
unknown-provenance, fail-closed) name has its mint refused BEFORE the
metadata write and the refusal reported loudly on the durability channel;
the engine un-trash stands (the leg is a deliberate post-pass and never
throws). The #11725 MEASURED RESIDUAL tripwire is inverted in the same
change, plus a non-packaged control and a fail-closed case.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012WkdHQwHr2KQmaX7P1BHzi
* docs(permissions): re-anchor the system-context census row for permission-set-projection.ts (pure shift, +6)
The #12020 restore-leg comment block shifted the middleware's isSystem
read from :1009 to :1015; census site count and page anchor count are
1:1 and the read text is byte-identical to origin/main, so this is the
census gate's FIX class (a pure shift), rewritten by its own --fix.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012WkdHQwHr2KQmaX7P1BHzi
---------
Co-authored-by: Claude <noreply@anthropic.com>
Extend the packaged-permission-set lock ("lock the base, clone to customize", 2026-08-24 ruling) to the `restore` leg of the permission-set write-through — the one write point that did not consult it. The leg now checks provenance before re-authoring a restored record's definition into metadata: a package-declared name (or one whose provenance cannot be resolved — fail-closed) has its re-author refused and the refusal reported loudly on the durability channel, while the engine's un-trash stands (this leg runs after it and deliberately never throws). With the mint refused, boot reconciliation re-projects the declared body, so the environment converges to the package truth instead of a silent fork. Org-owned sets restore exactly as before.
Copy file name to clipboardExpand all lines: content/docs/permissions/system-context.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -96,7 +96,7 @@ that silently does not happen.
96
96
| 7 | Metadata-plane schema masking exempt (ADR-0106 D4) | metadata-core | Get: unmasked object schema. Note: the exemption is a **caller** property — it short-circuits before the security service is consulted |`object-schema-fls.ts:228`|
97
97
| 8 |`explain()` may target a principal other than the caller | plugin-security | Get: no `manage_users` / delegated-admin check |`security-plugin.ts:3808`|
98
98
| 9 | Anonymous-deny treats the caller as authenticated | core | Get: passes the 401 seam with no `userId`|`anonymous-deny.ts:154`|
| 12 | Per-request performance timings disclosed | observability | Get: timing headers a normal caller cannot pull |`perf-timing.ts:474`|
102
102
| 13 | Permission-set **overlay discard** skips the tenant-admin assertion | plugin-security | Get: an overlay can be discarded with no authenticated tenant administrator |`permission-set-overlay-discard.ts:142`|
/** The package-declared body every case in this file turns on. */
@@ -273,13 +296,16 @@ describe('[#11725] the restore leg of the permission-set write-through', () => {
273
296
expect(ql.overlays.length,'no overlay of a packaged set was minted').toBe(0);
274
297
});
275
298
276
-
it('MEASURED RESIDUAL: the same set through RESTORE is re-authored with no lock consulted and no refusal',async()=>{
277
-
// ⚠️ Pins the residual, not a desired behaviour. See this file's header:
278
-
// the follow-up that extends the lock to this leg inverts this case.
299
+
it('LOCK AT THE RESTORE LEG: the same set through RESTORE keeps the engine un-trash but the re-author is REFUSED — reported on the durability channel, never thrown',async()=>{
300
+
// ⭐ The INVERSION of #11725's MEASURED RESIDUAL, demanded by that case's
301
+
// own comment and delivered by #12020. It used to assert: no refusal, one
302
+
// save, the packaged body in the overlay store. Now the lock is consulted
303
+
// before the leg's one guarded write, and every half inverts.
279
304
//
280
305
// Identical fixture to the CONTROL above — same ql, same registry, same
281
306
// protocol posture, same row. The ONLY difference is the operation, so the
282
-
// difference in outcome is attributable to the leg and nothing else.
307
+
// difference in outcome is attributable to the leg and nothing else. The
308
+
// hatch is OPEN, so anything that refuses can only be the write-door lock.
0 commit comments