Skip to content

In-session secret entry the model never sees (TUI + desktop) #6263

Description

@Hmbown

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 <p> 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    • Status
      Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions