You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ci: make CI standalone (drop estate reusable workflows + third-party setup action) (#603)
## Make CI standalone (no external-repo reusable workflows on the gating
path)
Follow-up to the #602 investigation: the PR-gating `build`/`lint`/`test`
never ran because several workflows were in `startup_failure`. This
makes the **gating** CI self-contained — no dependency on the external
`hyperpolymath/standards` reusable workflows and no third-party
toolchain action — so it runs regardless of that repo's state or an org
"allowed actions" policy.
### Root cause found
The estate **`spark-theatre-gate.yml`** carries a documented note
(BP008): **a `concurrency:` block in a reusable-workflow *caller*, when
the reusable also declares concurrency on the same key, is rejected at
run-creation → `startup_failure`** (no check-run is ever emitted).
`governance.yml` and `secret-scanner.yml` both still had caller-level
`concurrency:` blocks calling estate reusables → that is why they
startup-failed, while `hypatia`/`spark` (no stacking) passed. The
standalone replacements here are **normal** workflows, so their
concurrency blocks are safe.
### Changes
| Workflow | Before | After |
|---|---|---|
| **ci.yml** | `ocaml/setup-ocaml` (third-party) + first-party pins with
**fictional** version comments (`checkout # v6.0.3`, `upload-artifact #
v7.0.1`) | Self-hosted OCaml via `apt + opam` (`ocaml-system`,
base-compiler fallback; dune-project needs ≥4.14); only first-party
`actions/*` at real major tags |
| **governance.yml** | calls
`hyperpolymath/standards/.../governance-reusable.yml@main` | local
`tools/ci/governance-standalone.sh` (Jekyll ban, MPL-1.0 SPDX-header
ban, **PR-delta** DOC-FORMAT) |
| **secret-scanner.yml** | calls
`hyperpolymath/standards/.../secret-scanner-reusable.yml` + `secrets:
inherit` | local `tools/ci/secret-scan-standalone.sh` (pure-shell,
high-confidence patterns, no secrets) |
| **scorecard.yml** | calls
`hyperpolymath/standards/.../scorecard-reusable.yml` | direct
`ossf/scorecard-action` (mirrors the already-direct
`scorecard-enforcer.yml`) |
New: `tools/ci/governance-standalone.sh`,
`tools/ci/secret-scan-standalone.sh` (both `chmod +x`).
### Verification (local)
```
tools/ci/governance-standalone.sh → PASS (Jekyll: none; MPL-1.0 headers: none)
tools/ci/governance-standalone.sh main → PASS (no newly-added docs/ .md)
tools/ci/secret-scan-standalone.sh → PASS (no high-confidence secrets in tracked files)
python3 -c yaml.safe_load on all 4 workflows → valid
bash -n on both scripts → ok
```
The gates were calibrated against the tree first: a naïve gate would
false-fail (59 pre-existing `docs/*.md`, 14 `MPL-1.0` *mentions* in
policy/docs), so the checks are header-aware (0 actual `SPDX: MPL-1.0`
headers) and DOC-FORMAT is **delta-only** (matches the canonical "PR
that adds a docs/ .md" semantics; pre-existing files are never
retro-flagged).
### Left intentionally (not "fully" standalone — by design)
- **hypatia-scan.yml**, **spark-theatre-gate.yml** — estate-proprietary
scanners (neurosymbolic / SPARK), **currently passing**. No public
standalone equivalent exists; stubbing them would *lose* real coverage.
Left calling the estate reusable.
- **mirror.yml** — cross-forge mirroring is inherently external; not a
CI gate.
- **release.yml** — its `ocaml/setup-ocaml` runs on a **cross-platform
matrix (Linux + macOS)**; a Linux-only `apt` inline setup would break
the macOS release builds, and the publish path isn't testable here. Not
PR-gating.
- Standard community actions elsewhere (`github/codeql-action`,
`denoland/setup-deno`, `dtolnay/rust-toolchain`,
`haskell-actions/setup`, `peter-evans/repository-dispatch`) — normal,
non-estate; inlining toolchain setups (esp. cross-platform) is a larger
follow-up. Happy to do these if you want.
### Notes / trade-offs for review
- First-party `actions/*` are pinned to **major tags** (`@v4`) rather
than SHAs, because the prior SHA pins were labelled with nonexistent
versions. `scorecard-enforcer.yml`'s `check-critical` job warns
(non-blocking) on `@vN` pins. Re-pin to verified upstream SHAs if you
prefer; first-party actions are always allowed under any allowlist.
- The self-hosted OCaml step bumps the affected jobs' `timeout-minutes`
10 → 25 to cover the toolchain install.
- I can't exercise GitHub runner behaviour from here; CI on this PR is
the real test. If `ci.yml` still startup-fails after this, the remaining
cause is isolated to first-party actions and points at an org
Actions-policy/platform issue (owner-side).
- Alternative considered: the **minimal** fix for
governance/secret-scanner is simply removing the stacked `concurrency:`
block (keeps the canonical estate checks). This PR goes standalone per
request, but that option remains if you'd rather keep estate coverage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01Lz7pRcec2Z3tVtaAhvB3M8
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Lz7pRcec2Z3tVtaAhvB3M8)_
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments