diff --git a/.github/workflows/branch-checks.yml b/.github/workflows/branch-checks.yml index 72f8273c1a..7b0c77c8fd 100644 --- a/.github/workflows/branch-checks.yml +++ b/.github/workflows/branch-checks.yml @@ -164,8 +164,8 @@ jobs: run: | cargo clippy --workspace --all-targets -- -D warnings cargo clippy --manifest-path e2e/rust/Cargo.toml --all-targets -- -D warnings - cargo check --manifest-path examples/governance-interceptor/Cargo.toml --all-targets - cargo check --manifest-path examples/supervisor-middleware-content-guard/Cargo.toml --all-targets + cargo clippy --manifest-path examples/governance-interceptor/Cargo.toml --all-targets -- -D warnings + cargo clippy --manifest-path examples/supervisor-middleware-content-guard/Cargo.toml --all-targets -- -D warnings - name: Test env: @@ -207,6 +207,11 @@ jobs: exit 1 fi + - name: Verify Cargo lockfiles unchanged + run: | + tasks/scripts/check-cargo-lockfiles.sh + git diff --exit-code HEAD -- ':(glob)**/Cargo.lock' + python: name: Python (${{ matrix.runner }}) needs: pr_metadata @@ -247,7 +252,6 @@ jobs: run: | bash tasks/scripts/test-gateway-pull-policy.sh bash tasks/scripts/test-gateway-config.sh - go: name: Go SDK needs: pr_metadata diff --git a/TESTING.md b/TESTING.md index 5d9674dd06..aaad71aa41 100644 --- a/TESTING.md +++ b/TESTING.md @@ -46,6 +46,8 @@ Run Rust tests only: mise run test:rust # cargo test --workspace ``` +Rust validation checks tracked Cargo lockfiles; run `mise run rust:lockfiles:check` to check them directly. If one is stale, refresh it with Cargo using its adjacent manifest, review the diff, and commit the update. + ## Python Unit Tests Python unit tests use the `*_test.py` suffix convention (not `test_*` prefix) diff --git a/architecture/build.md b/architecture/build.md index 5f3b913e1b..d6ad9914a9 100644 --- a/architecture/build.md +++ b/architecture/build.md @@ -514,6 +514,9 @@ Published docs live in `docs/`, and Fern site configuration lives in `fern/`. Se ## Validation Expectations +Rust CI rejects stale or modified Cargo lockfiles and runs Clippy for the +workspace, E2E crate, and standalone examples. + - Run `mise run pre-commit` before committing. - Run `mise run test` after code changes. - Run `mise run e2e` for sandbox, policy, driver, or deployment changes when the diff --git a/tasks/ci.toml b/tasks/ci.toml index cc4158448f..e2a388e6b1 100644 --- a/tasks/ci.toml +++ b/tasks/ci.toml @@ -54,6 +54,7 @@ description = "Run repository lint checks" depends = [ "license:check", "rust:format:check", + "rust:lockfiles:check", "rust:lint", "python:format:check", "python:lint", diff --git a/tasks/rust.toml b/tasks/rust.toml index e62e22b3cf..e8c45fd54c 100644 --- a/tasks/rust.toml +++ b/tasks/rust.toml @@ -5,17 +5,24 @@ ["rust:check"] description = "Check all Rust crates for errors" +depends = ["rust:lockfiles:check"] run = "cargo check --workspace" run_windows = "powershell -NoProfile -ExecutionPolicy Bypass -File tasks/scripts/windows-msvc.ps1 check native" hide = true +["rust:lockfiles:check"] +description = "Verify all tracked Cargo lockfiles are current" +run = "tasks/scripts/check-cargo-lockfiles.sh" +hide = true + ["rust:lint"] description = "Lint Rust code with Clippy (deny warnings)" +depends = ["rust:lockfiles:check"] run = [ "cargo clippy --workspace --all-targets -- -D warnings", "cargo clippy --manifest-path e2e/rust/Cargo.toml --all-targets -- -D warnings", - "cargo check --manifest-path examples/governance-interceptor/Cargo.toml --all-targets", - "cargo check --manifest-path examples/supervisor-middleware-content-guard/Cargo.toml --all-targets", + "cargo clippy --manifest-path examples/governance-interceptor/Cargo.toml --all-targets -- -D warnings", + "cargo clippy --manifest-path examples/supervisor-middleware-content-guard/Cargo.toml --all-targets -- -D warnings", ] run_windows = "powershell -NoProfile -ExecutionPolicy Bypass -File tasks/scripts/windows-msvc.ps1 lint native" hide = true diff --git a/tasks/scripts/check-cargo-lockfiles.sh b/tasks/scripts/check-cargo-lockfiles.sh new file mode 100755 index 0000000000..bd74d8d647 --- /dev/null +++ b/tasks/scripts/check-cargo-lockfiles.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +check_lockfile() { + local lockfile="$1" + local manifest="${lockfile%Cargo.lock}Cargo.toml" + + if [[ ! -f "$manifest" ]]; then + printf 'error: tracked lockfile %s has no adjacent Cargo.toml\n' "$lockfile" >&2 + return 1 + fi + + printf 'Checking %s\n' "$lockfile" + if ! cargo metadata \ + --locked \ + --format-version 1 \ + --manifest-path "$manifest" \ + >/dev/null; then + printf 'error: validation failed for %s\n' "$lockfile" >&2 + return 1 + fi +} + +main() { + local lockfile + local found=0 + local failed=0 + + cd "$(git rev-parse --show-toplevel)" + + # Policy: every tracked Cargo.lock represents an intentionally reproducible + # Cargo workspace and must resolve against its adjacent Cargo.toml. Manifests + # that intentionally do not own a lockfile are outside this check. + while IFS= read -r -d '' lockfile; do + found=1 + check_lockfile "$lockfile" || failed=1 + done < <(git ls-files -z -- ':(glob)**/Cargo.lock') + + if [[ "$found" -eq 0 ]]; then + echo "error: no tracked Cargo.lock files found" >&2 + return 1 + fi + + if [[ "$failed" -ne 0 ]]; then + echo "Resolve the reported errors. If a lockfile needs updating, refresh it with Cargo and commit the result." >&2 + fi + + return "$failed" +} + +main "$@" diff --git a/tasks/test.toml b/tasks/test.toml index 0fa0bd8496..8c41e70025 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -78,6 +78,7 @@ run = "bash tasks/scripts/e2e-gpu-build-images.sh" ["test:rust"] description = "Run Rust tests" +depends = ["rust:lockfiles:check"] env = { OPENSHELL_TELEMETRY_ENABLED = "false" } run = [ # Run the workspace once without openshell-server so we can run that crate