Skip to content

feat: add Bitwarden Password Manager provider#166

Open
ashebanow wants to merge 17 commits into
cachix:mainfrom
ashebanow:bitwarden-provider
Open

feat: add Bitwarden Password Manager provider#166
ashebanow wants to merge 17 commits into
cachix:mainfrom
ashebanow:bitwarden-provider

Conversation

@ashebanow

@ashebanow ashebanow commented Jul 17, 2026

Copy link
Copy Markdown

Adds a Bitwarden Password Manager provider (bw://) backed by the official bw CLI.

This resumes the effort from #24 — the renewed discussion in #15 is what inspired picking this work back up. It starts from the Password Manager core of that PR and reworks it for today's codebase.

What's included

  • bw:// provider shelling out to the bw CLI, with vault-wide access to all item types: logins, cards, identities, SSH keys, and secure notes
  • Provider id bw matches the CLI it drives and the cargo feature, mirroring how bws:// is named after the bws CLI
  • Sensible per-type default fields, plus explicit selection via URI query params (bw://?type=login&field=username) and BITWARDEN_DEFAULT_TYPE / BITWARDEN_DEFAULT_FIELD env vars (prefix kept clear of the bw CLI's own BW_* namespace)
  • ref = { item = "...", field = "..." } mapping in secretspec.toml, so secret keys stay valid identifiers while pointing at arbitrarily named vault items
  • Collection/organization addressing (bw://org@collection) and self-hosted servers (?server=)
  • Item creation and update on secretspec set
  • Curated error mapping for common bw failure modes: CLI not installed (with install instructions), not logged in, vault locked; secret values pass via stdin and the session via the environment, never argv
  • bw cargo feature (default-enabled; adds only a base64 dependency since the provider drives the CLI rather than linking an SDK)
  • Docs: provider page (docs/providers/bw.md with 0.16 version notice) and all provider listings per the adding-providers checklist — sidebar, llms.txt description, concepts/reference tables, security table, landing page, quick-start, README — each labeled (0.16+)
  • CHANGELOG entry under Unreleased, unit tests for URI/config parsing
  • tests/bitwarden_integration.sh: end-to-end suite against a real vault covering all five item types, ref mapping, env-var defaults, error paths, and set/update; auto-creates and cleans up its own test items
  • bitwarden-cli added to devenv for integration testing

Changes relative to #24

  • Secrets Manager support dropped — upstream now ships a dedicated bws:// provider, so this PR is Password Manager only
  • Ported to the current ProviderUrl/Address API and provider registration
  • Add Bitwarden provider with comprehensive security enhancements #24's custom timeout machinery, error-message sanitizer, and perf instrumentation were not carried over — the rewrite follows the same straightforward CLI-execution pattern as the 1Password/LastPass providers
  • Integration script hardened: automatic test-item setup/teardown and valid-identifier keys via ref mapping
  • The integration script's header documents a vaultwarden-based path to fully automated, credential-free testing (future work)

Testing

  • cargo test --all green locally (macOS)
  • Integration script run against a real vault: all item types, ref mapping, env-var defaults, error handling, and set/update paths

Notes for reviewers

  • Provider listings are complete per the adding-providers checklist (sidebar, concepts/reference tables, landing page, quick-start, README), all labeled 0.16+
  • Real-world testing so far has focused on a personal vault exercising all five item types; organization/collection layouts have had lighter coverage — extra scrutiny welcome there
  • The integration script's header documents a vaultwarden-based path to fully automated, credential-free testing, left as future work

Refs #15 (inspiration for resuming), supersedes #24.

AI Note: this project's code and documentation were produced with the help of UI. The old pull request was developed with the help of Claude Code and Claude Opus/Sonnet, the additional work for this pull request was done using my custom pi environment and Deepseek v4 Pro/Flash.

ashebanow and others added 16 commits July 17, 2026 15:00
Integrate Bitwarden Password Manager (bw CLI) as a secretspec
provider. The provider supports vault-wide item access across all
Bitwarden item types (Login, Card, Identity, SSH Key, Secure Note)
with smart field extraction, URI-based configuration
(bitwarden://[org@]collection?server=...&type=...&field=...),
and session-based authentication via BW_SESSION.

Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Upstream now ships a native BWS SDK provider (bws.rs), so the
unified Password Manager + Secrets Manager provider must be reduced
to Password Manager only. Remove the BitwardenService enum,
BWS-specific config fields, execute_bws_command method, and
bws:// scheme handling from register_provider! and TryFrom.

Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Upstream's Provider trait has evolved from dynamic dispatch with
(project, key, profile) signatures to a static-registration pattern
with Address, ProviderUrl, and ProviderCredentials. Rewrite
BitwardenConfig's TryFrom to accept &ProviderUrl, add
convention_address/supported_coords/with_credentials/uri, and
update get/set to accept Address<'_> parameters resolved via
resolve_coords. Field resolution respects the native address
coordinate first, then BITWARDEN_DEFAULT_FIELD, then config.

Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Wire the bitwarden module into the provider registry with a bw
feature flag (bw = ["dep:base64"], enabled by default). The base64
dependency encodes JSON for the bw CLI's item create/edit stdin
path. Add four unit tests covering provider creation, collection,
org-collection URI parsing, and bws:// scheme rejection.

Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
The bitwarden.md page was drafted for a dual-service (bw + bws)
provider. Strip empty code blocks, the Secrets Manager access token
section, and a stray bullet left behind after BWS content removal.

Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Add .pi/ to .gitignore for pi-agent task output.
The collapsible_if lint in config::migrate_macos_config is a
pre-existing upstream warning surfaced by clippy during this
branch's development.

Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Replace the manual setup requirements with an auto-provisioning
setup_test_data() function that creates Bitwarden items if they
don't exist, and registers an EXIT trap to clean them up unless
--keep-test-data is passed.

Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Replace invalid TOML keys ("Deploy SSH Key", etc.) with valid
bw_integration_test_* identifiers and ref = { item, field }
mapping, matching the new Provider API address model.

Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
Co-Authored-By: deepseek-v4-pro <noreply@deepseek.com>
The entry landed in the already-released 0.15.0 section during the
rebase; the provider targets the next release.
The provider wraps the `bw` CLI, so the id now matches the tool it
drives and the existing cargo feature, mirroring how the bws provider
is named after the bws CLI. URIs change from bitwarden:// to bw://.
The provider is unreleased, so there is no compatibility impact.

Module, source file, and docs page follow the id (provider::bw,
providers/bw.md). BITWARDEN_DEFAULT_TYPE/FIELD env vars keep their
prefix to stay clear of the bw CLI's own BW_* namespace.
Add the Bitwarden Password Manager provider to every listing the
adding-providers checklist names: sidebar and llms.txt description,
concepts and reference tables (with security row), landing page
metadata/hero/bento (provider count 14 -> 15), quick-start and README
config-init examples, and the rustdoc provider summary. All entries
carry the 0.16+ label; the provider page gains the version notice.

The landing grid's existing plain 'Bitwarden' label becomes 'Bitwarden
Secrets Manager' to disambiguate the two Bitwarden providers.
bw can prompt on stdin (e.g. for the master password when a session is
missing or expired). stdin is null or closed on our invocations so a
prompt could not hang us, but --nointeraction makes bw fail fast with
its own clear error instead of a confusing EOF-related one, which
matters in CI and other headless contexts.
@bsorescu

Copy link
Copy Markdown
Contributor

Vaultwarden testing done, as promised on #15: the full tests/bitwarden_integration.sh suite passes 19/19 against a disposable Vaultwarden (vaultwarden/server:latest) through the genuine bw CLI 2026.6.0 — reads across all item types (login, card, identity, SSH key, secure note, custom fields), writes (set creating login/card items), and the error-handling cases.

And since you asked about automating it: I've opened ashebanow#2 against your branch implementing the FUTURE WORK plan from the script header — disposable Vaultwarden + fixture account, no repository secrets, fork-PR-friendly. Two gotchas discovered on the way, handled in the harness:

  • the 2026+ bw CLI refuses plain http:// servers outright, so the harness fronts Vaultwarden with a Caddy TLS proxy (internal self-signed cert + NODE_TLS_REJECT_UNAUTHORIZED=0 scoped to the fixture run);
  • bw has no register, so a small vaultwarden_bootstrap.py implements the client-side registration crypto (PBKDF2 → HKDF stretch → EncString type 2 → RSA keypair) against the identity API.

BITWARDENCLI_APPDATA_DIR keeps the whole thing isolated from the developer's real bw config. A GitHub Actions job wiring this up should be a ~20-line follow-up once this lands.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants