In-session secret entry the model never sees (TUI + desktop)
- Dominant language
- Rust
- Stars
- 41k
- Forks
- 3.6k
- Avg merge
- 13h 59m
- Merged PRs (30d)
- 299
Description
## Problem
Setting a provider or connector token mid-session means leaving the TUI and running `codewhale auth set` in another terminal. The agent asks for a GitHub token; the person has to break flow to provide one.
The obvious fix — let them paste it into the composer — is the one thing we must not build. A secret typed into the composer becomes a user message, and from there it reaches the transcript, the session event log, the compaction summary, and the model's context. That is a credential disclosure, not a UX wart.
## What already exists (do not rebuild)
The storage half is done and is good:
- `codewhale-secrets`: `KeyringStore` trait, `FileKeyringStore` default at `~/.codewhale/secrets/`, opt-in OS keyring via `CODEWHALE_SECRET_BACKEND=system|keyring`, `InMemoryKeyringStore` for tests
- `Secrets::resolve` precedence: config -> secret store -> env
- CLI `codewhale auth set --provider
` already does a hidden prompt, plus `--api-key-stdin`. Never a CLI argument, so it never reaches shell history
- `zeroize::Zeroizing` is already used on the credential handoff path
The OS keyring is deliberately NOT the default, and that reasoning should be preserved: on macOS every unsigned or rebuilt binary is a new Keychain ACL principal, so credentials written by one build stop being readable by the next. `crates/secrets/src/account.rs` bars account sessions from Keychain entirely and asserts it in a test.
## What to build
An in-session secret entry surface (a slash command opening a modal, or equivalent) that writes straight to the existing secret store.
The whole value is in the boundary, so it has to be built as a boundary rather than an input field:
- the modal's buffer is never appended to the transcript
- it is never written to the session event log or any replay artifact
- it never reaches compaction or any model request
- it is never echoed to the terminal
- it is held in `Zeroizing` and dropped immediately after the store write
- paste is supported, because these are long tokens
Reuse `CWC_PROVIDER_KEY_SHAPES`-style pre-save shape hints where they exist, so an obviously truncated key is caught before it is stored rather than failing later as an opaque 401.
## Acceptance
The test that matters is adversarial, not a happy path: enter a known sentinel value through the modal, then assert that the sentinel appears in **no** session artifact — not the transcript, not the event log, not a compaction summary, not any outbound model request body — and that it **is** readable back from the secret store. A feature that passes a happy-path test and fails this one is worse than not shipping it.
Desktop (GPUI) has `credentials.rs` doing the equivalent paste-and-forget for provider keys already; the TUI is the gap.
Contributor guide
Research direction
Start by reading desktop credentials.rs, the existing codewhale-secrets store and CLI auth set flow, then locate the TUI command and modal entry points. Add an adversarial test using a sentinel secret: it must be readable from the secret store while absent from the transcript, event log, replay artifacts, compaction summary and outbound model request body.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- authentication, cli, desktop, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100