/** * Local encrypted secret store. * * Storage layout (both files under `getConfigDir()`, honoring * `SPECTRAL_CONFIG_DIR` for tests): * - `/secrets.key` 32 random bytes, mode 0600 — AES-256 key * - `/secrets.json.enc` AES-256-GCM encrypted JSON, mode 0600 * * Encrypted file layout: * - bytes 0-7: magic `"SPSECRT1"` (format tag) * - bytes 8-19: 12-byte random IV * - bytes 20-35: 16-byte GCM auth tag * - bytes 36+: ciphertext (UTF-8 JSON) * * Security rules enforced here and by this module's consumers: * - `listSecrets()` returns ONLY `{ name, createdAt, updatedAt }` — values are * never part of any listing. * - `getSecretValue()` is INTERNAL: it is consumed only by * `getSecretEnvVars()` (env-var injection into the agent's bash tool). It * is deliberately NOT re-exported from `./index.js`, so neither the relay * handlers nor the LLM-facing tool surface can reach it. * - No caller ever logs a value; error messages and listings carry names only. * * All I/O is synchronous by design: `getSecretEnvVars()` must be callable from * the sync `getShellEnv()` in `src/sdk/coding-agent/utils/shell.ts`. The store * is tiny (values are capped at 64 KiB each), so sync reads are negligible. * * Keep this module zero-side-effect on import: nothing touches the filesystem * until one of the exported functions is called. */ /** Secret names: start with a letter, then letters/digits/underscores, max 64 chars. */ export declare const SECRET_NAME_PATTERN: RegExp; /** Maximum UTF-8 byte size of a secret value (64 KiB). */ export declare const MAX_SECRET_VALUE_BYTES: number; /** Metadata-safe view of a secret: NEVER includes the value. */ export interface SecretMeta { name: string; createdAt: string; updatedAt: string; } /** Thrown when a secret name is missing/invalid after normalization. */ export declare class SecretNameError extends Error { constructor(message: string); } /** Thrown when a secret value exceeds `MAX_SECRET_VALUE_BYTES`. */ export declare class SecretValueError extends Error { constructor(message: string); } /** Thrown when the encrypted store is unreadable, corrupt, or key-mismatched. */ export declare class SecretStoreCorruptError extends Error { constructor(message: string); } /** Path to the AES-256 key file (32 random bytes). Lazily computed — see `getConfigDir`. */ export declare function getSecretKeyPath(): string; /** Path to the AES-256-GCM encrypted store. Lazily computed — see `getConfigDir`. */ export declare function getSecretDataPath(): string; /** * Normalize a secret name per the shared contract: trim surrounding * whitespace, uppercase, then validate against `SECRET_NAME_PATTERN`. * Throws `SecretNameError` with a generic message — the offending raw input * is never echoed back, so it can't leak into logs. */ export declare function normalizeSecretName(raw: string): string; /** * Return the secret env vars (name → value) for injection into the agent * shell environment. Synchronous, mtime-cached: new/updated/deleted secrets * are picked up on the next call without a CLI restart. * * Failure modes degrade gracefully — a corrupt store, missing key, or unreadable * file returns `{}` instead of throwing, because `getShellEnv()` is sync and * must never break bash spawning. No values are ever logged. */ export declare function getSecretEnvVars(): Record; /** * Create or update a secret. Returns the metadata-only view (never the value). * Throws `SecretNameError` for invalid names, `SecretValueError` for oversized * values, and `SecretStoreCorruptError` when the store cannot be read/written. * * Fully synchronous (no awaits): the read-modify-write below is atomic per * event-loop turn, so concurrent relay POSTs in one process can never * interleave — no mutex is needed. Cross-process writers are isolated by the * unique per-request tmp name + rename in `writeStoreData`; the last rename * wins and every writer re-reads the store on its next call. */ export declare function setSecret(rawName: string, value: string): SecretMeta; /** * Delete a secret. Returns true when a record was removed, false when the * name was not stored. Throws `SecretNameError` for invalid names. */ export declare function deleteSecret(rawName: string): boolean; /** * List secrets as metadata only — `{ name, createdAt, updatedAt }`. Values are * never part of the returned shape (this is the source for the relay GET * response and the `list_secrets` agent tool). */ export declare function listSecrets(): SecretMeta[]; /** * INTERNAL — read a single secret value. Used ONLY for env-var injection via * `getSecretEnvVars()`. Deliberately not re-exported from `./index.js` so it * cannot be reached from the relay handlers or the LLM-facing tool surface. * Never log the return value. */ export declare function getSecretValue(rawName: string): string | undefined; /** * Remove the store + key (test helper and future "reset secrets" support). * Returns true when either file was deleted. */ export declare function resetSecretStore(): boolean; //# sourceMappingURL=store.d.ts.map