ci: fail jobs that dirty the worktree (#29720)

## Why

CI jobs should not silently leave tracked changes or untracked files in
the repository worktree.

## What

- Add a shared final worktree-cleanliness action to 19 checkout-bearing
PR and main CI jobs.
- Ignore the intentional SDK scratch directory and nested V8 checkout.
- Pin Bazelisk in shared CI setup so `.bazelversion` remains
authoritative, avoiding `MODULE.bazel.lock` deltas on Windows runners.
- Leave `rust-ci-full` and release-only workflows unchanged.
- Update `AGENTS.md` to discourage review bots from asking for
`MODULE.bazel.lock` changes.
This commit is contained in:
Adam Perry @ OpenAI
2026-06-24 11:06:35 -07:00
committed by GitHub
Unverified
parent 390b73133b
commit 93c79046d6
12 changed files with 103 additions and 3 deletions
@@ -0,0 +1,19 @@
name: check-clean-worktree
description: Fail when a CI job leaves tracked changes or untracked files in the repository worktree.
runs:
using: composite
steps:
- name: Check for a clean worktree
shell: bash
run: |
set -euo pipefail
status="$(git -C "${GITHUB_WORKSPACE}" status --porcelain=v1 --untracked-files=normal --ignore-submodules=none)"
if [[ -z "${status}" ]]; then
exit 0
fi
echo "::error::CI job left tracked changes or untracked files in the repository worktree"
printf '%s\n' "${status}"
exit 1
@@ -34,6 +34,10 @@ runs:
- name: Set up Bazel
uses: bazel-contrib/setup-bazel@c5acdfb288317d0b5c0bbd7a396a3dc868bb0f86 # 0.19.0
# Without an explicit Bazelisk version, setup-bazel leaves PATH unchanged
# and Windows can use the runner's standalone Bazel, ignoring .bazelversion.
with:
bazelisk-version: 1.28.1
- name: Configure Bazel repository cache
id: configure_bazel_repository_cache
+20
View File
@@ -134,6 +134,10 @@ jobs:
path: ${{ steps.prepare_bazel.outputs.repository-cache-path }}
key: ${{ steps.prepare_bazel.outputs.repository-cache-key }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
test-windows-shard:
# Split the Windows Bazel test leg across separate Windows hosts. Jobs with
# BuildBuddy credentials use Linux RBE for build actions; test execution
@@ -239,6 +243,10 @@ jobs:
path: ${{ runner.temp }}/bazel-execution-logs
if-no-files-found: ignore
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
test-windows:
# Preserve the existing required-check surface while the real work happens
# in the sharded Windows jobs above.
@@ -333,6 +341,10 @@ jobs:
path: ${{ steps.prepare_bazel.outputs.repository-cache-path }}
key: ${{ steps.prepare_bazel.outputs.repository-cache-key }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
clippy:
timeout-minutes: 30
strategy:
@@ -433,6 +445,10 @@ jobs:
path: ${{ steps.prepare_bazel.outputs.repository-cache-path }}
key: ${{ steps.prepare_bazel.outputs.repository-cache-key }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
verify-release-build:
timeout-minutes: 30
strategy:
@@ -545,3 +561,7 @@ jobs:
with:
path: ${{ steps.prepare_bazel.outputs.repository-cache-path }}
key: ${{ steps.prepare_bazel.outputs.repository-cache-key }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+4
View File
@@ -32,3 +32,7 @@ jobs:
--head "$HEAD_SHA" \
--max-bytes 512000 \
--allowlist .github/blob-size-allowlist.txt
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+4
View File
@@ -32,3 +32,7 @@ jobs:
with:
rust-version: 1.95.0
manifest-path: ./codex-rs/Cargo.toml
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+4
View File
@@ -88,3 +88,7 @@ jobs:
- name: Prettier (run `pnpm run format:fix` to fix)
run: pnpm run format
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+4
View File
@@ -28,3 +28,7 @@ jobs:
uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2.2
with:
ignore_words_file: .codespellignore
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+20
View File
@@ -58,6 +58,10 @@ jobs:
echo "codex=$codex" >> "$GITHUB_OUTPUT"
echo "workflows=$workflows" >> "$GITHUB_OUTPUT"
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
# --- Fast Cargo-native PR checks -------------------------------------------
general:
name: Format / etc
@@ -83,6 +87,10 @@ jobs:
- name: Rust benchmark smoke test
run: just bench-smoke
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
cargo_shear:
name: cargo shear
runs-on: ubuntu-24.04
@@ -103,6 +111,10 @@ jobs:
- name: cargo shear
run: cargo shear --deny-warnings
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
argument_comment_lint_package:
name: Argument comment lint package
runs-on: ubuntu-24.04
@@ -154,6 +166,10 @@ jobs:
env:
RUST_MIN_STACK: "8388608" # 8 MiB
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
argument_comment_lint_prebuilt:
name: Argument comment lint - ${{ matrix.name }}
runs-on: ${{ matrix.runs_on || matrix.runner }}
@@ -205,6 +221,10 @@ jobs:
target: ${{ runner.os }}
buildbuddy-api-key: ${{ secrets.BUILDBUDDY_API_KEY }}
- name: Check for a clean worktree
if: always() && !cancelled() && steps.argument_comment_lint_gate.outputs.run == 'true'
uses: ./.github/actions/check-clean-worktree
# --- Gatherer job that you mark as the ONLY required status -----------------
results:
name: CI results (required)
+8
View File
@@ -41,6 +41,10 @@ jobs:
/tmp/uv/bin/uv run --frozen --no-sync pytest
'
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
sdks:
runs-on:
group: ${{ github.event.repository.name }}-runners
@@ -161,3 +165,7 @@ jobs:
path: |
~/.cache/bazel-repo-cache
key: bazel-cache-x86_64-unknown-linux-gnu-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+12
View File
@@ -97,6 +97,10 @@ jobs:
echo "${output}"
echo "${output}" >> "${GITHUB_OUTPUT}"
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
build:
name: Build ${{ matrix.variant }} ${{ matrix.target }}
needs: metadata
@@ -322,6 +326,10 @@ jobs:
name: v8-canary-${{ needs.metadata.outputs.v8_version }}-${{ matrix.variant }}-${{ matrix.target }}
path: dist/${{ matrix.target }}/*
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
build-windows-source:
name: Build ptrcomp-sandbox ${{ matrix.target }} from source
needs: metadata
@@ -459,3 +467,7 @@ jobs:
with:
name: v8-canary-${{ needs.metadata.outputs.v8_version }}-ptrcomp-sandbox-${{ matrix.target }}
path: dist/${{ matrix.target }}/*
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+2
View File
@@ -60,6 +60,8 @@ yarn-error.log*
# ci
.vercel/
.netlify/
/.tmp/sdk-ci/
/upstream-rusty-v8/
# patches
apply_patch/
+2 -3
View File
@@ -35,9 +35,8 @@ In the codex-rs folder where the rust code lives:
- When working with MCP tool calls, prefer using `codex-rs/codex-mcp/src/mcp_connection_manager.rs` to handle mutation of tools and tool calls. Aim to minimize the footprint of changes and leverage existing abstractions rather than plumbing code through multiple levels of function calls.
- Do not call `reset_client_session` unnecessarily; let the incremental check logic decide whether to reuse the previous request.
- If you change Rust dependencies (`Cargo.toml` or `Cargo.lock`), run `just bazel-lock-update` from the
repo root to refresh `MODULE.bazel.lock`, and include that lockfile update in the same change.
- After dependency changes, run `just bazel-lock-check` from the repo root so lockfile drift is caught
locally before CI.
repo root to refresh `MODULE.bazel.lock`, and include that lockfile update in the same change. CI
verifies lockfile drift.
- Bazel does not automatically make source-tree files available to compile-time Rust file access. If
you add `include_str!`, `include_bytes!`, `sqlx::migrate!`, or similar build-time file or
directory reads, update the crate's `BUILD.bazel` (`compile_data`, `build_script_data`, or test