Skip to content

fix(gates): drop mapfile so the hardcoded-defaults gate runs on macOS - #729

Open
ayaangazali wants to merge 1 commit into
RunanywhereAI:mainfrom
ayaangazali:fix/gate-bash32-mapfile
Open

fix(gates): drop mapfile so the hardcoded-defaults gate runs on macOS#729
ayaangazali wants to merge 1 commit into
RunanywhereAI:mainfrom
ayaangazali:fix/gate-bash32-mapfile

Conversation

@ayaangazali

@ayaangazali ayaangazali commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

What is wrong

check_no_hardcoded_defaults.sh cannot run on macOS. On a stock Mac:

$ /bin/bash scripts/validation/gates/check_no_hardcoded_defaults.sh
scripts/validation/gates/check_no_hardcoded_defaults.sh: line 70: mapfile: command not found
$ echo $?
127

mapfile is bash 4. macOS ships bash 3.2 as /bin/bash (3.2.57 here), and the shebang is #!/usr/bin/env bash, so it resolves to that unless someone happens to have a newer bash earlier on PATH. The gate exits 127 before reading a single file, and it only ever passes because pr-build.yml's centralization job runs on ubuntu-22.04.

Why this is a rule and not my preference

Two sibling scripts already state the constraint and avoid these builtins because of it:

bindings/swift/scripts/sync-dist-repo.sh:178

Built with read loops rather than mapfile: macOS ships bash 3.2, which has no mapfile, and this script must run on a stock macOS release runner.

scripts/build/build-core-android.sh:65

...array (declare -A) so this script works on macOS' default /bin/bash 3.2

I swept the tree for the bash 4 builtins (mapfile, readarray, declare -A, ${x^^}, ${x,,}) and this line is the only violation left. The other two hits are those comments.

It bites at the worst moment too: a contributor on a Mac reproducing a red gate locally gets a bash error instead of the list of offending files.

What this does

Replaces mapfile -t FILES with the read loop the sibling scripts use. FILES stays an array, so ${FILES[@]}, ${#FILES[@]}, the empty-scope guard and --list all behave as before. 8 insertions, 1 deletion.

Verification

On this Mac, /bin/bash = 3.2.57, no Homebrew bash installed.

Before: exit 127, mapfile: command not found.

After:

$ /bin/bash scripts/validation/gates/check_no_hardcoded_defaults.sh
OK: no re-declared defaults in 781 scanned SDK source files.
$ echo $?
0

I checked the array is complete rather than assuming it, since a read loop can silently drop a final line without a trailing newline. Running the find pipeline standalone gives exactly 781, matching the gate's count, and --list prints 781 paths plus its scanned 781 files line.

No test added: there is no harness for these gate scripts, and the check that matters is the one above, running it under the bash version that used to fail.

Summary by CodeRabbit

  • Bug Fixes
    • Improved validation compatibility with older Bash versions while preserving existing file-discovery and scope-filtering behavior.

`mapfile` is bash 4. macOS ships bash 3.2 as /bin/bash, so the gate exits 127
with `mapfile: command not found` before it reads a single file. It only ever
passes because the centralization job runs on ubuntu-22.04.

Two sibling scripts already state this constraint and avoid the same builtins
for it:

  bindings/swift/scripts/sync-dist-repo.sh:178
    Built with read loops rather than `mapfile`: macOS ships bash 3.2, which
    has no mapfile, and this script must run on a stock macOS release runner.

  scripts/build/build-core-android.sh:65
    ...array (`declare -A`) so this script works on macOS' default /bin/bash 3.2

This gate is the one place that breaks the rule, and it breaks it exactly when
a contributor on a Mac tries to reproduce a red gate locally: instead of the
list of offending files they get a bash error.

Replaced with the read loop the sibling scripts use. `FILES` stays an array, so
`${FILES[@]}` / `${#FILES[@]}` and `--list` are unchanged.
Copilot AI lite review requested due to automatic review settings August 17, 2026 17:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ayaangazali

Copy link
Copy Markdown
Contributor Author

Heads up on the red python-linux (3.9) and (3.12) cells here: they are not from this diff.

Both are red on main too, at b2d2ff6d (run 32011099890), with "The job has exceeded the maximum execution time of 1h30m0s". The job hangs inside auditwheel repair because the prep step's ln -sf libonnxruntime.so lib/libonnxruntime.so.1 overwrites the middle link of the chain the new RunAnywhere desktop prebuilt ships, turning libonnxruntime.so and libonnxruntime.so.1 into a symlink loop.

I opened #736 with the evidence and a one-line guard. Nothing to do on this PR; every other check here is green.

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.

2 participants