Skip to content

Bypass env in the closed-stdin autolint test - #129

Merged
cgraf78 merged 1 commit into
mainfrom
agent/ci-fix-closed-stdin
Nov 3, 2026
Merged

cgraf78 merged 1 commit into
mainfrom
agent/ci-fix-closed-stdin

Conversation

@cgraf78

@cgraf78 cgraf78 commented Nov 3, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes the scheduled Tests failure in https://github.com/cgraf78/checkrun/actions/runs/41596810832, where test/suites/autolint-test failed files0 stdin: closed descriptor exits 2 and ... is actionable on the Ubuntu and WSL legs after ubuntu-latest moved to Ubuntu 26.04. Supersedes #128.

Root cause: the product guard was never at fault. The test closed fd 0 and then ran bin/autolint through its #!/usr/bin/env bash shebang. Ubuntu 26.04's coreutils are uutils (the runner image lists coreutils 9.5-1ubuntu2+0.0.0~ubuntu25), so /usr/bin/env is a Rust binary, and Rust's std runtime reopens any closed descriptor 0-2 on /dev/null (O_RDWR) before main. autolint therefore received an open, empty /dev/null stream, which is indistinguishable from a deliberate </dev/null empty manifest, and exited 0 quietly.

  • The closed-stdin case now runs as "$BASH" "$AUTOLINT" --files0-from - <&-, so the closed descriptor reaches the guard on every platform. The other --files0-from - cases still go through the shebang.
  • _autolint_read_files0 is unchanged: its /dev/stdin probe is correct whenever fd 0 actually arrives closed. Probe closed stdin with an fd duplication in _autolint_read_files0 #128's fd-duplication probe could not help, because by then fd 0 is genuinely open on /dev/null; Probe closed stdin with an fd duplication in _autolint_read_files0 #128's later attribution to bash came from a probe that itself ran through /usr/bin/env bash -c.
  • No user-facing behavior changes. On uutils hosts, autolint --files0-from - <&- launched through PATH still exits 0, since the closed descriptor never reaches the process; nothing in-process can tell that apart from </dev/null.

Testing

  • Reproduced locally with a minimal Rust exec wrapper standing in for uutils env: fd 0 arrives as lrwx ... -> /dev/null and autolint --files0-from - <&- exits 0 with no output (the CI signature); GNU env and direct bash keep fd 0 closed and exit 2 with the actionable message.
  • Probe closed stdin with an fd duplication in _autolint_read_files0 #128's CI diagnostic showed fd 0 inside autolint as lrwx /dev/null, matching Rust's O_RDWR reopen rather than a shell redirect.
  • Mutation check: with the guard disabled, the updated invocation exits 0, so both assertions still catch a regression.
  • test/suites/autolint-test: 517 passed, 0 failed.
  • test/checkrun-test: everything passes except the schema-refresh refs cases, which fail locally only because this host lacks the Python referencing library; that suite is untouched and runs in CI.
  • checkrun format, checkrun lint, and shellcheck-inventory/run.sh at the locked cgraf78/actions SHA pass.

Review

Fresh-eyes review by two independent reviewers, both approving:

  • Root cause and correctness: independently confirmed the Rust std O_RDWR reopen and that "$BASH" "$AUTOLINT" still exercises the real guard, including when the suite itself is launched through a Rust env. This PR's Ubuntu/WSL legs are the on-runner proof that bash 5.3 does not reopen fd 0.
  • Cross-platform side effects: $BASH is always the suite's own absolute bash; BSD, GNU, and busybox env leave closed descriptors alone; the WSL leg is simulated on the Ubuntu runner (same uutils env); Termux does not run this suite; no docs promise closed-stdin behavior. Addressed: commit header style and comment wording that now attributes the reopen to Rust's std runtime.

Summary
The scheduled `Tests` run failed `files0 stdin: closed descriptor` on
the Ubuntu and WSL legs once `ubuntu-latest` moved to Ubuntu 26.04.
The product guard was never at fault: the test closed fd 0 and then
ran `bin/autolint` through its `#!/usr/bin/env bash` shebang, and
Ubuntu 26.04's `env` comes from uutils coreutils. Rust's std runtime
reopens any closed descriptor 0-2 on /dev/null before `main`, so
autolint received an open, empty /dev/null stream, indistinguishable
from a deliberate `</dev/null` empty manifest.

- run the closed-stdin case as `"$BASH" "$AUTOLINT"`, so the closed
  descriptor reaches the guard on every platform
- leave `_autolint_read_files0` unchanged: its `/dev/stdin` probe is
  correct whenever fd 0 actually arrives closed
- supersedes the automated fix in #128, which blamed the probe and
  then bash

Testing
- reproduced locally with a minimal Rust exec wrapper standing in for
  uutils `env`: fd 0 arrives as /dev/null and `autolint --files0-from
  - <&-` exits 0 silently, while GNU `env` and direct `bash` keep fd 0
  closed and exit 2 with the actionable message
- #128's CI diagnostic showed fd 0 as `lrwx` /dev/null inside
  autolint, matching Rust's O_RDWR reopen rather than a shell redirect
- removing the guard makes the updated invocation exit 0, so the test
  still catches a regression
- `test/suites/autolint-test`: 517 passed, 0 failed
- `test/checkrun-test`: only `schema-refresh` refs cases fail, from
  the local host lacking the `referencing` library; that suite is
  untouched
- `checkrun format`, `checkrun lint`, and the shellcheck-inventory
  check at the locked cgraf78/actions SHA pass
@cgraf78
cgraf78 merged commit aac5530 into main Nov 3, 2026
51 of 57 checks passed
@cgraf78
cgraf78 deleted the agent/ci-fix-closed-stdin branch November 3, 2026 15:03
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