tools/redact_trial.py reads stdin and writes stdout, opening no path (SonarCloud S2083, S8707)

Merged
DO
5d ago
+122-37

SonarCloud has two findings open on main against tools/redact_trial.py: S2083 (path injection) and S8707. The tool opened the two paths it was given. As #273 did for its drift comparer, it now opens no path at all:

  • Standard input carries the raw capture in.
  • Standard output carries what is left out, written as UTF-8 whatever the locale.
  • Standard error names each removal, by where it was and never what it held.
  • Any argument is refused before anything is read.

It still runs as python3 -m tools.redact_trial from the repo, since it reads tools/check_trials.py's rules. So it cannot run as python3 -I, which would drop the repo from its path.

Callers

Every call moves from redact_trial RAW OUT > REPORT to redact_trial < RAW > OUT 2> REPORT:

  • the trial scripts of P-4, P-8, P-13 and P-39;
  • the App's script, tools/trial_as_app.sh, which sends the report through its pipe: < "$1" 2>&1 > clean | sed;
  • tools/rulesets_drift.sh;
  • the skill's step 4, and P-13's runbook.

The three calls that discard the report say so and stop when the redaction fails.

P-26's script, on its own branch, makes the same change when it next merges main.

Behaviour kept

  • Line ends. CR LF and a lone CR are read as a line's end, as the old read from a file did. gh api --include ends its head's lines with CR LF. Read as bytes without this, a head would be redacted as body. This was the review's blocker.
  • Encoding. Bytes that are not UTF-8 stop it, with nothing written, as before.

Tests and mutants

  • Redaction.test_it_opens_no_path_it_is_given covers:
    • each argument refused before a byte is read;
    • a run through pipes, as the scripts run it;
    • a CR LF head;
    • bytes that are not UTF-8;
    • an ASCII locale;
    • the App script's redirection order.
  • The rulesets drift stand-in now answers with CR LF heads, as gh does.
  • Three new mutants are killed: the tool reading a path it is given, keeping CR LF, and writing in the locale's encoding. The two older mutants of the redaction still are.

Verification and review

  • make verify passed in the worktree, with history, at SIM_SEEDS=40: 889 tests. The scripts' stand-in tests run the real redaction through the new calls.
  • A fresh Claude review with a security pass on 7e21663 found one blocker (CR LF), two majors (the locale's encoding, failures made silent) and five minors. All are fixed in the fix round, except two minors:
    • an empty clean file can be left when the tool fails, which holds nothing;
    • the flush is untested.
  • Muse: not run (the Maintainer, 2026-10-20: Kernel/hook only).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Redaction now processes trial captures through standard input and output, simplifying integration with command-line workflows.
    • Cleaned captures continue to remove credentials, sensitive headers, and credential-like content.
    • Redaction diagnostics are reported separately from cleaned output.
  • Bug Fixes

    • Line-ending handling is now consistent across input formats.
    • Output is always encoded as UTF-8.
    • Redaction failures now produce clear errors and stop affected trial workflows safely.