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
105 changes: 70 additions & 35 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
# SPDX-License-Identifier: MPL-2.0
#
# Standalone CI: no dependency on third-party actions or external-repo
# reusable workflows. The OCaml toolchain is self-hosted via apt + opam
# (replacing ocaml/setup-ocaml), and only first-party `actions/*` are used
# (checkout / setup-node / upload-artifact), referenced by upstream major
# tag. dune-project requires OCaml >= 4.14, satisfied by the runner's apt
# OCaml (ocaml-system), with a base-compiler fallback.
#
# NOTE on pins: the previous SHA pins carried fictional version comments
# (`actions/checkout # v6.0.3`, `actions/upload-artifact # v7.0.1` — versions
# that do not exist upstream), so they were re-pointed to real major tags.
# Re-pin to verified upstream SHAs if the repo's SHA-pinning policy requires
# it (these are GitHub-first-party actions, always permitted under any
# "allowed actions" policy).
name: CI
on:
push:
Expand All @@ -9,27 +23,36 @@ permissions:
contents: read
# Actions concurrency pool. Applied only to read-only check workflows
# (no publish/mutation), so cancelling a superseded run is always safe.
# Safe here: this is a normal workflow (not a reusable-workflow caller),
# so there is no caller/reusable concurrency stacking (the BP008 startup
# failure class).
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 25

steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up OCaml
uses: ocaml/setup-ocaml@e32b06a3e831ff2fbc6f08cf35be2085e3918014 # v3
with:
ocaml-compiler: "5.1"
uses: actions/checkout@v4
- name: Set up OCaml toolchain (self-hosted; replaces ocaml/setup-ocaml)
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends opam ocaml
opam init --bare --disable-sandboxing --yes
# Prefer the runner's system OCaml (>= 4.14 satisfies dune-project)
# for an instant switch; fall back to a pinned base compiler.
opam switch create . ocaml-system --no-install --yes \
|| opam switch create . ocaml-base-compiler.4.14.2 --no-install --yes
opam exec -- ocaml -version
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v4
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: opam install . --deps-only --with-test --with-doc
run: opam install . --deps-only --with-test --with-doc --yes
- name: Install tree-sitter CLI (for res-to-affine walker tests)
# Same rationale as the migration-assistant job (see below):
# npm distribution is the fast CI install (~5 s). The walker
Expand Down Expand Up @@ -72,21 +95,25 @@ jobs:
run: opam exec -- dune build @fmt
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 25

steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up OCaml
uses: ocaml/setup-ocaml@e32b06a3e831ff2fbc6f08cf35be2085e3918014 # v3
with:
ocaml-compiler: "5.1"
uses: actions/checkout@v4
- name: Set up OCaml toolchain (self-hosted; replaces ocaml/setup-ocaml)
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends opam ocaml
opam init --bare --disable-sandboxing --yes
opam switch create . ocaml-system --no-install --yes \
|| opam switch create . ocaml-base-compiler.4.14.2 --no-install --yes
opam exec -- ocaml -version
- name: Install dependencies
# Match the build job: `dune build` compiles everything including
# test/ (which depends on alcotest, with-test) and the @doc target
# below (which depends on odoc, with-doc). Without these flags, lint
# fails on missing alcotest before it ever reaches the doc step.
run: opam install . --deps-only --with-test --with-doc
run: opam install . --deps-only --with-test --with-doc --yes
- name: Build
run: opam exec -- dune build
- name: Lint with odoc
Expand All @@ -97,17 +124,21 @@ jobs:
# §"Bench standards". Does NOT block merge. Promotion to a
# ratcheted gate requires a calibrated baseline first.
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 25

steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up OCaml
uses: ocaml/setup-ocaml@e32b06a3e831ff2fbc6f08cf35be2085e3918014 # v3
with:
ocaml-compiler: "5.1"
uses: actions/checkout@v4
- name: Set up OCaml toolchain (self-hosted; replaces ocaml/setup-ocaml)
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends opam ocaml
opam init --bare --disable-sandboxing --yes
opam switch create . ocaml-system --no-install --yes \
|| opam switch create . ocaml-base-compiler.4.14.2 --no-install --yes
opam exec -- ocaml -version
- name: Install dependencies
run: opam install . --deps-only --with-test --with-doc
run: opam install . --deps-only --with-test --with-doc --yes
- name: Build bench targets
run: opam exec -- dune build @bench --force
continue-on-error: true
Expand All @@ -133,7 +164,7 @@ jobs:
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload bench log
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@v4
with:
name: bench-output
path: bench-output.log
Expand All @@ -143,17 +174,21 @@ jobs:
# docs/standards/TESTING.adoc §"Coverage (visibility-only)".
# No merge-blocking floor today.
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 25

steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up OCaml
uses: ocaml/setup-ocaml@e32b06a3e831ff2fbc6f08cf35be2085e3918014 # v3
with:
ocaml-compiler: "5.1"
uses: actions/checkout@v4
- name: Set up OCaml toolchain (self-hosted; replaces ocaml/setup-ocaml)
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends opam ocaml
opam init --bare --disable-sandboxing --yes
opam switch create . ocaml-system --no-install --yes \
|| opam switch create . ocaml-base-compiler.4.14.2 --no-install --yes
opam exec -- ocaml -version
- name: Install dependencies
run: opam install . --deps-only --with-test --with-doc
run: opam install . --deps-only --with-test --with-doc --yes
- name: Run tests with bisect_ppx instrumentation
run: |
opam exec -- dune runtest --force --instrument-with bisect_ppx
Expand All @@ -178,7 +213,7 @@ jobs:
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload coverage HTML
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@v4
with:
name: coverage-html
path: _coverage
Expand All @@ -203,9 +238,9 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v4
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install test runner dependencies
Expand Down Expand Up @@ -248,9 +283,9 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v4
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install tree-sitter CLI
Expand Down
34 changes: 24 additions & 10 deletions .github/workflows/governance.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
# SPDX-License-Identifier: MPL-2.0
# governance.yml — single wrapper calling the shared estate governance bundle
# in hyperpolymath/standards. Replaces ~8 duplicated per-repo governance
# workflows (verisimiser#59 estate rollout). Load-bearing build/security
# workflows (rust-ci, codeql, dependabot, release, secret-scanner, scorecard)
# stay standalone in this repo.
#
# Standalone governance gate. Previously a thin caller of
# `hyperpolymath/standards/.github/workflows/governance-reusable.yml@main`;
# that cross-repo dependency (a) coupled this repo's CI to another repo's
# moving `@main` and (b) startup-failed because a `concurrency:` block in a
# reusable-workflow caller, when the reusable also declares concurrency on the
# same key, is rejected at run-creation (the BP008 class — see
# spark-theatre-gate.yml's note). This self-contained version runs the repo's
# own conservative, delta-aware checks (tools/ci/governance-standalone.sh) and
# is a normal workflow, so the concurrency block is safe to keep.
name: Governance
on:
push:
branches: [main, master]
pull_request:
workflow_dispatch:
# Estate guardrail: cancel superseded runs so re-pushes / rebased PR
# updates do not pile up queued runs against the shared account-wide
# Actions concurrency pool. Applied only to read-only check workflows
# (no publish/mutation), so cancelling a superseded run is always safe.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
governance:
uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@main
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch base ref (DOC-FORMAT delta)
if: github.event_name == 'pull_request'
run: git fetch --no-tags origin "+refs/heads/${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF}"
- name: Run governance gate
env:
GITHUB_BASE_REF: ${{ github.base_ref }}
run: ./tools/ci/governance-standalone.sh
40 changes: 27 additions & 13 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
# SPDX-License-Identifier: MPL-2.0
#
# Standalone OpenSSF Scorecard. Previously a thin caller of
# `hyperpolymath/standards/.github/workflows/scorecard-reusable.yml`; that
# cross-repo dependency had a persistent startup_failure history (see the
# prior note in this file's git history). This self-contained version calls
# `ossf/scorecard-action` directly — mirroring the already-direct sibling
# `scorecard-enforcer.yml` — so there is no external-repo workflow dependency.
# `ossf/scorecard-action` / `github/codeql-action` stay SHA-pinned (third-party
# actions); they match the pins used in scorecard-enforcer.yml.
name: Scorecards supply-chain security
on:
branch_protection_rule:
schedule:
- cron: '23 4 * * 1'
push:
branches: [main]
# Workflow-level permissions are read-only. The job that calls the
# reusable upgrades to the writes required by `ossf/scorecard-action`.
# Job-level permissions REPLACE workflow-level for the job, so a bare
# `permissions: read-all` at workflow level + writes at job level is
# equivalent to `contents: read` at workflow level — both yield the
# same effective set at the job. We match the canonical caller in
# `hyperpolymath/standards/.github/workflows/scorecard-reusable.yml`
# (and the known-good sibling julia-professional-registry/scorecard.yml)
# to eliminate the prior `read-all` / `contents: read` divergence as a
# possible cause of the persistent `startup_failure` (every run since
# adoption — see PR #457's test-plan delta).
permissions:
contents: read
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
security-events: write
id-token: write
uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@e03686486e11b662834d7090dffae54c3e96fd59
secrets: inherit
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Run analysis
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- name: Upload SARIF to code-scanning
uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v3
with:
sarif_file: results.sarif
18 changes: 16 additions & 2 deletions .github/workflows/secret-scanner.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
# SPDX-License-Identifier: MPL-2.0
#
# Standalone secret scan. Previously a thin caller of
# `hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml`
# with `secrets: inherit`; that cross-repo dependency startup-failed (the
# caller's `concurrency:` block stacked on the reusable's — the BP008 class,
# see spark-theatre-gate.yml) and required inheriting org secrets. This
# self-contained version runs a pure-shell high-confidence scan
# (tools/ci/secret-scan-standalone.sh), needs no secrets, and as a normal
# workflow can keep its concurrency block.
name: Secret Scanner
on:
pull_request:
Expand All @@ -11,5 +20,10 @@ permissions:
contents: read
jobs:
scan:
uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@3e4bd4c93911750727e2e4c66dff859e00079da0
secrets: inherit
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run standalone secret scan
run: ./tools/ci/secret-scan-standalone.sh
67 changes: 67 additions & 0 deletions tools/ci/governance-standalone.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
#
# Standalone governance gate.
#
# Replaces the external `hyperpolymath/standards` governance-reusable.yml so
# this repo's CI carries no cross-repo workflow dependency. It is deliberately
# conservative and delta-aware: it enforces the unambiguous estate rules that
# the current tree already satisfies, and treats DOC-FORMAT as a PR-delta
# check (matching the canonical "on any PR that adds a docs/ .md" semantics)
# so the 59 pre-existing docs/*.md files are never retro-flagged.
#
# This is a best-effort local reimplementation; it is NOT byte-for-byte the
# canonical estate bundle (which is not visible from this repo). See the
# `standalone-ci` PR for the trade-off discussion.
#
# Usage: tools/ci/governance-standalone.sh [BASE_REF]
# BASE_REF (or $GOVERNANCE_BASE_REF / $GITHUB_BASE_REF) enables the
# DOC-FORMAT delta check; if absent the delta check is skipped.
set -uo pipefail

fail=0
note() { printf ' %s\n' "$*"; }
err() { printf '::error::%s\n' "$*"; fail=1; }

echo "== Governance gate (standalone) =="

# --- [1] Jekyll artifacts are banned (estate SSG is hyperpolymath/casket-ssg)
echo "[1/3] Jekyll artifacts"
jekyll=$(find . \( -path ./.git -o -path ./_build -o -path ./node_modules \) -prune -o \
\( -name '_config.yml' -o -name 'Gemfile' -o -iname 'jekyll*.yml' \
-o -iname 'jekyll-gh-pages*.yml' \) -print 2>/dev/null || true)
if [ -n "$jekyll" ]; then
err "Jekyll artifacts present (migrate to hyperpolymath/casket-ssg):"
printf '%s\n' "$jekyll" | sed 's/^/ /'
else note "none"; fi

# --- [2] MPL-1.0 license headers are banned (must be MPL-2.0) ---------------
# Match the actual SPDX identifier, not mere prose mentions of the ban (the
# policy docs legitimately discuss MPL-1.0).
echo "[2/3] MPL-1.0 SPDX headers"
mpl1=$(grep -rIl --exclude-dir=.git --exclude-dir=_build --exclude-dir=node_modules \
-E 'SPDX-License-Identifier:[[:space:]]*MPL-1\.0' . 2>/dev/null || true)
if [ -n "$mpl1" ]; then
err "MPL-1.0 SPDX headers found (rewrite to MPL-2.0):"
printf '%s\n' "$mpl1" | sed 's/^/ /'
else note "none"; fi

# --- [3] DOC-FORMAT (delta): newly-added docs/ files must be .adoc ----------
# Community-health files keep their canonical .md names.
echo "[3/3] DOC-FORMAT (newly-added docs/ files must be .adoc)"
base="${1:-${GOVERNANCE_BASE_REF:-${GITHUB_BASE_REF:-}}}"
if [ -n "$base" ] && git rev-parse --verify --quiet "origin/$base" >/dev/null 2>&1; then
added=$(git diff --name-only --diff-filter=A "origin/$base...HEAD" -- 'docs/' 2>/dev/null \
| grep -E '\.md$' \
| grep -viE '/(CONTRIBUTING|CODE_OF_CONDUCT|SECURITY|CHANGELOG|README)\.md$' || true)
if [ -n "$added" ]; then
err "new docs/ .md files added (rename to .adoc per DOC-FORMAT):"
printf '%s\n' "$added" | sed 's/^/ /'
else note "no newly-added docs/ .md files"; fi
else
note "no base ref available — delta check skipped"
fi

echo
if [ "$fail" -ne 0 ]; then echo "Governance gate: FAIL"; exit 1; fi
echo "Governance gate: PASS"
Loading
Loading