Skip to content

Commit 876f5a5

Browse files
committed
chore(changeset): record the plugin-security default-permission-set reader correction (#15298)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m
1 parent 9044dba commit 876f5a5

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
"@objectstack/plugin-security": patch
3+
---
4+
5+
fix(plugin-security): the app default permission set resolves from the first level that NAMES one (#15298)
6+
7+
`declaredPermissionSets` carried a docblock stating a short-circuit its code did
8+
not have:
9+
10+
> The `packages[]` pass only supplies a set where the top level had none — which
11+
> is precisely the option-B artifact.
12+
13+
The code pushed the flattened top level and then **every** package body
14+
unconditionally, so on today's additive artifact (flattened level *and*
15+
`packages[]` both present) every permission set was collected twice. Nothing
16+
observable came of it — the sole caller is private and takes the first
17+
`isDefault` set, which the flattened copy still supplied — so this corrects a
18+
false written contract on a security-path reader, not a live defect. That
19+
distinction is the point: the sentence was load-bearing, because it was the
20+
stated reason the reader half was revertible on its own and safe to land before
21+
the emitter half (#14512), and the next reader would have believed the mechanism
22+
was there.
23+
24+
The reader now walks the discipline the docblock claims — start from the
25+
expression this program replaced, `appDefaultPermissionSetName(config.permissions)`,
26+
and consult `packages[]` only where it came back `undefined`.
27+
28+
- **The condition is the resolved NAME, never the `permissions` container.**
29+
Branching on the container re-creates the silent loss the reader program
30+
exists to remove, one shape further along: a flattened level that carries
31+
permission sets but marks none of them `isDefault` is legal today and
32+
hand-authorable in any `objectstack.config.ts`, and a container-shaped
33+
condition (`Array.isArray(flattened)`, with or without `&& length > 0`) shorts
34+
it past the whole `packages[]` pass and answers `undefined` — nothing thrown,
35+
nothing logged, every member of the app back down to the platform floor alone.
36+
Reading the answer also retires the `[]`-is-truthy trap rather than patching
37+
around it.
38+
- **The package order is resolved BEFORE the top level is consulted.**
39+
`resolveArtifactPackageOrder` refuses a malformed `packages` — not an array,
40+
an entry inlined instead of wrapped under `manifest:`, a duplicate package id
41+
— with an ADR-0112 envelope this reader does not catch, and that refusal must
42+
not become conditional on whether the flattened level happened to name a
43+
default first. An artifact is either loadable or refused; which level answered
44+
is not part of that question.
45+
- **No emitted artifact changes its answer.** Measured, not argued: 26 shapes —
46+
the composed additive artifact, its option-B derivative, the collection-zoo
47+
fixtures behind the #15004 acceptance pin, every config the unit suite drives,
48+
the three malformed-`packages` refusals, and the hand-authored mixed shapes —
49+
return byte-identical results before and after, with `@objectstack/plugin-security`
50+
rebuilt and the change proven present in `dist/` on each leg.

0 commit comments

Comments
 (0)