Files
2026-05-27 23:29:53 +01:00

65 lines
3.9 KiB
Markdown

<!-- markdownlint-disable MD024 -->
# Capability Spec Delta: crypto-bin (crypto-completion)
**Package**: `@suaveplan/crypto-bin`
**Status**: PROPOSED
> Every requirement below carries a `**Verified by:**` line at authoring time. This is a new package; the entire spec below is `## ADDED Requirements`.
## ADDED Requirements
### Requirement: hash-password CLI hash mode
The package SHALL ship a `suaveplan-hash-password` bin that, when invoked with `--password <pw>` and no `--verify`, hashes the password using the requested algorithm (default `argon2id`, opt-in `--algo blake2b`) and writes the resulting stored-hash string to stdout, exiting with code 0. The CLI SHALL route through `@suaveplan/cli`'s arg parser (so `--help` works automatically) and SHALL NEVER call `process.exit` directly — it SHALL use `cli.exit(code)` to keep test harness compatibility.
#### Scenario: argon2id mode prints stored hash
- **WHEN** `suaveplan-hash-password --password "correct horse battery staple"` is invoked
- **THEN** stdout contains a string starting with `"$argon2id$"` AND the exit code is 0
#### Scenario: blake2b mode prints stored hash
- **WHEN** `suaveplan-hash-password --password "..." --algo blake2b` is invoked
- **THEN** stdout contains a string starting with `"$blake2b$"` AND the exit code is 0
**Verified by:** `packages/crypto/crypto-bin/src/hash-password/hash-password.test.ts::"argon2id mode writes a $argon2id$-prefixed hash to stdout and exits 0"` AND `packages/crypto/crypto-bin/src/hash-password/hash-password.test.ts::"blake2b mode writes a $blake2b$-prefixed hash to stdout and exits 0"`
---
### Requirement: hash-password CLI verify mode
When invoked with `--password <pw>` and `--verify <stored>`, the bin SHALL detect the algorithm from the stored hash's prefix, run the matching verify function (`verifyPasswordArgon2id` or `verifyPasswordBlake2b`), exit with code 0 on match and code 1 on mismatch. The bin SHALL NOT print anything to stdout in verify mode (so the exit code is the only signal — suitable for use in shell pipelines).
#### Scenario: matching password exits 0
- **WHEN** the stored hash and the password agree
- **THEN** the exit code is 0 AND stdout is empty
#### Scenario: non-matching password exits 1
- **WHEN** the stored hash and the password disagree
- **THEN** the exit code is 1 AND stdout is empty
**Verified by:** `packages/crypto/crypto-bin/src/hash-password/hash-password.test.ts::"verify mode exits 0 when password matches stored hash"` AND `packages/crypto/crypto-bin/src/hash-password/hash-password.test.ts::"verify mode exits 1 when password does not match stored hash"`
---
### Requirement: hash-password CLI argument validation
The bin SHALL reject malformed invocations (missing `--password`, unknown `--algo`, malformed `--verify` value) with a non-zero exit code and a `SuaveplanError` whose code is one of `CRYPTO.HASH_PASSWORD_CLI_BAD_ARGS`, `CRYPTO.HASH_PASSWORD_CLI_UNKNOWN_ALGO`, or `CRYPTO.HASH_PASSWORD_CLI_VERIFY_FAILED`. The error message SHALL be human-readable and SHALL be printed to stderr (not stdout, so it does not contaminate pipe output).
#### Scenario: missing --password rejected
- **WHEN** `suaveplan-hash-password` is invoked with no `--password`
- **THEN** the exit code is non-zero AND stderr mentions `--password` AND the underlying error code is `CRYPTO.HASH_PASSWORD_CLI_BAD_ARGS`
#### Scenario: unknown algorithm rejected
- **WHEN** `suaveplan-hash-password --password pw --algo bcrypt` is invoked
- **THEN** the exit code is non-zero AND the underlying error code is `CRYPTO.HASH_PASSWORD_CLI_UNKNOWN_ALGO` AND `context.algo === "bcrypt"`
**Verified by:** `packages/crypto/crypto-bin/src/hash-password/hash-password.spec-conformance.test.ts::"missing --password emits HASH_PASSWORD_CLI_BAD_ARGS"` AND `packages/crypto/crypto-bin/src/hash-password/hash-password.spec-conformance.test.ts::"unknown --algo emits HASH_PASSWORD_CLI_UNKNOWN_ALGO"`
<!-- markdownlint-enable MD024 -->