Skip to content

feat(cli): init command - #29

Merged
ericliswan merged 4 commits into
mainfrom
feat/cli-init
Oct 27, 2026
Merged

ericliswan merged 4 commits into
mainfrom
feat/cli-init

Conversation

@ericliswan

Copy link
Copy Markdown
Owner

Summary

Implements pwv init. It prompts for the master password twice, rejects passwords shorter than 12 characters or with a zxcvbn score below 3, and creates an empty vault. It refuses to replace an existing vault unless --force is given; in that case the old file is kept as <vault>.bak.

Closes #28

Type of change

  • feat - [ ] fix - [ ] docs - [x] test - [ ] refactor - [ ] ci/chore - [ ] security

How was this tested?

  • cargo fmt --all --check, cargo clippy --workspace --all-targets --all-features -- -D warnings (and without features), cargo test --workspace --all-features, cargo deny check
  • Unit tests for the strength check: too short, weak (error never contains the password), strong
  • Integration tests through the real binary: the new vault unlocks with the master password; a second init fails with exit 1 and leaves the file unchanged; --force replaces it and keeps the old bytes in .bak; mismatched and weak passwords fail without creating a file or echoing the password
  • By hand: init, re-init, --force and weak passwords on macOS

Security checklist

  • No secret in args, env vars, logs, Debug output, errors or panics (strength errors repeat zxcvbn's fixed feedback text only)
  • Crypto is called only from pwv-core::kdf / pwv-core::crypto
  • Any new header/file-format field is inside the AAD and validated on load (no format change)
  • Failure paths have tests (wrong password, tampering, bad input)
  • Docs (README / DESIGN / THREAT_MODEL) updated if behaviour changed (no doc change needed until the v0.5 README)

Notes for the reviewer

  • The strength check runs before the confirmation prompt, so a weak password fails on the first entry.
  • zxcvbn keeps pieces of the password in its result without zeroizing them. The result is dropped straight away; this goes in the README limitations about memory copies.
  • New feature pwv-cli/insecure-test-kdf forwards to pwv-core and is off by default. Without it, the vault-creating CLI tests are ignored with a reason, because the production KDF in a debug build took 23 s for three tests. CI's --all-features run executes them.
  • New dependency: zxcvbn 3.1.1 (MIT). It pulls in derive_builder, fancy-regex, itertools and lazy_static, and cargo deny is clean.

The vault is created only after both entries match, and init refuses to
run when a vault already exists at the target path.

Refs #28
The replaced vault stays recoverable as <vault>.bak, which storage
already writes before every rename.

Refs #28
Requires at least 12 characters and a zxcvbn score of 3, checked before
the confirmation prompt. The error repeats zxcvbn's fixed feedback text
so the user learns why, without the password appearing in the output.

Refs #28
Covers unlocking the new vault, refusing to overwrite without --force,
keeping the replaced file as .bak, and rejecting mismatched or weak
passwords without echoing them. pwv-cli forwards insecure-test-kdf to
pwv-core; without it these tests are ignored, because the production KDF
takes several seconds per run in a debug build.

Refs #28
@ericliswan

Copy link
Copy Markdown
Owner Author

Self-review: read the full gh pr diff. Checked the following:

  • Secrets are exposed only for the length count, zxcvbn, and the confirmation comparison; nothing derived from them is printed.
  • The strength error is built from zxcvbn's fixed Warning/Suggestion text, and the tests assert the password doesn't appear in it.
  • Overwrite protection checks try_exists, so a permission error surfaces instead of being read as "no vault".
  • --force relies on storage's existing .bak copy, and an integration test checks that.
  • The release build has no insecure-test-kdf; the feature is opt-in only.
  • 180 changed lines excluding Cargo.lock.

Not covered: interactive hidden prompts on a real TTY (manual only).

@ericliswan
ericliswan merged commit ce3a266 into main Oct 27, 2026
4 checks passed
@ericliswan
ericliswan deleted the feat/cli-init branch October 27, 2026 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(cli): init command

1 participant