Skip to content

Commit b1ac258

Browse files
committed
refactor(cloud-connection): answer a held install-local session through a module-private refusal
The refusal moves out of the exported plugin class into a module-private function, so the emitted declarations gain no private member. Both door paths (the listing and the four mutating doors) still answer the 401 first and the held session second, on the one consult in resolveInstallPrincipal. Claude-Session: https://claude.ai/code/session_01VoSxBQujKLZKPwK2u5ehQ6 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 20d325c commit b1ac258

2 files changed

Lines changed: 29 additions & 33 deletions

File tree

‎packages/cloud-connection/src/cloud-connection-auth-gate.pin.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
* (`sessionFromAuthService`, under both resolution modes). Seven of its
1313
* eight doors call it; `/status` reads no session at all.
1414
* - `MarketplaceInstallLocalPlugin` reads it in ONE place
15-
* (`resolveInstallPrincipal`), and all five doors open with the same
16-
* admission (`admitInstallCaller`).
15+
* (`resolveInstallPrincipal`), and all five doors answer a held session
16+
* through the same refusal (`refuseHeldSession`).
1717
*
1818
* Each consults `evaluateAuthGate` (`@objectstack/core`) once, with no request
1919
* path, so the shared allow-list can grant no exemption. No route either plugin

‎packages/cloud-connection/src/marketplace-install-local-plugin.ts‎

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ import {
113113
resolveAuthzContext,
114114
isAuthzStoreUnavailableError,
115115
// ADR-0069 — the authentication-policy gate's ONE decision, asked of the
116-
// session `resolveInstallPrincipal` reads (see `admitInstallCaller`).
116+
// session `resolveInstallPrincipal` reads (see `refuseHeldSession`).
117117
evaluateAuthGate,
118118
type AuthGate,
119119
// [#16013] The ADMISSION seam's posture derivation, in ONE call — the same
@@ -547,11 +547,28 @@ interface InstallPrincipal {
547547
/**
548548
* ADR-0069: the authentication-policy posture of the session this
549549
* admission resolved, present only for a session the policy holds.
550-
* `admitInstallCaller` refuses on it.
550+
* `refuseHeldSession` refuses on it.
551551
*/
552552
authGate?: AuthGate;
553553
}
554554

555+
/**
556+
* ADR-0069: the refusal every install-local door gives a session the
557+
* authentication policy HOLDS (an expired password, enforced MFA not yet
558+
* enrolled), right after the 401 and before the caller's capabilities are
559+
* consulted or the ledger is read. Such a session is gated out of every
560+
* protected resource until it remediates, so it gets REST's answer: `403`
561+
* with the gate's own `code` and `message`, in this plugin's envelope. The
562+
* consult itself happens once, in `resolveInstallPrincipal`; this only
563+
* answers on it, in one place, so a door added later cannot copy a weaker
564+
* answer. `null` when the session is not held.
565+
*/
566+
function refuseHeldSession(c: any, principal: InstallPrincipal): Response | null {
567+
if (!principal.authGate) return null;
568+
const { code, message } = principal.authGate;
569+
return c.json({ success: false, error: { code, message } }, 403);
570+
}
571+
555572
/**
556573
* [#15204 W2] What an admitted mutating request carries past
557574
* `requireInstallCapability`: the acting user, plus the two inputs ADR-0131
@@ -1742,9 +1759,10 @@ export class MarketplaceInstallLocalPlugin implements Plugin {
17421759
// Before the ledger is touched, exactly as the mutating doors refuse
17431760
// before any work: a refused caller must not be able to learn what is
17441761
// installed from timing or from a downstream storage error.
1745-
const admitted = await this.admitInstallCaller(c, ctx);
1746-
if (!admitted.ok) return admitted.response;
1747-
const { principal } = admitted;
1762+
const principal = await this.resolveInstallPrincipal(c, ctx);
1763+
if (!principal) return this.refuseUnauthenticated(c);
1764+
const held = refuseHeldSession(c, principal);
1765+
if (held) return held;
17481766
const operator = principal.systemPermissions.includes(INSTALL_LOCAL_CAPABILITY);
17491767

17501768
const { entries, skipped } = this.readAll();
@@ -3389,29 +3407,6 @@ export class MarketplaceInstallLocalPlugin implements Plugin {
33893407
error: { code: 'UNAUTHENTICATED', message: 'Authentication required.' },
33903408
}, 401);
33913409

3392-
/**
3393-
* ADR-0069: the floor all five doors open with, the listing included.
3394-
* Nobody authenticated is `401` ({@link refuseUnauthenticated}). A session
3395-
* the authentication policy HOLDS (an expired password, enforced MFA not
3396-
* yet enrolled) is gated out of every protected resource until it
3397-
* remediates, so it gets REST's answer: `403` with the gate's own `code`
3398-
* and `message`, in this plugin's envelope, before its capabilities are
3399-
* consulted and before the ledger is read. One helper for the same reason
3400-
* the 401 is one literal: a door added later cannot copy a weaker answer.
3401-
*/
3402-
private admitInstallCaller = async (
3403-
c: any,
3404-
ctx: PluginContext,
3405-
): Promise<{ ok: true; principal: InstallPrincipal } | { ok: false; response: Response }> => {
3406-
const principal = await this.resolveInstallPrincipal(c, ctx);
3407-
if (!principal) return { ok: false, response: this.refuseUnauthenticated(c) };
3408-
if (principal.authGate) {
3409-
const { code, message } = principal.authGate;
3410-
return { ok: false, response: c.json({ success: false, error: { code, message } }, 403) };
3411-
}
3412-
return { ok: true, principal };
3413-
};
3414-
34153410
/**
34163411
* [#8976] The shared refusal for the four mutating routes: 401 when nobody
34173412
* is authenticated, 403 when somebody is but holds no authoring capability,
@@ -3436,9 +3431,10 @@ export class MarketplaceInstallLocalPlugin implements Plugin {
34363431
ctx: PluginContext,
34373432
action: string,
34383433
): Promise<InstallAdmission | { ok: false; response: Response }> => {
3439-
const admitted = await this.admitInstallCaller(c, ctx);
3440-
if (!admitted.ok) return admitted;
3441-
const { principal } = admitted;
3434+
const principal = await this.resolveInstallPrincipal(c, ctx);
3435+
if (!principal) return { ok: false, response: this.refuseUnauthenticated(c) };
3436+
const held = refuseHeldSession(c, principal);
3437+
if (held) return { ok: false, response: held };
34423438
if (!principal.systemPermissions.includes(INSTALL_LOCAL_CAPABILITY)) {
34433439
ctx.logger?.warn?.(
34443440
`[MarketplaceInstallLocal] refused ${action} for ${principal.userId} — `

0 commit comments

Comments
 (0)