@@ -52,6 +52,20 @@ const NO_DEFAULT_CRED_INPUTS = new Set([
5252// instances don't have. The bundle still ships in the release so the entry stays auditable.
5353const NOT_INSTALLABLE = new Set ( [ "gatekeeper-email" ] ) ;
5454
55+ // Ambient gatekeepers the deploy service installs on every fresh core deploy, server-side with
56+ // no user interaction. Members must take no inputs of any kind (enforced below): a preinstall
57+ // has nobody to ask.
58+ const PREINSTALL = new Set ( [ "gatekeeper-context" , "gatekeeper-scheduler" ] ) ;
59+
60+ // Gatekeepers that may be installed at most once per instance; the deploy service enforces this
61+ // at install time. The giveaway is the account declaring an agent singleton
62+ // (`AccountDescription.singleton` — context's `ContextLibrary`, scheduler's `ScheduleSession`):
63+ // the Workshop auto-provisions those accounts and folds the singleton into every workspace as an
64+ // ambient gatekeeper, so a second install would hand every user a duplicate ambient capsule.
65+ // Independent of PREINSTALL in principle; the two sets coincide today only because every ambient
66+ // gatekeeper we ship is also preinstalled.
67+ const SINGLETON = new Set ( [ "gatekeeper-context" , "gatekeeper-scheduler" ] ) ;
68+
5569export const DEFAULT_CRED_INPUTS = [
5670 {
5771 name : "CLIENT_ID" ,
@@ -205,12 +219,18 @@ export function buildWorkerEntry({ pkgName, config, mainModule, modules, deployI
205219 bindings . push ( { type : "secret_text" , name : input . name , text : `$SECRET(${ input . name } )` } ) ;
206220 }
207221 }
222+ if ( PREINSTALL . has ( pkgName ) && inputs . length > 0 ) {
223+ throw new Error ( `${ pkgName } is preinstalled but declares input(s); preinstalls run ` +
224+ `with no user interaction, so this release would be broken` ) ;
225+ }
208226 }
209227
210228 return {
211229 kind,
212230 ...( kind === "gatekeeper" ? { shortName : shortName ( pkgName ) } : { } ) ,
213231 installable,
232+ ...( PREINSTALL . has ( pkgName ) ? { preinstall : true } : { } ) ,
233+ ...( SINGLETON . has ( pkgName ) ? { singleton : true } : { } ) ,
214234 mainModule,
215235 modules : modules . map ( ( { name, type, sha256, size } ) => ( {
216236 name, type, sha256, size, r2Key : moduleR2Key ( sha256 ) ,
0 commit comments