diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index afc1cea684a..42246e7e52f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -359,6 +359,14 @@ jobs: - name: gix-pack with all features (including wasm) run: cd gix-pack && cargo build --all-features --target "$TARGET" + check-mode: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Find scripts with mode/shebang mismatch + run: etc/check-mode.sh + check-packetline: strategy: fail-fast: false @@ -441,6 +449,7 @@ jobs: - test-32bit-cross - lint - cargo-deny + - check-mode - check-packetline - check-blocking diff --git a/etc/check-mode.sh b/etc/check-mode.sh new file mode 100755 index 00000000000..4bc15b79ba5 --- /dev/null +++ b/etc/check-mode.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -eu -o pipefail + +# 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 +} + +# Check regular files named with a `.sh` suffix. +while read -rd '' mode oid _stage_number path; do + case "$mode" in + 100644 | 100755) + check "$mode" "$oid" "$path" + ;; + esac +done < <(git ls-files -sz -- '*.sh') + +exit "$status" diff --git a/gix-diff/tests/fixtures/make_diff_for_rewrites_repo.sh b/gix-diff/tests/fixtures/make_diff_for_rewrites_repo.sh old mode 100644 new mode 100755 diff --git a/gix-merge/tests/fixtures/make_blob_repo.sh b/gix-merge/tests/fixtures/make_blob_repo.sh old mode 100644 new mode 100755 diff --git a/gix-merge/tests/fixtures/text-baseline.sh b/gix-merge/tests/fixtures/text-baseline.sh old mode 100644 new mode 100755 diff --git a/gix-merge/tests/fixtures/tree-baseline.sh b/gix-merge/tests/fixtures/tree-baseline.sh old mode 100644 new mode 100755 diff --git a/gix-revision/tests/fixtures/merge_base_octopus_repos.sh b/gix-revision/tests/fixtures/merge_base_octopus_repos.sh old mode 100644 new mode 100755 diff --git a/justfile b/justfile index 6323a0670da..42b8cb0c449 100755 --- a/justfile +++ b/justfile @@ -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