// ============================================================ // ADMIN LOCKDOWN // With several admins, everything in the admin panel is editable by all of // them — prompts, model policy, retrieval limits, SMTP. Lockdown separates // "runs the service day to day" from "changes how the service behaves". // // It is an environment variable, deliberately, not a setting. A setting could // be switched off by any admin, which would make it decoration. Only someone // with access to the host and a restart can lift it. // // Locked settings stay visible — an admin should be able to see how the system // is configured — but the field is read-only and the server refuses the write. // The refusal is the real control; the read-only field is only courtesy. // ============================================================ // Everything that changes how the assistant answers, what it costs, or how mail // leaves the building. var LOCKED_PREFIXES = Object.freeze([ 'prompt.', // every prompt, including the clinical ones 'clinical_assistant.', // models, allowlists, retrieval limits, budgets 'models.', // model policy: default, custom, enabled set 'tts.', 'stt.', 'embeddings.', 'smtp.', // where mail goes and who it authenticates as 'email.' // the templates that mail sends ]); // Day-to-day operation stays with ordinary admins. var EDITABLE_WHEN_LOCKED = Object.freeze([ 'announcement.', 'registration_enabled', 'registration_invite_only', 'feature.', 'site.' ]); function enabled(env) { var raw = (env || process.env).ADMIN_LOCKDOWN; return String(raw == null ? '' : raw).toLowerCase() === 'true'; } // A key is locked when lockdown is on and it is not on the day-to-day list. // Anything unrecognised is locked: a setting added later should need a // deliberate decision to become editable, rather than defaulting to open. function isLocked(key, env) { if (!enabled(env)) return false; var name = String(key || ''); for (var i = 0; i < EDITABLE_WHEN_LOCKED.length; i++) { var allowed = EDITABLE_WHEN_LOCKED[i]; if (name === allowed || (allowed.endsWith('.') && name.startsWith(allowed))) return false; } return true; } // What the admin UI needs to render itself correctly. function state(env) { return { enabled: enabled(env), lockedPrefixes: LOCKED_PREFIXES.slice(), editablePrefixes: EDITABLE_WHEN_LOCKED.slice(), reason: 'ADMIN_LOCKDOWN is set on the server. Locked settings can only be changed by someone with host access.' }; } // One message, so every refusal reads the same wherever it comes from. function refusal(key) { return 'This setting is locked. The server is in admin lockdown (ADMIN_LOCKDOWN), ' + 'so "' + key + '" can only be changed by someone with host access.'; } module.exports = { LOCKED_PREFIXES, EDITABLE_WHEN_LOCKED, enabled, isLocked, state, refusal };