| ... | @@ -40,7 +40,6 @@ import * as Path from "effect/Path"; | ... | @@ -40,7 +40,6 @@ import * as Path from "effect/Path"; |
| 40 | import * as PubSub from "effect/PubSub"; | 40 | import * as PubSub from "effect/PubSub"; |
| 41 | import * as Ref from "effect/Ref"; | 41 | import * as Ref from "effect/Ref"; |
| 42 | import * as Schema from "effect/Schema"; | 42 | import * as Schema from "effect/Schema"; |
| 43 | import * as SchemaIssue from "effect/SchemaIssue"; | | |
| 44 | import * as Semaphore from "effect/Semaphore"; | 43 | import * as Semaphore from "effect/Semaphore"; |
| 45 | import * as Scope from "effect/Scope"; | 44 | import * as Scope from "effect/Scope"; |
| 46 | import * as Stream from "effect/Stream"; | 45 | import * as Stream from "effect/Stream"; |
| ... | @@ -67,7 +66,7 @@ const normalizeServerSettings = ( | ... | @@ -67,7 +66,7 @@ const normalizeServerSettings = ( |
| 67 | (cause) => | 66 | (cause) => |
| 68 | new ServerSettingsError({ | 67 | new ServerSettingsError({ |
| 69 | settingsPath: "<memory>", | 68 | settingsPath: "<memory>", |
| 70 | detail: `failed to normalize server settings: ${SchemaIssue.makeFormatterDefault()(cause.issue)}`, | 69 | operation: "normalize", |
| 71 | cause, | 70 | cause, |
| 72 | }), | 71 | }), |
| 73 | ), | 72 | ), |
| ... | @@ -277,7 +276,7 @@ const make = Effect.gen(function* () { | ... | @@ -277,7 +276,7 @@ const make = Effect.gen(function* () { |
| 277 | (cause) => | 276 | (cause) => |
| 278 | new ServerSettingsError({ | 277 | new ServerSettingsError({ |
| 279 | settingsPath, | 278 | settingsPath, |
| 280 | detail: "failed to check settings file existence", | 279 | operation: "check-exists", |
| 281 | cause, | 280 | cause, |
| 282 | }), | 281 | }), |
| 283 | ), | 282 | ), |
| ... | @@ -288,7 +287,7 @@ const make = Effect.gen(function* () { | ... | @@ -288,7 +287,7 @@ const make = Effect.gen(function* () { |
| 288 | (cause) => | 287 | (cause) => |
| 289 | new ServerSettingsError({ | 288 | new ServerSettingsError({ |
| 290 | settingsPath, | 289 | settingsPath, |
| 291 | detail: "failed to read settings file", | 290 | operation: "read-file", |
| 292 | cause, | 291 | cause, |
| 293 | }), | 292 | }), |
| 294 | ), | 293 | ), |
| ... | @@ -305,6 +304,7 @@ const make = Effect.gen(function* () { | ... | @@ -305,6 +304,7 @@ const make = Effect.gen(function* () { |
| 305 | yield* Effect.logWarning("failed to parse settings.json, using defaults", { | 304 | yield* Effect.logWarning("failed to parse settings.json, using defaults", { |
| 306 | path: settingsPath, | 305 | path: settingsPath, |
| 307 | issues: Cause.pretty(decoded.cause), | 306 | issues: Cause.pretty(decoded.cause), |
| | 307 | cause: decoded.cause, |
| 308 | }); | 308 | }); |
| 309 | return DEFAULT_SERVER_SETTINGS; | 309 | return DEFAULT_SERVER_SETTINGS; |
| 310 | } | 310 | } |
| ... | @@ -318,13 +318,6 @@ const make = Effect.gen(function* () { | ... | @@ -318,13 +318,6 @@ const make = Effect.gen(function* () { |
| 318 | | 318 | |
| 319 | const getSettingsFromCache = Cache.get(settingsCache, cacheKey); | 319 | const getSettingsFromCache = Cache.get(settingsCache, cacheKey); |
| 320 | | 320 | |
| 321 | const toSettingsError = (detail: string, cause: unknown) => | | |
| 322 | new ServerSettingsError({ | | |
| 323 | settingsPath, | | |
| 324 | detail, | | |
| 325 | cause, | | |
| 326 | }); | | |
| 327 | | | |
| 328 | const materializeProviderEnvironmentSecrets = ( | 321 | const materializeProviderEnvironmentSecrets = ( |
| 329 | settings: ServerSettings, | 322 | settings: ServerSettings, |
| 330 | ): Effect.Effect<ServerSettings, ServerSettingsError> => | 323 | ): Effect.Effect<ServerSettings, ServerSettingsError> => |
| ... | @@ -343,11 +336,15 @@ const make = Effect.gen(function* () { | ... | @@ -343,11 +336,15 @@ const make = Effect.gen(function* () { |
| 343 | const secret = yield* secretStore | 336 | const secret = yield* secretStore |
| 344 | .get(providerEnvironmentSecretName({ instanceId, name: variable.name })) | 337 | .get(providerEnvironmentSecretName({ instanceId, name: variable.name })) |
| 345 | .pipe( | 338 | .pipe( |
| 346 | Effect.mapError((cause) => | 339 | Effect.mapError( |
| 347 | toSettingsError( | 340 | (cause) => |
| 348 | `failed to read sensitive environment variable ${variable.name}`, | 341 | new ServerSettingsError({ |
| 349 | cause, | 342 | settingsPath, |
| 350 | ), | 343 | operation: "read-secret", |
| | 344 | providerInstanceId: instanceId, |
| | 345 | environmentVariable: variable.name, |
| | 346 | cause, |
| | 347 | }), |
| 351 | ), | 348 | ), |
| 352 | ); | 349 | ); |
| 353 | environment.push({ | 350 | environment.push({ |
| ... | @@ -382,13 +379,18 @@ const make = Effect.gen(function* () { | ... | @@ -382,13 +379,18 @@ const make = Effect.gen(function* () { |
| 382 | for (const variable of instance.environment) { | 379 | for (const variable of instance.environment) { |
| 383 | const secretName = providerEnvironmentSecretName({ instanceId, name: variable.name }); | 380 | const secretName = providerEnvironmentSecretName({ instanceId, name: variable.name }); |
| 384 | if (!variable.sensitive) { | 381 | if (!variable.sensitive) { |
| 385 | yield* secretStore | 382 | yield* secretStore.remove(secretName).pipe( |
| 386 | .remove(secretName) | 383 | Effect.mapError( |
| 387 | .pipe( | 384 | (cause) => |
| 388 | Effect.mapError((cause) => | 385 | new ServerSettingsError({ |
| 389 | toSettingsError(`failed to remove environment secret ${variable.name}`, cause), | 386 | settingsPath, |
| 390 | ), | 387 | operation: "remove-secret", |
| 391 | ); | 388 | providerInstanceId: instanceId, |
| | 389 | environmentVariable: variable.name, |
| | 390 | cause, |
| | 391 | }), |
| | 392 | ), |
| | 393 | ); |
| 392 | environment.push(redactProviderEnvironmentVariable(variable)); | 394 | environment.push(redactProviderEnvironmentVariable(variable)); |
| 393 | continue; | 395 | continue; |
| 394 | } | 396 | } |
| ... | @@ -396,22 +398,32 @@ const make = Effect.gen(function* () { | ... | @@ -396,22 +398,32 @@ const make = Effect.gen(function* () { |
| 396 | nextSecretKeys.add(secretName); | 398 | nextSecretKeys.add(secretName); |
| 397 | if (!variable.valueRedacted) { | 399 | if (!variable.valueRedacted) { |
| 398 | if (variable.value.length > 0) { | 400 | if (variable.value.length > 0) { |
| 399 | yield* secretStore | 401 | yield* secretStore.set(secretName, textEncoder.encode(variable.value)).pipe( |
| 400 | .set(secretName, textEncoder.encode(variable.value)) | 402 | Effect.mapError( |
| 401 | .pipe( | 403 | (cause) => |
| 402 | Effect.mapError((cause) => | 404 | new ServerSettingsError({ |
| 403 | toSettingsError(`failed to persist environment secret ${variable.name}`, cause), | 405 | settingsPath, |
| 404 | ), | 406 | operation: "write-secret", |
| 405 | ); | 407 | providerInstanceId: instanceId, |
| | 408 | environmentVariable: variable.name, |
| | 409 | cause, |
| | 410 | }), |
| | 411 | ), |
| | 412 | ); |
| 406 | environment.push({ ...variable, value: "", valueRedacted: true }); | 413 | environment.push({ ...variable, value: "", valueRedacted: true }); |
| 407 | } else { | 414 | } else { |
| 408 | yield* secretStore | 415 | yield* secretStore.remove(secretName).pipe( |
| 409 | .remove(secretName) | 416 | Effect.mapError( |
| 410 | .pipe( | 417 | (cause) => |
| 411 | Effect.mapError((cause) => | 418 | new ServerSettingsError({ |
| 412 | toSettingsError(`failed to remove environment secret ${variable.name}`, cause), | 419 | settingsPath, |
| 413 | ), | 420 | operation: "remove-secret", |
| 414 | ); | 421 | providerInstanceId: instanceId, |
| | 422 | environmentVariable: variable.name, |
| | 423 | cause, |
| | 424 | }), |
| | 425 | ), |
| | 426 | ); |
| 415 | const { valueRedacted: _omit, ...rest } = variable; | 427 | const { valueRedacted: _omit, ...rest } = variable; |
| 416 | environment.push(rest); | 428 | environment.push(rest); |
| 417 | } | 429 | } |
| ... | @@ -431,16 +443,18 @@ const make = Effect.gen(function* () { | ... | @@ -431,16 +443,18 @@ const make = Effect.gen(function* () { |
| 431 | if (!variable.sensitive) continue; | 443 | if (!variable.sensitive) continue; |
| 432 | const secretName = providerEnvironmentSecretName({ instanceId, name: variable.name }); | 444 | const secretName = providerEnvironmentSecretName({ instanceId, name: variable.name }); |
| 433 | if (nextSecretKeys.has(secretName)) continue; | 445 | if (nextSecretKeys.has(secretName)) continue; |
| 434 | yield* secretStore | 446 | yield* secretStore.remove(secretName).pipe( |
| 435 | .remove(secretName) | 447 | Effect.mapError( |
| 436 | .pipe( | 448 | (cause) => |
| 437 | Effect.mapError((cause) => | 449 | new ServerSettingsError({ |
| 438 | toSettingsError( | 450 | settingsPath, |
| 439 | `failed to remove stale environment secret ${variable.name}`, | 451 | operation: "remove-stale-secret", |
| | 452 | providerInstanceId: instanceId, |
| | 453 | environmentVariable: variable.name, |
| 440 | cause, | 454 | cause, |
| 441 | ), | 455 | }), |
| 442 | ), | 456 | ), |
| 443 | ); | 457 | ); |
| 444 | } | 458 | } |
| 445 | } | 459 | } |
| 446 | | 460 | |
| ... | @@ -468,7 +482,7 @@ const make = Effect.gen(function* () { | ... | @@ -468,7 +482,7 @@ const make = Effect.gen(function* () { |
| 468 | (cause) => | 482 | (cause) => |
| 469 | new ServerSettingsError({ | 483 | new ServerSettingsError({ |
| 470 | settingsPath, | 484 | settingsPath, |
| 471 | detail: "failed to write settings file", | 485 | operation: "write-file", |
| 472 | cause, | 486 | cause, |
| 473 | }), | 487 | }), |
| 474 | ), | 488 | ), |
| ... | @@ -492,7 +506,7 @@ const make = Effect.gen(function* () { | ... | @@ -492,7 +506,7 @@ const make = Effect.gen(function* () { |
| 492 | (cause) => | 506 | (cause) => |
| 493 | new ServerSettingsError({ | 507 | new ServerSettingsError({ |
| 494 | settingsPath, | 508 | settingsPath, |
| 495 | detail: "failed to prepare settings directory", | 509 | operation: "prepare-directory", |
| 496 | cause, | 510 | cause, |
| 497 | }), | 511 | }), |
| 498 | ), | 512 | ), |
| ... | @@ -571,7 +585,10 @@ const make = Effect.gen(function* () { | ... | @@ -571,7 +585,10 @@ const make = Effect.gen(function* () { |
| 571 | materializeProviderEnvironmentSecrets(settings).pipe( | 585 | materializeProviderEnvironmentSecrets(settings).pipe( |
| 572 | Effect.catch((error: ServerSettingsError) => | 586 | Effect.catch((error: ServerSettingsError) => |
| 573 | Effect.logWarning("failed to materialize provider environment secrets", { | 587 | Effect.logWarning("failed to materialize provider environment secrets", { |
| 574 | detail: error.detail, | 588 | operation: error.operation, |
| | 589 | providerInstanceId: error.providerInstanceId, |
| | 590 | environmentVariable: error.environmentVariable, |
| | 591 | cause: error.cause, |
| 575 | }).pipe(Effect.as(settings)), | 592 | }).pipe(Effect.as(settings)), |
| 576 | ), | 593 | ), |
| 577 | ), | 594 | ), |