39 lines · 2.0 KB · TypeScript
RawDownload
import { Effect } from "effect"; import { StorageError, type SecretProvider } from "@executor/sdk"; import { getPassword, setPassword, deletePassword } from "./keyring"; // ---------------------------------------------------------------------------// SecretProvider adapter — bridges keyring into SDK resolution chain//// The underlying `@napi-rs/keyring` sync API encodes "no entry" as an// ordinary return value (`getPassword()` → `null`, `deletePassword()` →// `false`), and only throws on real failures (keychain locked, permission// denied, platform init failure, etc.). `keyring.ts` wraps those thrown// failures as `KeychainError`. We translate `KeychainError` →// `StorageError` so the HTTP edge can capture it to telemetry and surface// an opaque `InternalError({ traceId })` — previously `orElseSucceed`// silently converted every failure into "nothing found", which made it// impossible to debug why secrets weren't resolving.// --------------------------------------------------------------------------- const toStorageError = (cause: { readonly message: string; readonly cause?: unknown }) =>  new StorageError({ message: cause.message, cause: cause.cause ?? cause }); // Scope arg is ignored — keychain partitions by `serviceName`, which the// host fixes per executor at construction time. A future refactor could// fold `scope` into the service name, but today a keychain provider// instance is already one-scope.export const makeKeychainProvider = (serviceName: string): SecretProvider => ({  key: "keychain",  writable: true,  get: (secretId, _scope) =>    getPassword(serviceName, secretId).pipe(Effect.mapError(toStorageError)),  set: (secretId, value, _scope) =>    setPassword(serviceName, secretId, value).pipe(Effect.mapError(toStorageError)),  delete: (secretId, _scope) =>    deletePassword(serviceName, secretId).pipe(Effect.mapError(toStorageError)),  // Keychain doesn't support enumerating — you need to know the account name  list: undefined,});