Files
hermes-agent/.github/workflows/case-collision-check.yml
T
ethernet 375ce8eee5 ci: block tracked paths that collide case-insensitively
Linux is case-sensitive; Windows and macOS are not. Two tracked paths
differing only by case (README.md vs readme.md, src/Foo.py vs SRC/foo.py)
land fine on Linux and silently break every clone on a case-insensitive
host — the filesystem holds one, so checkout fails or whichever wins
clobbers the other. Git won't stop the pair from landing; it only warns
at checkout time on a case-insensitive FS. This is the enforcement point.

Adds scripts/check-case-collisions.py (index scan keyed on casefolded
full paths) + an unconditional workflow_call job wired into ci.yaml and
the all-checks-pass gate — unconditional because a collision can ship in
any kind of PR (docs, JS, config), not just Python, so gating on a
language lane would be the same passive-rule trap the infographic check
closes. Tests in tests/scripts/test_case_collision_check.py build
collisions via git update-index --cacheinfo so they run on
case-insensitive filesystems too.
2026-09-01 15:37:57 -04:00

34 lines
1.2 KiB
YAML

name: Case Collision Check
# Rejects PRs that track two files whose paths differ only by case
# (README.md vs readme.md, src/Foo.py vs SRC/foo.py).
#
# Linux is case-sensitive; Windows and macOS (default) are not. A
# case-colliding pair lives fine in a Linux checkout and silently breaks
# every clone on a case-insensitive host — the filesystem can hold only
# one of them, so checkout fails or whichever wins overwrites the other.
# Git won't prevent the pair from landing (it only warns at checkout time,
# on a case-insensitive FS, for the client doing the checkout), so the only
# enforcement point is CI, on Linux, against the index.
#
# Runs unconditionally (no change-classifier gate): a collision can ship in
# any kind of PR — docs, JS, config, not just Python — so gating on a
# language lane would be the same "passive rule that cannot enforce a
# policy" trap the infographic check exists to close.
on:
workflow_call:
permissions:
contents: read
jobs:
check-case-collisions:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Run case-collision checker
run: python3 scripts/check-case-collisions.py