Files
ironclaw/scripts
Henry Park 58529a20a8 fix(composition): stop icacls writing to the CLI's stdout on Windows (#7200)
`write_standalone_secret_master_key` restricted the key file by shelling out
to `icacls` with `.status()`, which lets the child inherit our stdio. On
success `icacls` announces itself:

    processed file: C:\...\reborn-local-dev-secrets-master-key
    Successfully processed 1 files; Failed processing 0 files

Runtime assembly runs before a CLI command prints its own result, so that
banner landed at the front of `ironclaw.exe`'s stdout and corrupted every
`--json` command that builds a runtime:

    SmokeFailure: extension search --json did not emit valid JSON:
      Expecting value: line 1 column 1 (char 0)

Character 0 was the `p` of `processed`. The command exited 0 and its JSON was
intact — just no longer the only thing on stdout.

`profile list --json` passed in the same run because it is pure in-process
(`RebornProfile::all()` plus a `println!`) and never assembles a runtime. The
Unix branch is unaffected: it sets `mode(0o600)` at open and spawns nothing.
This is the only subprocess anywhere in the boot path.

It fires on essentially every fresh run: no cached key file, no
IRONCLAW_SECRETS_MASTER_KEY override, and IRONCLAW_DISABLE_OS_KEYCHAIN makes
the keychain miss deterministic, so the generate-fresh-key branch is taken.

Switched to `output()`, which captures both pipes. That keeps the child's
chatter out of our stdout contract and lets the failure path report what
icacls actually said instead of only its exit status.

Also hardens the smoke harness that found this, because it discarded the
evidence: a JSON parse failure now echoes the length and repr of what
arrived, exit-0-with-empty-stdout is called out by name with stderr attached,
and subprocess output is decoded as UTF-8 explicitly rather than through
Python's locale encoding (the ANSI code page on Windows, which would mangle
any non-ASCII byte in a payload we are about to parse).

Regression coverage is at the smoke tier, which is where this class is
actually reachable — the three new harness tests pin that a leading banner, a
BOM, and a silent success each name themselves. There is no Windows Rust test
lane that reaches this code; #7182 added the only Windows test execution in
CI and it is scoped to ironclaw_filesystem. The changed expressions were
type-checked standalone on the host, since #[cfg(windows)] hides them from
every local build and cross-compiling the crate fails in ring's C build.

Found by release preflight run 30962170467 on release/1.1.0-rc.1.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 18:00:13 -07:00
..