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
38 changes: 22 additions & 16 deletions .github/workflows/governance-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1115,24 +1115,19 @@ jobs:
# governance jobs on every PR estate-wide. github.sha resolves to the
# same merge commit but is always fetchable.
ref: ${{ github.sha }}
- name: Checkout standards for the duplicate-key check
- name: Checkout the pinned Standards policy helpers
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: hyperpolymath/standards
ref: main
# Execute helper code from the same immutable Standards revision as
# this reusable workflow. A moving `main` checkout would let a caller
# pinned to workflow revision X execute implementation revision Y.
ref: ${{ job.workflow_sha }}
path: .standards-dupkey
sparse-checkout: |
scripts/check-workflow-duplicate-keys.sh
tools/policy/check-workflows-parse.sh
sparse-checkout-cone-mode: false
# ⚠ Not fatal if the file is absent. This checkout is pinned to
# standards@main, so during a rename of the script the fetch finds
# nothing — the new name does not exist on main until the renaming pull
# request merges. Without this, the RENAME ITSELF fails the linter, on
# the one pull request that cannot possibly be at fault. See the
# fallback in the next step.
continue-on-error: true

- name: Parse every tracked workflow
run: |
if [ "$GITHUB_REPOSITORY" = hyperpolymath/standards ]; then
Expand All @@ -1142,7 +1137,7 @@ jobs:
SCRIPT=".standards-dupkey/tools/policy/check-workflows-parse.sh"
fi
if [ ! -f "$SCRIPT" ]; then
echo "::error::workflow parser gate not found in standards@main or locally"
echo "::error::workflow parser gate not found in the pinned Standards revision or locally"
exit 1
fi
bash "$SCRIPT"
Expand All @@ -1157,10 +1152,9 @@ jobs:
# were dead this way, including a CodeQL workflow with zero
# successful runs in its entire lifetime.
set -euo pipefail
# Standards must exercise its pull-request scripts; every consumer
# must use the canonical scripts fetched from standards@main. A
# file-existence fallback is insufficient because the old script on
# main still exists while its replacement is being tested.
# Standards exercises its pull-request scripts; every consumer uses
# the canonical scripts fetched from this workflow's immutable
# Standards revision.
if [ "$GITHUB_REPOSITORY" = hyperpolymath/standards ]; then
SCRIPT="scripts/check-workflow-duplicate-keys.sh"
echo "Using this repository's own copy (standards self-lint)."
Expand All @@ -1169,13 +1163,25 @@ jobs:
fi
if [ ! -f "$SCRIPT" ]; then
echo "::error::duplicate-key checker not found — neither fetched from" \
"standards@main nor present locally."
"the pinned Standards revision nor present locally."
exit 1
fi
cp "$SCRIPT" "$RUNNER_TEMP/dupkeys.sh"
# The lockfile gate below runs in a consumer checkout, where the
# standards helper is not present. Preserve the canonical helper
# before removing this sparse standards checkout.
if [ "$GITHUB_REPOSITORY" = hyperpolymath/standards ]; then
LOCK_SCRIPT="scripts/update-actions-lock.sh"
echo "Using this repository's own actions-lock verifier (standards self-lint)."
else
LOCK_SCRIPT=".standards-dupkey/scripts/update-actions-lock.sh"
fi
if [ ! -f "$LOCK_SCRIPT" ]; then
echo "::error::actions-lock verifier not found — neither fetched from" \
"the pinned Standards revision nor present locally."
exit 1
fi
cp "$LOCK_SCRIPT" "$RUNNER_TEMP/update-actions-lock.sh"
rm -rf .standards-dupkey
bash "$RUNNER_TEMP/dupkeys.sh" .github/workflows

Expand Down
38 changes: 1 addition & 37 deletions .github/workflows/self-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,40 +54,4 @@ jobs:
python3 -m pip install --user --quiet pyyaml

- name: Run tests/*.sh and scripts/tests/*.sh
run: |
set -uo pipefail

mapfile -t TESTS < <(
{
find tests -maxdepth 1 -name '*.sh' -type f
find scripts/tests -maxdepth 1 -name '*.sh' -type f
} | sort
)

# Fail closed. If the suite is empty the discovery is broken, and a
# green tick here would assert something untrue.
if [ ${#TESTS[@]} -eq 0 ]; then
echo "::error::No tests found under tests/ or scripts/tests/ — discovery is broken."
exit 1
fi
echo "Discovered ${#TESTS[@]} test file(s)."

failed=0
for t in "${TESTS[@]}"; do
echo "::group::$t"
if bash "$t"; then
echo "PASS $t"
else
rc=$?
echo "::error file=$t::$t failed (exit $rc)"
failed=$((failed+1))
fi
echo "::endgroup::"
done

echo
if [ "$failed" -gt 0 ]; then
echo "::error::$failed of ${#TESTS[@]} test file(s) failed."
exit 1
fi
echo "All ${#TESTS[@]} test file(s) passed."
run: bash scripts/run-shell-test-suite.sh
2 changes: 1 addition & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ build:

# Run all sub-project test suites
test:
# K9 Rust binding tests now live in hyperpolymath/k9-ecosystem (rs/) — see #491
@bash scripts/run-shell-test-suite.sh

# Regression test: test aggregation fails for missing prerequisites and test failures.
test-runner-test:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: MPL-2.0
# Allowlist Preflight — surfaces an Actions-allowlist gap as an ORDINARY red
# check instead of an opaque, estate-wide `startup_failure` blackout.
# Allowlist Preflight — thin, reproducible caller of the canonical focused
# Standards implementation. It surfaces an Actions-allowlist gap as an
# ordinary red check instead of an opaque `startup_failure` blackout.
#
# Under `allowed_actions: selected`, a workflow that `uses:` an un-allowlisted
# action/reusable dies at STARTUP with no job and no log. This job uses ONLY
Expand All @@ -27,14 +28,4 @@ concurrency:
jobs:
allowlist:
name: Actions allowlist coverage
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Every workflow `uses:` must be on the canonical allowlist
run: |
# Fetch the estate detector; it fetches the canonical allowlist itself.
curl -fsSL https://raw.githubusercontent.com/hyperpolymath/standards/main/scripts/check-allowed-actions.sh -o "${RUNNER_TEMP}/check-allowed-actions.sh"
bash "${RUNNER_TEMP}/check-allowed-actions.sh"
uses: hyperpolymath/standards/.github/workflows/allowlist-preflight-reusable.yml@f8cc276bb0add12debc9eddce79e2a842bac5d3e
41 changes: 41 additions & 0 deletions scripts/run-shell-test-suite.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# Canonical fail-closed shell test discovery used by CI and `just test`.
set -uo pipefail

mapfile -t TESTS < <(
{
find tests -maxdepth 1 -name '*.sh' -type f
find scripts/tests -maxdepth 1 -name '*.sh' -type f
} | sort
)

if [ "${#TESTS[@]}" -eq 0 ]; then

Check failure on line 13 in scripts/run-shell-test-suite.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_standards&issues=AaBZdiU9tTCy1S7t087H&open=AaBZdiU9tTCy1S7t087H&pullRequest=697
echo "ERROR: no tests found under tests/ or scripts/tests/ — discovery is broken." >&2
exit 1
fi

echo "Discovered ${#TESTS[@]} test file(s)."
failed=0

for test_file in "${TESTS[@]}"; do
echo "::group::$test_file"

if bash "$test_file"; then
echo "PASS $test_file"
else
status=$?
echo "::error file=$test_file::$test_file failed (exit $status)"

Check warning on line 28 in scripts/run-shell-test-suite.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Redirect this error message to stderr (>&2).

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaBZdiU9tTCy1S7t087I&open=AaBZdiU9tTCy1S7t087I&pullRequest=697
failed=$((failed + 1))
fi

echo "::endgroup::"
done

echo
if [ "$failed" -gt 0 ]; then

Check failure on line 36 in scripts/run-shell-test-suite.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_standards&issues=AaBZdiU9tTCy1S7t087J&open=AaBZdiU9tTCy1S7t087J&pullRequest=697
echo "ERROR: $failed of ${#TESTS[@]} test file(s) failed." >&2
exit 1
fi

echo "All ${#TESTS[@]} test file(s) passed."
14 changes: 7 additions & 7 deletions scripts/tests/actions-lock-update-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ cat > "$WORK/bin/fake-gh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if [ "${2:-}" = "--verify-local" ]; then
grep -q "actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1" \
grep -q "actions/checkout@v7.0.1" \
.github/workflows/actions.lock
sed -i 's#uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1#uses: actions/checkout@v7.0.1#' \
.github/workflows/ci.yml
sed -i '1i# verifier-only mutation' .github/workflows/ci.yml
case "${FAKE_VERIFY_FINDING:-}" in
reusable-exact)
printf '%s\n' '{"valid":false,"findings":[{"workflow":".github/workflows/reusable.yml","category":"stale","dependency":"hyperpolymath/standards@abc123"}]}'
Expand Down Expand Up @@ -60,7 +59,8 @@ if [ "${2:-}" = "--verify-local" ]; then
;;
esac
fi
sed -i '1i# This workflow is managed by gh actions-lock.' .github/workflows/ci.yml
grep -q '^# This workflow is managed by gh actions-lock.$' .github/workflows/ci.yml ||
sed -i '1i# This workflow is managed by gh actions-lock.' .github/workflows/ci.yml
sed -i 's#actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1#actions/checkout@v7.0.1#' \
.github/workflows/ci.yml
cat > .github/workflows/actions.lock <<'LOCK'
Expand All @@ -81,10 +81,10 @@ chmod +x "$WORK/bin/fake-gh"
cd "$WORK"
GH_BIN="$WORK/bin/fake-gh" bash "$UPDATE" .github/workflows >/dev/null

grep -q 'uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' \
grep -q 'uses: actions/checkout@v7.0.1' \
.github/workflows/ci.yml
[ "$(grep -c '^# This workflow is managed by gh actions-lock.$' .github/workflows/ci.yml)" -eq 1 ]
grep -q "'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1':" \
grep -q "'actions/checkout@v7.0.1':" \
.github/workflows/actions.lock

cp .github/workflows/ci.yml "$WORK/ci.before"
Expand All @@ -93,7 +93,7 @@ GH_BIN="$WORK/bin/fake-gh" bash "$UPDATE" .github/workflows >/dev/null
cmp -s "$WORK/ci.before" .github/workflows/ci.yml
cmp -s "$WORK/lock.before" .github/workflows/actions.lock

echo "PASS: Actions lock refresh preserves inline SHA source and is idempotent"
echo "PASS: Actions lock refresh keeps authoritative symbolic source and is idempotent"

# Verification is mutating in released gh-actions-lock versions too. The safe
# verification mode must restore workflow bytes while leaving the lock intact.
Expand Down
59 changes: 59 additions & 0 deletions scripts/tests/governance-reusable-contract-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# Static regression contract for the reusable governance boundaries.
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
GOVERNANCE="$ROOT/.github/workflows/governance-reusable.yml"
FOCUSED="$ROOT/.github/workflows/allowlist-preflight-reusable.yml"
RSR_SEED="$ROOT/rhodium-standard-repositories/.github/workflows/allowlist-preflight.yml"
LOCK_HELPER="$ROOT/scripts/update-actions-lock.sh"

fail() {
echo "FAIL: $*" >&2
exit 1
}

helper_checkout="$(grep -F -A 18 -- '- name: Checkout the pinned Standards policy helpers' "$GOVERNANCE")"
# GitHub expression is an asserted literal.
# shellcheck disable=SC2016
printf '%s\n' "$helper_checkout" | grep -Fq 'ref: ${{ job.workflow_sha }}' ||
fail "governance helpers are not fetched from job.workflow_sha"
if printf '%s\n' "$helper_checkout" | grep -Eq '^[[:space:]]*ref:[[:space:]]*main[[:space:]]*$'; then
fail "governance helper execution still follows moving main"
fi

if grep -Fq 'bash scripts/update-actions-lock.sh --verify-local' "$GOVERNANCE"; then
fail "reusable governance still assumes a consumer-local Standards helper"
fi
# RUNNER_TEMP is an asserted workflow literal.
# shellcheck disable=SC2016
grep -Fq 'bash "$RUNNER_TEMP/update-actions-lock.sh" --verify-local' "$GOVERNANCE" ||
fail "reusable governance does not execute the staged pinned lock verifier"

for workflow in "$GOVERNANCE" "$FOCUSED"; do
grep -Fq 'Live Actions policy (credentialed advisory)' "$workflow" ||
fail "$workflow lacks the distinct live-policy advisory job"
grep -Fq "if: \${{ env.GH_TOKEN == '' }}" "$workflow" ||
fail "$workflow does not report a missing optional credential"
grep -Fq "if: \${{ env.GH_TOKEN != '' }}" "$workflow" ||
fail "$workflow can run the live API without a credential guard"
# rc is an asserted workflow-script literal.
# shellcheck disable=SC2016
grep -Fq 'if [ "$rc" -eq 3 ]; then' "$workflow" ||
fail "$workflow conflates API unavailability with a policy verdict"
done

grep -Eq 'uses: hyperpolymath/standards/.github/workflows/allowlist-preflight-reusable.yml@[0-9a-f]{40}$' \
"$RSR_SEED" || fail "RSR allowlist seed is not a thin immutable reusable-workflow caller"
if grep -Eq 'raw\.githubusercontent\.com/.*/main|curl[[:space:]]' "$RSR_SEED"; then
fail "RSR allowlist seed still downloads executable policy from moving main"
fi

grep -Fq 'when actions.lock is present, gh actions-lock is authoritative' "$LOCK_HELPER" ||
fail "lock helper does not state the authoritative-lock contract"
if grep -Fq 'relock-sha-keys.sh' "$LOCK_HELPER"; then
fail "lock helper still rewrites generated lock keys around legacy inline SHAs"
fi

echo "PASS: reusable governance uses one pinned implementation with focused and suite entry points"
Loading
Loading