Skip to content

Commit

Permalink
Check for executable bits that disagree with shebangs
Browse files Browse the repository at this point in the history
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.)
  • Loading branch information
EliahKagan committed Nov 28, 2024
1 parent 1d73d00 commit bcf17d8
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,24 @@ jobs:
- name: gix-pack with all features (including wasm)
run: cd gix-pack && cargo build --all-features --target "$TARGET"

check-modes:
# FIXME: Only run this on ubuntu-latest (don't use a matrix).
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]

runs-on: ${{ matrix.os }}

defaults:
run:
shell: bash

steps:
- uses: actions/checkout@v4
- name: Find scripts with mode/shebang mismatch
run: etc/check-mode.sh

check-packetline:
strategy:
fail-fast: false
Expand Down
41 changes: 41 additions & 0 deletions etc/check-mode.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash

set -eu -o pipefail
shopt -s lastpipe

# Go to the worktree's root. (Even if the dir name ends in a newline.)
root_padded="$(git rev-parse --show-toplevel && echo -n .)"
root="${root_padded%$'\n.'}"
cd -- "$root"

symbolic_shebang="$(printf '#!' | od -An -ta)"
status=0

function check () {
local mode="$1" oid="$2" path="$3" symbolic_magic

# Extract the first two bytes (or less if shorter) and put in symbolic form.
symbolic_magic="$(git cat-file blob "$oid" | od -N2 -An -ta)"

# Check for inconsistency between the mode and whether `#!` is present.
if [ "$mode" = 100644 ] && [ "$symbolic_magic" = "$symbolic_shebang" ]; then
printf 'mode -x but has shebang: %q\n' "$path"
elif [ "$mode" = 100755 ] && [ "$symbolic_magic" != "$symbolic_shebang" ]; then
printf 'mode +x but no shebang: %q\n' "$path"
else
return 0
fi

status=1
}

# For now, check just regular files named with a `.sh` suffix.
git ls-files -sz -- '*.sh' | while read -rd '' mode oid _stage_number path; do
case "$mode" in
100644 | 100755)
check "$mode" "$oid" "$path"
;;
esac
done

exit "$status"
Empty file.
2 changes: 2 additions & 0 deletions etc/delete-after-testing/not empty.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This doesn't start with a #!.
#! on another line doesn't count.
4 changes: 4 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ fmt:
find-yanked:
cargo install --debug --locked --no-default-features --features max-pure --path .

# Find shell scripts whose +x/-x bits and magic bytes (e.g. `#!`) disagree
check-mode:
./etc/check-mode.sh

# Delete gix-packetline-blocking/src and regenerate from gix-packetline/src
copy-packetline:
./etc/copy-packetline.sh

0 comments on commit bcf17d8

Please sign in to comment.