ci: one composite setup action for every repo-owned workflow; the yaml lint gate runs for real; one loader behind the workflow pins - #199
Conversation
File size check0 over a hard cap (fails), 6 warning(s).
Split the file, wrap the line, shorten or exempt the comment, or list the path in 4 managed file(s) skipped; repo-platform owns them. |
There was a problem hiding this comment.
🟡 Changes recommended
The formatter executes PR-controlled code with a write-capable token, and the fleet pin test permits obsolete branches.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Centralizes repo-owned workflow setup and enforces consistent Bun, dependency, YAML lint, action-pin, and timeout policies.
Changes:
- Adds a shared Bun/yamllint setup composite.
- Migrates repo-owned workflows and consolidates workflow loaders.
- Adds comprehensive workflow policy tests.
File summaries
| File | Description |
|---|---|
.github/actions/setup/action.yml |
Adds the shared setup composite. |
.github/actions/fetch-test-artifacts/action.yml |
Updates setup dependency documentation. |
.github/workflows/auto-fix.yml |
Uses the shared setup action. |
.github/workflows/auto-format.yml |
Adds concurrency, timeout, and shared setup. |
.github/workflows/checks.yml |
Standardizes setup, timeouts, and YAML linting. |
.github/workflows/copilot-setup-steps.yml |
Uses the pinned shared setup. |
.github/workflows/e2e-nightly.yml |
Adds documentation, timeout, and shared setup. |
.github/workflows/nightly-fuzz.yml |
Consolidates setup and installation. |
.github/workflows/nightly.yml |
Consolidates setup and tightens timeouts. |
.github/workflows/post-green.yml |
Centralizes build dependency setup. |
.github/workflows/update-release-pr.yml |
Uses setup without dependency installation. |
.github/workflows/update-release.yml |
Centralizes release-job setup. |
package.json |
Makes missing yamllint fatal in CI. |
test/docs/checks-workflow.test.ts |
Adopts the shared loader and setup assertions. |
test/docs/e2e-nightly-workflow.test.ts |
Adopts the shared workflow reader. |
test/docs/npm-publish-workflows.test.ts |
Consolidates workflow types and loading. |
test/docs/post-green-workflow.test.ts |
Consolidates workflow loading and expected setup. |
test/docs/repo-owned-workflows.test.ts |
Adds workflow policy and negative-control tests. |
test/docs/workflow-loader.ts |
Adds shared workflow parsing and setup predicates. |
Review details
- Files reviewed: 19/19 changed files
- Comments generated: 2
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…l lint gate runs for real; one loader behind the workflow pins
6bed8bc to
123852d
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The broad CI and release-workflow refactor includes privileged patch handoff and publishing paths that warrant final human validation.
Review details
- Files reviewed: 19/19 changed files
- Comments generated: 0 new
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate findings affect privileged patch application and compatibility with older branches and drafts.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (4)
.github/workflows/auto-fix.yml:71
- Existing PR branches that predate this action cannot run the updated auto-fix job. The checkout above replaces the workspace with
github.event.pull_request.head.ref; if that branch lacks.github/actions/setup/action.yml, this localusespath is missing and the build fails before the fix is generated. Make the setup action available independently of the PR head, or migrate those heads before enabling this workflow.
- uses: ./.github/actions/setup
.github/workflows/auto-format.yml:39
- Existing PR branches that predate this action cannot run the updated formatter job. The checkout above replaces the workspace with
github.event.pull_request.head.ref; if that branch lacks.github/actions/setup/action.yml, this localusespath is missing and formatting fails before it produces a patch. Make the setup action available independently of the PR head, or migrate those heads before enabling this workflow.
# The install puts the locked biome in node_modules, so the format runs the gate's biome, not the newest one.
.github/workflows/update-release.yml:68
- The release recovery job can fail before it runs when the draft targets a commit from before this composite was added.
package-releasechecks outsteps.source.outputs.shaabove, then this local action is resolved from that checkout; a pending draft for an older merge therefore has no.github/actions/setup/action.yml, so reruns cannot recover it despite the workflow's recovery contract. Make the setup action available from the workflow revision, or add a one-time path for pending drafts before using it here.
- uses: ./.github/actions/setup
test/docs/repo-owned-workflows.test.ts:131
needsBuntreats text in comments and heredoc bodies as executed Bun commands.RUNS_BUNis applied to the wholerunscalar, socat <<EOF\nbun test\nEOFor# bun testmakes a no-Bun job derive0 setup steps for a job running bun; the negative control below even codifies the comment as true. FilterexecutedLinesand shell comments before applying this predicate, otherwise harmless documentation can fail the workflow pin.
const needsBun = (step: Step) =>
RUNS_BUN.test(step.run ?? "") || (!isSetup(step) && (step.uses ?? "").startsWith("./"));
- Files reviewed: 19/19 changed files
- Comments generated: 1
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved release-recovery, timeout, stale-head formatting, and workflow-pin issues block approval.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (5)
.github/workflows/auto-format.yml:96
- A moved-head formatting request is dropped because the unconditional cleanup removes the label. For example, if the PR branch advances after
format, this guard exits successfully and the laterRemove the fix-lint labelstep still runs; this workflow triggers only onlabeled, so no run is queued for the new head. Preserve a stale-head flag and re-addfix-lintafter cleanup (or skip removal on this path) so the newer head is formatted.
if [ "$(git rev-parse HEAD)" != "$HEAD_SHA" ]; then
echo "::notice::head moved since the format; skipping the stale formatting push"
exit 0
.github/workflows/e2e-nightly.yml:26
- A hung or slow e2e run is now cancelled by this job timeout before the reporting steps can run. GitHub treats a job timeout as cancellation, so the
if: failure()upload and issue steps at lines 54 and 66 are skipped;nightly-fuzz.ymldocuments the same failure mode and wraps its fuzz command withtimeout. Add command-level timeouts that fail before the job limit, or run the reporting path on cancellation.
timeout-minutes: 15
.github/workflows/update-release.yml:155
- npm publish recovery has the same older-target failure. This job checks out
needs.package-release.outputs.source-sha; when that SHA predates the setup composite,uses: ./.github/actions/setupis absent and the job stops beforeBuild the library, even if package-release is made compatible. Keep the setup action available from the current workflow revision for this job too.
- uses: ./.github/actions/setup
test/docs/repo-owned-workflows.test.ts:146
- The workflow pin accepts a setup step that is allowed to fail. For example, adding
continue-on-error: truehere leavessetupOfreturning the samecomposite(...)pin, so a failed Bun install can be ignored and later steps run without the locked dependencies. Include the setup step'scontinue-on-errorin the projection and add a negative control for this case.
const setup = setups[0] as Step;
const early = steps.slice(0, steps.indexOf(setup)).filter(needsBun);
test/docs/repo-owned-workflows.test.ts:394
- The pin gate accepts a truncated version comment even though this policy requires
# vX.Y.Z. For example,actions/checkout@<40-hex-sha> # v7matches this regex and passespinProblem, so a stale or incomplete version annotation is not rejected. Require exactly three numeric components (and add that negative control).
const VERSION_COMMENT = /^v\d+(?:\.\d+)*$/;
- Files reviewed: 19/19 changed files
- Comments generated: 1
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🟡 Changes recommended
The documented setup-composite shape regression pin is absent, leaving the central action contract untested.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 19/19 changed files
- Comments generated: 1
- Review effort level: Balanced
… composite to its contract
Before
After
What changed
One composite,
.github/actions/setup, sets up the pinned bun and the locked install for every repo-owned workflow job; the yaml lint gate runs for real; one typed loader sits behind the workflow pins.Behavior changes
auto-format.ymlandcopilot-setup-steps.ymlran the newest bun (no version file); auto-format also ran the newest biome. Both now run the pinned bun and the locked biome.timeout-minutes(15 unless its comment says why); 8 jobs had none; nightlychecks60 -> 15 andfloat-canary30 -> 15.checks#checkandnightly#float-canaryinstall yamllint 1.38.0 and lint; a CI run without yamllint fails instead of skipping.formatjob and a contents-writepushjob; the push skips on a moved head and is leased to the formatted head. One run per PR at a time.--ignore-scripts(lefthook is a git hook no runner uses); the five jobs that run a bare script or resolve the lockfile themselves install nothing.Proof
bun run checkexit 0 (with the real yamllint);bun test test/docs483 pass;bun run build:checkzero drift; actionlint clean; all-green pass on the PR head.Technical details
installinput skips only on a literalfalse(any letter case, matching GitHub's comparison); the pin test rejects expressions and misspelled inputs, so no runtime validation step exists. Local actions stay on the./form; the$/self-repository sweep is recorded below..bun-version;bun install --frozen-lockfile --ignore-scriptsunlessinstall: "false";pipx install yamllint==1.38.0whenyamllint: "true"(measured 0.8s; the ubuntu image already ships that version, so pipx only verifies it;Lint (yaml)2s). Checkout and setup-node stay in the caller (their options differ per job). 23 of 25 repo-owned jobs use it;auto-fix#pushandnightly#reportrun no bun.nightly-fuzz60 (a 50-minute fuzz run bounded below it),copilot-setup-steps59 (Copilot's documented ceiling, now stated). Measured on recent runs: e2e-smoke 3m50s, e2e-nightly 4m, everything else under 2m30s.test/docs/workflow-loader.ts(128 lines: typedStep/Job/Workflow/CompositeAction, readers, the managed/repo-owned split by header, the setup predicates) replaces the four copies in the checks, npm-publish, e2e-nightly, and post-green tests.test/docs/repo-owned-workflows.test.ts(196 lines) holds the invariants no single file shows: composite-once-or-no-bun plus timeout over every repo-owned job; no step inside the composite masks its failure; everyuses:a local path, the fleet action at@stable, or a full sha with a# vX.Y.Zcomment, one sha per action, read from the YAML syntax tree (block, flow, alias); the two commit-back push jobs run no PR code under their write token and lease the push to the patched head; lint:yaml runs in exactly the jobs the composite hands yamllint to, and the script fails under CI and skips locally when yamllint is absent.e2e-nightly.ymlgets a header;nightly#checksgates its probe onsteps.setup; fetch-test-artifacts' header names the setup composite it needs before it; the fleet-action pin accepts@stablealone.self-repository(Low, 5 -> 30 hits): it prefers GitHub's new$/pathform for local actions, which main already trips on the existing composite.Line accounting (against the merge base 131780e):
.github/workflows, 10 repo-owned files).github/actions)test/docs)package.json)timeout-minuteslines and the comments that state their reasons come in; auto-format alone is +75/-19 (+56) for the read/write pair with the patch handoff, the head-moved guard, and the lease.Review:
@stablealone; a staged-path check in auto-format's push job, later removed by the owner's simplification review since a same-repo author already has push on the branch and GitHub refuses GITHUB_TOKEN pushes of workflow edits, so it added no authorization boundary; the composite'scontinue-on-errorinvariant), 1 recorded (the checkout-predates-the-action window below).continue-on-error).uses:scan missing flow steps; expression-valued inputs; aliased values and keys plus flow-map comments; a bun step ahead of the composite; a local composite as a bun user without setup; setup-bun inside another composite); rounds 6-12 confirmed each later delta, the 12th the simplification (one comment fix folded).Recorded, not built:
uses: ./...to the$/...self-repository form (one sweep, runner floor 2.336.0). It also resolves the action from the workflow revision instead of the checkout: until then a release draft whose target predates this PR recovers by re-running its original run's failed jobs, not from a newer run, and a PR branch behind main rebases before auto-fix or auto-format can run on it.scripts: trueinstall variant (no job needs lifecycle scripts).env,working-directory, andidof the composite's steps (none is set today).Coordination: based on main after #196, #197, and #198 landed; the fuzz-issue
uses:lines and auto-fix's generatorrun:lines are untouched. Main moved once more (#201); a local rebase replays every commit cleanly and was not pushed (no force-push after review began); the squash merge is conflict-free.