radicle-heartwood-lfs/crates/radicle-cli
Maciek "mab122" Bator ff762ef8f2 Prompt interactively for passphrase instead of requiring RAD_PASSPHRASE
Private-repo LFS operations need a signer capable of ECDH, which
ssh-agent (the normal day-to-day flow after `rad auth`) can't provide --
that's a hard protocol limitation (standard ssh-agent only implements
signing, there's no key-agreement request type), not a gap in our code,
so there's no way to make it work "through the agent" the way signing
does.

Previously the only alternative to an unencrypted keystore was setting
RAD_PASSPHRASE, which breaks the normal ssh-agent-based workflow and
means putting a password in an environment variable -- not ergonomic,
and not how any other `rad` command behaves.

`rad` already has an established fallback for exactly this situation:
`crate::terminal::io::signer` tries ssh-agent first, and if that's
unavailable/unregistered and we're connected to a TTY, prompts
interactively for the passphrase via `inquire` (reusing the existing
`PassphraseValidator`). `lfs_crypto::load_signer` was missing this last
step entirely -- it only tried "unencrypted keystore" then
"RAD_PASSPHRASE" then gave up. Added the same interactive-prompt
fallback, reusing the exact same validator/prompt helpers already used
elsewhere, before falling back to a hard failure.

This covers the common case (an interactive `git commit` triggering the
pre-commit hook, which inherits the terminal's TTY) with no environment
variable needed at all. Only genuinely non-interactive contexts (CI, a
script with no TTY) still need RAD_PASSPHRASE -- and get a fast, clear
failure rather than hanging, since `inquire` returns `Ok(None)` on
`NotTTY` rather than blocking (verified: piping /dev/null as stdin still
fails immediately, not a timeout).

Verified against a real encrypted keystore through an actual pty (via
`script`, since a plain non-interactive shell doesn't have a TTY to
prompt on): the masked "Passphrase:" prompt appears, accepts the typed
passphrase, and produces a correctly encrypted note -- with
RAD_PASSPHRASE unset the entire time.
2026-07-14 17:59:04 +02:00
..
examples radicle/cob/identity: Enforce sibling-accept invariant for `RevisionAccept` in `action` 2026-07-03 15:22:13 +01:00
src Prompt interactively for passphrase instead of requiring RAD_PASSPHRASE 2026-07-14 17:59:04 +02:00
tests cli/examples: Introduce a suite of merge and revert tests for patch.target 2026-06-09 11:37:26 +02:00
CHANGELOG.md cli: Release 0.21.0 2026-05-06 21:15:54 +01:00
Cargo.toml Add client-side encryption for private-repo LFS objects 2026-07-14 16:01:49 +02:00
build.rs repo: Move workspace crates into `crates` subdirectory 2025-06-09 15:09:21 +02:00