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
2 changes: 0 additions & 2 deletions .github/workflows/actions.lock
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ workflows:
- 'softprops/action-gh-release@v3.0.3'
'.github/workflows/rsr-compliance-canary.yml':
- 'actions/checkout@v7.0.1'
'.github/workflows/runtime-policy.yml':
- 'actions/checkout@v7.0.1'
'.github/workflows/rust-ci.yml':
- 'hyperpolymath/standards@75bd5994470661a099df562d6d5ad2fe744dbd66'
'.github/workflows/scorecard.yml':
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/estate-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ jobs:
# and the sync gate names each one if its record goes missing.
- name: actions.lock SHA-ref regression controls
run: bash tests/workflows/actions_lock_sha_refs_test.sh
# The gate above must reject each way the retired runtime policy could
# come back, including a workflow and lock record restored together.
- name: Runtime policy retirement guards reject each regression
run: bash tests/workflows/runtime_policy_retirement_test.sh
# The Scorecard calling job's own permissions map must grant actions: read;
# the workflow-level grant does not reach a job that declares its own map.
- name: Scorecard caller grants
Expand Down
72 changes: 0 additions & 72 deletions .github/workflows/runtime-policy.yml

This file was deleted.

19 changes: 19 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
== Changelog
Comment thread
coderabbitai[bot] marked this conversation as resolved.

== 2026-10-19 — runtime-policy.yml folded into governance

* `.github/workflows/runtime-policy.yml` is removed, with its
`actions.lock` record, as rsr-template-repo#244 does at the source. This
repository's copy still said Deno was retired. It failed any repository
holding `bun.lock`, `deno.lock` and `pnpm-lock.yaml` together, which is
what `js-runtimes regen` writes. Governance already covers the check.
"Language / package anti-pattern policy" fails any tracked
`package-lock.json`, and the "JS runtimes" jobs check each lock against
`package.json` (standards cicd-regularisation spec §14).
* `scripts/validate-template.sh` and
`tests/workflows/validate_workflows_test.sh` require `governance.yml` in
its place. `tests/workflows/runtime_policy_migration_test.sh` checks both
validators reject a tree without `governance.yml`, and
`actions_lock_sha_refs_test.sh`, which Estate Rules runs, requires the
workflow and its lock record to stay gone and runs that test.
`tests/workflows/runtime_policy_retirement_test.sh`, also in Estate Rules,
restores the workflow or its lock record in each way the gate must catch
and checks the gate rejects every one.

== 2026-10-19 — lock records carry tag refs; standards re-pinned to `75bd599`

Expand Down
6 changes: 5 additions & 1 deletion scripts/validate-template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,11 @@ REQUIRED_WORKFLOWS=(
# none of the 55 repos carrying it ever adopted Bun. This list was not
# updated, so it has required two files the template deliberately no longer
# ships — which is why validate-template.sh has been red since that merge.
"runtime-policy.yml"
# runtime-policy.yml is folded into governance in turn (standards
# cicd-regularisation spec §14): "Language / package anti-pattern policy"
# fails any tracked package-lock.json and the "JS runtimes" jobs check each
# lock against package.json. So governance.yml is what this list requires.
"governance.yml"
"secret-scanner.yml"
)

Expand Down
18 changes: 18 additions & 0 deletions tests/workflows/actions_lock_sha_refs_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ command -v jq >/dev/null || fail "jq is required"
yq --version | grep -q 'github.com/mikefarah/yq/' || fail "mikefarah yq v4 is required"
yq -o=json '.' "$LOCK" > "$FIXTURE/lock.json"

# Folding runtime policy into governance must remove both the workflow and
# its lock entry. A valid, fully locked legacy workflow would pass sync alone.
[[ ! -e "$WF_DIR/runtime-policy.yml" && ! -L "$WF_DIR/runtime-policy.yml" ]] \
|| fail "runtime-policy.yml must remain folded into governance"
jq -e '.workflows | has(".github/workflows/runtime-policy.yml") | not' \
"$FIXTURE/lock.json" >/dev/null || fail "runtime-policy.yml must not retain a lock entry"
echo "PASS: retired runtime-policy workflow and lock entry are absent"

# Use the standards pin actually called by governance, so a later standards
# update does not require copying its commit into this test.
STANDARDS=$(jq -er '
Expand Down Expand Up @@ -83,6 +91,11 @@ while IFS='|' read -r action tag_ref owner_id repo_id; do

pinned_record "$key" "$FIXTURE/lock.json" \
|| fail "$key must have a symbolic ref and its own SHA as commit"
# Another nonempty symbolic ref also passes pinned_record, but would no
# longer identify the tag assigned to this action by the relock operation.
jq -e --arg key "$key" --arg tag "$tag_ref" '
.dependencies[$key].ref == $tag
' "$FIXTURE/lock.json" >/dev/null || fail "$key must retain its relocked tag $tag_ref"
jq -e --arg key "$key" --argjson owner "$owner_id" --argjson repo "$repo_id" '
.dependencies[$key] | .owner_id == $owner and .repo_id == $repo
' "$FIXTURE/lock.json" >/dev/null || fail "$key lost its repository identity"
Expand Down Expand Up @@ -192,3 +205,8 @@ CASES

[[ "$checked" == 12 ]] || fail "expected to check all twelve changed dependency records"
echo "PASS: actions.lock SHA-ref regression controls ($checked dependencies)"

# This regression gate already runs in Estate Rules CI. Include the validators'
# migration controls so requiring governance in place of runtime-policy cannot
# regress while the workflow and its lock entry still look correct.
bash "$REPO/tests/workflows/runtime_policy_migration_test.sh"
200 changes: 200 additions & 0 deletions tests/workflows/runtime_policy_migration_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
#
# PR #13: both validators must require governance in place of runtime-policy.
# Exercise the real scripts against an isolated repository, including negative
# controls. The template validator treats missing workflows as errors; the
# workflow validator reports them as recommendations and still exits zero.
# Usage: bash tests/workflows/runtime_policy_migration_test.sh
set -euo pipefail

repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
scratch=$(mktemp -d)
trap 'rm -rf "$scratch"' EXIT
fixture="$scratch/repository with spaces"
workflows="$fixture/.github/workflows"

# Report all arguments as a failure message and print any validator logs from
# $scratch to stderr. Terminates the test script with exit status 1.
fail() {
echo "FAIL: $*" >&2
for log in "$scratch/template.log" "$scratch/workflows.log"; do
if [[ -f "$log" ]]; then cat "$log" >&2; fi
done
exit 1
}

# Supply the unrelated structure checks with a minimal complete repository.
# Copy the real deed readers so an early setup error cannot look like the
# expected rejection of a missing governance workflow.
mkdir -p "$workflows" "$fixture/.machine_readable" "$fixture/scripts" \
"$fixture/src/interface/Abi" "$fixture/src/interface/ffi/src" \
"$fixture/src/interface/ffi/test" "$fixture/src/interface/generated/abi" \
"$fixture/docs/developer" "$fixture/docs/governance"
cp "$repo/scripts/deed-field.sh" "$repo/scripts/check-no-a2ml.sh" "$fixture/scripts/"
cat > "$fixture/fixture_chora.deed" <<'DEED'
(repo-deed
(status :phase active)
(maturity :level experimental)
(meta :type library)
(ecosystem :project "fixture")
(anchor :purpose "workflow validation fixture")
(policies (maintenance-axes :corrective-first #t)))
DEED
for file in README.adoc EXPLAINME.adoc LICENSE Justfile AUDIT.adoc \
TOPOLOGY.adoc CONTRIBUTING.md docs/developer/ABI-FFI-README.adoc \
src/interface/Abi/Types.idr src/interface/Abi/Layout.idr \
src/interface/Abi/Foreign.idr src/interface/abi.ipkg \
src/interface/ffi/build.zig src/interface/ffi/src/main.zig \
src/interface/ffi/test/integration_test.zig; do
printf '%s\n' '# SPDX-License-Identifier: MPL-2.0' > "$fixture/$file"
done

# Compiler calls are outside this regression's scope. Bash functions keep the
# test independent of locally installed compilers and create no build outputs.

# Stub the Zig compiler: return 0 only for the single argument "build";
# return 1 for any other invocation without compiling or writing files.
zig() { [[ $# == 1 && $1 == build ]]; }

Check warning on line 58 in tests/workflows/runtime_policy_migration_test.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_resource-algebra&issues=AaFVSNn3nEr8M5v5PU4b&open=AaFVSNn3nEr8M5v5PU4b&pullRequest=13

# Stub Idris2: return 0 only for "--typecheck src/interface/abi.ipkg";
# return 1 for any other invocation without invoking the real compiler.
idris2() { [[ $# == 2 && $1 == --typecheck && $2 == src/interface/abi.ipkg ]]; }

Check warning on line 62 in tests/workflows/runtime_policy_migration_test.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_resource-algebra&issues=AaFVSNn3nEr8M5v5PU4d&open=AaFVSNn3nEr8M5v5PU4d&pullRequest=13

Check warning on line 62 in tests/workflows/runtime_policy_migration_test.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_resource-algebra&issues=AaFVSNn3nEr8M5v5PU4c&open=AaFVSNn3nEr8M5v5PU4c&pullRequest=13
export -f zig idris2

# Write a minimal workflow with an SPDX header and name to the path in $1,
# overwriting any existing file. Returns the status of the printf command.
write_workflow() {
printf '%s\n' '# SPDX-License-Identifier: MPL-2.0' 'name: Fixture' > "$1"

Check warning on line 68 in tests/workflows/runtime_policy_migration_test.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_resource-algebra&issues=AaFVSNn3nEr8M5v5PU4e&open=AaFVSNn3nEr8M5v5PU4e&pullRequest=13
}

# Keep the fixture's contract independent of the validators' arrays: deriving
# it from their implementation would also copy a regressed requirement.
for workflow in hypatia-scan codeql scorecard quality mirror instant-sync \
guix-policy security-policy wellknown-enforcement workflow-linter \
governance secret-scanner; do
write_workflow "$workflows/$workflow.yml"
done
cp "$workflows/governance.yml" "$scratch/governance.yml"

# Validate the current $fixture against the expected governance presence.
# Arguments: $1 case label, $2 "yes" or "no" for governance.yml presence,
# $3 "both" (default) or "template" to select the validators to check.
# Writes validator logs under $scratch and prints PASS, returning 0 on success;
# calls fail to print diagnostics and exit 1 on any unexpected result.
run_case() {
local label=$1 governance_present=$2 template_status=0 workflow_status=0
local validators=${3:-both}
local expected_status=0 expected_errors=0
if [[ "$governance_present" == no ]]; then
expected_status=1
expected_errors=1
fi

# Verbose mode exposes which required workflow was actually resolved.
bash "$repo/scripts/validate-template.sh" "$fixture" 1 \
> "$scratch/template.log" 2>&1 || template_status=$?
[[ "$template_status" == "$expected_status" ]] \
|| fail "$label: template validator exited $template_status, expected $expected_status"
[[ $(grep -c 'ERROR' "$scratch/template.log" || true) == "$expected_errors" ]] \
|| fail "$label: template validator reported unrelated errors"

if [[ "$governance_present" == yes ]]; then
grep -Fq 'Workflow found: governance.yml' "$scratch/template.log" \
|| fail "$label: template validator did not recognize governance"
grep -Fq 'Validation PASSED' "$scratch/template.log" \
|| fail "$label: template validator did not reach its passing summary"
else
grep -Fq 'Required workflow missing: governance.yml' "$scratch/template.log" \
|| fail "$label: template rejection did not identify governance"
grep -Fq 'Validation FAILED' "$scratch/template.log" \
|| fail "$label: template validator did not reach its failing summary"
fi
if grep -Eq '(Required workflow missing:|Workflow found:) runtime-policy\.yml' \
"$scratch/template.log"; then
fail "$label: template validator still requires runtime-policy.yml"
fi
if [[ "$validators" == template ]]; then
echo "PASS: $label (template validator)"
return
fi

bash "$repo/tests/workflows/validate_workflows_test.sh" "$workflows" \
> "$scratch/workflows.log" 2>&1 || workflow_status=$?
[[ "$workflow_status" == 0 ]] \
|| fail "$label: workflow recommendations unexpectedly failed validation"
grep -Fq 'Workflow validation PASSED' "$scratch/workflows.log" \
|| fail "$label: workflow validator did not reach its summary"
local expected_found=12
if [[ "$governance_present" == no ]]; then expected_found=11; fi
grep -Fq "Found $expected_found/12 required workflows" "$scratch/workflows.log" \
|| fail "$label: workflow validator reported an unexpected required-workflow count"

if [[ "$governance_present" == yes ]]; then
grep -Fq 'Found: governance.yml' "$scratch/workflows.log" \
|| fail "$label: workflow validator did not recognize governance"
if grep -Fq 'Missing: governance.yml' "$scratch/workflows.log"; then
fail "$label: workflow validator also reported governance missing"
fi
else
grep -Fq 'Missing: governance.yml' "$scratch/workflows.log" \
|| fail "$label: workflow validator did not recommend governance"
if grep -Fq 'Found: governance.yml' "$scratch/workflows.log"; then
fail "$label: workflow validator accepted a substitute for governance"
fi
fi

if grep -Eq '(Missing:|Found:) runtime-policy\.yml' "$scratch/workflows.log"; then
fail "$label: workflow validator still requires runtime-policy.yml"
fi
echo "PASS: $label (both validators)"
}

run_case 'governance alone satisfies the migrated requirement' yes

rm "$workflows/governance.yml"
run_case 'neither workflow leaves governance missing' no

write_workflow "$workflows/runtime-policy.yml"
run_case 'legacy runtime policy cannot substitute for governance' no

cp "$scratch/governance.yml" "$workflows/governance.yml"
run_case 'governance is recognized when a legacy workflow is also present' yes

rm "$workflows/runtime-policy.yml" "$workflows/governance.yml"
mkdir "$workflows/governance.yml"
# The workflow validator's generic scan also treats named directories as
# malformed YAML files; isolate this presence boundary to template validation.
run_case 'a directory named governance.yml is not a workflow file' no template
rmdir "$workflows/governance.yml"

cp "$scratch/governance.yml" "$workflows/governance.yaml"
run_case 'governance.yaml does not satisfy the required governance.yml path' no
rm "$workflows/governance.yaml"

# The presence check must resolve the exact top-level path, even though the
# workflow validator also scans nested files for generic formatting checks.
mkdir "$workflows/nested"
cp "$scratch/governance.yml" "$workflows/nested/governance.yml"
run_case 'nested governance cannot satisfy the top-level requirement' no
rm -r "$workflows/nested"

cp "$scratch/governance.yml" "$workflows/Governance.yml"
run_case 'governance workflow names are case-sensitive' no
rm "$workflows/Governance.yml"

# Match the validators' regular-file contract: a dangling link is missing,
# while a link resolving to a regular workflow file satisfies the requirement.
# As with the directory case, the generic workflow scan rejects the unreadable
# link separately, so isolate the missing-file boundary to template validation.
ln -s missing-governance.yml "$workflows/governance.yml"
run_case 'a dangling governance symlink is missing' no template
rm "$workflows/governance.yml"

cp "$scratch/governance.yml" "$workflows/governance-target.yml"
ln -s governance-target.yml "$workflows/governance.yml"
run_case 'a governance symlink resolving to a workflow file is accepted' yes
rm "$workflows/governance.yml" "$workflows/governance-target.yml"

cp "$scratch/governance.yml" "$workflows/governance.yml"
run_case 'restoring governance restores passing validation' yes
Loading
Loading