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
8 changes: 8 additions & 0 deletions .github/workflows/estate-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ jobs:
# the spine's at mint and left every Julia mint with Lock Sync red.
- name: Archetype lock fragments merge into a valid lock
run: bash tests/workflows/archetype_lock_merge_test.sh
# The four SHA-keyed leaves standards' reusables add keep an immutable ref,
# 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 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
run: bash tests/workflows/scorecard_permissions_test.sh
# The CHECK half of the template contract. repo-init has always written an
# answer-file (now the child deed's (provenance) clause); nothing ever read it.
# This is the missing reader, and it covers the #200/#201/#203 class:
Expand Down
43 changes: 29 additions & 14 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
== Changelog


== 2026-10-14 — governance pin `da2c748` → `934b879`

* The six standards reusables (governance, hypatia-scan, mirror, rust-ci,
scorecard, secret-scanner) move to hyperpolymath/standards `934b879`.
At `da2c748`, governance ran its lock gate from a fixed helper pin with an
unpinned gh-actions-lock. Under v0.2.0 that gate failed *Actions lockfile
verify* on every job-level reusable ref, although it had accepted each one
as coverage. The new pin runs the gate at its own commit, with v0.2.0
pinned (standards#1250).
* `actions.lock`: the `hyperpolymath/standards` record is rewritten at the
new pin with its called workflows' `uses:` union, and closed over the four
refs that union adds (setup-bun, setup-deno, upload-artifact,
rust-toolchain). The old record and the three refs only it named are
removed.
== 2026-10-14 — Scorecard grants `actions: read`; four lock refs kept immutable (resource-algebra#7)

* `.github/workflows/scorecard.yml`: the calling job grants `actions: read`.
Its job-level `permissions:` block replaces the workflow-level one, so the
workflow-level grant never reached scorecard-reusable.yml, whose Packaging
check needs it.
* `actions.lock`: the four leaves that the reusables at standards `934b879` add
(upload-artifact, setup-deno, rust-toolchain, setup-bun) record their SHA as
`ref`, not the tag copied from standards' lock.
`tests/workflows/actions_lock_sha_refs_test.sh` checks this, with negative
controls, and `tests/workflows/scorecard_permissions_test.sh` checks the
grant; both run in Estate Rules.
* The governance re-pin that #7 was opened for had already landed, in #8.

== 2026-10-14 — minted, and the estate checks made green

* Minted with `just repo-init`. The repository had been created from
rsr-template-repo df09a6c with GitHub's template copy and never minted,
so it still declared itself the template. The deed is now
`resource-algebra_chora.deed` (clade `fv`), placeholders are filled,
and CLAUDE.md and the repository map describe this repository.
* `build/just/repo-init.just`: the non-interactive mint now completes;
just's own interpolation, the arrival pack, the repository map, the
state-validation detector and the OpenSSF audit table survive the mint.
* `scripts/check-agda.sh`: each expected rejection must land on the
fixture's `invalid` definition.
* `PROOF-STATUS.adoc` moved to `docs/status/PROOF-STATUS.adoc`.
* CI: the standards reusables re-pinned to standards main, with a closed
`actions.lock`; `CITATION.cff` gained its required `message`.

== 2026-10-14 — MinMax and morphisms (resource-algebra#3)

Expand Down
70 changes: 70 additions & 0 deletions tests/workflows/scorecard_permissions_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
#
# PR #7: the caller's explicit job permission map must grant actions: read.
# Top-level grants do not supply omitted scopes in a job permission map.
# Run: bash tests/workflows/scorecard_permissions_test.sh
# Requires mikefarah/yq v4.
set -euo pipefail

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

fail() { echo "FAIL: $*" >&2; exit 1; }
yq --version | grep -q 'github.com/mikefarah/yq.*version v4\.' \
|| fail "mikefarah/yq v4 is required"

permissions_ok() {
yq -e '
.jobs.scorecard.permissions |
(.actions == "read" and .contents == "read" and
.["security-events"] == "write" and .["id-token"] == "write")
' "$1" >/dev/null 2>&1

Check warning on line 24 in tests/workflows/scorecard_permissions_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=AaE6NODRghVCWurGcl4s&open=AaE6NODRghVCWurGcl4s&pullRequest=9
}

reject_mutant() {
local label=$1 expression=$2
cp "$workflow" "$fixture/mutant.yml"
yq -i "$expression" "$fixture/mutant.yml"
cmp -s "$workflow" "$fixture/mutant.yml" && fail "$label: mutation did not change the workflow"
if permissions_ok "$fixture/mutant.yml"; then
fail "$label: invalid job permissions accepted"
fi
}

permissions_ok "$workflow" || fail "Scorecard lacks a required caller grant"

# The original failure: workflow-level actions: read is still present, but the
# job's explicit map omits actions. A text search would incorrectly pass this.
reject_mutant "top-level-only actions grant" 'del(.jobs.scorecard.permissions.actions)'
reject_mutant "actions disabled" '.jobs.scorecard.permissions.actions = "none"'
reject_mutant "unnecessary actions write access" '.jobs.scorecard.permissions.actions = "write"'
reject_mutant "null actions grant" '.jobs.scorecard.permissions.actions = null'
reject_mutant "empty job permission map" '.jobs.scorecard.permissions = {}'
reject_mutant "missing job permission map" 'del(.jobs.scorecard.permissions)'

# A grant on a sibling job cannot authorize the reusable call either.
reject_mutant "actions grant on the wrong job" '
del(.jobs.scorecard.permissions.actions) |
.jobs.other.permissions.actions = "read"
'

# Adding the staleness-check grant must preserve the existing checkout, SARIF
# upload and OIDC grants needed by this same reusable call.
for scope in contents security-events id-token; do
SCOPE="$scope" reject_mutant "missing $scope grant" \
'del(.jobs.scorecard.permissions[strenv(SCOPE)])'
done

# YAML quoting, comments and key order have no effect on permission semantics.
cp "$workflow" "$fixture/reordered.yml"
yq -i '.jobs.scorecard.permissions = {
"id-token": "write", "security-events": "write",
"contents": "read", "actions": "read"
}' "$fixture/reordered.yml"
printf '\n# actions: none (a comment, not a grant)\n' >>"$fixture/reordered.yml"
permissions_ok "$fixture/reordered.yml" || fail "equivalent YAML permissions rejected"

echo "PASS: Scorecard caller grants; 10 invalid permission controls rejected; equivalent YAML accepted"
Loading