plan: clarify phased secrets implementation
This commit is contained in:
parent
50ccf0f21b
commit
faac237f0d
|
|
@ -1,64 +1,146 @@
|
||||||
---
|
---
|
||||||
id: 20260529-145355-manifest-profile-encrypted-secrets
|
id: 20260529-145355-manifest-profile-encrypted-secrets
|
||||||
slug: manifest-profile-encrypted-secrets
|
slug: manifest-profile-encrypted-secrets
|
||||||
title: Encrypted secret store for manifest profiles
|
title: Manifest/Profile: local key-value secret store
|
||||||
status: open
|
status: open
|
||||||
kind: feature
|
kind: feature
|
||||||
priority: P2
|
priority: P2
|
||||||
labels: [manifest, profiles, secrets, security]
|
labels: [manifest, profiles, secrets, security, cli, tui]
|
||||||
created_at: 2026-05-29T14:53:55Z
|
created_at: 2026-05-29T14:53:55Z
|
||||||
updated_at: 2026-05-31T21:04:45Z
|
updated_at: 2026-05-31T21:19:29Z
|
||||||
assignee: null
|
assignee: null
|
||||||
legacy_ticket: null
|
legacy_ticket: null
|
||||||
---
|
---
|
||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
WebSearch/WebFetch made API keys more visible as a UX problem: `WebSearch` currently expects `web.search.api_key_env`, so users must export `BRAVE_SEARCH_API_KEY` before starting the Pod/TUI process. That is inconvenient for long-lived Pods, profile switching, and per-project/provider configuration.
|
Credential configuration still relies on process environment variables in important paths:
|
||||||
|
|
||||||
This should not be solved by adding `.env` loading as an implicit side effect. `.env` files are easy to leak into projects, do not solve profile-specific credential selection cleanly, and still expose secrets through process environments. Instead, when manifest profiles are designed/implemented, add a first-class encrypted secret store that manifests/profiles can reference.
|
- provider API keys use `AuthRef::ApiKey { env, file }` and provider-default `INSOMNIA_API_KEY_*` names;
|
||||||
|
- WebSearch currently uses `web.search.api_key_env`;
|
||||||
|
- normal runtime intentionally does not load `.env` files.
|
||||||
|
|
||||||
Related work item: `work-items/open/20260527-000022-manifest-profiles/item.md`.
|
This should not be solved by implicit `.env` loading. `.env` files are easy to leak into projects, do not solve profile-specific credential selection cleanly, and still expose secrets through process environments.
|
||||||
|
|
||||||
|
The desired replacement is a local key-value secret store plus explicit references from manifest/profile/tool configuration.
|
||||||
|
|
||||||
|
The security target is intentionally modest. This is not a high-assurance password manager. The goal is to avoid casual plaintext exposure and generic environment-variable scraping, not to defend against a local attacker with the user's account or process memory access.
|
||||||
|
|
||||||
|
## Intent
|
||||||
|
|
||||||
|
Implement a provider-independent local key-value secret store and use it as the normal credential path for provider and WebSearch credentials.
|
||||||
|
|
||||||
|
The logical store model is just:
|
||||||
|
|
||||||
|
```text
|
||||||
|
{
|
||||||
|
"anthropic/default" = "sk-..."
|
||||||
|
"web/brave/default" = "..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The store must not know that a key is Anthropic, Brave, OpenAI, or any other provider-specific kind. Provider/model/tool configuration chooses which key to reference.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Design a typed secret reference format for manifest/profile fields that need credentials.
|
### Store model
|
||||||
- Add a new encrypted-store reference form, e.g. `api_key_secret = "brave.search.default"` or a more general `SecretRef` enum.
|
|
||||||
- Existing env references such as `api_key_env = "BRAVE_SEARCH_API_KEY"` may be supported only as a migration/compatibility input during the transition; the target state is to remove credential environment-variable configuration rather than keep it as a normal fallback.
|
- Add a local secret/key store that maps a validated string id to a secret string value.
|
||||||
- Secret references must be explicit in resolved config; do not silently read arbitrary `.env` files.
|
- Keep the user-visible logical schema provider-independent: `id -> value`.
|
||||||
- Add an encrypted local secret store suitable for API keys/tokens.
|
- Do not add provider-specific slots, credential kinds, or required metadata to the store schema.
|
||||||
- Store secrets outside tracked project files by default, under the user data/config directory.
|
- Technical envelope fields needed for versioning/nonce/ciphertext/checksum are allowed, but they must not become user-facing semantic metadata.
|
||||||
- Use authenticated encryption and atomic writes.
|
- Store data outside the repository, under the user data directory, e.g. `<data_dir>/secrets/store.json` or equivalent.
|
||||||
- Do not log plaintext secrets, include them in session logs, expose them to model context, or return them through normal tool output.
|
- Use atomic writes.
|
||||||
- Keep encrypted blobs out of git-managed work-items/memory/session records.
|
- Validate ids:
|
||||||
- Integrate with manifest profiles.
|
- reject empty ids;
|
||||||
- Profiles should be able to select different secret names for different roles/providers, e.g. Orchestrator/Coder/Researcher or web search provider variants.
|
- reject path traversal / absolute-path-like ids;
|
||||||
- Profile resolution should validate that referenced secrets exist or produce a clear startup/tool diagnostic.
|
- reject control characters;
|
||||||
- A profile switch must not require restarting the shell just to change API keys.
|
- bound length;
|
||||||
- Provide a small CLI/TUI management surface.
|
- allow a conservative useful set such as ASCII alnum plus `._/-`.
|
||||||
- Add/update/list/delete secrets without printing plaintext by default.
|
|
||||||
- Support non-interactive set from stdin for scripts.
|
### Obfuscation / encryption stance
|
||||||
- Show references and metadata, not secret values.
|
|
||||||
- Consider migration helpers from existing env-var based configuration, but keep migration optional.
|
- Apply lightweight encryption or obfuscation at rest so the file is not a casual plaintext key dump.
|
||||||
- Update credential consumers.
|
- Do not claim strong local security guarantees.
|
||||||
- WebSearch should use encrypted secret refs instead of requiring env vars.
|
- Do not introduce OS keychain dependency or interactive passphrase UX in this ticket.
|
||||||
- Provider API keys/tokens and future hosted/search credentials should use the same mechanism.
|
- Do not store plaintext values in logs, work items, session history, diagnostics, or normal command output.
|
||||||
- Remove env-var credential configuration from the normal supported path once encrypted secret refs and migration diagnostics exist.
|
- Decryption/decoding failures must fail closed and name only the key id, not the value.
|
||||||
- Security and UX constraints.
|
|
||||||
- Fail closed when a referenced secret is missing or cannot be decrypted.
|
### `insomnia keys` TUI management
|
||||||
- Diagnostics should name the missing reference, not the secret value.
|
|
||||||
- Do not add hidden context injection or history mutation for secret resolution.
|
- Add `insomnia keys` as an interactive TUI key manager.
|
||||||
- Document the threat model and limitations, including OS account access and backup implications.
|
- The product CLI owner (`insomnia` crate) routes the subcommand.
|
||||||
|
- Use the TUI implementation crate for the terminal screen if practical.
|
||||||
|
- Minimum UI features:
|
||||||
|
- list key ids;
|
||||||
|
- add/set a key;
|
||||||
|
- delete a key with confirmation;
|
||||||
|
- quit.
|
||||||
|
- Do not display plaintext values in the list or normal screen output.
|
||||||
|
- During add/set, mask the value input or otherwise avoid echoing plaintext.
|
||||||
|
- Scriptable commands such as `insomnia keys set <id> --stdin` may be added if convenient, but the required user surface is the TUI manager.
|
||||||
|
|
||||||
|
### Config references / consumers
|
||||||
|
|
||||||
|
- Use explicit secret references from configuration.
|
||||||
|
- Existing `AuthRef::SecretRef { ref_ }` in manifest model should resolve through the new store for provider API keys.
|
||||||
|
- WebSearch must gain an explicit secret reference path so Brave search can be configured without `BRAVE_SEARCH_API_KEY` / `api_key_env`.
|
||||||
|
- Prefer a generic auth/secret-ref shape if it stays small.
|
||||||
|
- A focused `api_key_secret = "web/brave/default"` field is acceptable if it avoids a broad schema redesign.
|
||||||
|
- Secret refs are resolved at the consumer/runtime boundary only; resolved config/debug output must not contain plaintext.
|
||||||
|
- The store must not implicitly choose default keys based on provider name. No ambient lookup like "anthropic automatically reads anthropic/default" unless the profile/config explicitly references it.
|
||||||
|
|
||||||
|
### Env credential migration
|
||||||
|
|
||||||
|
- Do not load `.env` files.
|
||||||
|
- Do not add new credential environment variables.
|
||||||
|
- Existing env credential paths may remain temporarily as compatibility/migration input during this ticket if removing all of them would make the change too large.
|
||||||
|
- If env credential paths remain, docs and diagnostics should prefer `insomnia keys` + secret refs as the normal path.
|
||||||
|
- The target state is to remove credential env configuration from normal profile use in a follow-up or final phase of this ticket if feasible.
|
||||||
|
|
||||||
|
## Phases within this ticket
|
||||||
|
|
||||||
|
1. Core store
|
||||||
|
- key-value store API;
|
||||||
|
- id validation;
|
||||||
|
- lightweight encrypted/obfuscated file format;
|
||||||
|
- atomic load/save;
|
||||||
|
- focused tests.
|
||||||
|
2. `insomnia keys` TUI manager
|
||||||
|
- list/add/delete;
|
||||||
|
- masked input;
|
||||||
|
- no plaintext display.
|
||||||
|
3. Provider integration
|
||||||
|
- implement provider `AuthRef::SecretRef` resolution through the store;
|
||||||
|
- keep plaintext in memory only;
|
||||||
|
- fail closed on missing/invalid/decode failures.
|
||||||
|
4. WebSearch integration
|
||||||
|
- add a secret-ref credential path;
|
||||||
|
- make Brave search usable without env credentials.
|
||||||
|
5. Docs and migration
|
||||||
|
- update `docs/environment.md` and manifest/profile docs;
|
||||||
|
- document the modest security target honestly;
|
||||||
|
- point users to `insomnia keys` and secret refs as the normal credential path.
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- A high-assurance password manager.
|
||||||
|
- OS keychain integration.
|
||||||
|
- Passphrase prompt UX.
|
||||||
|
- Provider-specific secret-store schema.
|
||||||
|
- Automatic provider-name-to-secret-id lookup.
|
||||||
|
- Loading `.env` files.
|
||||||
|
- Changing Codex OAuth behavior unless a narrow integration need appears.
|
||||||
|
- Reworking model/provider catalog ownership.
|
||||||
|
|
||||||
## Acceptance criteria
|
## Acceptance criteria
|
||||||
|
|
||||||
- Manifest/profile schema has a typed credential reference for encrypted secret-store entries; env-var credential inputs are at most transitional migration inputs, not the final supported configuration path.
|
- A user can run `insomnia keys` and manage key ids interactively.
|
||||||
- Encrypted secret-store files are created outside the repository by default and use authenticated encryption with atomic update behavior.
|
- The store persists key-value entries under the user data directory without plaintext values in the on-disk file.
|
||||||
- A user can add/list/delete a Brave Search API key in the secret store and configure `WebSearch` to use it without exporting an environment variable.
|
- Store id validation rejects unsafe ids.
|
||||||
- Resolved configuration and diagnostics never display plaintext secrets.
|
- Provider `AuthRef::SecretRef` resolves through the store and does not print/serialize plaintext.
|
||||||
- Missing/decryption-failed secrets produce clear fail-closed errors.
|
- WebSearch can use a configured secret ref without exporting an environment variable.
|
||||||
- Existing env-var based credential configuration is either removed or produces an explicit migration diagnostic after encrypted secret references are available.
|
- Missing key, invalid id, unreadable store, and decode/decrypt failure produce clear fail-closed errors naming only the key id.
|
||||||
- Documentation explains how profiles reference secrets, how to manage them, and why credential env vars are no longer the normal path.
|
- `docs/environment.md` no longer presents credential env vars as the normal path and documents the limited protection goal.
|
||||||
- Focused tests cover config parsing/resolution, missing secret diagnostics, no-plaintext serialization/logging paths, and WebSearch secret resolution.
|
- Focused tests cover store round-trip, id validation, decode failure, provider secret-ref resolution, WebSearch secret-ref resolution, and no-plaintext debug/serialization paths where applicable.
|
||||||
- `cargo fmt --check`
|
- `cargo fmt --check`, relevant crate tests/checks, `./tickets.sh doctor`, and `git diff --check` pass.
|
||||||
- Relevant manifest/provider/tools/pod tests pass.
|
|
||||||
|
|
|
||||||
|
|
@ -147,4 +147,41 @@ Implications for implementation planning:
|
||||||
- Provider/WebSearch integration should resolve `secret_ref` by direct key lookup only.
|
- Provider/WebSearch integration should resolve `secret_ref` by direct key lookup only.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: plan author: hare at: 2026-05-31T21:19:29Z -->
|
||||||
|
|
||||||
|
## Plan
|
||||||
|
|
||||||
|
Preflight update: implementation-ready as a single phased ticket.
|
||||||
|
|
||||||
|
Finalized intent:
|
||||||
|
- Build a provider-independent local key-value secret store and wire it into provider/WebSearch credential resolution.
|
||||||
|
- Add `insomnia keys` as the required interactive TUI management surface.
|
||||||
|
- Keep the security claim modest: avoid casual plaintext exposure and generic env scraping; do not claim strong local security.
|
||||||
|
|
||||||
|
Settled decisions:
|
||||||
|
- Store model is user-visible `id -> value`; no provider-specific slots and no required metadata.
|
||||||
|
- Store may use technical envelope fields for version/nonce/ciphertext/checksum, but those are implementation details.
|
||||||
|
- No OS keychain, passphrase UX, or high-assurance key-management dependency in this ticket.
|
||||||
|
- No automatic provider-name-to-secret-id lookup. Config must explicitly reference a key id.
|
||||||
|
- This is one ticket with phases, not separate tickets.
|
||||||
|
|
||||||
|
Suggested implementation order:
|
||||||
|
1. Add a focused secret store crate/module with id validation, obfuscated/encrypted persistence, atomic writes, and tests.
|
||||||
|
2. Add `insomnia keys` TUI manager for list/add/delete with masked input.
|
||||||
|
3. Implement provider `AuthRef::SecretRef` resolution through the store.
|
||||||
|
4. Add WebSearch secret-ref configuration path.
|
||||||
|
5. Update docs and migration messaging.
|
||||||
|
|
||||||
|
Critical risks for coder/reviewer:
|
||||||
|
- Accidentally turning the store into provider-aware schema.
|
||||||
|
- Displaying plaintext in Debug/errors/TUI list output.
|
||||||
|
- Overstating security guarantees in docs.
|
||||||
|
- Adding ambient defaults that recreate the env-var problem in secret-store form.
|
||||||
|
- Expanding into OS keychain/passphrase design despite the settled modest threat model.
|
||||||
|
|
||||||
|
Validation should include focused tests for id validation, store round-trip, decode failure, provider secret-ref resolution, WebSearch secret-ref resolution, and no plaintext in display/debug paths where applicable.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user