From 6d7c418fe5ad87581a4211784b18dd0b37549b6b Mon Sep 17 00:00:00 2001 From: Maximo Guk <62088388+Maximo-Guk@users.noreply.github.com> Date: Fri, 7 Aug 2026 09:48:09 -0500 Subject: [PATCH] Setup public infrastructure for preinstalling ambient gatekeepers --- scripts/release-manifest.test.js | 17 +++++++++++++++++ scripts/release/manifest-lib.mjs | 20 ++++++++++++++++++++ scripts/testdata/golden-manifest.json | 4 ++++ 3 files changed, 41 insertions(+) diff --git a/scripts/release-manifest.test.js b/scripts/release-manifest.test.js index d59be953..7d3e37ea 100644 --- a/scripts/release-manifest.test.js +++ b/scripts/release-manifest.test.js @@ -157,6 +157,23 @@ test("worker entries carry the deploy contract", () => { namespace_id: "$KV_CONTEXT_COLLECTIONS_ID" }); assert.deepEqual(context.inputs, []); + // Ambient gatekeepers are preinstalled on every core deploy; preinstalls must take no + // secret inputs (nobody is around to supply them). Both also declare an account-level agent + // singleton, so both are install-once. + assert.equal(context.preinstall, true); + assert.equal(context.singleton, true); + assert.equal(workers["gatekeeper-scheduler"].preinstall, true); + assert.equal(workers["gatekeeper-scheduler"].singleton, true); + assert.deepEqual(workers["gatekeeper-scheduler"].inputs, []); + assert.equal(google.preinstall, undefined); + assert.equal(google.singleton, undefined); + for (const [name, entry] of Object.entries(workers)) { + if (entry.preinstall) { + assert.ok(entry.installable, `${name}: preinstall requires installable`); + assert.deepEqual(entry.inputs, [], `${name}: preinstall requires no inputs`); + } + } + // Module blobs are content-addressed. for (const [name, entry] of Object.entries(workers)) { assert.ok(entry.modules.some((m) => m.name === entry.mainModule), diff --git a/scripts/release/manifest-lib.mjs b/scripts/release/manifest-lib.mjs index 6b4c9ffd..550fbfc0 100644 --- a/scripts/release/manifest-lib.mjs +++ b/scripts/release/manifest-lib.mjs @@ -52,6 +52,20 @@ const NO_DEFAULT_CRED_INPUTS = new Set([ // instances don't have. The bundle still ships in the release so the entry stays auditable. const NOT_INSTALLABLE = new Set(["gatekeeper-email"]); +// Ambient gatekeepers the deploy service installs on every fresh core deploy, server-side with +// no user interaction. Members must take no inputs of any kind (enforced below): a preinstall +// has nobody to ask. +const PREINSTALL = new Set(["gatekeeper-context", "gatekeeper-scheduler"]); + +// Gatekeepers that may be installed at most once per instance; the deploy service enforces this +// at install time. The giveaway is the account declaring an agent singleton +// (`AccountDescription.singleton` — context's `ContextLibrary`, scheduler's `ScheduleSession`): +// the Workshop auto-provisions those accounts and folds the singleton into every workspace as an +// ambient gatekeeper, so a second install would hand every user a duplicate ambient capsule. +// Independent of PREINSTALL in principle; the two sets coincide today only because every ambient +// gatekeeper we ship is also preinstalled. +const SINGLETON = new Set(["gatekeeper-context", "gatekeeper-scheduler"]); + export const DEFAULT_CRED_INPUTS = [ { name: "CLIENT_ID", @@ -205,12 +219,18 @@ export function buildWorkerEntry({ pkgName, config, mainModule, modules, deployI bindings.push({ type: "secret_text", name: input.name, text: `$SECRET(${input.name})` }); } } + if (PREINSTALL.has(pkgName) && inputs.length > 0) { + throw new Error(`${pkgName} is preinstalled but declares input(s); preinstalls run ` + + `with no user interaction, so this release would be broken`); + } } return { kind, ...(kind === "gatekeeper" ? { shortName: shortName(pkgName) } : {}), installable, + ...(PREINSTALL.has(pkgName) ? { preinstall: true } : {}), + ...(SINGLETON.has(pkgName) ? { singleton: true } : {}), mainModule, modules: modules.map(({ name, type, sha256, size }) => ({ name, type, sha256, size, r2Key: moduleR2Key(sha256), diff --git a/scripts/testdata/golden-manifest.json b/scripts/testdata/golden-manifest.json index d6f89704..6e578876 100644 --- a/scripts/testdata/golden-manifest.json +++ b/scripts/testdata/golden-manifest.json @@ -188,7 +188,9 @@ "invocation_logs": false } }, + "preinstall": true, "shortName": "context", + "singleton": true, "vars": { "BASE_URL": "$PUBLIC_BASE_URL/gatekeeper/context" } @@ -697,7 +699,9 @@ "invocation_logs": false } }, + "preinstall": true, "shortName": "scheduler", + "singleton": true, "vars": { "BASE_URL": "$PUBLIC_BASE_URL/gatekeeper/scheduler" }