From e4641cae27a56264ea3e731d893a07ed5bbbe03b Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Tue, 6 Oct 2026 14:44:44 +0100 Subject: [PATCH 1/2] fix(lock): restore Asana/push-signed-commits entry dropped by #1160 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #1160 relock regenerated actions.lock from .github/workflows/ only and dropped the dependency used by the composite action .github/actions/signed-push/action.yml:42. `uses ⊆ actions.lock` has been red on main since ce92a8cd ("not in actions.lock: Asana/push-signed-commits@d615ca88"). This restores the entry byte for byte as it stood on 5751b97e (ref v1.3, same commit and ids, same transitive uses). Verified: .githooks/validate-actions-lock.sh rc=1 before (1 ref missing), rc=0 after (26/26); scripts/check-lock-sync.sh rc=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01P48P9ErT8UFFeDUfEQiYV7 --- .github/workflows/actions.lock | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index 779b73296..a28bbd2e2 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -215,6 +215,13 @@ dependencies: repo_id: 496012378 uses: - 'actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f' + 'asana/push-signed-commits@d615ca88d8e1a946734c24970d1e7a6c56f34897': + ref: 'v1.3' + commit: 'sha1-d615ca88d8e1a946734c24970d1e7a6c56f34897' + owner_id: 1472111 + repo_id: 772313726 + uses: + - 'actions/setup-python@v2' 'dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067': ref: 'v1' commit: 'sha1-7e38f4b43b4db5c8dd498af069a4f6196df1d067' From 824b98ab5bdc1a68c7c283a70aa61dc18243cd54 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Tue, 6 Oct 2026 14:46:11 +0100 Subject: [PATCH 2/2] fix(governance): R5 scan no longer exits silently under bash -e The R5 step runs under `bash -e`. A bare `out=$(grep ...)` that matched nothing returned 1 and killed the step before `rc` was read, so a clean file aborted the scan with no message. Capture the status with `|| rc=$?` instead. tests/test_governance_r5_bash_e.sh drives the extracted loop: RED 3/4 before the fix (no-match case exited early), GREEN 4/4 after. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01P48P9ErT8UFFeDUfEQiYV7 --- .github/workflows/governance-reusable.yml | 6 +- tests/test_governance_r5_bash_e.sh | 80 +++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100755 tests/test_governance_r5_bash_e.sh diff --git a/.github/workflows/governance-reusable.yml b/.github/workflows/governance-reusable.yml index 6150c2b2a..b02ce9792 100644 --- a/.github/workflows/governance-reusable.yml +++ b/.github/workflows/governance-reusable.yml @@ -977,7 +977,11 @@ jobs: if [ -n "$canon" ] && [ "$f_" = "$canon" ]; then continue; fi [ -f "$f_" ] || continue for pat in "${pats[@]}"; do - out=$(grep -nE -e "$pat" -- "$f_" 2>"$err"); rc=$? + # The step runs under `bash -e`: a bare `out=$(grep …)` that matches nothing + # returns 1 and kills the step silently before rc is read. `|| rc=$?` keeps + # the status without tripping -e. + rc=0 + out=$(grep -nE -e "$pat" -- "$f_" 2>"$err") || rc=$? if [ "$rc" -eq 0 ]; then while IFS= read -r line; do echo "::error file=$f_,line=${line%%:*}::[R5:$rid] ${line#*:} → route to ${canon:-drop or move to a canonical source}" diff --git a/tests/test_governance_r5_bash_e.sh b/tests/test_governance_r5_bash_e.sh new file mode 100755 index 000000000..63baf2b05 --- /dev/null +++ b/tests/test_governance_r5_bash_e.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell +# +# test_governance_r5_bash_e.sh — runs the R5 canonical-reference drift step of +# .github/workflows/governance-reusable.yml exactly as a runner does: the step's +# `run:` text, extracted with yq, under `bash -e` (a step with no `shell:` runs +# as `bash -e {0}` on ubuntu runners). +# +# Regression: under `-e`, `out=$(grep …)` on an include file with no match +# returned 1 and aborted the step before `rc=$?` — exit 1, no output, no +# annotation. echidna#410 went red on clean content. The planted-hit cases are +# the positive control: a real drift must still fail and name the line. +# +# Run: bash tests/test_governance_r5_bash_e.sh +set -uo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +F="$ROOT/.github/workflows/governance-reusable.yml" +STEP='Canonical-reference drift (R5 generic)' +WORK="$(mktemp -d)" +trap 'rm -rf "$WORK"' EXIT +pass=0; fail=0 + +# Print the R5 step's run: text; fail the suite if the step cannot be found. +extract_step() { + yq -r ".jobs.\"security-policy\".steps[] | select(.name == \"$STEP\") | .run" "$F" +} + +# Build a fixture repo in $1 with one rule over the given include files. +# Remaining args are "path:content" pairs written into the fixture. +make_fixture() { + local dir="$1"; shift + mkdir -p "$dir/.github/canonical-references" + cat > "$dir/.github/canonical-references/drift.yml" <<'RULE' +id: test-drift +description: planted drift marker +canonical_pointer: CANON.md +patterns: + - "DRIFT_MARKER_[0-9]+" +scope: + include: [a.md, b.md] +RULE + local pair + for pair in "$@"; do printf '%s\n' "${pair#*:}" > "$dir/${pair%%:*}"; done +} + +# assert