Harden auth scopes, SQL/WebCRT gates, and per-install JWT secrets.

Add capability RBAC, Alembic bootstrap, optional worker schedulers, and close public docs by default so lab installs stay usable without shared signing keys.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-08-02 16:24:34 +08:00
parent cb8e0d23c5
commit 633a9d55bd
38 changed files with 1808 additions and 452 deletions

View file

@ -817,7 +817,7 @@ export function WebcrtPage() {
const pending: TermTab = {
key,
sessionId,
wsUrl: webcrtWsUrl(sessionId),
wsUrl: "",
termEpoch: (existing?.termEpoch || 0) + 1,
target,
status: "connecting",
@ -833,9 +833,12 @@ export function WebcrtPage() {
return [...without, pending];
});
setActiveTabKey(key);
void webcrtWsUrl(sessionId).then((wsUrl) => {
updateTab(key, { wsUrl });
});
showOk(t("webcrt.opened", { name: deviceLabel(target) }));
},
[showOk, t],
[showOk, t, updateTab],
);
const openAuthForTarget = useCallback((target: CliTargetItem, errorHint?: string) => {
@ -927,7 +930,7 @@ export function WebcrtPage() {
async_connect: true,
};
const sess = await createWebcrtSession(body);
const wsUrl = webcrtWsUrl(sess.session_id);
const wsUrl = await webcrtWsUrl(sess.session_id);
updateTab(key, {
sessionId: sess.session_id,
wsUrl,
@ -966,9 +969,12 @@ export function WebcrtPage() {
status: "connecting",
connectPhase: "authenticating",
termEpoch: tab.termEpoch + 1,
wsUrl: webcrtWsUrl(tab.sessionId),
wsUrl: "",
errorMessage: undefined,
});
void webcrtWsUrl(tab.sessionId).then((wsUrl) => {
updateTab(tab.key, { wsUrl });
});
setActiveTabKey(tab.key);
return true;
},

View file

@ -8,7 +8,7 @@ const SECTIONS: WorkbenchSection[] = ["monitoring", "operations", "system"];
export function WorkbenchPage() {
const { t } = useI18n();
const { isAdmin } = useAuth();
const { isAdmin, hasScope } = useAuth();
return (
<div className="workbench">
@ -19,6 +19,7 @@ export function WorkbenchPage() {
{modulesInSection(section)
.filter((mod) => !mod.workbenchHidden)
.filter((mod) => !mod.adminOnly || isAdmin)
.filter((mod) => !mod.requiredScope || hasScope(mod.requiredScope) || isAdmin)
.map((mod) => (
<button
key={mod.moduleId}