name: CI on: pull_request: push: branches: [main] permissions: contents: read jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Shellcheck run: bash .github/scripts/shellcheck-all.sh - name: Install actionlint env: ACTIONLINT_VERSION: 1.7.12 run: | curl -fsSLo actionlint.tar.gz \ "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" tar -xzf actionlint.tar.gz actionlint sudo install actionlint /usr/local/bin/actionlint - name: Actionlint run: bash .github/scripts/actionlint-all.sh - name: Self-ref pin # The pin rules (issue #9; #1 D3): a stale CEREMONY_SELF_REF fails # CI here, not a consumer's release. run: bash .github/scripts/self-ref-check.sh - name: Tests env: # The npm-backed version_write case may skip locally when npm is # absent; in CI a skip must be a failure, or the case could # quietly stop running (issue #3's test contract). CEREMONY_REQUIRE_NPM: 1 run: bash test/run.sh # The release exercise (issue #9's scratch caller) on every PR, so the # parse proof and the merge door's step-replay are standing, reviewable # evidence — not a dispatch someone must remember to run. PR-ONLY, and # the gate is load-bearing: this CI also runs on push to main, and a # workflow_call from THAT context would hand release.yml a genuine # push+refs/heads/main event — the merge door's exact gate — opening a # live door from CI. A pull_request event can never satisfy either # door's `if:`. release-exercise: if: github.event_name == 'pull_request' uses: ./.github/workflows/release-exercise.yml # The self-guards (issue #11): this repo eats exactly what it serves. The # three guard actions run against the REAL tree — VERSION, CHANGELOG.md, # drills/ — through the same `uses:` steps every consumer's CI carries. # These steps are also the composite-action wiring proof (issue #5's # acceptance criterion: action.yml resolving, $GITHUB_ACTION_PATH, the # relative lib sourcing) that action-exercise carried with scratch files # while this repo had no tree of its own to guard; the armed and # drill-recorded scratch steps moved here per the armed step's own # eviction note — the file backend hardcodes the VERSION name, so a # scratch write would SHADOW the real file, not sit beside it. self-guards: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: # The monotonic guard compares HEAD against the merge base; a # shallow checkout cannot resolve it, and in CI that is a hard # failure, not a skip (the action's description). fetch-depth: 0 - uses: ./actions/changelog-armed - uses: ./actions/changelog-monotonic - uses: ./actions/drill-recorded # Exercises changelog-monotonic the way a consumer does, against a # CONSTRUCTED history. The self-guards job above runs the same action on # the real tree, but there its containment half is only as interesting as # the PR's own diff; this job commits a known base and an insert-above # edit on top, so a real, non-vacuous containment run is standing # evidence on every PR. (Armed and drill-recorded moved to self-guards — # the real tree now exercises them; monotonic stays because it reads no # version source, so it is immune to the VERSION-shadowing problem that # evicted the other two.) action-exercise: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Construct a scratch history for the monotonic guard # The monotonic guard's input is a DIFF, so its exercise needs # history, not just a file: commit a scratch changelog, mark that # commit as the fixture base, then commit an insert-above edit on # top — a real containment run, not just an action.yml parse. The # base ref is the in-job branch, passed explicitly, because this # job's shallow PR checkout carries no origin/main for the input's # default to resolve (consumers get that via fetch-depth: 0, per # the action's description). Scratch-named file so the real # CHANGELOG.md is never shadowed; the commits live only in this # job's checkout and are never pushed. run: | git config user.name ceremony-ci git config user.email ceremony-ci@users.noreply.github.com printf '# Changelog\n\n## Unreleased\n\n## 0.1.0 — 2026-07-01\n\n- Shipped entry.\n' > CHANGELOG.monotonic.scratch.md git add CHANGELOG.monotonic.scratch.md git commit -m 'fixture: monotonic base' git branch monotonic-fixture-base printf '# Changelog\n\n## Unreleased\n\n- Entry inserted above.\n\n## 0.1.0 — 2026-07-01\n\n- Shipped entry.\n' > CHANGELOG.monotonic.scratch.md git commit -am 'fixture: insert above' - uses: ./actions/changelog-monotonic with: changelog: CHANGELOG.monotonic.scratch.md base-ref: monotonic-fixture-base