Skip to content

Commit 8ab3f98

Browse files
committed
chore(service-storage): declare the storage gate narrowing as breaking, and correct the lifecycle-arm comment
The changeset now grades @objectstack/service-storage minor, carries the narrowing arm, the BREAKING banner and the ADR-0087 disposition, in the form of this package's own precedent for the same ADR-0069 act. The lifecycle-arm comment in the gate reader now says what is true on each route. No code change. Claude-Session: https://claude.ai/code/session_01Nk17Z26X5DB59iQztDBADH Co-authored-by: Claude <noreply@anthropic.com>
1 parent 82adc50 commit 8ab3f98

2 files changed

Lines changed: 17 additions & 7 deletions

File tree

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
---
2-
'@objectstack/service-storage': patch
2+
'@objectstack/service-storage': minor
33
---
44

5-
fix(service-storage): the storage family gate and the route judge the same credential
5+
fix(service-storage)!: the storage family gate and the route judge the same credential
66

7-
A session the ADR-0069 authentication policy HOLDS (an expired password, enforced MFA not yet enrolled) is now refused on every route of the storage family whatever else the request carries. The family door fronts routes that serve different credentials, so it judges every credential a route can serve: the held session's own posture, and a held key's owner through the shared key-admission seam. The result is a `403` with the gate's posture code before any of the family's own logic runs, so the gate and the route never judge a different credential.
7+
Clause-②: no (narrowing) — a session the ADR-0069 policy holds is refused on every storage route whatever else the request carries; no published schema, export or option moves.
88

9-
No request a storage route refuses today becomes accepted, and no export, schema or accepted value changes.
9+
<!-- adr-0087: not-required (no-migration-prescription) A runtime authentication narrowing at the storage route family mounted directly on the host server, not a metadata change. No spec key, export, option, config field, response field or stored shape is removed, renamed or re-shaped, and a session the policy does not hold receives the same answers as before, so there is no tombstone and nothing for `objectstack migrate meta` to rewrite. What narrows is which requests the family serves: a session whose user carries the ADR-0069 posture is now refused with the gate's 403 whatever else the request carries. The other categories are closed on facts: the package publishes (not unpublished); no ADR-0087 id covers these routes and this diff adds none (not registered / already-registered); and no published interface or type changes (not runtime-interface-only / type-surface-only). -->
1010

11-
Clause-②: no
11+
**BREAKING** (an accept-set narrowing), shipped as `minor` under the launch-window convention for breaking changes.
12+
13+
ADR-0069 holds a signed-in user out of every protected resource while their password has expired or while enforced MFA is not yet enrolled, until they remediate, and every route of the storage family is one. The family's gate and its routes now judge the same credential: the gate judges every credential a route of the family can serve.
14+
15+
- **Refused now:** a session the policy holds gets `403` with the gate's own `code` (`PASSWORD_EXPIRED`, `PASSWORD_RESET_REQUIRED` or `MFA_REQUIRED`) and `message` on every storage route, whatever else the request carries, before the family does anything else. While a gate is active, a session that cannot be read is the family's declared `503` (`SERVICE_UNAVAILABLE`), whatever else the request carries.
16+
- **Unchanged:** a session the policy does not hold is served exactly as before, apart from that outage answer; an API key whose owner holds an `account`-scope posture is refused with that posture, as before; and while no gate feature is active nothing changes.
17+
18+
What changes for you. A user the policy holds must remediate (change the password, or enroll an authenticator) before any storage route answers them, whatever else their request carries. There is nothing to configure.

‎packages/services/service-storage/src/storage-service-plugin.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,8 +1287,11 @@ function buildAuthGateSessionReader(
12871287
await resolveAdmissionTenancyPosture(registry),
12881288
userAuthGateSourceOf(auth),
12891289
// [#23367] The API-key lifecycle policy, from the same service. A key
1290-
// its own lifecycle refuses (`lifecycle`) carries no posture; the
1291-
// route that would serve it fails it closed.
1290+
// its own lifecycle refuses (`lifecycle`) carries no posture. The
1291+
// parent-governed download, whose composition reads keys, refuses it
1292+
// with its own code; the session-serving routes (uploads, the
1293+
// unclaimed-file download) never read a key and answer by the session
1294+
// alone; the raw-transfer routes answer by their capability token.
12921295
apiKeyLifecyclePolicySourceOf(auth),
12931296
);
12941297
if (admission.outcome === 'held') return { authGate: admission.gate };

0 commit comments

Comments
 (0)