You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Add portal playground mode: anonymous browser-pinned sessions
PORTAL_PLAYGROUND=1 lets one deployment serve as a public try-it
instance. An unauthenticated browser navigation mints an anonymous
playground-<random> principal into the ordinary portal_session cookie,
so every visitor gets their own scoped sessions, files, memory, and
sandbox through the same personal-scope isolation real teammates use.
Non-HTML requests without a session still get 401, so only real page
loads mint. /auth/login keeps the full OIDC flow for the one admin,
/admin refuses anonymous sessions outright, and signing out simply
starts a fresh identity on the next visit.
Minting is rate-limited per client IP through the core's durable
single-use claim store, failing closed to a 429 page when the claim
cannot be recorded, so restarts and blue-green deploys cannot reset the
budget. The claim-store helper moves from plugins/auth to the shared
chassis package now that both the auth broker and the portal consume it.
* Harden playground mode after independent review
Refuse to boot when playground is combined with a domain-wide cookie,
an apps domain, or deployment proxying, since those surfaces never see
the anon flag and would take an anonymous session at face value. Refuse
out-of-range mint knobs instead of silently serving 429 to everyone:
the core grants at most 64 claim slots per request and a 24-hour claim
horizon, so values outside those bounds brick minting. Bucket IPv6
minting per /64 so a routed prefix cannot rotate through fresh budgets,
and warn at boot when the socket address would make every visitor share
one bucket behind a reverse proxy. Refuse anonymous sessions the
connect and secret-drop flows so real OAuth tokens and dropped secrets
cannot be attached to a throwaway principal that a cleared cookie
orphans.
"PORTAL_PLAYGROUND_MINTS_PER_IP must be an integer between 1 and 64 (the core grants at most 64 claim slots per request)",
1181
+
);
1182
+
}
1183
+
if(
1184
+
!Number.isInteger(PLAYGROUND_MINT_WINDOW_S)||
1185
+
PLAYGROUND_MINT_WINDOW_S<60||
1186
+
PLAYGROUND_MINT_WINDOW_S>86400
1187
+
){
1188
+
problems.push(
1189
+
"PORTAL_PLAYGROUND_MINT_WINDOW_S must be an integer between 60 and 86400 (the core's claim horizon is 24 hours)",
1190
+
);
1191
+
}
1192
+
if(COOKIE_DOMAIN||APPS_DOMAIN){
1193
+
problems.push(
1194
+
"PORTAL_PLAYGROUND requires PORTAL_COOKIE_DOMAIN and PORTAL_APPS_DOMAIN unset — a domain-wide cookie would carry anonymous sessions to app subdomains, which never see the anon flag",
1195
+
);
1196
+
}
1197
+
if(DEPLOYMENTS_ENABLED){
1198
+
problems.push(
1199
+
"PORTAL_PLAYGROUND requires PORTAL_DEPLOYMENTS_ENABLED unset — anonymous visitors must not reach deployed apps",
1200
+
);
1201
+
}
1202
+
}
1086
1203
if(APPS_DOMAIN&&!COOKIE_DOMAIN){
1087
1204
problems.push(
1088
1205
"PORTAL_APPS_DOMAIN requires PORTAL_COOKIE_DOMAIN (app returnTo without a domain-wide session cookie loops sign-in forever)",
@@ -1208,6 +1325,14 @@ export function startServer(): void {
1208
1325
console.warn(
1209
1326
`[portal] PORTAL_LOCAL_AUTH_BYPASS=1 -- using ${LOCAL_AUTH_PRINCIPAL} as the local session principal (dev/test only)`,
1210
1327
);
1328
+
if(PLAYGROUND)
1329
+
console.warn(
1330
+
`[portal] PORTAL_PLAYGROUND=1 -- unauthenticated visitors get anonymous browser-pinned sessions (${PLAYGROUND_MINTS_PER_IP} mints per IP per ${PLAYGROUND_MINT_WINDOW_S}s); admin sign-in stays on /auth/login`,
1331
+
);
1332
+
if(PLAYGROUND&&!ON_FLY&&XFF_TRUSTED_HOPS===0)
1333
+
console.warn(
1334
+
"[portal] playground mint limits key on the socket address — set PORTAL_XFF_TRUSTED_HOPS when behind a reverse proxy, or every visitor shares one bucket",
1335
+
);
1211
1336
console.log(
1212
1337
"[portal] /admin access is derived (portal → admin surface /api/whoami over 6PN → core canAdminister); the core's ADMIN_GRANTS is the one source of admin identity",
0 commit comments