diff --git a/.github/workflows/branch-checks.yml b/.github/workflows/branch-checks.yml index 5d4a98c61a..15293454c9 100644 --- a/.github/workflows/branch-checks.yml +++ b/.github/workflows/branch-checks.yml @@ -153,6 +153,10 @@ jobs: cache-bin: "false" cmd-format: nix develop .#devShells.${{ matrix.system }}.default -c {0} + - name: Verify Cargo lockfiles + if: matrix.system == 'x86_64-linux' + run: tasks/scripts/check-cargo-lockfiles.sh + - name: Format run: | cargo fmt --all -- --check @@ -162,10 +166,10 @@ jobs: - name: Lint 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 --locked --workspace --all-targets -- -D warnings + cargo clippy --locked --manifest-path e2e/rust/Cargo.toml --all-targets -- -D warnings + cargo check --locked --manifest-path examples/governance-interceptor/Cargo.toml --all-targets + cargo check --locked --manifest-path examples/supervisor-middleware-content-guard/Cargo.toml --all-targets - name: Test env: diff --git a/TESTING.md b/TESTING.md index 14ec3c2055..ccb183f61f 100644 --- a/TESTING.md +++ b/TESTING.md @@ -46,6 +46,8 @@ Run Rust tests only: mise run test:rust # cargo test --workspace ``` +Run `mise run rust:lockfiles:check` to validate every tracked Cargo lockfile against its adjacent manifest. Cargo diagnostics explain whether a failure requires refreshing a lockfile or resolving another problem, such as registry access. To refresh a stale lockfile, run `cargo metadata --format-version 1 --manifest-path path/to/Cargo.toml > /dev/null` with the adjacent manifest, review and commit the lockfile changes, then rerun `mise run pre-commit`. + ## Python Unit Tests Python unit tests use the `*_test.py` suffix convention (not `test_*` prefix) diff --git a/tasks/rust.toml b/tasks/rust.toml index e62e22b3cf..2189da2d53 100644 --- a/tasks/rust.toml +++ b/tasks/rust.toml @@ -5,17 +5,22 @@ ["rust:check"] description = "Check all Rust crates for errors" -run = "cargo check --workspace" +run = "cargo check --locked --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)" 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 --locked --workspace --all-targets -- -D warnings", + "cargo clippy --locked --manifest-path e2e/rust/Cargo.toml --all-targets -- -D warnings", + "cargo check --locked --manifest-path examples/governance-interceptor/Cargo.toml --all-targets", + "cargo check --locked --manifest-path examples/supervisor-middleware-content-guard/Cargo.toml --all-targets", ] 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 bb1fa2e9ab..712b91b9a6 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -267,4 +267,3 @@ description = "Run GPU e2e against a standalone gateway with the Docker compute env = { OPENSHELL_E2E_DOCKER_GPU = "1", OPENSHELL_E2E_DOCKER_TEST = "gpu", OPENSHELL_E2E_DOCKER_FEATURES = "e2e-docker-gpu" } depends = ["e2e:conformance:build"] run = "OPENSHELL_CONFORMANCE_BIN=\"${OPENSHELL_CONFORMANCE_BIN:-$PWD/target/debug/openshell-conformance}\" e2e/rust/e2e-docker.sh" -