Fix CLI OpenPGP passphrase provisioning and secure-storage identity #60

Closed
opened 2026-08-10 07:22:24 +00:00 by hugo · 1 comment
Owner

Objective

Make CLI OpenPGP passphrase retrieval use the canonical application identity and provide a complete interactive fallback when no passphrase exists in secure storage.

Problem

The CLI currently only retrieves the org.ironstorage.openpgp-passphrase record for a key fingerprint (observed with fingerprint beginning 3B98 and ending 5429). It never creates that record, and a missing secret is flattened to Unavailable in crates/storage/src/secret_store.rs.

The org.ironstorage service prefix is not this application identity. The bundle identifier is de.rfc1437.ironstorage, and related secure-storage service and account identifiers must align with it.

Scope

  • Replace the incorrect OpenPGP secure-storage service identity with de.rfc1437.ironstorage.openpgp-passphrase everywhere, including tests and platform bridges.
  • Preserve a typed missing-secret condition instead of flattening it to general unavailability.
  • When the CLI needs an OpenPGP passphrase and none exists in secure storage, prompt for it securely on the terminal without echoing it.
  • Define and implement persistence through the storage-owned secure-secret orchestration so future CLI invocations can retrieve the passphrase.
  • Keep passphrases out of logs, errors, debug output, command arguments, and ordinary terminal output.

Acceptance criteria

  • A missing passphrase causes an interactive hidden terminal prompt in the CLI and successful encrypted-entry access when the supplied passphrase is correct.
  • The supplied passphrase is stored under the canonical de.rfc1437.ironstorage.openpgp-passphrase service and fingerprint account, then reused without prompting.
  • Cancellation, incorrect passphrases, secure-storage denial or unavailability, and persistence failures are typed, redacted, and do not corrupt existing records.
  • Tests cover missing, prompt-and-store, reuse, cancellation, wrong passphrase, and storage failure paths.
  • All password-store and secure-secret decisions remain in crates/storage; the CLI only collects terminal input and invokes the Rust API.
  • No external process is launched and no unsafe Rust is introduced.
## Objective Make CLI OpenPGP passphrase retrieval use the canonical application identity and provide a complete interactive fallback when no passphrase exists in secure storage. ## Problem The CLI currently only retrieves the org.ironstorage.openpgp-passphrase record for a key fingerprint (observed with fingerprint beginning 3B98 and ending 5429). It never creates that record, and a missing secret is flattened to Unavailable in crates/storage/src/secret_store.rs. The org.ironstorage service prefix is not this application identity. The bundle identifier is de.rfc1437.ironstorage, and related secure-storage service and account identifiers must align with it. ## Scope - Replace the incorrect OpenPGP secure-storage service identity with de.rfc1437.ironstorage.openpgp-passphrase everywhere, including tests and platform bridges. - Preserve a typed missing-secret condition instead of flattening it to general unavailability. - When the CLI needs an OpenPGP passphrase and none exists in secure storage, prompt for it securely on the terminal without echoing it. - Define and implement persistence through the storage-owned secure-secret orchestration so future CLI invocations can retrieve the passphrase. - Keep passphrases out of logs, errors, debug output, command arguments, and ordinary terminal output. ## Acceptance criteria - A missing passphrase causes an interactive hidden terminal prompt in the CLI and successful encrypted-entry access when the supplied passphrase is correct. - The supplied passphrase is stored under the canonical de.rfc1437.ironstorage.openpgp-passphrase service and fingerprint account, then reused without prompting. - Cancellation, incorrect passphrases, secure-storage denial or unavailability, and persistence failures are typed, redacted, and do not corrupt existing records. - Tests cover missing, prompt-and-store, reuse, cancellation, wrong passphrase, and storage failure paths. - All password-store and secure-secret decisions remain in crates/storage; the CLI only collects terminal input and invokes the Rust API. - No external process is launched and no unsafe Rust is introduced.
hugo added this to the 02 - Mutt-style terminal UI milestone 2026-08-10 07:22:24 +00:00
hugo added the bug label 2026-08-10 07:22:24 +00:00
hugo closed this issue 2026-08-10 07:43:36 +00:00
Author
Owner

Implemented in c82c792 and pushed to main.

Implementation:

  • Replaced every native secret-store service prefix from org.ironstorage to the canonical bundle identity: de.rfc1437.ironstorage.openpgp-passphrase and de.rfc1437.ironstorage.https-git.
  • Preserved missing, denied, cancelled, unavailable, and persistence failure as distinct secret-provider outcomes.
  • Added storage-owned interactive passphrase provisioning. The CLI terminal adapter collects a hidden passphrase only when stdin is a terminal; storage decides when prompting is needed.
  • Added crypto provider lifecycle callbacks so a prompted passphrase is created in secure storage only after it successfully decrypts or signs. Rejected passphrases are zeroized and never persisted.
  • Kept existing canonical records immutable on races and failures; create errors do not overwrite any record.
  • Added real fixture tests for prompt, successful decrypt, persistence, no-prompt reuse, wrong passphrase, cancellation, denial, and create failure, plus a complete CLI show/reuse integration test and canonical service-name assertions.

Review confirmed passphrases remain absent from logs, debug output, arguments, and ordinary prompt output. No process launch or unsafe Rust was introduced.

Verification passed:

  • cargo fmt --all -- --check
  • RUSTFLAGS=-D warnings cargo check --workspace --all-targets
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace
Implemented in c82c792 and pushed to main. Implementation: - Replaced every native secret-store service prefix from org.ironstorage to the canonical bundle identity: de.rfc1437.ironstorage.openpgp-passphrase and de.rfc1437.ironstorage.https-git. - Preserved missing, denied, cancelled, unavailable, and persistence failure as distinct secret-provider outcomes. - Added storage-owned interactive passphrase provisioning. The CLI terminal adapter collects a hidden passphrase only when stdin is a terminal; storage decides when prompting is needed. - Added crypto provider lifecycle callbacks so a prompted passphrase is created in secure storage only after it successfully decrypts or signs. Rejected passphrases are zeroized and never persisted. - Kept existing canonical records immutable on races and failures; create errors do not overwrite any record. - Added real fixture tests for prompt, successful decrypt, persistence, no-prompt reuse, wrong passphrase, cancellation, denial, and create failure, plus a complete CLI show/reuse integration test and canonical service-name assertions. Review confirmed passphrases remain absent from logs, debug output, arguments, and ordinary prompt output. No process launch or unsafe Rust was introduced. Verification passed: - cargo fmt --all -- --check - RUSTFLAGS=-D warnings cargo check --workspace --all-targets - cargo clippy --workspace --all-targets -- -D warnings - cargo test --workspace
Sign in to join this conversation.