Skip to content

Add KeePassXC and pass external fallback providers#63

Open
jmcte wants to merge 9 commits into
mainfrom
claude/external-fallback-providers-49
Open

Add KeePassXC and pass external fallback providers#63
jmcte wants to merge 9 commits into
mainfrom
claude/external-fallback-providers-49

Conversation

@jmcte
Copy link
Copy Markdown
Contributor

@jmcte jmcte commented May 22, 2026

Summary

Extends the reduced-security --external-fallback path beyond 1password and
bitwarden to also support keepassxc and pass, per #49.

Closes #49.

Both new providers reuse the existing validated absolute-path execution model
(owner-only, no ~, no relative paths, 0755-or-tighter mode, bounded output,
process-group timeout). Fallback payloads keep transport: "external_cli" /
securityMode: "reduced_external_cli" and nothing is cached.

KeePassXC

  • Requires fallbackProviderDatabase with an absolute .kdbx path.
  • Reads the master password from APW_KEEPASSXC_PASSWORD and feeds it to
    keepassxc-cli over stdin.
  • Runs search then show --show-protected --attributes UserName,Password,URL.

pass

  • Relies on gpg-agent for unlock; APW never handles the master key.
  • Parses pass find <host> tree output into terminal entry candidates only.
  • Prefers leaf matches, then any path segment equal to the host, then broad
    substring fallback.
  • Covers multiple top-level roots and nested host directories so APW does not
    synthesize paths like old-root/web/example.com.

Verification

  • cargo test --manifest-path rust/Cargo.toml pass_pick_entry_ - passed, 5 tests
  • cargo test --manifest-path rust/Cargo.toml login_ - relevant unit tests passed before the sandbox entered socket e2e coverage; the e2e socket bind is sandbox-blocked here
  • cargo fmt --manifest-path rust/Cargo.toml -- --check - passed
  • bash scripts/ci/run-fast-checks.sh - passed
  • git diff --check - passed

Notes

  • Real KeePassXC / pass CLIs are not available in this environment. Happy paths are exercised against shell-script simulators; a maintainer should still smoke-test against real CLIs on macOS before release.

Closes #49.

Extends the reduced-security `--external-fallback` path beyond
`1password` and `bitwarden` to also support `keepassxc` and `pass`.
Both reuse the existing validated absolute-path execution model
(owner-only, no `~`, no relative paths, 0755-or-tighter, bounded
output, process-group timeout) so no new attack surface is introduced.

KeePassXC:
- requires `fallbackProviderDatabase` (absolute .kdbx path) in
  ~/.apw/config.json
- reads the master password from APW_KEEPASSXC_PASSWORD and feeds it to
  keepassxc-cli over stdin; never written to disk or cached
- runs `search` then `show --show-protected --attributes
  UserName,Password,URL` and maps the result into the existing
  external_cli payload shape

pass (passwordstore.org):
- relies on gpg-agent for the unlock, so APW never handles the key
- discovers entries with `pass find <host>`, preferring an entry whose
  leaf name equals the host over a substring match
- parses `pass show` output: line 1 is the password, `user:`/`username:`
  /`login:` and `url:`/`website:` lines supply the rest

`run_external_provider_command` gains an optional stdin-feeding variant
used only by KeePassXC; existing callers are unchanged. Provider
failures map to typed APW errors: missing entry -> no_results, malformed
CLI output -> proto_invalid_response, missing config/database ->
invalid_config. Fallback payloads keep transport "external_cli" /
securityMode "reduced_external_cli" and nothing is cached.

Adds 8 tests (pass tree parsing, pass/keepassxc happy paths, and the
typed-error paths for missing entry, missing master password, and
missing database). README.md and docs/SECURITY_POSTURE_AND_TESTING.md
document the per-provider setup and security posture.
@jmcte jmcte marked this pull request as ready for review May 22, 2026 17:35
@jmcte jmcte requested a review from pheidon as a code owner May 22, 2026 17:35
@jmcte jmcte enabled auto-merge (squash) May 22, 2026 17:35
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6ce21db765

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rust/src/native_app.rs
Copy link
Copy Markdown
Contributor

@pheidon pheidon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot approve this yet. The pass find tree parser over-counts top-level depth because a root row like └── web is treated as depth 1 instead of depth 0. That leaves the previous root on the stack when a later top-level sibling appears, so a real listing with multiple roots can synthesize invalid entry paths such as old-root/new-root/example.com and then call pass show on the wrong path.

Please fix the depth calculation, for example by subtracting the branch marker level with a saturating adjustment, and add a regression test with multiple top-level pass find roots where the matching host is under the second root. CI is otherwise green, but this parser bug blocks approval.

@athena-omt athena-omt added area:infra Infrastructure, CI, release, governance, scripts, or repo setup. lane:daedalus Daedalus implementation/forge lane. review:athena Athena review governance requested. risk:medium Medium-risk change; normal care required. state:waiting-checks Waiting for CI/check status to settle. status:needs-review PR is ready for Athena review. labels May 23, 2026
@jmcte jmcte removed the state:waiting-checks Waiting for CI/check status to settle. label May 24, 2026
@jmcte
Copy link
Copy Markdown
Contributor Author

jmcte commented May 24, 2026

Requested-change follow-up is addressed and ready for re-review.

  • The pass find tree parser no longer carries a previous top-level root into a later sibling root.
  • Added regression coverage for multiple top-level pass find roots where the matching host is under the second root, preventing synthesized paths such as old-root/new-root/example.com.
  • Current live checks are green.
  • Thread-aware review query shows no current non-outdated unresolved review threads.

Verification recorded on the PR:

  • cargo test --manifest-path rust/Cargo.toml pass_pick_entry_
  • relevant login_ provider tests
  • cargo fmt --manifest-path rust/Cargo.toml -- --check
  • bash scripts/ci/run-fast-checks.sh
  • git diff --check

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

Labels

area:infra Infrastructure, CI, release, governance, scripts, or repo setup. lane:daedalus Daedalus implementation/forge lane. review:athena Athena review governance requested. risk:medium Medium-risk change; normal care required. status:needs-review PR is ready for Athena review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Roadmap: expand external fallback providers (KeePassXC, pass)

4 participants