diff --git a/apps/server/src/serverSettings.test.ts b/apps/server/src/serverSettings.test.ts index 4526e2c988a4..58e59245ce62 100644 --- a/apps/server/src/serverSettings.test.ts +++ b/apps/server/src/serverSettings.test.ts @@ -1039,6 +1039,37 @@ it.layer(NodeServices.layer)("server settings", (it) => { }).pipe(Effect.provide(makeServerSettingsLayer())), ); + it.effect("preserves inline sensitive provider environment values on a redacted save", () => + Effect.gen(function* () { + const serverSettings = yield* ServerSettingsModule.ServerSettingsService; + const serverConfig = yield* ServerConfig.ServerConfig; + const fileSystem = yield* FileSystem.FileSystem; + const instanceId = ProviderInstanceId.make("codex_personal"); + yield* fileSystem.writeFileString( + serverConfig.settingsPath, + '{"providerInstances":{"codex_personal":{"driver":"codex","environment":[{"name":"OPENROUTER_API_KEY","value":"inline-secret","sensitive":true}],"config":{}}}}', + ); + const clientSettings = ServerSettingsModule.redactServerSettingsForClient( + yield* serverSettings.getSettings, + ); + assert.equal(clientSettings.providerInstances[instanceId]?.environment?.[0]?.value, ""); + + const saved = yield* serverSettings.updateSettings({ + providerInstances: clientSettings.providerInstances, + }); + + assert.equal(saved.providerInstances[instanceId]?.environment?.[0]?.value, "inline-secret"); + assert.notInclude( + yield* fileSystem.readFileString(serverConfig.settingsPath), + "inline-secret", + ); + assert.equal( + (yield* serverSettings.getSettings).providerInstances[instanceId]?.environment?.[0]?.value, + "inline-secret", + ); + }).pipe(Effect.provide(makeServerSettingsLayer())), + ); + it.effect("stores sensitive provider instance environment values outside settings.json", () => Effect.gen(function* () { const serverSettings = yield* ServerSettingsModule.ServerSettingsService; diff --git a/apps/server/src/serverSettings.ts b/apps/server/src/serverSettings.ts index 5f2550534883..fbcae24fb197 100644 --- a/apps/server/src/serverSettings.ts +++ b/apps/server/src/serverSettings.ts @@ -609,9 +609,22 @@ const make = Effect.gen(function* () { } nextSecretKeys.add(secretName); - if (!variable.valueRedacted) { - if (variable.value.length > 0) { - yield* secretStore.set(secretName, textEncoder.encode(variable.value)).pipe( + let valueToPersist = variable.valueRedacted ? undefined : variable.value; + if (variable.valueRedacted) { + const currentVariable = current.providerInstances[ + ProviderInstanceId.make(instanceId) + ]?.environment?.findLast((entry) => entry.name === variable.name); + if ( + currentVariable?.sensitive && + !currentVariable.valueRedacted && + currentVariable.value.length > 0 + ) { + valueToPersist = currentVariable.value; + } + } + if (valueToPersist !== undefined) { + if (valueToPersist.length > 0) { + yield* secretStore.set(secretName, textEncoder.encode(valueToPersist)).pipe( Effect.mapError( (cause) => new ServerSettingsError({