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
116 changes: 116 additions & 0 deletions .github/workflows/actions-lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# SPDX-License-Identifier: MPL-2.0
name: Actions lock

# Keeps .github/workflows/actions.lock in step with the workflows, remotely.
#
# Why this exists. A workflow listed in actions.lock runs only the commits the
# lock records. When a `uses:` ref changes and the lock does not, that workflow
# ends in startup_failure with no check run at all. Dependabot bumps `uses:`
# refs but does not yet rewrite the lock (dependabot-core gates that behind its
# `github_actions_lockfile` experiment), so every Actions bump broke CI here:
# #34 moved lean-action to v1.6.1 and codeql-action to v4.38.2 while the lock
# still named v1.6.0 / v4.38.0. Branch pins also go stale: the lock held
# cicd-suite@main at 5a10b72, before cicd-suite #32 fixed the gate that fails
# estate-audit on this repo.
#
# What it does. Runs the official extension (github/gh-actions-lock, pinned
# below) with --relock, which records new refs and advances branch pins to
# upstream HEAD, then opens a PR that changes ONLY actions.lock. A run that
# wants to touch any workflow file is refused (same assert as #25).
#
# When. On every push to main that changes a workflow (so a merged Dependabot
# bump is relocked within minutes), weekly (so branch pins track latest), and
# on demand.
#
# ⚠ NO `uses:` ANYWHERE, DELIBERATELY (see labels.yml): this workflow must run
# precisely when the lock is stale, so it depends on no action.
#
# Token. Falls back to GITHUB_TOKEN. Add a repository secret
# AUTOMATION_TOKEN (fine-grained: Contents, Issues, Pull requests and Workflows
# read/write on this repo) if GitHub refuses a GITHUB_TOKEN write under
# .github/workflows/, and so that CI runs on the PR it opens (PRs opened with
# GITHUB_TOKEN do not trigger workflows). The track-*.yml workflows share it.

on:
push:
branches: [main]
paths:
- '.github/workflows/*.yml'
- '.github/workflows/*.yaml'
schedule:
- cron: "41 6 * * 1" # weekly, after Dependabot's Monday run
workflow_dispatch:

permissions:
contents: read

concurrency:
group: actions-lock
cancel-in-progress: false

jobs:
relock:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
env:
GH_ACTIONS_LOCK_VERSION: v0.2.0
GH_TOKEN: ${{ secrets.AUTOMATION_TOKEN || secrets.GITHUB_TOKEN }}
BASE: main
BRANCH: ci/relock-actions
steps:
- name: Relock and open a lockfile-only PR
run: |
set -euo pipefail
gh extension install github/gh-actions-lock --pin "$GH_ACTIONS_LOCK_VERSION"
gh auth setup-git
gh repo clone "$GITHUB_REPOSITORY" repo -- --quiet --depth 1 --branch "$BASE"
cd repo

# Scope: the workflows the lock already tracks, plus every workflow
# with no `uses:` (recorded as [], nothing to rewrite). An untracked
# workflow WITH refs, e.g. the estate's canonical secret-scanner
# caller, is left alone: onboarding it may rewrite its SHA ref, so
# that stays a reviewed, manual step. A scoped run never prunes
# out-of-scope entries.
mapfile -t scope < <(
{ sed -n "/^workflows:/,/^dependencies:/s/^ '\(\.github\/workflows\/[^']*\)':.*$/\1/p" \
.github/workflows/actions.lock
for f in .github/workflows/*.yml .github/workflows/*.yaml; do
[ -f "$f" ] && ! grep -qE '^[[:space:]]*(-[[:space:]]+)?uses:' "$f" && echo "$f"
done
} | sort -u | while read -r p; do [ -f "$p" ] && echo "$p"; done)
printf 'relocking: %s\n' "${scope[@]}"

gh actions-lock --relock --no-narrow --no-migrate-local-actions --no-interactive "${scope[@]}"

changed=$(git status --porcelain | awk '{print $2}')
if [ -z "$changed" ]; then
echo "actions.lock is current; nothing to do."
exit 0
fi
if [ "$changed" != ".github/workflows/actions.lock" ]; then
echo "::error::The relock wanted to change more than actions.lock. Refusing; handle by hand:"
git status --porcelain
exit 1
fi
git --no-pager diff --stat

git switch --quiet -c "$BRANCH"
git -c user.name='github-actions[bot]' \
-c user.email='41898583+github-actions[bot]@users.noreply.github.com' \
commit --quiet -am "chore(actions): relock actions.lock" \
-m "Regenerated by .github/workflows/actions-lock.yml with github/gh-actions-lock $GH_ACTIONS_LOCK_VERSION (--relock --no-narrow --no-migrate-local-actions). Only actions.lock changes; every workflow file is byte-identical."
if ! git push --quiet --force origin "$BRANCH"; then
Comment thread
coderabbitai[bot] marked this conversation as resolved.
echo "::error::Push refused. If GitHub rejected a GITHUB_TOKEN write under .github/workflows/, add the AUTOMATION_TOKEN secret described at the top of this workflow."
exit 1
fi

body="Regenerated by \`actions-lock.yml\` (run $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) with \`github/gh-actions-lock $GH_ACTIONS_LOCK_VERSION --relock\`. Only \`.github/workflows/actions.lock\` changes."
if [ -n "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[].number')" ]; then
echo "Updated the open relock PR."
else
gh pr create --base "$BASE" --head "$BRANCH" \
--title "chore(actions): relock actions.lock" --body "$body"
fi
21 changes: 0 additions & 21 deletions .github/workflows/actions.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ workflows:
- 'github/codeql-action@v4.38.0'
'.github/workflows/label-triage.yml': []
'.github/workflows/labels.yml': []
'.github/workflows/main-estate-audit.yml':
- 'actions/checkout@v7.0.1'
- 'hyperpolymath/cicd-suite@main'
'.github/workflows/pages.yml':
- 'actions/checkout@v7.0.1'
- 'actions/deploy-pages@v5.0.1'
Expand Down Expand Up @@ -51,24 +48,6 @@ dependencies:
commit: 'sha1-b96794f015dfd88f77b49b1c93e0fa7110f94c63'
owner_id: 9919
repo_id: 259445878
'hyperpolymath/cicd-suite@main':
ref: 'main'
commit: 'sha1-5a10b72e574ef63855fafd4568a4c178657f3294'
owner_id: 6759885
repo_id: 1326697643
uses:
- 'hyperpolymath/deed-ecosystem@f9d999b60cb5f383679ea19912bcdc49c944973a'
- 'hyperpolymath/k9-ecosystem@2155aa26a21758f2ba119f61bc7e0e1981c106fb'
'hyperpolymath/deed-ecosystem@f9d999b60cb5f383679ea19912bcdc49c944973a':
ref: 'main'
commit: 'sha1-f9d999b60cb5f383679ea19912bcdc49c944973a'
owner_id: 6759885
repo_id: 1275649586
'hyperpolymath/k9-ecosystem@2155aa26a21758f2ba119f61bc7e0e1981c106fb':
ref: 'main'
commit: 'sha1-2155aa26a21758f2ba119f61bc7e0e1981c106fb'
owner_id: 6759885
repo_id: 1275650185
'leanprover/lean-action@v1.6.0':
ref: 'v1.6.0'
commit: 'sha1-50fcf42d2e460296f1a34b402e990d1b24f8b596'
Expand Down
106 changes: 21 additions & 85 deletions .github/workflows/main-estate-audit.yml
Original file line number Diff line number Diff line change
@@ -1,95 +1,31 @@
# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.

name: Central Estate CI/CD Audit

# Thin caller of the estate audit, which lives in hyperpolymath/cicd-suite as
# a reusable workflow and reports five component checks: governance,
# hygiene, manifests, languages, advisory. Do not copy the audit's steps in
# here. A copy freezes this repository at whatever cicd-suite commit its
# actions.lock happened to hold, and fixes made upstream never arrive.
#
# The pin is a full SHA, advanced weekly by track-estate-audit.yml (a PR
# whose own run of this audit is the check).
#
# ⚠ DE-ONBOARDED from actions.lock, deliberately, like the secret-scanner
# caller. A reusable workflow onboarded cross-repo startup-fails with zero
# jobs under sha_pinning_required (see the header of cicd-suite's
# main-estate-audit.yml). Do not run a full-directory `gh actions-lock` that
# re-onboards this file. If one does, cicd-suite/scripts/deonboard-estate-audit.sh
# reverses it.

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
estate-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7.0.1

- name: Required Files Gate
uses: hyperpolymath/cicd-suite/actions/required-files-check@main

- name: Code Hygiene Gate
uses: hyperpolymath/cicd-suite/actions/code-hygiene-check@main

- name: Manifest Validation Gate
uses: hyperpolymath/cicd-suite/actions/manifest-check@main

- name: Idris2 ABI Purity Gate
uses: hyperpolymath/cicd-suite/actions/idris2-abi-check@main

- name: Zig UnifiedApiAdapter API Gate
uses: hyperpolymath/cicd-suite/actions/zig-unified-api-adapter-check@main

- name: Contractile Validation Gate
uses: hyperpolymath/cicd-suite/actions/contractile-validation-check@main

- name: Recipes Set Validation Gate
uses: hyperpolymath/cicd-suite/actions/recipes-set-check@main

- name: Affirmation Document Gate
uses: hyperpolymath/cicd-suite/actions/affirmation-check@main

- name: Academic Referencing Gate
uses: hyperpolymath/cicd-suite/actions/referencing-check@main

- name: Semantic Audit Gate
uses: hyperpolymath/cicd-suite/actions/semantic-audit-check@main

- name: SPDX License Gate
uses: hyperpolymath/cicd-suite/actions/spdx-license-check@main

- name: Proof Runner Gate
uses: hyperpolymath/cicd-suite/actions/proof-runner-check@main

- name: PRAT Testing Gate
uses: hyperpolymath/cicd-suite/actions/prat-check@main

- name: Panic Attack & Pons Gate
uses: hyperpolymath/cicd-suite/actions/custom-tools-check@main

- name: WWW & Well-Known Compliance Gate
uses: hyperpolymath/cicd-suite/actions/www-compliance-check@main

- name: BoJ Cartridge Validation Gate
uses: hyperpolymath/cicd-suite/actions/boj-cartridge-check@main

- name: Formatting Validation Gate
uses: hyperpolymath/cicd-suite/actions/formatting-check@main

- name: Accreditations & Badges Gate
uses: hyperpolymath/cicd-suite/actions/badges-check@main

- name: Metrics Extraction Gate
uses: hyperpolymath/cicd-suite/actions/metrics-check@main

- name: Linguist & Banned Languages Gate
uses: hyperpolymath/cicd-suite/actions/linguist-check@main

- name: Test & Benchmarks Dashboard Gate
uses: hyperpolymath/cicd-suite/actions/tests-benches-check@main

- name: Hosting & Site Status Gate
uses: hyperpolymath/cicd-suite/actions/hosting-check@main

- name: Git-Sea Analytics Gate
uses: hyperpolymath/cicd-suite/actions/gitsea-check@main

- name: Trust & Humans Validation Gate
uses: hyperpolymath/cicd-suite/actions/trust-humans-check@main

- name: Are We UnAPI Gate (Secret Scanning)
uses: hyperpolymath/cicd-suite/actions/secrets-check@main

- name: Reasonably Good Token Validation Gate
uses: hyperpolymath/cicd-suite/actions/vaulted-tokens-check@main
estate:
uses: hyperpolymath/cicd-suite/.github/workflows/main-estate-audit.yml@afa28ff81dc89ae7bd2304eead22917ec1733904 # cicd-suite#50 head; re-pin to its merge commit
90 changes: 90 additions & 0 deletions .github/workflows/track-estate-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# SPDX-License-Identifier: MPL-2.0
name: Track latest estate audit

# Weekly: is the cicd-suite estate audit this repository calls behind
# cicd-suite's main? If so, open a PR that moves the pin in
# main-estate-audit.yml to cicd-suite HEAD. The PR's own estate-audit run is
# the check: merge it when the five components are green. Nothing reaches
# main unreviewed.
#
# ⚠ NO `uses:` ANYWHERE, DELIBERATELY: actions.lock is keyed by workflow path,
# and this must run even when the lock is stale.
#
# Token: AUTOMATION_TOKEN, a fine-grained token on this repository with
# Contents, Pull requests and Workflows set to read/write. In practice it is
# required: the bump edits a file under .github/workflows/, which
# GITHUB_TOKEN may not write, and a PR opened by GITHUB_TOKEN does not trigger
# the estate-audit run that validates it.

on:
schedule:
- cron: "23 7 * * 1" # weekly, Monday
workflow_dispatch:

permissions:
contents: read

concurrency:
group: track-estate-audit
cancel-in-progress: false

jobs:
bump:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
env:
GH_TOKEN: ${{ secrets.AUTOMATION_TOKEN || secrets.GITHUB_TOKEN }}
BRANCH: ci/track-estate-audit
CALLER: .github/workflows/main-estate-audit.yml
BOT_EMAIL: 41898583+github-actions[bot]@users.noreply.github.com
steps:
- name: Move the cicd-suite pin to HEAD and open a PR
run: |
set -euo pipefail
gh auth setup-git
base=$(gh repo view "$GITHUB_REPOSITORY" --json defaultBranchRef --jq .defaultBranchRef.name)
gh repo clone "$GITHUB_REPOSITORY" repo -- --quiet --depth 1 --branch "$base"
cd repo

pinned=$(grep -oE 'cicd-suite/\.github/workflows/main-estate-audit\.yml@[0-9a-f]{40}' "$CALLER" \
| sed 's/.*@//' | head -n 1 || true)
if [ -z "$pinned" ]; then
echo "::error::$CALLER does not call cicd-suite's reusable estate audit at a full SHA."
exit 1
fi
head=$(git ls-remote https://github.com/hyperpolymath/cicd-suite.git HEAD | cut -f1)
echo "pinned ${pinned:0:7}, cicd-suite HEAD ${head:0:7}"
if [ "$pinned" = "$head" ]; then
echo "Already at cicd-suite HEAD."
exit 0
fi

# The bot branch is rebuilt from the default branch each run, which
# would discard anything else on it. If someone has pushed to it
# (say, a fix the newer audit needed), leave it for review.
if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null; then
foreign=$(gh api "repos/$GITHUB_REPOSITORY/compare/$base...$BRANCH" \
--jq "[.commits[] | select(.commit.author.email != \"$BOT_EMAIL\")] | length")
if [ "$foreign" != 0 ]; then
echo "::warning::$BRANCH carries $foreign commit(s) not made by this workflow; leaving it alone. Merge its PR or delete the branch, then re-run."
exit 0
fi
fi

sed -i "s/$pinned/$head/g" "$CALLER"
git switch --quiet -c "$BRANCH"
git -c user.name='github-actions[bot]' -c user.email="$BOT_EMAIL" \
commit --quiet -am "ci(estate-audit): track cicd-suite ${head:0:7}"
if ! git push --quiet --force origin "$BRANCH"; then
echo "::error::Push refused: writing under .github/workflows/ needs the AUTOMATION_TOKEN secret described above."
exit 1
fi
body="Moves the estate audit to cicd-suite \`${head:0:7}\` (was \`${pinned:0:7}\`): https://github.com/hyperpolymath/cicd-suite/compare/$pinned...$head. This PR's estate-audit run is the check. Opened by \`track-estate-audit.yml\`."
if [ -n "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[].number')" ]; then
gh pr edit "$BRANCH" --title "ci(estate-audit): track cicd-suite ${head:0:7}" --body "$body"
else
gh pr create --base "$base" --head "$BRANCH" \
--title "ci(estate-audit): track cicd-suite ${head:0:7}" --body "$body"
fi
20 changes: 20 additions & 0 deletions STATE.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
= STATE — cross-session log

== 2026-10-14 — CI: actions.lock relocked remotely (not a rung)

* One root cause behind both red checks: `.github/workflows/actions.lock`
drifted.
- Dependabot (#34) bumped `lean-action` → v1.6.1 and `codeql-action` →
v4.38.2 but left the lock on v1.6.0 / v4.38.0, so `CI` ends in
`startup_failure`. dependabot-core still gates lock rewriting behind its
`github_actions_lockfile` experiment.
- The lock held `cicd-suite@main` at `5a10b72`, before cicd-suite #32 fixed
the Required Files Gate (`grep -v | wc -l` under `-e -o pipefail` on a
comment-only CODEOWNERS). That is why `estate-audit` fails. The bug is
already fixed upstream, so nothing needs filing.
* `.github/workflows/actions-lock.yml` (new, no `uses:`) runs
`github/gh-actions-lock v0.2.0 --relock` remotely. It triggers on pushes to
main that change a workflow, weekly, and on dispatch. It is scoped to the
workflows the lock already tracks plus every workflow with no `uses:`, and opens a PR only when
`actions.lock` alone changes.
* Gates: actionlint 1.7.7 (with shellcheck) clean. The run itself can only
be exercised on GitHub, because this sandbox cannot reach the GitHub API.

== 2026-10-14 — toolchain v4.34.0 → v4.34.1 (patch; review finding on #36)

* CodeRabbit flagged #36 (Major, security): v4.34.1 is the patched
Expand Down
Loading