Repository navigation
Commit 448374d
Part of #24446
U2 of #24446: the marketplace refusal. It works to the measurement in
6355301005 and the seat's GO in 6355317159, under claim 6355237423. U1
(the boot report) landed as `54df640b38`. The ADR-0126 dated note is a
separate Tier H docs PR that the seat cuts. #24446 remains open for it.
Clause-②: yes (narrowing): a marketplace re-install that installed
before is now refused `409` while it would un-make an access choice made
in this system, until the same call confirms it (narrowing); the door
gains the `confirmAccessUpgrade` body field and the
`ACCESS_UPGRADE_CONFIRMATION_REQUIRED` code, plugin-security gains the
`security.accessUpgradeCheck` service and its exports, and the CLI gains
`--confirm-access-upgrade <token>` (widening).
Metadata-protocol: none
## What changed
**`cloud-connection`: step 2c of `POST
/api/v1/marketplace/install-local`.** It runs on a managed re-install
over an installed package (`findConflict === 'marketplace'`), after the
D5e gate and before the first write (`manifest.register`). A fresh
install has no customer choice of its own to un-make, so it is never
checked. The door asks the `security.accessUpgradeCheck` service as a
capability question, so `cloud-connection` takes no runtime dependency
on `plugin-security`.
- **Findings:** `409 ACCESS_UPGRADE_CONFIRMATION_REQUIRED`, and nothing
is registered or written.
- `error.details.findings` names each finding: its kind, type, name, the
candidates and binding positions, the missing names, and a one-line
`describe`.
- `error.details.findingSet` is the token, and
`error.details.confirmWith` is the retry.
- **The confirmation:** the same request with `confirmAccessUpgrade:
<findingSet>`.
- The token confirms exactly the findings it names. If the findings
change, it no longer matches and the call is refused again with the
fresh set.
- A bare `true` confirms nothing.
- A confirmed install records `accessUpgradeConfirmation: { findingSet,
confirmedBy, confirmedAt }` in its ledger entry.
- **The check stopped** (the ledger, the catalog or the declared rules
unreadable): `503 SERVICE_UNAVAILABLE`, and nothing is written.
- **No check service** (no security plugin in the composition): the
upgrade proceeds, and one `warn` line says no check ran.
**`plugin-security`: `access-upgrade-check.ts` (new), registered by
`SecurityPlugin` as `security.accessUpgradeCheck`.** It runs U1's
`collectAccessUpgradeFindings` unchanged and restates none of its rules.
It runs it twice:
1. over the registry as it stands;
2. over a projection of that registry with package P's items taken from
the incoming manifest:
- the catalog entries (permission sets, positions, capabilities) with
`packageId === P`;
- the declared sharing rules;
- P's objects and fields: the registry's field set, less what P's
previous version declared, plus the incoming declaration's.
The customer's state (the ledger, the `sys_sharing_rule` rows) is never
projected. The answer is the **delta**: what run 2 finds that run 1 does
not, and a finding that only grew keeps its new parts only. So a finding
that predates the upgrade, or that another package caused, never blocks
it; U1's boot report keeps raising those. "P's previous version" is the
door's ledger entry, or else the registry's own record of the package.
Sources are resolved at every call.
**`spec`: one error-code ledger row**,
`ACCESS_UPGRADE_CONFIRMATION_REQUIRED` under
`@objectstack/cloud-connection`, and the three generated reference pages
that list it.
**`cli`: `os package install … --confirm-access-upgrade <token>`.** It
sends the token. On the refusal, it prints every finding's `describe`
line and the exact retry.
## Who sees it
- **Walled (`isolated`, `group`):** only the platform operator reaches
step 2c. The existing ADR-0131 D12 refusal answers a tenant
administrator `403` before the check runs, and shows no finding.
- **`single`:** the administrator (`manage_metadata`).
## Limits, as in U1 (accepted by the seat, 6353222762)
- A re-enablement is "suspected": nothing records which name replaced
which.
- The field-deny check reads "grants the same object", not "copied
from".
- "The old name carrying a clone" is carried by the switch-off half
(ADR-0126 §9).
- An object that the incoming manifest adds and the registry does not
yet hold is judged on its declared fields only, without the fields the
registry would inject.
## Scope held
- Not `runtime/src/domains/packages.ts` (`POST /api/v1/packages` with
`overwrite`). It is the seat's follow-up card, which calls this same
service.
- Not cloud's own install path. If it has one, it calls this service in
cloud's follow-up.
- Not `docs/adr/**`, not U1's boot report (imported read-only), and no
`ORGANIZATION_OWNERSHIP_SHAPE_GENERATION` change.
- `cloud-connection` gains `@objectstack/plugin-security` as a
**devDependency** only, for its door test. There is no cycle: it already
reaches plugin-security through `@objectstack/runtime`.
## Tests
-
**`cloud-connection/src/marketplace-install-local-access-upgrade.test.ts`**
(34). The real door runs against the real `createAccessUpgradeCheck`,
over an in-memory access state with version 1 installed through the
door. For each of the four types (permission set, position, sharing
rule, capability):
- `single`: the administrator gets 409 with the finding;
- `isolated` and `group`: the operator gets 409;
- `isolated` and `group`: a tenant administrator gets 403 from the wall,
the check is not called, and no finding is shown;
- CONTROLs under `single` and `isolated` (200).
- Plus: the token installs and is recorded; `true` and a stale token are
refused; a finding that predates the upgrade does not block it; a
stopped check gives 503 and writes nothing; no check service means 200
and a warning.
- **`plugin-security/src/access-upgrade-check.test.ts`** (15). The check
as `SecurityPlugin` registers it, over a real `ObjectQL` and SQL driver,
for the four types with CONTROLs. It also covers a clone naming a field
the upgrade removes (version 1 read from the registry), a field deny the
managed set gains, the delta, the fail-closed stop, and "unbound before
start".
- **`cli/test/package-install-access-upgrade.test.ts`** (3): the flag,
its absence, and the refusal's rendering.
- **Ablations**, each red and then restored from the committed source:
- disabling step 2c turns 21 door pins red;
- refusing on the whole projected report instead of the delta turns the
"predates" pin red in both suites;
- turning off the catalog projection turns 4 of the check's pins red.
The proof readings are in the os-dev-report on #24446: CI, the dispatch
gates, `check-governed-merges --branch`, R1, R4 under `isolated` and
`group`, the upgrade harness and the dogfood battery.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01U9Aia8cnVwrpSUL9KgVzdu)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent d12e650 commit 448374d
18 files changed
Lines changed: 1472 additions & 9 deletions
File tree
- .changeset
- content/docs
- deployment
- references/api
- packages
- cli
- src/commands/package
- test
- cloud-connection
- src
- plugins/plugin-security/src
- spec/src/api
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2982 | 2982 | | |
2983 | 2983 | | |
2984 | 2984 | | |
| 2985 | + | |
2985 | 2986 | | |
2986 | 2987 | | |
2987 | 2988 | | |
| |||
2997 | 2998 | | |
2998 | 2999 | | |
2999 | 3000 | | |
| 3001 | + | |
| 3002 | + | |
| 3003 | + | |
| 3004 | + | |
| 3005 | + | |
| 3006 | + | |
| 3007 | + | |
| 3008 | + | |
| 3009 | + | |
| 3010 | + | |
| 3011 | + | |
| 3012 | + | |
| 3013 | + | |
| 3014 | + | |
| 3015 | + | |
| 3016 | + | |
3000 | 3017 | | |
3001 | 3018 | | |
3002 | 3019 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
352 | 352 | | |
353 | 353 | | |
354 | 354 | | |
355 | | - | |
| 355 | + | |
356 | 356 | | |
357 | 357 | | |
358 | 358 | | |
| |||
406 | 406 | | |
407 | 407 | | |
408 | 408 | | |
| 409 | + | |
409 | 410 | | |
410 | 411 | | |
411 | 412 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| |||
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
| 92 | + | |
92 | 93 | | |
93 | 94 | | |
94 | 95 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
256 | 256 | | |
257 | 257 | | |
258 | 258 | | |
| 259 | + | |
259 | 260 | | |
260 | 261 | | |
261 | 262 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
117 | 117 | | |
118 | 118 | | |
119 | 119 | | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
120 | 130 | | |
121 | 131 | | |
122 | 132 | | |
| |||
198 | 208 | | |
199 | 209 | | |
200 | 210 | | |
| 211 | + | |
201 | 212 | | |
202 | 213 | | |
203 | 214 | | |
| |||
227 | 238 | | |
228 | 239 | | |
229 | 240 | | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
230 | 255 | | |
231 | 256 | | |
232 | 257 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
81 | 90 | | |
82 | 91 | | |
83 | 92 | | |
| |||
0 commit comments