fix: let a signed-out visitor read the public site

Every public screen rendered its terminal error surface, and the network log
explained why: no request to /api/v1/public ever left the browser.

The credential collaborator asks the Studio helper first, which returns null
for any profile it does not own — "not mine, use your own logic". Below that,
the fallback reads the session and refuses anything that is not authenticated.
The public operations declare the ANONYMOUS profile, so they fell into that
fallback, and a signed-out visitor is exactly who the public site is for.

An anonymous profile carries no credentials by definition — the registry
refuses to install one that even allows a credential header — so it must never
consult the session. It now short-circuits with an empty credential patch,
keyed on the profile's transport rather than a profile id, so any anonymous
operation is covered rather than one named surface.

This could only appear once the public source became HTTP; until this week
that path had never run in a browser. The suites did not catch it because they
exercise the gateway and the screens, not the composition root's credential
decision — that seam has no test, and this is what it costs.
This commit is contained in:
DongHyeonka
2026-08-21 00:43:54 +09:00
parent 31dca00857
commit 03986da3d6
+12
View File
@@ -513,6 +513,18 @@ export async function createRuntimeAdapters(
techLogCsrf,
);
if (studioOutcome) return studioOutcome;
// An anonymous profile carries no credentials by definition — the
// registry refuses to install one that allows any credential header. It
// must therefore never consult the session: a signed-out visitor's state
// is `unauthenticated`, and falling through below refused every public
// read before it left the browser. The public site rendered its terminal
// error surface on every screen with no request in the network log.
//
// Keyed on the profile's transport rather than a profile id, so any
// anonymous operation is covered rather than one named surface.
if (INSTALLED_REST_AUTH_PROFILES.get(operation.authProfileId)?.transport === "ANONYMOUS") {
return Object.freeze({ kind: "READY" as const, headers: Object.freeze({}) });
}
const state = authSession.getState();
if (state === "integration-failed") {
return Object.freeze({ kind: "UNAVAILABLE" as const });