From 8ad8e1ab7b3383439d1f6fea4382794cc341af47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Guilhermo=20de=20Barros=20Val=C3=A9rio?= Date: Sat, 10 Oct 2026 04:55:47 +0200 Subject: [PATCH 1/2] test(self-tests): refuse a fake script with an env shebang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flake's self-tests run in the Nix build sandbox, which has no /usr/bin/env, so a fake written with #!/usr/bin/env passes locally and fails only in CI; it broke #61 and #81 on the same day. tests/self-tests.sh now fails on any #!/usr/bin/env below a file's first line in scripts/, plugins/ and tests/, and checks itself on a red and a green fixture each run. Closes #83 Tested: tests/self-tests.sh green on main with #81's fakes; a planted #81-style fake in scripts/temps.sh fails it naming the line, removed it passes; the fixture check red/green; shellcheck (warning+); docs_lint Cost: ~$1.33 · diff-size estimate (cost-split --estimate-commit) Co-Authored-By: Claude --- tests/self-tests.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/self-tests.sh b/tests/self-tests.sh index 4a5ee6e..a2071b3 100755 --- a/tests/self-tests.sh +++ b/tests/self-tests.sh @@ -27,5 +27,18 @@ t() { # /dev/null | grep -vE '^[^:]+:1:'; } +fx="$(mktemp -d)"; trap 'rm -rf "$log" "$fx"' EXIT +printf '#!/usr/bin/%s bash\ncat >fake <"$fx/red.sh" +printf '#!/usr/bin/%s bash\ncat >fake <"$fx/green.sh" +if [ "$(env_shebangs "$fx/red.sh" | wc -l)" -eq 1 ] && [ -z "$(env_shebangs "$fx/green.sh")" ]; then + echo "ok env-shebang check (fixtures)" +else failed=$((failed + 1)); echo "FAIL env-shebang check: its fixtures were judged wrong"; fi +if offenders="$(env_shebangs scripts plugins tests)"; then + failed=$((failed + 1)); echo "FAIL a fake with an env shebang (use #!\$BASH, or sys.executable in Python):"; sed 's/^/ /' <<<"$offenders" +else echo "ok no env-shebang fakes"; fi [ "$failed" -eq 0 ] || { echo "self-tests: $failed failed" >&2; exit 1; } echo "self-tests: all ok" From f258b803f97efc737fd2bc9697330a4b5ec7c33c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Guilhermo=20de=20Barros=20Val=C3=A9rio?= Date: Sat, 10 Oct 2026 04:56:04 +0200 Subject: [PATCH 2/2] docs(development): fakes start with #!$BASH, and why MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of #83: the self-test section names the convention tests/self-tests.sh now enforces. Tested: docs_lint Cost: ~$0.15 · diff-size estimate (one paragraph) Co-Authored-By: Claude --- docs/3-development.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/3-development.md b/docs/3-development.md index 13b5f09..8fffb9f 100644 --- a/docs/3-development.md +++ b/docs/3-development.md @@ -24,7 +24,10 @@ Every tool and hook has a `--self-test` that runs offline: no network, no `gh` l in temporary repos, `gh` stubbed where a command needs it, and fixtures from `scripts/fixtures/`. A change to a script extends its self-test first and watches it fail, then makes it pass. A new script goes into `tests/self-tests.sh`'s `sh_tests` or `py_tests` list, which is the one list -both `just quality` and the flake's `self-tests` check read. +both `just quality` and the flake's `self-tests` check read. A fake script a self-test writes +starts with `#!$BASH` (a Python one runs under `sys.executable`), never `#!/usr/bin/env`: the +flake's sandbox has no `/usr/bin/env`, so such a fake passes locally and fails in CI, and +`tests/self-tests.sh` refuses it. A self-test that creates git repos starts with `unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_PREFIX GIT_COMMON_DIR` and