Skip to content

docs(ci): add .buildkite/ scaffold + Buildkite setup runbook#486

Open
mattwilkinsonn wants to merge 15 commits into
mainfrom
sea-587-buildkite-migration--poseidon
Open

docs(ci): add .buildkite/ scaffold + Buildkite setup runbook#486
mattwilkinsonn wants to merge 15 commits into
mainfrom
sea-587-buildkite-migration--poseidon

Conversation

@mattwilkinsonn

@mattwilkinsonn mattwilkinsonn commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Pull request

Summary

Establishes the Buildkite CI infrastructure by adding the .buildkite/ directory with an orchestrator pipeline, a lints pipeline, a tool-install script, and a comprehensive setup runbook (docs/buildkite-setup.md). The lints job is removed from .github/workflows/ci.yml and migrated to Buildkite, where it runs as the seal-lints downstream pipeline triggered by the orchestrator.

Changes

  • Added .buildkite/README.md describing the pipeline layout, path-filtering strategy, and which workflows intentionally remain on GitHub Actions
  • Added .buildkite/pipelines/orchestrator.yml as the single Buildkite GitHub App entrypoint: runs the Graphite-CI optimizer, then uses monorepo-diff-buildkite-plugin to fan out trigger: steps to per-concern downstream pipelines based on path filters mirroring .github/path-filters/*.yml
  • Added .buildkite/pipelines/lints.yml running check-fmt, actionlint, and the docs site lint/check suite (biome, markdownlint-cli2, astro check) on a linux-amd64 hosted agent with S3-backed bun install cache
  • Added .buildkite/scripts/lints-install-tools.sh to idempotently install rustfmt, actionlint (SHA-pinned), just, nvm/Node 24, and bun on the agent
  • Removed the lints job from .github/workflows/ci.yml
  • Added buildkite-agent and bk CLI installation to just install-deps — via Homebrew on macOS and via pinned release tarballs into $CARGO_HOME/bin on Linux
  • Added docs/buildkite-setup.md covering the full one-time setup: Buildkite org and agent queue configuration, GitHub App installation, required-status-check naming and two-step rollout order, path filtering, Graphite integration, per-pipeline secrets inventory, and S3-backed cache strategy

Notes for reviewers

  • The orchestrator's trigger: steps for seal-test-linux, seal-test-macos, seal-live-tests, seal-clients-even-terminal, and seal-docs are wired but those downstream pipeline YAML files are not included in this PR — they land separately.
  • The runbook documents the two-step required-check rollout order (land pipeline first, add to ruleset after first conclusion) to avoid locking the merge queue.
  • Live API Tests can also be triggered by adding a live-tests label to a PR, independent of path changes, via a dedicated trigger: step in the orchestrator.
  • Downstream pipelines have no direct GitHub App connection — commit statuses (buildkite/seal-lints, buildkite/seal-test-linux, etc.) are posted back to GitHub through the orchestrator's triggered builds.

@linear-code

linear-code Bot commented Jun 6, 2026

Copy link
Copy Markdown

SEA-587

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Buildkite CI: README and placeholders, an orchestrator pipeline that fans out to downstream pipelines via monorepo-diff, a lints pipeline and installer script, GitHub Actions lints removal, Justfile tooling installs, and a detailed runbook in docs/buildkite-setup.md.

Changes

Buildkite CI Infrastructure Documentation

Layer / File(s) Summary
Buildkite overview and directory index
.buildkite/README.md
README introduces the .buildkite/ layout and orchestrator fan-out model, explains the monorepo-diff static YAML trigger approach, lists which CI workflows remain on GitHub Actions, and points to the detailed runbook and local tooling expectations.
Directory structure placeholders
.buildkite/hooks/.gitkeep, .buildkite/pipelines/.gitkeep
Placeholder .gitkeep files describe the purpose of hooks/ and pipelines/ and note they can be removed when real files are added.
Orchestrator, lints pipeline, and installer script
.buildkite/pipelines/orchestrator.yml, .buildkite/pipelines/lints.yml, .buildkite/scripts/lints-install-tools.sh, .github/workflows/ci.yml
Adds an orchestrator pipeline with a Graphite optimizer and monorepo-diff-based watch: triggers to synchronously trigger downstream pipelines, an always-run seal-lints trigger, a new lints pipeline to run formatting/actionlint/docs checks, an idempotent installer script for lints tooling, and removes the previous lints job from GitHub Actions CI.
Local tooling install changes
Justfile
Extends install-deps to install buildkite-agent and bk on macOS (Homebrew) and Linux (resolve GitHub releases and install binaries into ${CARGO_HOME:-$HOME/.cargo}/bin), with warnings on failures.
Buildkite setup and configuration runbook
docs/buildkite-setup.md
Adds a detailed runbook covering one-time Buildkite/GitHub App setup, commit-status naming and rollout, agent/queue configuration, monorepo path-filter coordination, Graphite integration, secret naming/injection, S3-backed cache configuration and key shapes, developer tooling/workflows, and verification notes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 In burrows of YAML the pipelines bloom,

Orchestrator hums and fans out the room,
Hooks and scripts snug in .buildkite/ nests,
Runbook and lints keep our checks at rest,
I hop, I stamp—green checkmarks are my guests.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding Buildkite CI scaffold and setup runbook.
Description check ✅ Passed The description comprehensively details all changes in the PR, including new files, removed jobs, and updates to existing files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sea-587-buildkite-migration--poseidon

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor Author

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • Merge Queue - adds this PR to the back of the merge queue
  • Merge Queue Fast Track - for urgent changes, fast-track this PR to the front of the merge queue

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has required the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps

greptile-apps Bot commented Jun 6, 2026

Copy link
Copy Markdown

Greptile Summary

Establishes the Buildkite CI infrastructure: a .buildkite/ scaffold with an orchestrator pipeline, a lints pipeline, a CI base image (Dockerfile.ci), path-filter files, a path-filtered fan-out script with a pure-bash test harness, and a comprehensive setup runbook. The lints job is removed from .github/workflows/ci.yml and migrated to Buildkite, where it runs as seal-lints triggered by the orchestrator.

  • The orchestrator + fan-out design is well-thought-out: single-sourced path filters drive both local just ci gating and Buildkite trigger steps, and the ci-image → consumer depends_on chaining prevents racing a stale image on the same build.
  • The test-linux.yml pipeline carefully handles the bwrap-in-docker flag set (SYS_ADMIN, apparmor/seccomp/systempaths=unconfined, /dev/fuse), non-root via ci-entrypoint, and the build+test single-job constraint to avoid unreliable CoW cache-volume cross-job artifact visibility.
  • Several supply-chain hardening issues (SHA verification gaps in Dockerfile.ci, mutable graphite-ci#main plugin ref, missing git fetch before merge-base) were flagged in prior review threads and remain open.

Confidence Score: 4/5

Safe to merge with the understanding that the open prior-thread issues will be addressed in follow-up commits.

The fan-out script calls git merge-base HEAD origin/main without first fetching origin/main, which can abort the entire orchestrator build on shallow Buildkite checkouts — every PR fan-out step fails with no downstream pipelines triggered. This is a real operational failure mode on the new infrastructure's critical path.

.buildkite/scripts/fan-out.sh (missing fetch before merge-base), .buildkite/images/Dockerfile.ci (SHA verification gaps), .buildkite/pipelines/orchestrator.yml (mutable graphite-ci plugin ref)

Important Files Changed

Filename Overview
.buildkite/scripts/fan-out.sh Orchestrator path-filter fan-out script; correctly reads filter files and emits trigger steps — but git merge-base HEAD origin/main runs without a prior git fetch origin main, so the ref may be absent on shallow Buildkite checkouts (flagged in prior thread).
.buildkite/images/Dockerfile.ci Base CI image with pinned tool versions; amd64 actionlint is SHA-verified but arm64 is not, and cargo-binstall, sccache, just, and taplo are all fetched without integrity checks (flagged in prior threads).
.buildkite/pipelines/orchestrator.yml Single entrypoint pipeline; withgraphite/graphite-ci#main plugin is pinned to a mutable branch ref, breaking the repo's supply-chain pinning posture (flagged in prior thread).
.buildkite/pipelines/lints.yml Lints pipeline running fmt, actionlint, and docs site checks inside seal-ci; well-structured with correct S3-backed bun cache and frozen-lockfile enforcement.
.buildkite/pipelines/test-linux.yml Linux test pipeline with clippy and nextest steps; correctly handles bwrap-in-docker flags, CoW cache volumes, sccache R2 credentials, and nextest exit-code capture for JUnit artifact upload.
.buildkite/scripts/test-fan-out.sh Pure-bash test harness for fan-out.sh; comprehensive coverage of filter parsing, path matching, trigger shape, and depends_on chaining scenarios.
.buildkite/pipelines/ci-image.yml Image build-and-push pipeline; uses OIDC auth (no PAT), --push direct to registry, and post-push smoke check. No --platform flag needed since hosted agents are amd64-only for now.
.buildkite/images/ci-entrypoint.sh Container entrypoint that re-owns root-owned mounts then drops to uid 1000 via setpriv; handles the hosted-agent ownership seam correctly.
Justfile Adds buildkite-agent and bk CLI to install-deps; updates ci/path-filter comments to point at .buildkite/; one historical SEA-499 comment was incorrectly updated from .github/path-filters.yml to .buildkite/path-filters.yml.
docs/buildkite-setup.md Comprehensive one-time setup runbook; BUILDKITE_SECRETS_ prefix naming convention was flagged as incorrect in a prior thread.
.github/workflows/ci.yml Lints job removed and migrated to Buildkite; remaining GHA workflows are unchanged in behavior.

Reviews (30): Last reviewed commit: "fix(ci): junit artifact copied past the ..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.buildkite/README.md:
- Around line 37-39: Update the phrasing for the `nightly.yml` bullet so it
doesn't claim "non-x64 runners" while listing `macos-26-intel`; instead describe
that `nightly.yml` runs across multiple architectures/hosts — e.g., "coverage
for multiple architectures/hosts (e.g., `ubuntu-24.04-arm`, `macos-latest`,
`macos-26-intel`)" — so the entry for `nightly.yml` accurately reflects
inclusion of both ARM and Intel mac runners.

In `@docs/buildkite-setup.md`:
- Around line 31-34: The text incorrectly treats "pull_request: synchronize" as
a separate event; update the sentence to say Buildkite listens to the GitHub
'pull_request' event (including actions like 'synchronize') and 'push' events,
so rephrase to clarify that 'synchronize' is an action under 'pull_request'
rather than its own event and ensure the identifiers 'pull_request' and
'synchronize' are used precisely in the sentence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ac2e0551-487e-416a-96f3-7661eec839b2

📥 Commits

Reviewing files that changed from the base of the PR and between 207c70f and 15ab235.

📒 Files selected for processing (4)
  • .buildkite/README.md
  • .buildkite/hooks/.gitkeep
  • .buildkite/pipelines/.gitkeep
  • docs/buildkite-setup.md

Comment thread .buildkite/README.md Outdated
Comment thread docs/buildkite-setup.md Outdated
Comment thread docs/buildkite-setup.md
Comment thread .buildkite/README.md Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.buildkite/pipelines/orchestrator.yml (1)

169-183: ⚠️ Potential issue | 🟡 Minor

Prevent duplicate seal-live-tests triggers when both LLM paths change and the live-tests label is present

  • Buildkite doesn’t automatically deduplicate multiple trigger steps that target the same downstream pipeline; each matching trigger step creates its own downstream build.
  • .buildkite/pipelines/orchestrator.yml contains two separate seal-live-tests triggers (the LLM path-filtered one plus the label-gated one build.pull_request.labels includes "live-tests"), with no cancellation/dedup mechanism configured here.
  • Mitigate by enabling “Cancel Intermediate Builds” on the seal-live-tests pipeline (or document that the double-run is intentional/acceptable).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.buildkite/pipelines/orchestrator.yml around lines 169 - 183, The pipeline
has two separate trigger steps that both call the downstream pipeline
"seal-live-tests" (the LLM path-filtered trigger plus the label-gated trigger
labeled ":satellite: Live API Tests (label-triggered)"), which can cause
duplicate downstream builds when a PR both changes LLM paths and has the
"live-tests" label; fix by enabling "Cancel Intermediate Builds" (or equivalent
automatic dedup/cancellation) on the downstream "seal-live-tests" pipeline OR
add documentation/comments near the trigger step explaining the double-run is
intentional/acceptable so maintainers know why duplicates occur; ensure the
change references the trigger name "seal-live-tests" and the label-gated step to
avoid accidental edits elsewhere.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/buildkite-setup.md`:
- Around line 156-160: The PR objectives claim GRAPHITE_TOKEN is no longer
required but the docs and pipeline still reference GRAPHITE_TOKEN and the
orchestrator injects graphite_token: "$$GRAPHITE_TOKEN"; either update the PR
objectives summary to state that GRAPHITE_TOKEN is required, or remove
references and injection of GRAPHITE_TOKEN from docs/buildkite-setup.md and
.buildkite/pipelines/orchestrator.yml; specifically reconcile and change the PR
objectives text to match the actual state or remove the env var usage
(GRAPHITE_TOKEN and graphite_token) from the orchestrator pipeline and docs so
they are consistent.

In `@Justfile`:
- Around line 159-216: The bk download URL is incorrect; update the bk_url
construction in the bk installation block (where bk_tag is resolved) to use the
published asset name pattern "bk_${bk_tag}_linux_${bk_arch}.tar.gz" instead of
"cli_${bk_tag}_linux_${bk_arch}.tar.gz" so the URL becomes
https://github.com/buildkite/cli/releases/download/v${bk_tag}/bk_${bk_tag}_linux_${bk_arch}.tar.gz;
ensure this change is made in the code that sets bk_url (the section using
bk_tag and bk_arch before fetching and extracting bk).

---

Outside diff comments:
In @.buildkite/pipelines/orchestrator.yml:
- Around line 169-183: The pipeline has two separate trigger steps that both
call the downstream pipeline "seal-live-tests" (the LLM path-filtered trigger
plus the label-gated trigger labeled ":satellite: Live API Tests
(label-triggered)"), which can cause duplicate downstream builds when a PR both
changes LLM paths and has the "live-tests" label; fix by enabling "Cancel
Intermediate Builds" (or equivalent automatic dedup/cancellation) on the
downstream "seal-live-tests" pipeline OR add documentation/comments near the
trigger step explaining the double-run is intentional/acceptable so maintainers
know why duplicates occur; ensure the change references the trigger name
"seal-live-tests" and the label-gated step to avoid accidental edits elsewhere.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b12ca056-d8c2-4579-a0d5-edd3b391488d

📥 Commits

Reviewing files that changed from the base of the PR and between 15ab235 and 4149144.

📒 Files selected for processing (7)
  • .buildkite/README.md
  • .buildkite/pipelines/lints.yml
  • .buildkite/pipelines/orchestrator.yml
  • .buildkite/scripts/lints-install-tools.sh
  • .github/workflows/ci.yml
  • Justfile
  • docs/buildkite-setup.md
💤 Files with no reviewable changes (1)
  • .github/workflows/ci.yml

Comment thread docs/buildkite-setup.md Outdated
Comment thread Justfile
mattwilkinsonn added a commit that referenced this pull request Jun 7, 2026
@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch from 6389736 to 8b87901 Compare June 7, 2026 23:43

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.buildkite/pipelines/orchestrator.yml (1)

39-39: ⚠️ Potential issue | 🟠 Major

Pin the Graphite Buildkite plugin to an immutable ref (don’t use #main)

In .buildkite/pipelines/orchestrator.yml (line 39), - withgraphite/graphite-ci#main: should be changed to - withgraphite/graphite-ci#<git-tag> or the most robust - withgraphite/graphite-ci#<full-commit-sha>. Buildkite recommends immutable plugin refs (tags/SHAs) and avoiding branch refs like #main; Graphite’s plugin repo does not appear to provide stable version tags, so pinning to a specific commit SHA is the practical option here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.buildkite/pipelines/orchestrator.yml at line 39, Replace the mutable plugin
ref "- withgraphite/graphite-ci#main:" with an immutable ref by pinning to a
specific tag or full commit SHA (e.g. "- withgraphite/graphite-ci#<git-tag>" or
"- withgraphite/graphite-ci#<full-commit-sha>") so the Buildkite pipeline uses a
fixed plugin version; update the occurrence of "-
withgraphite/graphite-ci#main:" accordingly in the orchestrator pipeline
definition.
Justfile (1)

184-207: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Verify downloaded Buildkite binaries before installing them to PATH.

This block installs executables from GitHub release tarballs without checksum/signature validation, which weakens the trust boundary for local developer tooling.

Suggested hardening
-                    if curl -fsSL -o "$tmp_dir/bk.tar.gz" "$bk_url"; then
+                    checks_url="https://github.com/buildkite/cli/releases/download/v${bk_tag}/checksums.txt"
+                    if curl -fsSL -o "$tmp_dir/checksums.txt" "$checks_url" \
+                       && curl -fsSL -o "$tmp_dir/bk.tar.gz" "$bk_url" \
+                       && (cd "$tmp_dir" && grep "bk_${bk_tag}_linux_${bk_arch}.tar.gz" checksums.txt | sha256sum --check --strict); then
                         tar -xzf "$tmp_dir/bk.tar.gz" -C "$tmp_dir" bk
                         install -m 0755 "$tmp_dir/bk" "$bin_dir/bk"
#!/usr/bin/env bash
set -euo pipefail
echo "Agent release assets:"
gh api repos/buildkite/agent/releases/latest --jq '.assets[].name'
echo
echo "CLI release assets:"
gh api repos/buildkite/cli/releases/latest --jq '.assets[].name'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Justfile` around lines 184 - 207, The script currently downloads
buildkite-agent and bk tarballs using ba_url/bk_url and installs files from
tmp_dir without integrity/authenticity checks; update the download-and-install
blocks for buildkite-agent (ba_url, tmp_dir, buildkite-agent) and bk (bk_url,
tmp_dir, bk) to (1) fetch corresponding release asset checksums or signatures
(via the GitHub releases API or provided .sha256/.asc assets), (2) verify the
downloaded tarball using sha256sum --check or gpg --verify before extracting,
(3) abort and emit a clear error if verification fails, and (4) only run
tar/extract and install -m 0755 into $bin_dir once verification succeeds,
ensuring tmp_dir cleanup still happens on both success and failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.buildkite/pipelines/orchestrator.yml:
- Line 39: Replace the mutable plugin ref "- withgraphite/graphite-ci#main:"
with an immutable ref by pinning to a specific tag or full commit SHA (e.g. "-
withgraphite/graphite-ci#<git-tag>" or "-
withgraphite/graphite-ci#<full-commit-sha>") so the Buildkite pipeline uses a
fixed plugin version; update the occurrence of "-
withgraphite/graphite-ci#main:" accordingly in the orchestrator pipeline
definition.

In `@Justfile`:
- Around line 184-207: The script currently downloads buildkite-agent and bk
tarballs using ba_url/bk_url and installs files from tmp_dir without
integrity/authenticity checks; update the download-and-install blocks for
buildkite-agent (ba_url, tmp_dir, buildkite-agent) and bk (bk_url, tmp_dir, bk)
to (1) fetch corresponding release asset checksums or signatures (via the GitHub
releases API or provided .sha256/.asc assets), (2) verify the downloaded tarball
using sha256sum --check or gpg --verify before extracting, (3) abort and emit a
clear error if verification fails, and (4) only run tar/extract and install -m
0755 into $bin_dir once verification succeeds, ensuring tmp_dir cleanup still
happens on both success and failure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 57ff2619-cbcf-4754-92a7-104b1ad3af35

📥 Commits

Reviewing files that changed from the base of the PR and between 6389736 and 8b87901.

📒 Files selected for processing (4)
  • .buildkite/pipelines/lints.yml
  • .buildkite/pipelines/orchestrator.yml
  • Justfile
  • docs/buildkite-setup.md

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.buildkite/pipelines/orchestrator.yml (2)

25-42: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pin the Graphite-CI plugin to a stable version or commit SHA.

The plugin reference withgraphite/graphite-ci#main tracks the main branch, which means the pipeline can break without warning if the plugin changes. For production CI stability, pin to a specific release tag or commit SHA (e.g., withgraphite/graphite-ci#v1.2.3 or withgraphite/graphite-ci#abc123).

📌 Proposed fix to pin the plugin version
     plugins:
-      - withgraphite/graphite-ci#main:
+      - withgraphite/graphite-ci#v1.0.0:  # Replace with actual stable version/SHA
           # GRAPHITE_TOKEN injected by Buildkite's pipeline-level
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.buildkite/pipelines/orchestrator.yml around lines 25 - 42, The pipeline
step using the Graphite CI plugin (label ":graphite: Graphite CI optimizer",
plugin reference withgraphite/graphite-ci#main) should be pinned to a specific
release tag or commit SHA instead of tracking `#main`; update the plugin
reference `withgraphite/graphite-ci#main` to a fixed identifier like
`withgraphite/graphite-ci#vX.Y.Z` or `withgraphite/graphite-ci#<commit-sha>` to
ensure CI stability and avoid unexpected breakage.

43-53: 🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff

Verify that synchronous lints trigger aligns with orchestrator performance goals.

The async: false configuration blocks the orchestrator step until the seal-lints pipeline completes. While this ensures correct commit-status ordering for branch protection, it also means the orchestrator agent remains occupied during the entire lints run (~8min cold-cache budget per lints.yml). If downstream pipelines will eventually run concurrently (seal-test-linux, seal-test-macos, etc.), confirm whether the orchestrator should block on lints or trigger all pipelines asynchronously and rely on GitHub's commit-status aggregation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.buildkite/pipelines/orchestrator.yml around lines 43 - 53, The orchestrator
step for the Lints pipeline currently uses "async: false" which blocks the
orchestrator agent while "seal-lints" runs; change the step with label
":hammer_and_wrench: Lints" (trigger: "seal-lints") to "async: true" so the
orchestrator no longer waits for completion, and add/adjust a brief comment
noting we rely on GitHub commit-status aggregation for final gating; if you
decide to keep synchronous behavior instead, document the performance tradeoff
and leave "async: false" intentionally.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.buildkite/pipelines/orchestrator.yml:
- Around line 25-42: The pipeline step using the Graphite CI plugin (label
":graphite: Graphite CI optimizer", plugin reference
withgraphite/graphite-ci#main) should be pinned to a specific release tag or
commit SHA instead of tracking `#main`; update the plugin reference
`withgraphite/graphite-ci#main` to a fixed identifier like
`withgraphite/graphite-ci#vX.Y.Z` or `withgraphite/graphite-ci#<commit-sha>` to
ensure CI stability and avoid unexpected breakage.
- Around line 43-53: The orchestrator step for the Lints pipeline currently uses
"async: false" which blocks the orchestrator agent while "seal-lints" runs;
change the step with label ":hammer_and_wrench: Lints" (trigger: "seal-lints")
to "async: true" so the orchestrator no longer waits for completion, and
add/adjust a brief comment noting we rely on GitHub commit-status aggregation
for final gating; if you decide to keep synchronous behavior instead, document
the performance tradeoff and leave "async: false" intentionally.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 099b1c85-d833-4290-b824-0e6d6f3a6085

📥 Commits

Reviewing files that changed from the base of the PR and between 8b87901 and 97d473b.

📒 Files selected for processing (2)
  • .buildkite/pipelines/lints.yml
  • .buildkite/pipelines/orchestrator.yml

Comment on lines +102 to +104
&& if [ "${actionlint_arch}" = "amd64" ]; then \
echo "${ACTIONLINT_SHA256} /tmp/${tarball}" | sha256sum --check --strict; \
fi \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SHA256 verification is only performed for amd64 architecture but skipped for arm64. This creates a security vulnerability where arm64 builds could download and execute a compromised actionlint binary without integrity verification.

# Fix: Add SHA256 verification for arm64 as well
ARG ACTIONLINT_SHA256_ARM64=<arm64_sha256_here>
...
&& if [ "${actionlint_arch}" = "amd64" ]; then \
       echo "${ACTIONLINT_SHA256}  /tmp/${tarball}" | sha256sum --check --strict; \
   elif [ "${actionlint_arch}" = "arm64" ]; then \
       echo "${ACTIONLINT_SHA256_ARM64}  /tmp/${tarball}" | sha256sum --check --strict; \
   fi \
Suggested change
&& if [ "${actionlint_arch}" = "amd64" ]; then \
echo "${ACTIONLINT_SHA256} /tmp/${tarball}" | sha256sum --check --strict; \
fi \
&& if [ "${actionlint_arch}" = "amd64" ]; then \
echo "${ACTIONLINT_SHA256} /tmp/${tarball}" | sha256sum --check --strict; \
elif [ "${actionlint_arch}" = "arm64" ]; then \
echo "${ACTIONLINT_SHA256_ARM64} /tmp/${tarball}" | sha256sum --check --strict; \
fi \

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch 3 times, most recently from d096d99 to 7800fe7 Compare June 11, 2026 01:33
Comment thread .buildkite/images/Dockerfile.ci
@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch 4 times, most recently from daefcdc to bef29b1 Compare June 11, 2026 02:17
Comment on lines +73 to +122
# sccache — RUSTC_WRAPPER target for the Test pipelines.
RUN ARCH="$(uname -m)" \
&& case "${ARCH}" in \
x86_64) sccache_target="x86_64-unknown-linux-musl" ;; \
aarch64) sccache_target="aarch64-unknown-linux-musl" ;; \
*) echo "unsupported arch ${ARCH}"; exit 1 ;; \
esac \
&& curl -fsSL "https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/sccache-v${SCCACHE_VERSION}-${sccache_target}.tar.gz" \
| tar -xz -C /tmp \
&& install -m 0755 "/tmp/sccache-v${SCCACHE_VERSION}-${sccache_target}/sccache" /usr/local/bin/sccache \
&& rm -rf /tmp/sccache-*

# just — release binary download. Avoids cargo-installing it inside
# the image (would pull every cargo dep).
RUN ARCH="$(uname -m)" \
&& case "${ARCH}" in \
x86_64) just_target="x86_64-unknown-linux-musl" ;; \
aarch64) just_target="aarch64-unknown-linux-musl" ;; \
*) echo "unsupported arch ${ARCH}"; exit 1 ;; \
esac \
&& curl -fsSL "https://github.com/casey/just/releases/download/${JUST_VERSION}/just-${JUST_VERSION}-${just_target}.tar.gz" \
| tar -xz -C /tmp just \
&& install -m 0755 /tmp/just /usr/local/bin/just \
&& rm /tmp/just

# actionlint — SHA-pinned release binary. Matches the version the
# old install-script used.
RUN ARCH="$(uname -m)" \
&& case "${ARCH}" in \
x86_64) actionlint_arch="amd64" ;; \
aarch64) actionlint_arch="arm64" ;; \
*) echo "unsupported arch ${ARCH}"; exit 1 ;; \
esac \
&& tarball="actionlint_${ACTIONLINT_VERSION}_linux_${actionlint_arch}.tar.gz" \
&& curl -fsSL -o "/tmp/${tarball}" "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/${tarball}" \
&& if [ "${actionlint_arch}" = "amd64" ]; then \
echo "${ACTIONLINT_SHA256} /tmp/${tarball}" | sha256sum --check --strict; \
fi \
&& tar -xzf "/tmp/${tarball}" -C /tmp actionlint \
&& install -m 0755 /tmp/actionlint /usr/local/bin/actionlint \
&& rm "/tmp/${tarball}" /tmp/actionlint

# taplo — TOML formatter, used by hk.pkl pre-push hook + occasional
# CI use. Release assets are named by plain machine arch:
# `taplo-linux-x86_64.gz` / `taplo-linux-aarch64.gz`.
RUN ARCH="$(uname -m)" \
&& curl -fsSL "https://github.com/tamasfe/taplo/releases/download/${TAPLO_VERSION}/taplo-linux-${ARCH}.gz" \
| gunzip > /tmp/taplo \
&& install -m 0755 /tmp/taplo /usr/local/bin/taplo \
&& rm /tmp/taplo

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security No integrity check for taplo, sccache, or just

sccache, just, and taplo are all fetched from GitHub release URLs and installed directly — sccache and just via tar pipe, taplo via gunzip pipe — with no SHA256 verification. actionlint for amd64 correctly verifies its hash (lines 108–110), making the pattern inconsistent: a compromised or tampered release artifact for any of these three tools would be silently baked into seal-ci:latest and then run as root inside every downstream pipeline. The fix is the same pattern already used for actionlint — add ARG SHA256 constants per-arch and sha256sum --check after the download.

@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch 2 times, most recently from 0ab0a21 to 5c0a853 Compare June 11, 2026 02:44
@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch from 5c0a853 to d2bab06 Compare June 11, 2026 03:09
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown

Docs preview: https://e0efbd7e.seal-docs.pages.dev

Comment on lines +53 to +54
- sealedsecurity/secret-env#v1.0.0:
variables:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security Graphite-CI plugin pinned to mutable #main branch

The withgraphite/graphite-ci#main reference resolves to whatever commit is at main in that repo at build time, so any change — including a supply-chain compromise — is silently adopted by every orchestrator build. Every other external reference in this PR is pinned: docker#v5.13.0 uses a version tag, dorny/paths-filter in the GHA workflows uses a full commit SHA, and graphite-ci-action in the deleted ci.yml was pinned to @26bc0dcdeaba101794931d67a464ecbb21a76a8b. Pinning withgraphite/graphite-ci to a specific commit SHA keeps the same security posture the rest of the repo maintains.

- sealedsecurity/secret-env#v1.0.0:
variables:
BUILDKITE_PLUGIN_GRAPHITE_CI_GRAPHITE_TOKEN: GRAPHITE_CI_TOKEN
- withgraphite/graphite-ci#main: {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security Pin the withgraphite/graphite-ci plugin to a specific commit SHA to match the security posture used everywhere else in this PR (docker#v5.13.0, the deleted ci.yml's @26bc0dcdeaba101794931d67a464ecbb21a76a8b, and dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d). Resolve the current HEAD of the plugin and pin it here.

Suggested change
- withgraphite/graphite-ci#main: {}
- withgraphite/graphite-ci#<COMMIT_SHA>: {}

Comment on lines +73 to +74
message: "\$BUILDKITE_MESSAGE"
EOF

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Fan-out script computes diff against origin/main, but runs without git fetch

fan-out.sh calls git merge-base HEAD origin/main to find the diff base, but Buildkite hosted agents check out via the GitHub App and may not have origin/main populated in their shallow clone — the origin/main ref is only guaranteed present after an explicit git fetch origin main. If the ref is absent, git merge-base exits non-zero and the fan-out step aborts, causing the orchestrator build to fail with no downstream pipelines triggered. Consider adding git fetch origin main --no-tags --depth=1 before the merge-base call.

@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch 2 times, most recently from 030d2c1 to 067f534 Compare June 11, 2026 14:27
Comment on lines +43 to +45
test_patterns_unknown_filter_is_empty() {
! filter_patterns ci-image 2>/dev/null | grep -Fqx 'no-such-pattern'
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Test does not match its intent. The test test_patterns_unknown_filter_is_empty checks whether filter_patterns ci-image output contains 'no-such-pattern', but ci-image is a known/existing filter, not an unknown one.

# Current (incorrect):
test_patterns_unknown_filter_is_empty() {
  ! filter_patterns ci-image 2>/dev/null | grep -Fqx 'no-such-pattern'
}

# Should be:
test_patterns_unknown_filter_is_empty() {
  [[ -z "$(filter_patterns no-such-filter 2>/dev/null)" ]]
}

The test should call filter_patterns with a non-existent filter name and verify the output is empty. The current implementation will pass even if unknown filters return data, failing to catch the bug it's supposed to detect.

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch 2 times, most recently from 69ef990 to fbc1a65 Compare June 11, 2026 15:40
@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch from fbc1a65 to 404ee7b Compare June 11, 2026 16:39
Comment on lines +103 to +115
RUN ARCH="$(uname -m)" \
&& case "${ARCH}" in \
x86_64) binstall_target="x86_64-unknown-linux-musl" ;; \
aarch64) binstall_target="aarch64-unknown-linux-musl" ;; \
*) echo "unsupported arch ${ARCH}"; exit 1 ;; \
esac \
&& curl -fsSL "https://github.com/cargo-bins/cargo-binstall/releases/download/v${CARGO_BINSTALL_VERSION}/cargo-binstall-${binstall_target}.tgz" \
| tar -xz -C /usr/local/bin cargo-binstall \
&& cargo binstall --no-confirm \
"cargo-nextest@${NEXTEST_VERSION}" \
"cargo-edit@${CARGO_EDIT_VERSION}" \
"cargo-update@${CARGO_UPDATE_VERSION}" \
&& chmod -R a+w "${CARGO_HOME}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security cargo-binstall bootstrap tarball has no SHA256 check

The cargo-binstall release tarball is downloaded and piped directly into tar with no integrity verification — yet it is then trusted to install cargo-nextest, cargo-edit, and cargo-update. A compromised or tampered release artifact would silently backdoor everything that cargo binstall subsequently installs, since those invocations inherit the compromised binary's behavior. The prior review thread at line 117 flags sccache, just, and taplo for the same missing-SHA pattern, but cargo-binstall is the installer for the others and so carries compounded risk. The fix is the same: add an ARG CARGO_BINSTALL_SHA256_AMD64 / ARG CARGO_BINSTALL_SHA256_ARM64 and sha256sum --check --strict before extracting.

@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch from b751254 to 7351c3d Compare June 11, 2026 18:43
@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch from e7e1f9a to f0c7978 Compare June 11, 2026 21:01
@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch from 3ccc0d1 to bb0cf67 Compare June 12, 2026 01:15
@mattwilkinsonn mattwilkinsonn force-pushed the sea-587-buildkite-migration--poseidon branch from bb0cf67 to 6b1061a Compare June 12, 2026 01:48
Comment thread .buildkite/scripts/fan-out.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant