Skip to content

Commit bcf17d8

Browse files
committed
Check for executable bits that disagree with shebangs
It is rare that text files should be stored in a repository with a leading `#!` (shebang, a.k.a. hashbang) but `-x` permissions, or with no leading `#!` but `+x` permissions. But it is easy for this to happen by accident. This introduces a script to check for that situation -- currently only in files whose names end in `.sh`, which are the files in which this minor problem has tended to arise in this repository. This adds a `justfile` recipe for it, as well as a CI job that runs the script. (The CI job does not run it via `just`, since not doing so allows it to save time by not installing anything.) Currently, this: - Looks only at what is committed and staged, ignoring unstaged files and unstaged mode changes. (This is intended to allow it to be cross platform, because on Windows, Git repositories support the same modes as anywhere else, but the filesystem doesn't support Unix-style executable permissions.) - Is implemented as a shell script. Unlike `copy-packetline.sh`, there would be no major disadvantage to having this be Rust code instead, since it is never used to correct a problem that keeps Rust code from building. - Is called from a separate CI job than any others. But it could probably be called from one of the existing jobs instead. There are some files already in the repository that fail the new check, which should be given `+x` permissions. In this commit, they are kept as-is, and new files that should be detected as *wrongly* having `+x` permissions are added. This is to verify that the script is fully working as expected, including when run on CI. Once that is confirmed, the new test files can be removed, the scripts missing `+x` fixed, and the CI job made to run only on Ubuntu. (See the commented discussion in GitoxideLabs#1589 for further information.)
1 parent 1d73d00 commit bcf17d8

File tree

5 files changed

+65
-0
lines changed

5 files changed

+65
-0
lines changed

.github/workflows/ci.yml

+18
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,24 @@ jobs:
359359
- name: gix-pack with all features (including wasm)
360360
run: cd gix-pack && cargo build --all-features --target "$TARGET"
361361

362+
check-modes:
363+
# FIXME: Only run this on ubuntu-latest (don't use a matrix).
364+
strategy:
365+
fail-fast: false
366+
matrix:
367+
os: [ ubuntu-latest, macos-latest, windows-latest ]
368+
369+
runs-on: ${{ matrix.os }}
370+
371+
defaults:
372+
run:
373+
shell: bash
374+
375+
steps:
376+
- uses: actions/checkout@v4
377+
- name: Find scripts with mode/shebang mismatch
378+
run: etc/check-mode.sh
379+
362380
check-packetline:
363381
strategy:
364382
fail-fast: false

etc/check-mode.sh

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
set -eu -o pipefail
4+
shopt -s lastpipe
5+
6+
# Go to the worktree's root. (Even if the dir name ends in a newline.)
7+
root_padded="$(git rev-parse --show-toplevel && echo -n .)"
8+
root="${root_padded%$'\n.'}"
9+
cd -- "$root"
10+
11+
symbolic_shebang="$(printf '#!' | od -An -ta)"
12+
status=0
13+
14+
function check () {
15+
local mode="$1" oid="$2" path="$3" symbolic_magic
16+
17+
# Extract the first two bytes (or less if shorter) and put in symbolic form.
18+
symbolic_magic="$(git cat-file blob "$oid" | od -N2 -An -ta)"
19+
20+
# Check for inconsistency between the mode and whether `#!` is present.
21+
if [ "$mode" = 100644 ] && [ "$symbolic_magic" = "$symbolic_shebang" ]; then
22+
printf 'mode -x but has shebang: %q\n' "$path"
23+
elif [ "$mode" = 100755 ] && [ "$symbolic_magic" != "$symbolic_shebang" ]; then
24+
printf 'mode +x but no shebang: %q\n' "$path"
25+
else
26+
return 0
27+
fi
28+
29+
status=1
30+
}
31+
32+
# For now, check just regular files named with a `.sh` suffix.
33+
git ls-files -sz -- '*.sh' | while read -rd '' mode oid _stage_number path; do
34+
case "$mode" in
35+
100644 | 100755)
36+
check "$mode" "$oid" "$path"
37+
;;
38+
esac
39+
done
40+
41+
exit "$status"

etc/delete-after-testing/empty.sh

Whitespace-only changes.

etc/delete-after-testing/not empty.sh

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This doesn't start with a #!.
2+
#! on another line doesn't count.

justfile

+4
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ fmt:
255255
find-yanked:
256256
cargo install --debug --locked --no-default-features --features max-pure --path .
257257

258+
# Find shell scripts whose +x/-x bits and magic bytes (e.g. `#!`) disagree
259+
check-mode:
260+
./etc/check-mode.sh
261+
258262
# Delete gix-packetline-blocking/src and regenerate from gix-packetline/src
259263
copy-packetline:
260264
./etc/copy-packetline.sh

0 commit comments

Comments
 (0)