Skip to content

fix(hush): --value never reads stdin, and hyphen values reach bws intact - #101

Merged
AojdevStudio merged 5 commits into
hush/0.0.xfrom
fix/hush-value-argv-and-stdin
Oct 30, 2026
Merged

AojdevStudio merged 5 commits into
hush/0.0.xfrom
fix/hush-value-argv-and-stdin

Conversation

@AojdevStudio

@AojdevStudio AojdevStudio commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Problem

Every fleet box runs a pre-broker hush build that calls bws directly. hush add --value still reads stdin to end of file, so it hangs while stdin is an open ssh connection. An agent waited 9 minutes on it. A value that starts with -, such as a PEM block, fails with bws secret create failed (exit status: 2) in hush add, hush edit, and the TUI.

Change

This PR targets the new maintenance branch hush/0.0.x, cut at 1e92b9b. Main removed this code in #84, so the fix cannot land there.

 // commands.rs add: Option::or evaluated stdin_value() before it looked at --value
-let value = value.or(stdin_value()?).context(...)?;
+let value = match value {
+    Some(value) => value,
+    None => stdin_value()?.context("no --value given and nothing piped on stdin")?,
+};

 // bws.rs: bws 2.1.0 parses a hyphen-leading positional or split option value as a flag
-bws secret create KEY VALUE PROJECT [--note N] -o json
-bws secret edit [--key K] [--value V] [--note N] ID -o json
+bws -o json secret create [--note=N] -- KEY VALUE PROJECT
+bws -o json secret edit [--key=K] [--value=V] [--note=N] -- ID

tests/bws_boundary.rs runs the built hush against a stub bws on PATH. The stub applies the bws 2.1.0 rule: a hyphen-leading token before -- must be a known option. Hyphen values go to hush as --value=... or on stdin.

Proof

Real BWS on aojdevlinux, over ssh, with stdin held open by a FIFO. The before binary is the installed ~/.cargo/bin/hush (e269d59). The after binary is a release build of this branch. Each test secret uses the HUSH_TEST_ prefix, and the script deletes them all.

## BEFORE 1. installed hush, add --value, stdin open and silent, 15s cap
exit=124 after 15s
## BEFORE 2. installed hush, add --value=PEM
Error: bws secret create failed (exit status: 2)
## BEFORE 3. installed hush, edit --value=PEM
Error: bws secret edit failed (exit status: 2)
## AFTER 1. fixed hush, add --value, stdin open and silent, 15s cap
created HUSH_TEST_1792735841_A (f6fa6dc6-...)   exit=0 after 1s
## AFTER 2. fixed hush, add --value=PEM
created HUSH_TEST_1792735841_B (7f2e677d-...)   exit=0
## AFTER 3. fixed hush, edit --stdin with piped PEM
updated HUSH_TEST_1792735841_C (a17fc154-...)   exit=0
## AFTER 4. fixed hush, edit --value=PEM
updated HUSH_TEST_1792735841_A                  exit=0
## AFTER 5. fixed hush, split --value PEM fails loudly in hush and writes nothing
error: unexpected argument -----BEGIN HUSH TEST VALUE----- (clap usage error)
## ROUNDTRIP. values read back from BWS
HUSH_TEST_1792735841_A holds the PEM exactly
HUSH_TEST_1792735841_B holds the PEM exactly
HUSH_TEST_1792735841_C holds the PEM exactly
cleanup: 0 HUSH_TEST_1792735841* secrets left
Check Before (1e92b9b src, new tests) After
add_with_value_never_waits_on_an_open_stdin fails: hush did not exit within 10s passes
add_sends_hyphen_leading_key_value_and_note_to_bws_intact fails: bws secret create failed (exit status: 2) passes
edit_sends_a_piped_pem_value_to_bws_intact fails: bws secret edit failed (exit status: 2) passes
edit_sends_hyphen_leading_key_and_note_to_bws_intact fails: bws secret edit failed (exit status: 2) passes
value_never_takes_the_next_flag_as_the_secret passes (guard for a round 1 regression) passes
add_without_value_reads_piped_stdin passes (pins the stdin path that already worked) passes
bun run check (fmt, 27 unit and 6 boundary tests, clippy -D warnings) passes, review-gate receipt at 89ced3e

The bws 2.1.0 parser rule was checked live with no token set. bws secret create K -----BEGIN-x <uuid> exits 2. bws -o json secret create --note=-n -- -K -----BEGIN-x <uuid> reaches "Missing access token".

Review

Interrogate panel on 1e92b9b...4294be3: Opus 5.5, Sonnet 5.5, GPT-6.1 Sol. Muse Wonder Full failed with a quota 429. Round 2 on the fix diff: GPT-6.1 Sol. A late Muse Spark pass asked for a piped stdin add test. Round 3 on that test: Grok 4.7, no findings.

Finding Disposition Reason
allow_hyphen_values let --value swallow the next flag, so --value --stdin stored --stdin (Opus, Sonnet) Fix Removed. Guard test value_never_takes_the_next_flag_as_the_secret.
Boundary tests passed a live BWS_ACCESS_TOKEN to any bws that shadows the stub (Opus) Fix env_remove for BWS_ACCESS_TOKEN and BWS_SERVER_URL.
Tests checked the value anywhere in argv, not the positional order (Opus, Sonnet) Fix Tests assert the exact bws argv of each call.
No test for a hyphen-leading key on create (Opus) Fix The create test uses --key=-HUSH_TEST_KEY.
operation_name test used the old edit argv shape (Opus) Fix Updated to --value=super-secret -- secret-id.
format!("--value=...") may free an unzeroed copy (Opus, Sonnet) Decline The same value is already unzeroed in the clap String and in the child argv that ps shows, as bws-tui/src/bws.rs:65 states.
--note and --key reject split hyphen values in the hush parser (Sonnet) Decline That fails loudly and writes nothing. The = form works, as edit_sends_hyphen_leading_key_and_note_to_bws_intact proves.
No test for hush add with piped stdin and no --value (Muse Spark) Fix add_without_value_reads_piped_stdin.
list, get, and delete pass a positional without -- (Muse Wonder Full) Decline Each one passes a UUID that came back from bws, never user text, as bws-tui/src/bws.rs:49,56,93 show. A UUID never starts with -.
With no --project on a terminal, add reads the project pick from stdin even with --value (Muse Wonder Full) Decline That is the documented interactive prompt. On a non-terminal stdin, the case that hung, the picker refuses without reading, at bws-tui/src/commands.rs:194.
Possible ETXTBSY race when the stub is executed (Sonnet) Decline hush execs the stub well after the write. Five runs on aojdevlinux passed.
PR body contract check failed with Module not found because hush/0.0.x had no checker Fix #108 adds the kit to hush/0.0.x, merged as a4ba7b1.

Merge danger

Door: two-way. Revert this PR to undo it. Merging changes no installed binary.
Blast radius: low. Only bws::create_secret, bws::edit_secret, and run change. Their callers are hush add, hush edit, and the TUI, and real BWS proves each one works.

Changes made by Claude Opus 5.5 via Claude Code

…es to bws intact

add evaluated stdin_value() eagerly through Option::or, so --value still
read stdin to EOF and hung on an open ssh connection.

bws 2.1.0 parses a hyphen-leading positional or split --opt value as a
flag and exits 2. create and edit now put options in --opt=value form
and positionals after --, with -o json first. add and edit --value take
hyphen-leading values.
…ndary tests

allow_hyphen_values let --value take a following flag as the secret, so
--value --stdin stored the text --stdin. Hyphen values go in as
--value=... or on stdin, which already parsed. The boundary tests now
assert the exact bws argv and never pass a real token to bws.
@coldtea-pr-lens

coldtea-pr-lens Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
  • Redraw · drawn at d60056d, the branch has moved on

Architecture

Architecture diagram for AojdevStudio/agentic-utilities at d60056d

Play the walkthrough


Data flow

Data flow diagram for AojdevStudio/agentic-utilities at d60056d

Follow each request


Review

✨ Nothing flagged · reviewed d60056d


Tip

Open a diagram on the canvas, then press W or click play to walk through the change one step at a time

🪧 More tips
  • Run npx skills add coldteadotai/pr-lens, then tell your coding agent: "Diagram the change you just made with PR Lens and attach it to the pull request."
  • Run npx @coldtea/pr-lens-cli analyze --base origin/main on a branch, then npx @coldtea/pr-lens-cli render .pr-lens/graph.json. Same lenses, your own model key, before the pull request exists
  • Click the link under each diagram to open it on a canvas you can zoom, pan and step through
  • The diagrams are links. Click one to open it on the canvas, then press W or click play to walk through the change
  • The CLI's render reads .github/pr-lens.yml and applies your renames, exclusions and lane pins at draw time
  • Set github.comment.collapsed: true in .github/pr-lens.yml to fold the comment behind one View architecture and data flow row. Drawing still runs as before
  • Set github.draw: on-demand in .github/pr-lens.yml and PR Lens stops drawing pull requests on its own. Comment @pr-lens draw on a pull request when you want that one drawn
  • Add .github/workflows/pr-lens.yml with coldteadotai/pr-lens/packages/action@v0 and your model provider's key as its api-key to run PR Lens from your own CI. Any /chat/completions endpoint works
  • After a push, tick Redraw to draw the latest commit
  • Switch GitHub to dark mode and the diagrams follow. The moving dots are this pull request's data in motion
  • Set github.description: false in .github/pr-lens.yml to stop PR Lens adding buttons to your PR descriptions

Thanks for using PR Lens! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out on X, Bluesky, Mastodon, Reddit or LinkedIn

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review: 1
  • main

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AojdevStudio

Copy link
Copy Markdown
Owner Author

Spec fidelity against the brief (two hush defects, plus edit and other value paths):

  • Defect 1 matches. With --value, hush add never touches stdin. Without it, stdin is read only when it is not a TTY, and the existing error says "no --value given and nothing piped on stdin". hush edit already read stdin only with --stdin, which conflicts with --value.
  • Defect 2 matches. The root cause was confirmed against real bws 2.1.0 (clap exits 2 on a hyphen-leading positional or split option value). The fix is the --opt=value form plus a -- separator, not escaping. It covers add, edit, and the TUI, which share bws::create_secret and bws::edit_secret. The other bws calls pass only UUIDs.
  • Deviation 1: the base is the new maintenance branch hush/0.0.x (cut at 1e92b9b), not main. Main removed --value and the bws write path in feat(hush): move human secret operations into the broker #84, and the fleet binaries predate feat(hush): move human secret operations into the broker #84.
  • Deviation 2: a hyphen-leading value goes to hush as --value=<v> or on stdin. The split form --value -----BEGIN still fails loudly in the hush parser and writes nothing. Accepting it let --value swallow the next flag, so review round 1 removed it.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes: Reviewed all three changed files, the shared CLI/TUI callers, and the upstream bws 2.1.0 argument contract.

  • Lazy stdin fallback: hush add no longer reads stdin when --value is supplied; existing stdin fallback behavior is preserved.
  • Literal argument forwarding: Create positionals follow --, edit options use --name=value, and global JSON output precedes subcommands so hyphen-leading fields reach bws intact.
  • Boundary regressions: Five subprocess tests cover held-open stdin, exact create/edit argv, multiline PEM input, and rejection of --value --stdin without a write.

Validation passed: 27 unit tests, five boundary tests, formatting, and Clippy with warnings denied. Live BWS writes were not repeated in this review. The separate PR-body check fails on the maintenance base checkout with Module not found ".claude/skills/open-pr/check.ts"; that failure is outside this Rust diff.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes: Reviewed the delta from d60056d to 89ced3e, with the full PR diff as context.

  • Added piped-stdin add coverage: The new subprocess test omits --value, supplies a multiline PEM on stdin, closes the pipe, and verifies the exact bws secret create argv, including the trailing newline. Production code is unchanged.

Validation passed: 27 unit tests, six boundary tests, Rust formatting, and Clippy with warnings denied. Live BWS writes were not repeated. The unrelated PR-body check still fails on the maintenance-base checkout with Module not found ".claude/skills/open-pr/check.ts", as in the previous review.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@AojdevStudio

Copy link
Copy Markdown
Owner Author

Spec fidelity at a78a56a: no deviations. The Problem names two defects. hush add --value hung on an open stdin, and hyphen-leading values failed in hush add, hush edit, and the TUI. The diff fixes both in bws.rs and commands.rs, and the real-BWS transcript in Proof shows each case. a78a56a only merges hush/0.0.x (PR #108, the PR body checker) into this branch. The PR diff against the base is byte-identical to the reviewed 89ced3e diff.

@AojdevStudio
AojdevStudio merged commit 9167a2b into hush/0.0.x Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant