Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/code-hygiene-self-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ on:
- 'actions/secrets-check/**'
- 'actions/boj-cartridge-check/**'
- 'actions/manifest-check/**'
- 'actions/required-files-check/**'
- 'actions/spdx-license-check/**'
- 'tests/**'
- '.github/workflows/code-hygiene-self-test.yml'
pull_request:
paths:
Expand All @@ -22,6 +25,9 @@ on:
- 'actions/secrets-check/**'
- 'actions/boj-cartridge-check/**'
- 'actions/manifest-check/**'
- 'actions/required-files-check/**'
- 'actions/spdx-license-check/**'
- 'tests/**'
- '.github/workflows/code-hygiene-self-test.yml'

permissions:
Expand All @@ -32,6 +38,22 @@ concurrency:
cancel-in-progress: true

jobs:

# Deliberately a SEPARATE job from `test`. The `test` job invokes composite
# actions, which drag transitive `uses:` edges into actions.lock; when one of
# those pins goes stale the job dies in `prepare`, before a single step runs —
# which is exactly how the defect this suite covers stayed invisible. This job
# touches nothing but checkout, so its square always reflects the suite.
shell-contract:
name: Composite shell contract
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- run: bash tests/composite-shell-contract.sh

test:
name: Gate controls
runs-on: ubuntu-latest
Expand Down
15 changes: 13 additions & 2 deletions actions/required-files-check/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ runs:
# .txt licence texts
# fixed names GitHub or convention dictates (CODEOWNERS, funding.yml,
# NOTICE, AUTHORS, MAINTAINERS) keep their form
# GitHub runs a composite step as `bash --noprofile --norc -e -o pipefail`.
# That `-e` comes from the harness, not from here, and `set -uo pipefail`
# does NOT clear it. It directly contradicts this gate's design: the whole
# script accumulates `fail=1` so it can report EVERY defect and exit once
# at the end. Under `-e` the first non-zero command kills the step instead,
# silently, before the line that would have explained itself.
# Measured 2026-09-22 on pons-asinorum: a comment-only CODEOWNERS made
# `grep -v ... | wc -l` exit 1, which killed the step one line ABOVE the
# message declaring that exact file valid. The count sites below are also
# individually guarded, so the contract survives someone re-adding `-e`.
set +e
set -uo pipefail
fail=0

Expand Down Expand Up @@ -100,7 +111,7 @@ runs:
CODEOWNERS)
# Rule 1: Solo-owned repos may have comment-only CODEOWNERS
# Check if file has any functional (non-comment) lines
functional_lines=$(grep -vE '^\s*(#|//|;|$)' "$f" | wc -l)
functional_lines=$(grep -cvE '^\s*(#|//|;|$)' "$f" || true) # || true: grep exits 1 on a comment-only file
if [ "$functional_lines" -eq 0 ]; then
# File is all comments - this is valid for solo-maintained repos per CODEOWNERS-POLICY.adoc Rule 1
echo " CODEOWNERS is comment-only (valid for solo-maintained repos per Rule 1)"
Expand All @@ -114,7 +125,7 @@ runs:
esac

# Documents are judged on substance.
body=$(grep -vE '^\s*(#|//|;|$)' "$f" | wc -l)
body=$(grep -cvE '^\s*(#|//|;|$)' "$f" || true) # || true: grep exits 1 on an all-comment file
if [ "$body" -lt 5 ]; then
echo "::error::$f has $body substantive lines — a stub, not a document."
fail=1
Expand Down
7 changes: 6 additions & 1 deletion actions/spdx-license-check/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ runs:
# Check that files have SPDX lines (heuristic check on some files)
# We ensure at least one SPDX line for code and one for docs is found in the repo

has_spdx=$(git grep -i "SPDX-License-Identifier" | wc -l)
# GitHub runs this step as `bash -e -o pipefail`. `git grep` exits 1 when
# it matches nothing, so without the guard below the ZERO-SPDX case — the
# only case this check exists to detect — killed the step outright, making
# the `::warning::` branch beneath unreachable and inverting the stated
# intent of the comment beside it. Measured 2026-09-22.
has_spdx=$({ git grep -i "SPDX-License-Identifier" || true; } | wc -l)
if [ "$has_spdx" -eq 0 ]; then
echo "::warning::No SPDX-License-Identifier lines found in the repository."
# exit 1 (disabled strictly to prevent total CI blockage until adoption)
Expand Down
156 changes: 156 additions & 0 deletions tests/composite-shell-contract.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
#
# Composite shell contract test.
#
# GitHub runs every composite `shell: bash` step as:
# bash --noprofile --norc -e -o pipefail {0}
#
# The `-e` is supplied by the harness, not by the script, and a script's own
# `set -uo pipefail` does NOT clear it. Any `x=$(grep ... )` is therefore a
# silent kill site whenever grep legitimately matches nothing.
#
# Two gates were dying that way on 2026-09-22 (measured on pons-asinorum):
#
# required-files-check a comment-only CODEOWNERS killed the step ONE LINE
# ABOVE the message declaring that exact file valid.
# spdx-license-check a repo with zero SPDX lines killed the step, making
# the `::warning::` branch beneath it unreachable and
# inverting the intent stated in its own comment.
#
# This suite reproduces the CI shell exactly, and — critically — kills a mutant.
# A gate suite that only ever goes green proves nothing.

set -uo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PASS=0; FAIL=0
ok() { printf ' ok %s\n' "$1"; PASS=$((PASS+1)); }

Check warning on line 28 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlj&open=AaDK8ODkoPthVyfSYqlj&pullRequest=32
bad() { printf ' FAIL %s\n' "$1"; FAIL=$((FAIL+1)); }

Check warning on line 29 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlk&open=AaDK8ODkoPthVyfSYqlk&pullRequest=32

command -v yq >/dev/null || { echo "yq is required (Y-1: gates read YAML with yq, never grep)"; exit 2; }

WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT

# --- the fixture: a repo that is VALID under every rule these gates state ----
# Solo-maintained (comment-only CODEOWNERS, explicitly valid per Rule 1) and
# carrying no SPDX headers (the case spdx-license-check exists to warn about).
FIX="$WORK/fixture"
mkdir -p "$FIX/crates"
cd "$FIX"
git init -q .
: > .editorconfig
: > .gitignore
: > .gitattributes
mkdir -p .github
cat > .github/CODEOWNERS <<'EOF'
# Solo-maintained repository.
# No path-specific owners are assigned; the sole maintainer owns everything.
EOF
cat > GOVERNANCE.adoc <<'EOF'
= Governance
This repository is maintained by a single owner.
Decisions are recorded in the issue tracker.
Changes land through pull requests.
Releases are tagged from main.
EOF
cat > ARCHITECTURE.adoc <<'EOF'
= Architecture
The implementation lives under crates/ in this repository.
Each crate is an independent unit.
Tests live beside the code they cover.
Build orchestration is a justfile.
EOF
cat > MAINTAINERS <<'EOF'
# Maintainers
hyperpolymath is the sole maintainer of this repository.
Contact goes through the issue tracker.
Security reports follow the disclosure policy.
Releases are cut by the maintainer.
Pull requests are reviewed by the maintainer before merge.
EOF
: > mise.toml
git add -A >/dev/null 2>&1
git -c user.email=t@example.invalid -c user.name=t commit -qm init >/dev/null 2>&1

# --- run a composite's script under the EXACT CI shell ----------------------
extract() { yq -r '.runs.steps[0].run' "$ROOT/actions/$1/action.yml"; }

Check warning on line 78 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqll&open=AaDK8ODkoPthVyfSYqll&pullRequest=32

Check warning on line 78 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlm&open=AaDK8ODkoPthVyfSYqlm&pullRequest=32

# Runs a composite script under the exact CI shell. The result cannot come back
# through a command substitution — that would run this in a subshell and lose
# the exit code — so it lands in $GATE_OUT / $GATE_RC.
GATE_OUT="$WORK/gate.out"
run_gate() { # <script>

Check warning on line 84 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlo&open=AaDK8ODkoPthVyfSYqlo&pullRequest=32
( cd "$FIX" && REPO_OWNER=hyperpolymath REPO_NAME=hyperpolymath/fixture \
bash --noprofile --norc -e -o pipefail "$1" ) > "$GATE_OUT" 2>&1

Check warning on line 86 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqln&open=AaDK8ODkoPthVyfSYqln&pullRequest=32
GATE_RC=$?
}

echo "== required-files-check on a valid solo-maintained repo =="
RF="$WORK/required-files.sh"; extract required-files-check > "$RF"
bash -n "$RF" || bad "extracted required-files script is not valid bash"
run_gate "$RF"
RC=$GATE_RC; OUT="$(cat "$GATE_OUT")"
[ "$RC" -eq 0 ] && ok "exits 0 (was 1: -e killed it at the comment-only CODEOWNERS)" \

Check failure on line 95 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlp&open=AaDK8ODkoPthVyfSYqlp&pullRequest=32
|| { bad "exits $RC, expected 0"; printf '%s\n' "$OUT" | sed 's/^/ /'; }
case "$OUT" in
*"CODEOWNERS is comment-only"*) ok "prints the Rule 1 acceptance it previously died before reaching" ;;
*) bad "never reached the Rule 1 acceptance message" ;;
esac
case "$OUT" in
*"All required files present"*) ok "reaches its own success line" ;;
*) bad "did not reach the success line" ;;
esac

echo "== spdx-license-check on a repo with zero SPDX headers =="
cp "$ROOT/LICENSE" "$FIX/LICENSE" 2>/dev/null || echo "MPL-2.0" > "$FIX/LICENSE"
SP="$WORK/spdx.sh"; extract spdx-license-check > "$SP"
bash -n "$SP" || bad "extracted spdx script is not valid bash"
run_gate "$SP"
RC=$GATE_RC; OUT="$(cat "$GATE_OUT")"
[ "$RC" -eq 0 ] && ok "exits 0 (was 1: -e killed it on the zero-match git grep)" \

Check failure on line 112 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlq&open=AaDK8ODkoPthVyfSYqlq&pullRequest=32
|| { bad "exits $RC, expected 0"; printf '%s\n' "$OUT" | sed 's/^/ /'; }
case "$OUT" in
*"::warning::No SPDX-License-Identifier lines found"*)
ok "the zero-SPDX warning branch is reachable at all" ;;
*) bad "zero-SPDX branch still unreachable — the check cannot detect what it exists for" ;;
esac

# --- MUTANT: restore the pre-fix form; the suite MUST go red ----------------
# Without this, every assertion above could be passing vacuously. Two things
# have to be true for the mutant to mean anything: it must PARSE (a mutant that
# fails `bash -n` produces a fake red), and the mutation must actually have been
# APPLIED (a no-op sed produces a fake green). Both are asserted, because both
# have already happened once while writing this file.
echo "== mutant: reinstate the unguarded count pipeline =="
MUT="$WORK/mutant.sh"
perl -pe 's/\$\(grep -cvE (.+?) \|\| true\).*$/\$(grep -vE $1 | wc -l)/' "$RF" > "$MUT"
perl -pi -e 's/^\s*set \+e\s*$/# (mutant) set +e removed\n/' "$MUT"

MUT_OK=1
grep -q 'wc -l' "$MUT" || { bad "mutant: count pipeline was not reinstated"; MUT_OK=0; }
grep -qE '^[[:space:]]*set \+e' "$MUT" && { bad "mutant: set +e was not removed"; MUT_OK=0; }

if [ "$MUT_OK" -eq 1 ] && bash -n "$MUT" 2>/dev/null; then

Check failure on line 135 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlr&open=AaDK8ODkoPthVyfSYqlr&pullRequest=32
ok "mutant parses and both mutations applied"
run_gate "$MUT"
RC=$GATE_RC; OUT="$(cat "$GATE_OUT")"
if [ "$RC" -ne 0 ]; then

Check failure on line 139 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqls&open=AaDK8ODkoPthVyfSYqls&pullRequest=32
# It must die for the RIGHT reason: silently, with no ::error:: of its
# own. A red caused by fixture drift would prove nothing about -e.
if printf '%s' "$OUT" | grep -q '::error::'; then
bad "mutant died with an ::error:: — that is a substance failure, not the -e kill"
else
ok "mutant dies SILENTLY (rc=$RC), no ::error:: — the -e kill is reproduced"
fi
else
bad "mutant SURVIVED: the suite does not actually test the -e contract"
fi
elif [ "$MUT_OK" -eq 1 ]; then

Check failure on line 150 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlt&open=AaDK8ODkoPthVyfSYqlt&pullRequest=32
bad "mutant does not parse — cannot prove non-vacuity"
fi

echo
echo "PASS=$PASS FAIL=$FAIL"
[ "$FAIL" -eq 0 ]

Check failure on line 156 in tests/composite-shell-contract.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaDK8ODkoPthVyfSYqlu&open=AaDK8ODkoPthVyfSYqlu&pullRequest=32
Loading