Skip to content

ci: one composite setup action for every repo-owned workflow; the yaml lint gate runs for real; one loader behind the workflow pins - #199

Merged
Vivswan merged 9 commits into
mainfrom
ci/composite-setup
Sep 13, 2026
Merged

Vivswan merged 9 commits into
mainfrom
ci/composite-setup

Conversation

@Vivswan

@Vivswan Vivswan commented Sep 13, 2026 •

Copy link
Copy Markdown
Owner

Before

# checks.yml, job `check`: one of 23 hand-copies across 10 repo-owned workflows
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
  with:
    bun-version-file: .bun-version      # auto-format.yml and copilot-setup-steps.yml: missing -> newest bun
- name: Install dependencies
  run: bun install --frozen-lockfile    # 8 jobs; 5 others add --ignore-scripts, one says why
- name: Lint (biome)
  run: bun run lint                     # no yaml lint step; `bun run check` skipped it too (yamllint absent)

After

timeout-minutes: 15                     # was missing on 8 jobs
steps:
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
  - uses: ./.github/actions/setup
    with:
      yamllint: "true"
  - name: Lint (biome)
    run: bun run lint
  - name: Lint (yaml)
    run: bun run lint:yaml              # yamllint 1.38.0 on the runner; missing under CI now exits 1

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

  • Bun and biome versions: auto-format.yml and copilot-setup-steps.yml ran the newest bun (no version file); auto-format also ran the newest biome. Both now run the pinned bun and the locked biome.
  • Timeouts: every repo-owned job has timeout-minutes (15 unless its comment says why); 8 jobs had none; nightly checks 60 -> 15 and float-canary 30 -> 15.
  • lint:yaml: checks#check and nightly#float-canary install yamllint 1.38.0 and lint; a CI run without yamllint fails instead of skipping.
  • auto-format: split like auto-fix into a contents-read format job and a contents-write push job; the push skips on a moved head and is leased to the formatted head. One run per PR at a time.
  • Installs: every job installs with --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 check exit 0 (with the real yamllint); bun test test/docs 483 pass; bun run build:check zero drift; actionlint clean; all-green pass on the PR head.
Technical details
  • Reviewer note (Copilot): the composite's install input skips only on a literal false (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.
  • Composite contract: setup-bun from .bun-version; bun install --frozen-lockfile --ignore-scripts unless install: "false"; pipx install yamllint==1.38.0 when yamllint: "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#push and nightly#report run no bun.
  • Timeouts kept above 15: nightly-fuzz 60 (a 50-minute fuzz run bounded below it), copilot-setup-steps 59 (Copilot's documented ceiling, now stated). Measured on recent runs: e2e-smoke 3m50s, e2e-nightly 4m, everything else under 2m30s.
  • Tests: test/docs/workflow-loader.ts (128 lines: typed Step/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; every uses: a local path, the fleet action at @stable, or a full sha with a # vX.Y.Z comment, 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.
  • Small fixes on the way: e2e-nightly.yml gets a header; nightly#checks gates its probe on steps.setup; fetch-test-artifacts' header names the setup composite it needs before it; the fleet-action pin accepts @stable alone.
  • zizmor 1.30.1: before/after identical except self-repository (Low, 5 -> 30 hits): it prefers GitHub's new $/path form for local actions, which main already trips on the existing composite.

Line accounting (against the merge base 131780e):

Kind Added Deleted Net
workflows (.github/workflows, 10 repo-owned files) 126 108 +18
actions (.github/actions) 33 1 +32
tests (test/docs) 410 201 +209
config (package.json) 1 1 0
  • workflows +18: nine files drop 66 setup lines for 21 composite calls and net -38; 11 timeout-minutes lines 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.
  • actions +32: the new composite (32 lines, 5 of them the header) and a one-line header fix in fetch-test-artifacts.
  • tests +209: the loader (+128) is where the four old tests' -201 comes from; the pin file (+196) is coverage that did not exist before, cut from 804 lines to the invariants no single file shows.

Review:

  • Copilot review: 4 threads folded (the auto-format split; the fleet pin at @stable alone; 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's continue-on-error invariant), 1 recorded (the checkout-predates-the-action window below).
  • Gate review at 6bed8bc: 1 nit folded as a follow-up commit (the shape pin projects continue-on-error).
  • Codex rubber-duck: 12 rounds, converged with zero findings. Rounds 1-5 each found one bypass of the pin derivation (case-insensitive input comparison; a line-regex 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:

  • Converting every local 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.
  • A runtime validation step for the composite's inputs.
  • A scripts: true install variant (no job needs lifecycle scripts).
  • Projecting env, working-directory, and id of the composite's steps (none is set today).
  • auto-fix's retry-after-rejection branch in auto-format's push (a rejected lease already fails the step, and the label still comes off).
  • Per-job snapshot pins (the composite step's inputs and gate per job, the composite's full step shape, the head-moved guard's notice text): cut by the simplification review as restatement of the files; the invariants stay.

Coordination: based on main after #196, #197, and #198 landed; the fuzz-issue uses: lines and auto-fix's generator run: 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.

Copilot AI balanced review requested due to automatic review settings September 13, 2026 07:37
@github-actions

Copy link
Copy Markdown
Contributor

File size check

0 over a hard cap (fails), 6 warning(s).

File Size Tier Cap
.github/scripts/release-pipeline.ts 1755 lines warn 1600
.github/scripts/release-pipeline.ts:339 168 chars warn 150
.github/scripts/release-pipeline.ts:1 26 comment lines (header) warn 25
.github/scripts/release-pipeline.ts:1572 13 comment lines warn 10
.github/workflows/post-green.yml:139 11 comment lines warn 10
test/docs/guides.test.ts:468 155 chars warn 150

Split the file, wrap the line, shorten or exempt the comment, or list the path in .file-size-allow.local with a # reason.

4 managed file(s) skipped; repo-platform owns them.

@Vivswan Vivswan added the merge-when-green Owner approved: merge once every gate is green label Sep 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread .github/workflows/auto-format.yml Outdated
Comment thread test/docs/repo-owned-workflows.test.ts Outdated
@Vivswan
Vivswan marked this pull request as ready for review September 13, 2026 07:43
…l lint gate runs for real; one loader behind the workflow pins
Copilot AI review requested due to automatic review settings September 13, 2026 07:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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.

Copilot AI review requested due to automatic review settings September 13, 2026 08:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 local uses path 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 local uses path 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-release checks out steps.source.outputs.sha above, 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

  • needsBun treats text in comments and heredoc bodies as executed Bun commands. RUNS_BUN is applied to the whole run scalar, so cat <<EOF\nbun test\nEOF or # bun test makes a no-Bun job derive 0 setup steps for a job running bun; the negative control below even codifies the comment as true. Filter executedLines and 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.

Comment thread .github/workflows/auto-format.yml
Copilot AI review requested due to automatic review settings September 13, 2026 08:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 later Remove the fix-lint label step still runs; this workflow triggers only on labeled, so no run is queued for the new head. Preserve a stale-head flag and re-add fix-lint after 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.yml documents the same failure mode and wraps its fuzz command with timeout. 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/setup is absent and the job stops before Build 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: true here leaves setupOf returning the same composite(...) pin, so a failed Bun install can be ignored and later steps run without the locked dependencies. Include the setup step's continue-on-error in 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> # v7 matches this regex and passes pinProblem, 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.

Comment thread .github/workflows/update-release.yml
Copilot AI review requested due to automatic review settings September 13, 2026 08:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread test/docs/repo-owned-workflows.test.ts
Copilot AI review requested due to automatic review settings September 13, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-when-green Owner approved: merge once every gate is green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants