From 716c977a96eeab834fd5b768640202fabef34b5f Mon Sep 17 00:00:00 2001 From: apostasie Date: Sat, 15 Aug 2026 19:25:08 -0700 Subject: [PATCH] Cleanup Signed-off-by: apostasie --- .../validate-issue-forms.sh | 0 .github/workflows/ci.yaml | 80 +++++++++++++------ Justfile | 2 +- README.md | 2 +- 4 files changed, 56 insertions(+), 28 deletions(-) rename .github/{workflows => scripts}/validate-issue-forms.sh (100%) diff --git a/.github/workflows/validate-issue-forms.sh b/.github/scripts/validate-issue-forms.sh similarity index 100% rename from .github/workflows/validate-issue-forms.sh rename to .github/scripts/validate-issue-forms.sh diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9806acf..b979282 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,11 +1,15 @@ -# CI for the organization's community-health repository. +# DO NOT EDIT MANUALLY. +# This workflow is generic — no project-specific content — and is destined to +# become part of the canonical baseline limen distributes. # -# The canonical shape — GitHub's own checkout pinned by SHA, aqua for the -# pinned toolchain, and `just` recipes identical to the ones a laptop runs — -# but on a single linux leg. ci.yaml is seeded once and is the project's own -# from there (see book/mandatory-files.md), and this repository ships no code: -# nothing here is platform-dependent, so the five-runner matrix the code -# repositories need would buy nothing but minutes. +# Design: minimal GitHub glue around the same tooling every developer runs +# locally. The only marketplace action is GitHub's own checkout, pinned by +# commit SHA (a tag can be moved to malicious code; a SHA cannot). Everything +# else is pinned, checksum-verified shell: aqua installs the repo's tools at +# the versions aqua.yaml pins, and `just` runs the exact recipes a laptop +# runs — CI green means the same thing as local green, by construction. +# Deliberately absent: runner egress filtering — the available options are +# third-party actions, which this workflow avoids on principle. name: ci on: @@ -13,7 +17,9 @@ on: branches: [main] pull_request: -# No default token permissions: each job states what it needs. +# No default token permissions: each job states what it needs. This workflow +# only ever reads the repository — it cannot write code, releases, or +# packages even if a step is compromised. permissions: {} # A superseded run (new push to the same branch/PR) is cancelled, not raced. @@ -21,6 +27,11 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# Every run step is bash on every runner: without this, windows defaults to +# PowerShell, which never sees the git-bash environment setup-aqua prepares +# (the whole matrix is designed to run the recipes under git-bash). Explicit +# bash also means `-eo pipefail` everywhere, which the implicit linux/macos +# default lacks. defaults: run: shell: bash @@ -30,11 +41,24 @@ jobs: strategy: fail-fast: false matrix: - # Single leg, but kept as a matrix so the check-run name stays - # `verify (ubuntu-24.04)` — the shape the canonical limen:main ruleset - # names in its required status checks. + # Pinned images, not -latest: a runner bump is a reviewed change. + # macOS is not redundant: its /bin/bash is 3.2, the portability floor + # the shared recipes target. arm64 (ubuntu-24.04-arm, windows-11-arm) + # and windows cover the rest of the supported release matrix — both + # windows legs run the recipes under git-bash (native arm64 tools + # where upstream ships them, Prism-emulated amd64 via aqua's + # windows_arm_emulation where it does not). + # These names are NOT the ruleset's required contexts — the `gate` job + # below is, precisely so this list can change without touching any + # repository's branch protection. + # + # Trimmed from the canonical matrix to a single linux leg: this is the + # organization's community-health repository and ships no code, so + # nothing here is platform-dependent — the five-runner matrix the code + # repositories need would buy nothing but minutes. os: [ubuntu-24.04] runs-on: ${{ matrix.os }} + # One linux leg linting a handful of files: nowhere near the canonical 45. timeout-minutes: 15 permissions: contents: read @@ -44,37 +68,39 @@ jobs: # The token is not left behind in .git/config: nothing in this # workflow talks to GitHub after checkout. persist-credentials: false - # Full history: `just do lint commits` validates the commit range - # against the PR's base branch, which a shallow clone lacks. + # Full history and refs: `just do lint commits` validates the commit + # range against the PR's base branch, which a shallow clone lacks. fetch-depth: 0 - name: Install aqua (pinned, checksum-verified) uses: ./.github/actions/setup-aqua - name: Install pinned tools - # Not optional: setup-aqua only installs aqua itself and puts its bin - # directory on PATH — that directory is EMPTY until this runs. The - # shims created here are what make `just` (and everything the recipes - # call) resolve at all. Link-only: each tool downloads lazily on first - # use and is verified against the committed aqua-checksums.json then, - # so a job only pays for the tools its recipes actually run. + # Link-only: the shims download each tool lazily on first use (and it + # is verified against the committed aqua-checksums.json then), so a + # job only ever pays for the tools its recipes actually run. run: aqua install --only-link - name: Lint run: just lint - name: Test - # A no-op today (the Justfile's `test` recipe is empty) — kept so the - # shape matches the canonical ci.yaml and tests run the day there are any. run: just test - # The single required status check, identical to the canonical ci.yaml's. - # This repository runs one leg where the code repositories run five — which - # is exactly why the ruleset names this job and not the matrix. + # The ONE required status check (see defaultRequiredChecks in + # internal/github/audit.go). Branch protection names contexts as strings, so + # requiring the matrix legs directly would bake this workflow's runner list + # into every repository's ruleset — and a project whose matrix differs then + # waits forever on checks that never report. This job collapses the matrix, + # whatever its shape, to a single stable name: change the legs above freely, + # the ruleset never moves. gate: needs: [verify] - # always(), with the result asserted: without it a failed dependency SKIPS - # this job, and a skipped required check does not block a merge. + # always(), and the result asserted explicitly. Without always() a failed + # or cancelled dependency SKIPS this job instead of failing it, and a + # skipped required check does not block a merge — branch protection that + # quietly stops protecting. `needs.verify.result` is success only when + # every matrix leg succeeded. if: always() runs-on: ubuntu-24.04 timeout-minutes: 5 @@ -82,6 +108,8 @@ jobs: steps: - name: Every verify leg succeeded env: + # Via env, never interpolated into the script: the shell sees data, + # not something the expression layer can rewrite into code. RESULT: ${{ needs.verify.result }} run: | printf 'verify: %s\n' "$RESULT" diff --git a/Justfile b/Justfile index 0e1cd61..91fd649 100644 --- a/Justfile +++ b/Justfile @@ -20,4 +20,4 @@ test: # Shell plus the aqua-pinned yq: no unpinned interpreter, and shellcheck lints # the script like any other we ship. issue-forms: - @.github/workflows/validate-issue-forms.sh + @.github/scripts/validate-issue-forms.sh diff --git a/README.md b/README.md index 64f4442..01d92df 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ formatted, and `do lint links` (lychee) proves the links resolve — but neither that a well-formed YAML file is a *valid issue form*. GitHub fails that silently: it does not reject the file, it just refuses to render the form. Since these templates are the org-wide fallback, a broken one breaks issue creation in every repository that has none of -its own. `.github/workflows/validate-issue-forms.sh` checks them against the form schema — +its own. `.github/scripts/validate-issue-forms.sh` checks them against the form schema — shell plus the aqua-pinned `yq`, so it introduces no interpreter the toolchain does not already pin, and `do lint shell` lints it like any other script we ship.