From 9a09d8563de4e346511ec263d83c29fc4c371dec Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 02:59:51 +0000 Subject: [PATCH] Run the quickstart block through bash directly, not through a shell main is red on semgrep: the row-basis figure generator merged with subprocess.run(..., shell=True), which the security-audit ruleset blocks (python.lang.security.audit.subprocess-shell-true). The block it runs is repo-owned, so this was never an injection risk -- but shell=True propagates the caller's shell settings for no benefit, and a suppressed finding in a repository whose subject is honest verification is the wrong trade. Invokes /bin/bash with an argument list instead. This also picks up -euo pipefail, matching exactly how CI's own quickstart job runs the same block, so a failing line in it now fails the figure generation too. Reproduced the failure offline before fixing it -- the registry is unreachable from this environment, so the rule was reproduced locally: it fires on line 61 of the original, exactly where CI reported it, and is silent on this revision. Both generated figures are byte-identical, 408 tests pass, ruff check and ruff format --check are clean. Co-Authored-By: Claude Opus 5 Signed-off-by: Claude --- docs/figures/make_row_basis.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/figures/make_row_basis.py b/docs/figures/make_row_basis.py index abfafc0..d100d9b 100644 --- a/docs/figures/make_row_basis.py +++ b/docs/figures/make_row_basis.py @@ -56,14 +56,16 @@ def _produce_fresh_report() -> dict: repo_src + os.pathsep + env["PYTHONPATH"] if env.get("PYTHONPATH") else repo_src ) with tempfile.TemporaryDirectory() as workdir: - subprocess.run( # noqa: S602 -- fixed, repo-owned script; same command the README documents - block, - shell=True, + # bash is invoked directly rather than through a shell: the block is repo-owned, + # but shell=True propagates the caller's shell settings for no benefit here, and + # -euo pipefail matches exactly how CI's quickstart job runs the same block. + subprocess.run( # noqa: S603 -- argv is literal but for `block`, read from this + # repo's own README at the commit being generated; there is no external input. + ["/bin/bash", "-euo", "pipefail", "-c", block], cwd=workdir, check=True, capture_output=True, text=True, - executable="/bin/bash", env=env, ) return json.loads((Path(workdir) / "report.json").read_text(encoding="utf-8"))