Files
codebase-memory-mcp/tests/test_shell_line_endings.sh
T
Martin Vogel f0a86ef2c2 feat(ci): seeded fuzz leg, and register both new legs as canonical entries
scripts/fuzz.sh drives the libFuzzer targets in two shapes from one entry:
a fixed --runs from a fixed --seed, so a CI smoke is a function of the code
and not a lottery (O9), and a time-boxed --max-total-time for exploration.
Checked-in seeds are copied into a working corpus under build/fuzz/, so a
run never rewrites the repository; a crash leaves its reproducer behind and
the script exits non-zero. Wired as a smoke into dry-run.yml and as
exploration into nightly-soak.yml.

The venue-parity contract rightly refused both workflow steps: a venue may
provision or plumb, but only a CANONICAL leg entry may exercise the
product, and neither script was registered. Registering them — rather than
working around the contract — is the fix, since both own their leg end to
end (build, corpus or binary, artifact paths, exit code) exactly as
soak-legs.sh owns the soak. _memwaste.yml joins the policed venue walk for
the same reason, and both scripts join the layer-5 interface probes.

Those probes immediately earned their keep, finding two real defects:
`fuzz.sh --help` exited 2 because the positional target consumed the flag,
and memwaste.sh read a typo'd flag as the repository path — which would
have indexed nothing and reported an empty lane as a clean one.

test_shell_line_endings.sh now degrades where the checkout has no
reachable repository metadata: the Linux container bind-mounts the working
tree, and a git worktree's .git is a pointer to the host repository, so
`git ls-files` cannot run there and the contract failed with "matched no
files — the glob set is broken", killing the leg before it compiled. It is
a repository property, so it stays gating in every venue that has the
metadata (macOS host, the Windows VM's real checkout at C:\cbm with 117
files, every hosted-CI checkout). test_version_metadata_contract.sh already
guards the same way for the same reason; the alternatives considered and
rejected are recorded at the case.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-18 03:31:42 +02:00

61 lines
2.4 KiB
Bash

#!/usr/bin/env bash
# Regression guard: shell entrypoints must remain LF in Windows checkouts so
# they can run directly from WSL and MSYS without a `bash\r` shebang failure.
#
# Distilled from PR #1272 by @xumian520, who both hit the breakage under
# core.autocrlf=true and wrote this contract so it stays fixed. The .sh rule
# itself landed via #1314; the extensionless git hooks need their own
# entries, which this guard also covers.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
# This contract reads REPOSITORY metadata (.gitattributes, through git's own
# attribute matcher). The Linux container leg mounts the WORKING TREE only, and
# a git worktree's .git is a file pointing at the host's main repository, which
# is not inside the container — so `git ls-files` cannot run there at all
# (verified 2026-09-17: `fatal: not a git repository`). The property is
# platform-independent and stays gated in every venue that has the metadata:
# the macOS host leg, the Windows VM (a real checkout at C:\cbm — 117 files
# checked there), and every hosted-CI checkout.
# Tried and rejected: mounting the host .git into the container — the worktree
# gitdir path would have to be reproduced inside, and container-root writes to
# the host repository are worse than a scoped skip; and matching .gitattributes
# patterns ourselves, which is a partial copy of git's attribute semantics and
# so a false-green risk. tests/test_version_metadata_contract.sh guards the
# same way for the same reason.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "SKIP: no repository metadata in this checkout (working tree without" \
"its git dir) — the line-ending contract gates on the host leg and CI"
exit 0
fi
failures=0
checked=0
while IFS= read -r -d '' path &&
IFS= read -r -d '' attribute &&
IFS= read -r -d '' eol; do
checked=$((checked + 1))
if [[ "$eol" != "lf" ]]; then
echo "FAIL: $path must declare eol=lf (got ${eol:-unset})" >&2
failures=$((failures + 1))
fi
done < <(
git ls-files -z '*.sh' 'scripts/git-hooks/*' 'scripts/hooks/*' |
git check-attr -z --stdin eol
)
if ((checked == 0)); then
echo "FAIL: the line-ending contract matched no files — the glob set is broken" >&2
exit 1
fi
if ((failures > 0)); then
echo "FAIL: $failures shell entrypoint(s) lack an LF checkout contract" >&2
exit 1
fi
echo "Shell line-ending contract passed ($checked files)"