Skip to content

Commit 3f10bdb

Browse files
hyperpolymathclaude
andcommitted
fix(governance): honour .hypatia-ignore / inline pragma for banned-language files
The ReScript/Go/Python anti-pattern steps did a naive `find` with no exemption path, ignoring the estate's declared machine-readable escape (`.hypatia-ignore` rule `cicd_rules/banned_language_file` + inline `# hypatia:ignore` pragma) that the Hypatia scanner itself honours. Re-emergence of a banned default despite a declared escape is a tooling defect per the Explicit-Escape Principle. Adds a shared exemption filter to those three checks; non-exempt files still fail (verified), clean repos no longer false-fail under pipefail. Unblocks hypatia#270 (and transitively #271), whose intentionally exempted criterion bench scripts were tripping the shared gate. Refs standards#72 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9b23627 commit 3f10bdb

1 file changed

Lines changed: 54 additions & 25 deletions

File tree

.github/workflows/governance-reusable.yml

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -134,34 +134,63 @@ jobs:
134134
print(f"✅ No TypeScript files outside allowlist ({len(exemption_patterns)} per-repo exemption(s) parsed).")
135135
PYEOF
136136
137-
- name: Check for ReScript
137+
# Shared escape hatch for the banned-language-file checks below.
138+
# Honours the estate's declared machine-readable exemption (standards#72,
139+
# Explicit-Escape Principle): a file is exempt from the
140+
# `cicd_rules/banned_language_file` rule if EITHER
141+
# * `.hypatia-ignore` contains the exact line
142+
# `cicd_rules/banned_language_file:<relpath>`, OR
143+
# * the file carries an inline `# hypatia:ignore ...
144+
# cicd_rules/banned_language_file` pragma in its first 8 lines
145+
# — the same escape the Hypatia scanner itself honours.
146+
- name: Check for ReScript / Go / Python (banned language files)
138147
run: |
139-
RES_FILES=$(find . -name "*.res" | grep -v node_modules || true)
140-
if [ -n "$RES_FILES" ]; then
141-
echo "❌ ReScript files detected - use AffineScript instead"
142-
echo "$RES_FILES"
143-
exit 1
144-
fi
145-
echo "✅ No ReScript files"
148+
rule="cicd_rules/banned_language_file"
146149
147-
- name: Check for Go
148-
run: |
149-
if find . -name "*.go" | grep -q .; then
150-
echo "❌ Go files detected - use Rust/WASM instead"
151-
find . -name "*.go"
152-
exit 1
153-
fi
154-
echo "✅ No Go files"
150+
is_exempt() {
151+
f="${1#./}"
152+
if [ -f .hypatia-ignore ] && grep -qxF "${rule}:${f}" .hypatia-ignore; then
153+
return 0
154+
fi
155+
if head -n 8 "$1" 2>/dev/null | grep -q "hypatia:ignore.*${rule}"; then
156+
return 0
157+
fi
158+
return 1
159+
}
155160
156-
- name: Check for Python (non-SaltStack)
157-
run: |
158-
PY_FILES=$(find . -name "*.py" | grep -v salt | grep -v _states | grep -v _modules | grep -v pillar | grep -v venv | grep -v __pycache__ || true)
159-
if [ -n "$PY_FILES" ]; then
160-
echo "❌ Python files detected - only allowed for SaltStack"
161-
echo "$PY_FILES"
162-
exit 1
163-
fi
164-
echo "✅ No non-SaltStack Python files"
161+
# $1 = human label, $2 = remediation hint, $3 = newline-separated
162+
# candidate paths (possibly empty). Reads via here-string so this
163+
# runs in the current shell — no subshell, exit propagates.
164+
enforce() {
165+
label="$1"; hint="$2"; candidates="$3"; violations=""
166+
while IFS= read -r f; do
167+
[ -z "$f" ] && continue
168+
if is_exempt "$f"; then
169+
echo "⏭️ exempt (${rule}): $f"
170+
continue
171+
fi
172+
violations="${violations}${f}
173+
"
174+
done <<< "$candidates"
175+
if [ -n "$(printf '%s' "$violations" | tr -d '[:space:]')" ]; then
176+
echo "❌ ${label} detected - ${hint}"
177+
printf '%s' "$violations"
178+
echo " (declare an exemption via .hypatia-ignore or an inline"
179+
echo " '# hypatia:ignore ${rule}' pragma if intentional)"
180+
exit 1
181+
fi
182+
echo "✅ No non-exempt ${label}"
183+
}
184+
185+
RES_FILES=$(find . -name "*.res" | grep -v node_modules || true)
186+
GO_FILES=$(find . -name "*.go" || true)
187+
PY_FILES=$(find . -name "*.py" | grep -v salt | grep -v _states \
188+
| grep -v _modules | grep -v pillar | grep -v venv \
189+
| grep -v __pycache__ || true)
190+
191+
enforce "ReScript files" "use AffineScript instead" "$RES_FILES"
192+
enforce "Go files" "use Rust/WASM instead" "$GO_FILES"
193+
enforce "Python files" "only allowed for SaltStack" "$PY_FILES"
165194
166195
- name: Check for npm/bun artifacts
167196
run: |

0 commit comments

Comments
 (0)