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
10 changes: 5 additions & 5 deletions .github/workflows/hypatia-scan-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
#
# Fork-local copy of hyperpolymath/standards/.github/workflows/
# Fork-local copy of metadatastician/standards/.github/workflows/
# hypatia-scan-reusable.yml at 01c9b0c9f2646ebea0b30a9588462642ac94aee9.
# Keep that source pin when updating this file and reapply the three fork deltas:
# 1. Do not upload SARIF for pull_request events. This lane is advisory on
Expand All @@ -11,7 +11,7 @@
# Raw findings and the verdict grid still cover the PR, while push and
# manual runs continue to reconcile code scanning on the default branch.
# 2. Pin the standards checkout explicitly. job.workflow_sha now names a
# MetaManifold commit, not a commit in hyperpolymath/standards.
# MetaManifold commit, not a commit in metadatastician/standards.
# 3. Filter only upstream-inherited TypeScript paths from the effective
# findings, validate the raw/effective JSON with pinned ijson-jcs, and keep
# raw scanner outputs plus fork-only paths/rules.
Expand Down Expand Up @@ -619,7 +619,7 @@ jobs:
continue-on-error: true
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: hyperpolymath/standards
repository: metadatastician/standards
persist-credentials: false
# Includes the filter's completion output and literal-glob matching.
# Keep the helper immutable and compatible with the strict gate.
Expand Down Expand Up @@ -703,7 +703,7 @@ jobs:
continue-on-error: true
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: hyperpolymath/standards
repository: metadatastician/standards
# This fork-local reusable's job.workflow_sha belongs to
# MetaManifold, not standards, so the source commit must be literal.
ref: 01c9b0c9f2646ebea0b30a9588462642ac94aee9
Expand Down Expand Up @@ -743,7 +743,7 @@ jobs:
# No renderer is missing evidence, rendered as such, never a pass.
jq -n '{schemaVersion: 1, label: "Hypatia grid", message: "indeterminate", color: "orange"}' > verdict-grid/badge.json
printf '%s\n%s\n' '<!-- verdict-grid:hypatia regenerated on every run -->' \
'🟠 indeterminate · the verdict grid renderer could not be checked out from hyperpolymath/standards; see the job log.' \
'🟠 indeterminate · the verdict grid renderer could not be checked out from metadatastician/standards; see the job log.' \
> verdict-grid/report.md
cat verdict-grid/report.md >> "$GITHUB_STEP_SUMMARY"
echo "state=orange" >> "$GITHUB_OUTPUT"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/hypatia-scan.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
#
# Fork governance lane. DEED and K9 conformance come from hyperpolymath/standards; the
# Fork governance lane. DEED and K9 conformance come from metadatastician/standards; the
# Hypatia verdict grid uses a fork-local copy of the standards reusable so its
# advisory PR scan cannot become a blocking code-scanning-results check. Both
# sources are pinned to commits. The grid covers Hypatia, panic-attack, pons
Expand Down Expand Up @@ -52,7 +52,7 @@ jobs:

deed:
name: DEED syntax
uses: hyperpolymath/standards/.github/workflows/deed-conformance.yml@75bd5994470661a099df562d6d5ad2fe744dbd66
uses: metadatastician/standards/.github/workflows/deed-conformance.yml@75bd5994470661a099df562d6d5ad2fe744dbd66

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Allow the transferred owner before switching reusable calls

Under the repository's current Actions policy, this new cross-owner uses: reference is rejected before any jobs are created. The incident documentation added in this same commit records the exact rejection and explicitly states that repointing the reference alone is insufficient (docs/maintenance/repository-hygiene.md:253-268); the Scorecard call at .github/workflows/scorecard.yml:23 is affected as well. Unless the Actions allowlist is updated as part of the rollout (or these checks are made local), Governance and Scorecard remain entirely dark after this purported fix.

Useful? React with 👍 / 👎.

permissions:
contents: read
with:
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/k9-conformance-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ name: k9-conformance
# Caller:
# jobs:
# k9:
# uses: hyperpolymath/standards/.github/workflows/k9-conformance.yml@<sha>
# uses: metadatastician/standards/.github/workflows/k9-conformance.yml@<sha>
# permissions:
# contents: read
# pull-requests: read
Expand Down Expand Up @@ -89,7 +89,7 @@ jobs:
# In this repo the PR's own validator is in the first checkout; a caller
# gets validator, contract and renderer from the canon checkout at
# job.workflow_sha.
CANON: ${{ github.repository == 'hyperpolymath/standards' && '.' || '.k9-canon' }}
CANON: ${{ github.repository == 'metadatastician/standards' && '.' || '.k9-canon' }}
NICKEL_VERSION: '1.18.0'
NICKEL_SHA256: '9cba4dd65ae9915ec61f73033aafcff307a377665a83fd8f530df086763318cb'
IJSON_JCS_REV: '0fdeea716fd558e9807362acf6f8202d56d8d88f'
Expand All @@ -104,10 +104,10 @@ jobs:
persist-credentials: false

- name: checkout the K9 validator, contract and renderer at this workflow's commit
if: github.repository != 'hyperpolymath/standards'
if: github.repository != 'metadatastician/standards'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: hyperpolymath/standards
repository: metadatastician/standards
ref: c6d78606f3928c22c3b0bdc6f5f5b47b96e05a5d
path: .k9-canon
persist-credentials: false
Expand All @@ -121,7 +121,7 @@ jobs:
WORKFLOW_SHA: c6d78606f3928c22c3b0bdc6f5f5b47b96e05a5d
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
if [ "$GITHUB_REPOSITORY" = "hyperpolymath/standards" ]; then
if [ "$GITHUB_REPOSITORY" = "metadatastician/standards" ]; then
echo "CANON_REF=$HEAD_SHA" >> "$GITHUB_ENV"
else
echo "CANON_REF=$WORKFLOW_SHA" >> "$GITHUB_ENV"
Expand Down Expand Up @@ -154,7 +154,7 @@ jobs:
|| echo "::warning::ijson-jcs did not install; report.json falls back to jq -S -c"

- name: Renderer regression tests
if: github.repository == 'hyperpolymath/standards'
if: github.repository == 'metadatastician/standards'
run: bash scripts/tests/k9-grid-test.sh

- name: Validator self-test
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
scorecard:
# The default-branch SARIF upload needs security-events: write; never
# expose that grant or the publication OIDC token to PR code.
uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@c6d78606f3928c22c3b0bdc6f5f5b47b96e05a5d
uses: metadatastician/standards/.github/workflows/scorecard-reusable.yml@c6d78606f3928c22c3b0bdc6f5f5b47b96e05a5d
permissions:
actions: read
contents: read
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/secret-scanner-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
# scan:
# permissions:
# contents: read
# uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@<sha>
# uses: metadatastician/standards/.github/workflows/secret-scanner-reusable.yml@<sha>
# # Deliberately NO `secrets:` line — the callee declares none and
# # needs none (see the Design note above).

Expand Down Expand Up @@ -214,7 +214,7 @@ jobs:
if: hashFiles('.gitleaks.toml') == ''
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: hyperpolymath/standards
repository: metadatastician/standards
ref: c6d78606f3928c22c3b0bdc6f5f5b47b96e05a5d
path: .standards-gitleaks
sparse-checkout: |
Expand Down Expand Up @@ -291,7 +291,7 @@ jobs:
if: steps.estate_baseline.outputs.referenced == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: hyperpolymath/standards
repository: metadatastician/standards
ref: c6d78606f3928c22c3b0bdc6f5f5b47b96e05a5d
path: .estate-baseline-checkout
sparse-checkout: config/gitleaks
Expand Down
72 changes: 72 additions & 0 deletions docs/maintenance/repository-hygiene.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,78 @@ acts on them; the first one was reached, wrongly, during the 2026-10-25 pass.
A new directory under `docs/` needs a whitelist line or it will not be
committed; `!docs/maintenance/` was added for this document.

## External pins can move under you

**Incident, 2026-10-25.** `hyperpolymath/standards` — the source of this
repository's DEED, K9, Hypatia, Scorecard and secret-scanner reusables — was
transferred to `metadatastician/standards` at 10:13 UTC. From the next run
onwards, every workflow that called one of its reusable workflows **failed at
plan time with zero jobs**, and GitHub displayed the run under the workflow's
file path instead of its `name:`, because the workflow never loaded far enough
to have one:

| Time | Workflow | Result |
| --- | --- | --- |
| 09:26 | `Governance (fork)` (`hypatia-scan.yml`) | success |
| 09:26 | `OpenSSF Scorecard` (`scorecard.yml`) | success |
| 10:13 | — standards repository transferred — | |
| 10:52 | `hypatia-scan.yml` on a pull request | failure, 0 jobs, 0 s |
| 11:27 | `hypatia-scan.yml`, `scorecard.yml` on the push | failure, 0 jobs, 0 s |
| 11:27 | `Secret Scanner` (local reusable only) | success |

The distinction is the whole lesson: **`actions/checkout` with
`repository: hyperpolymath/standards` kept working**, because git and the REST
API follow a transfer's redirect, while a `uses: <owner>/<repo>/.github/
workflows/<file>@<sha>` reference **does not**. So the scanners that *check the
repository out* were fine and the ones that *call a reusable workflow* were
dark. Both read as "governance is green" in a summary that does not look at
`conclusion` per workflow.

How to detect it in one command, before trusting a red or a green:

```
gh api repos/<owner>/<repo> --jq .full_name # a different name means transferred
```

### The actual cause is an Actions policy, not just the rename

Repointing the references is **not sufficient**, and the run says so once you can
read the annotation. A startup-failure run has no jobs and no logs, but its
workflow page carries one error:

> The reusable workflow `metadatastician/standards/.github/workflows/deed-conformance.yml@75bd5994…`
> is not allowed in `hyperpolymath/MetaManifold-WebUI` because all reusable
> workflows must be from a repository owned by `hyperpolymath` or match the
> pattern: `arena-ai-coding-agent[bot]`.

The repository's Actions policy permits reusable workflows only from
repositories owned by `hyperpolymath` — so `hyperpolymath/standards` was allowed
and `metadatastician/standards` is not, whatever name the workflow file uses.
The `uses:` references therefore cannot be repaired by editing this repository
alone. Three ways out, in increasing order of effort:

1. **Permit the new owner.** Repository → Settings → Actions → General →
*Access* for reusable workflows, and allow `metadatastician` (or "any
repository"). This is the smallest change and keeps the pins intact.
2. **Move `standards` back** under `hyperpolymath`. Then the existing workflow
files work unchanged, and no pull request is needed.
3. **Run DEED conformance from a checkout** instead of a remote `uses:`, the way
the K9, Hypatia and secret-scanner lanes already do. Correct, but it puts a
copy of someone else's workflow steps in this repository, and that copy then
drifts.

What was done: every reference was repointed at `metadatastician/standards`
with the **same pinned SHAs** (verified to resolve in the new location, with
matching commit subjects), `scripts/check-governance-contract.sh` now fails if
any workflow names the pre-transfer owner or if the Scorecard reusable stops
being the pinned file, and the mutation test carries a case for each. The pins
themselves did not move, so no new code is trusted; only the name used to reach
the same commits.

What a future reader should not do: "fix" a failed governance run by dropping
the `uses:` and inlining a scanner, or by pointing the pin at `@main`. Both turn
a loud failure into a quiet one.

## Decisions for the owner

These are not cleanup, they are choices with trade-offs; the reasoning is
Expand Down
18 changes: 15 additions & 3 deletions scripts/check-governance-contract.sh
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,13 @@

contains "$caller" 'uses: ./.github/workflows/hypatia-scan-reusable.yml' \
'the governance lane calls the fork-local reusable'
not_contains "$caller" 'uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@' \
# The standards repository is metadatastician/standards; it was
# hyperpolymath/standards until the transfer on 2026-10-25. Both names are
# checked, because a bypass through either one skips the fork guard.
not_contains "$caller" 'uses: metadatastician/standards/.github/workflows/hypatia-scan-reusable.yml@' \
'the governance lane cannot bypass the fork guard by calling standards directly'
not_contains "$caller" 'uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@' \
'the governance lane cannot bypass the fork guard through the pre-transfer name'
contains "$caller" 'needs: [workflow-contract]' \
'this contract runs before the Hypatia scan'
if grep -Eq '^ pull_request:$' <<<"$caller"; then
Expand Down Expand Up @@ -261,14 +266,21 @@
'the raw critical count cannot drive an exception-inconsistent advisory'

if renderer="$(step_block "$REUSABLE" 'Check out the verdict grid renderer at this workflow'"'"'s commit')"; then
contains "$renderer" 'repository: hyperpolymath/standards' \
contains "$renderer" 'repository: metadatastician/standards' \
'the renderer comes from the standards repository'
contains "$renderer" "ref: $STANDARDS_SHA" \
'the standards renderer uses the immutable source pin'
else
fail 'the standards renderer checkout exists'
fi

stale_owner="$(grep -rn 'hyperpolymath/standards' .github/workflows/ 2>/dev/null || true)"
if [ -z "$stale_owner" ]; then

Check failure on line 278 in scripts/check-governance-contract.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_MetaManifold-WebUI&issues=AaFy1JvW5WNdnY_XPw7A&open=AaFy1JvW5WNdnY_XPw7A&pullRequest=291
pass 'no workflow still names the pre-transfer standards owner'
else
fail "workflows still reference hyperpolymath/standards, which no longer resolves for a reusable uses: - $stale_owner"
fi

upload_count="$(grep -c 'uses: github/codeql-action/upload-sarif@' "$REUSABLE" || true)"
if [ "$upload_count" -eq 1 ]; then
pass 'there is exactly one SARIF upload site to guard'
Expand Down Expand Up @@ -313,7 +325,7 @@
not_contains "$secret_workflow" 'continue-on-error:' 'secret scanner failures cannot be advisory'
not_contains "$secret_workflow" 'pull_request_target:' 'secret scanning does not use a privileged PR trigger'
scorecard_workflow="$(cat .github/workflows/scorecard.yml)"
contains "$scorecard_workflow" 'uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@c6d78606f3928c22c3b0bdc6f5f5b47b96e05a5d' \
contains "$scorecard_workflow" 'uses: metadatastician/standards/.github/workflows/scorecard-reusable.yml@c6d78606f3928c22c3b0bdc6f5f5b47b96e05a5d' \
'Scorecard uses the audited immutable reusable'
if grep -Eq '^ pull_request(_target)?:' <<<"$scorecard_workflow"; then
fail 'Scorecard publication must not run against PR code'
Expand Down
7 changes: 6 additions & 1 deletion scripts/tests/test-governance-contract.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ reset_fixture() {
}
reset_fixture
bash "$fixture/scripts/check-governance-contract.sh" > "$fixture/log" 2>&1
for mutation in allowlist-addition baseline-zero-gate baseline-operator-gate baseline-grouping-gate sarif upstream-exception effective-grid jcs-manifest jcs-canonicalizer raw-ijson k9-pin k9-require k9-indeterminate k9-verdict scanner-advisory scanner-secrets scanner-trigger scorecard-trigger; do
for mutation in allowlist-addition baseline-zero-gate baseline-operator-gate baseline-grouping-gate sarif upstream-exception effective-grid jcs-manifest jcs-canonicalizer raw-ijson k9-pin k9-require k9-indeterminate k9-verdict scanner-advisory scanner-secrets scanner-trigger scorecard-trigger stale-standards-owner scorecard-owner; do
reset_fixture
case "$mutation" in
allowlist-addition) echo 'frontend/src/fork-only.ts' >> "$fixture/config/hypatia/upstream-typescript-allowlist.txt" ;;
Expand All @@ -35,6 +35,11 @@ for mutation in allowlist-addition baseline-zero-gate baseline-operator-gate bas
scanner-secrets) echo ' secrets: inherit' >> "$fixture/.github/workflows/secret-scanner.yml" ;;
scanner-trigger) sed -i 's/^ pull_request:/ pull_request_target:/' "$fixture/.github/workflows/secret-scanner.yml" ;;
scorecard-trigger) sed -i '/^on:/a\ pull_request:' "$fixture/.github/workflows/scorecard.yml" ;;
# The standards repository was transferred on 2026-10-25 and a reusable
# `uses:` no longer follows the old owner, so either of these mutations
# leaves a workflow that fails at plan time with no jobs at all.
stale-standards-owner) sed -i 's@metadatastician/standards@hyperpolymath/standards@g' "$fixture/.github/workflows/scorecard.yml" ;;
scorecard-owner) sed -i 's@metadatastician/standards/.github/workflows/scorecard-reusable.yml@metadatastician/standards/.github/workflows/other.yml@' "$fixture/.github/workflows/scorecard.yml" ;;
*) echo "ERROR: unknown mutation $mutation" >&2; exit 1 ;;
esac
if bash "$fixture/scripts/check-governance-contract.sh" > "$fixture/log" 2>&1; then
Expand Down
Loading