From 9a0b78102a0c18b6cec925a2b730756e6f6ad497 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:50:37 -0700 Subject: [PATCH 01/58] ci: pin Rust 1.97.1 in product verification --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f99a9c17..ce46c2265 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,8 +36,8 @@ jobs: run: npm ci - name: Sync Python dependencies run: uv sync --project services/analysis-engine --group dev --frozen - - name: Install stable Rust toolchain - run: rustup toolchain install stable --profile minimal + - name: Install Rust 1.97.1 toolchain + run: rustup toolchain install 1.97.1 --profile minimal - name: Build and install Rust numeric extension run: | VENV_PY="$PWD/services/analysis-engine/.venv/bin/python" @@ -58,13 +58,13 @@ jobs: with: node-version: 22.22.3 cache: npm - - name: Install stable Rust toolchain - run: rustup toolchain install stable --profile minimal + - name: Install Rust 1.97.1 toolchain + run: rustup toolchain install 1.97.1 --profile minimal - name: Install node dependencies run: npm ci - name: Build frontend run: npm run build --workspace @bandscope/desktop - name: Check Tauri shell - run: cargo +stable check --manifest-path apps/desktop/src-tauri/Cargo.toml --locked + run: cargo +1.97.1 check --manifest-path apps/desktop/src-tauri/Cargo.toml --locked - name: Test Tauri shell - run: cargo +stable test --manifest-path apps/desktop/src-tauri/Cargo.toml --locked + run: cargo +1.97.1 test --manifest-path apps/desktop/src-tauri/Cargo.toml --locked From 31dd8351197835f5800f40e673570591786827e1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:50:55 -0700 Subject: [PATCH 02/58] ci: pin Rust 1.97.1 in release preflight --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 84ace55d4..e5cd7a722 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,8 +40,8 @@ jobs: with: version: "0.8.6" enable-cache: false - - name: Install Rust stable - run: rustup toolchain install stable --profile minimal + - name: Install Rust 1.97.1 + run: rustup toolchain install 1.97.1 --profile minimal - name: Install node dependencies run: npm ci - name: Sync Python dependencies From 9ba4f2144b7e8a7e17c7bd1cd8655a310c926f1d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:51:14 -0700 Subject: [PATCH 03/58] ci: pin Rust 1.97.1 in dependency audit --- .github/workflows/security-audit.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml index 7d880c1a1..59865a163 100644 --- a/.github/workflows/security-audit.yml +++ b/.github/workflows/security-audit.yml @@ -43,10 +43,10 @@ jobs: run: uv sync --project services/analysis-engine --group dev --frozen - name: Audit Python dependencies run: uv run --project services/analysis-engine --with pip-audit==2.8.0 pip-audit --local --strict - - name: Install stable Rust toolchain - run: rustup toolchain install stable --profile minimal + - name: Install Rust 1.97.1 toolchain + run: rustup toolchain install 1.97.1 --profile minimal - name: Install cargo-audit - run: cargo +stable install cargo-audit --locked + run: cargo +1.97.1 install cargo-audit --locked - name: Audit Rust dependencies working-directory: apps/desktop/src-tauri - run: cargo +stable audit + run: cargo +1.97.1 audit From 08d524eee0287d9c2b285c2a71981eabfcaa8f86 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:52:45 -0700 Subject: [PATCH 04/58] ci: pin Rust 1.97.1 across release architectures --- .github/workflows/build-baseline.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build-baseline.yml b/.github/workflows/build-baseline.yml index 552f6d69d..b8ba47185 100644 --- a/.github/workflows/build-baseline.yml +++ b/.github/workflows/build-baseline.yml @@ -47,10 +47,10 @@ jobs: with: version: "0.8.6" enable-cache: false - - name: Install Rust stable - run: rustup toolchain install stable --profile minimal + - name: Install Rust 1.97.1 + run: rustup toolchain install 1.97.1 --profile minimal - name: Add Windows target - run: rustup target add $env:BANDSCOPE_TARGET_TRIPLE --toolchain stable + run: rustup target add $env:BANDSCOPE_TARGET_TRIPLE --toolchain 1.97.1 - name: Verify Windows antivirus baseline shell: pwsh run: | @@ -142,10 +142,10 @@ jobs: with: version: "0.8.6" enable-cache: false - - name: Install Rust stable - run: rustup toolchain install stable --profile minimal + - name: Install Rust 1.97.1 + run: rustup toolchain install 1.97.1 --profile minimal - name: Add Windows arm target - run: rustup target add $env:BANDSCOPE_TARGET_TRIPLE --toolchain stable + run: rustup target add $env:BANDSCOPE_TARGET_TRIPLE --toolchain 1.97.1 - name: Verify Windows antivirus baseline shell: pwsh run: | @@ -248,10 +248,10 @@ jobs: with: version: "0.8.6" enable-cache: false - - name: Install Rust stable - run: rustup toolchain install stable --profile minimal + - name: Install Rust 1.97.1 + run: rustup toolchain install 1.97.1 --profile minimal - name: Add macOS Intel target - run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain stable + run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain 1.97.1 - name: Install create-dmg run: brew install create-dmg - name: Install node dependencies @@ -306,10 +306,10 @@ jobs: with: version: "0.8.6" enable-cache: false - - name: Install Rust stable - run: rustup toolchain install stable --profile minimal + - name: Install Rust 1.97.1 + run: rustup toolchain install 1.97.1 --profile minimal - name: Add macOS arm target - run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain stable + run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain 1.97.1 - name: Install create-dmg run: brew install create-dmg - name: Install node dependencies From dfa2611b9b7aa3543eaba08849d40f660c78db17 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:53:28 -0700 Subject: [PATCH 05/58] build: pin Rust 1.97.1 --- rust-toolchain.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..725551148 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.97.1" +profile = "minimal" From 7bc959d8a818d37b757e658675c9c9eb769f59b2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:53:52 -0700 Subject: [PATCH 06/58] test: enforce the reviewed Rust compiler baseline --- scripts/checks/verify_rust_toolchain.py | 82 +++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 scripts/checks/verify_rust_toolchain.py diff --git a/scripts/checks/verify_rust_toolchain.py b/scripts/checks/verify_rust_toolchain.py new file mode 100644 index 000000000..5038b4774 --- /dev/null +++ b/scripts/checks/verify_rust_toolchain.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +"""Fail closed when BandScope Rust workflows drift from the reviewed compiler.""" + +from __future__ import annotations + +import sys +import tomllib +from pathlib import Path + + +REPOSITORY_ROOT = Path(__file__).resolve().parents[2] +RUST_TOOLCHAIN = REPOSITORY_ROOT / "rust-toolchain.toml" +DEPENDABOT = REPOSITORY_ROOT / ".github" / "dependabot.yml" +WORKFLOWS = REPOSITORY_ROOT / ".github" / "workflows" +EXPECTED_TOOLCHAIN = "1.97.1" +FLOATING_PATTERNS = ( + "rustup toolchain install stable", + "cargo +stable", + "--toolchain stable", +) + + +def _error(message: str) -> None: + print(f"rust-toolchain-contract: {message}", file=sys.stderr) + + +def main() -> int: + """Validate the root manifest, update lane, and every executable workflow.""" + + failures = 0 + manifest = tomllib.loads(RUST_TOOLCHAIN.read_text(encoding="utf-8")) + toolchain = manifest.get("toolchain", {}) + if toolchain.get("channel") != EXPECTED_TOOLCHAIN: + _error( + "rust-toolchain.toml must pin channel " + f"{EXPECTED_TOOLCHAIN}, found {toolchain.get('channel')!r}" + ) + failures += 1 + if toolchain.get("profile") != "minimal": + _error("rust-toolchain.toml must retain profile = 'minimal'") + failures += 1 + + dependabot = DEPENDABOT.read_text(encoding="utf-8") + for required in ( + 'package-ecosystem: "rust-toolchain"', + 'target-branch: "develop"', + 'interval: "weekly"', + ): + if required not in dependabot: + _error(f"Dependabot Rust toolchain lane is missing {required!r}") + failures += 1 + + workflow_text = "\n".join( + path.read_text(encoding="utf-8") + for path in sorted((*WORKFLOWS.glob("*.yml"), *WORKFLOWS.glob("*.yaml"))) + ) + for pattern in FLOATING_PATTERNS: + if pattern in workflow_text: + _error(f"workflow still contains floating Rust selector {pattern!r}") + failures += 1 + + expected_commands = ( + f"rustup toolchain install {EXPECTED_TOOLCHAIN} --profile minimal", + f"cargo +{EXPECTED_TOOLCHAIN} check", + f"cargo +{EXPECTED_TOOLCHAIN} test", + f"cargo +{EXPECTED_TOOLCHAIN} install cargo-audit --locked", + f"cargo +{EXPECTED_TOOLCHAIN} audit", + f"--toolchain {EXPECTED_TOOLCHAIN}", + ) + for command in expected_commands: + if command not in workflow_text: + _error(f"workflow compiler contract is missing {command!r}") + failures += 1 + + if failures: + return 1 + print(f"Rust compiler contract is pinned to {EXPECTED_TOOLCHAIN}.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 47da94adfbcdc0b4168147df098e67a52101033f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:54:08 -0700 Subject: [PATCH 07/58] test: run the Rust toolchain contract in quickcheck --- scripts/harness/quickcheck.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/harness/quickcheck.sh b/scripts/harness/quickcheck.sh index f2b87e4e8..993d3c536 100755 --- a/scripts/harness/quickcheck.sh +++ b/scripts/harness/quickcheck.sh @@ -9,6 +9,7 @@ python3 scripts/checks/verify_security_notes.py python3 scripts/checks/security_gates.py python3 scripts/checks/verify_supply_chain.py python3 scripts/checks/verify_github_bootstrap_policy.py +python3 scripts/checks/verify_rust_toolchain.py npm run lint npm run typecheck npm run test From 1b3870e2791a961a126b4e85a99b68fea604e57a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:54:24 -0700 Subject: [PATCH 08/58] ci: track the pinned Rust toolchain --- .github/dependabot.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2df162d89..c20f024e0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,5 +1,15 @@ version: 2 updates: + - package-ecosystem: "rust-toolchain" + directory: "/" + target-branch: "develop" + schedule: + interval: "weekly" + open-pull-requests-limit: 1 + labels: + - "dependencies" + - "rust" + - package-ecosystem: "npm" directory: "/" target-branch: "develop" From 120d1134fcb26f7f551d34d3fc84366b858b9ecb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 05:54:45 -0700 Subject: [PATCH 09/58] docs: record the Rust compiler authority --- docs/doctoring/rust-toolchain-freshness.md | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/doctoring/rust-toolchain-freshness.md diff --git a/docs/doctoring/rust-toolchain-freshness.md b/docs/doctoring/rust-toolchain-freshness.md new file mode 100644 index 000000000..685bb8943 --- /dev/null +++ b/docs/doctoring/rust-toolchain-freshness.md @@ -0,0 +1,31 @@ +# Rust toolchain freshness and reproducibility + +## Decision + +BandScope pins Rust `1.97.1` as the repository build compiler. The root +`rust-toolchain.toml`, product CI, release preflight, dependency audit, and +Windows/macOS amd64/arm64 packaging workflows all use that exact point release. +A floating `stable` selector is not accepted because it can change scientific, +security, and release evidence without a repository diff. + +The compiler pin does not add or raise `package.rust-version` in the workspace. +This change governs BandScope's reviewed build environment; it does not create a +new downstream minimum-supported-Rust promise for reusable crates. + +GitHub Dependabot monitors the root manifest through the `rust-toolchain` +ecosystem against the protected `develop` branch. A future compiler update must +therefore arrive as a reviewable pull request and pass the unchanged-head +Windows, macOS, analysis-engine, Tauri, release-preflight, audit, coverage, and +supply-chain gates. + +`scripts/checks/verify_rust_toolchain.py` runs in the canonical quickcheck and +fails when any executable workflow reintroduces `rustup toolchain install +stable`, `cargo +stable`, or `--toolchain stable`. + +## References + +GitHub. (2026). *Dependabot supports updates for Rust toolchains*. GitHub +Changelog. https://github.blog/changelog/ + +The Rust Release Team. (2026, July 16). *Announcing Rust 1.97.1*. Rust Blog. +https://blog.rust-lang.org/2026/07/16/Rust-1.97.1/ From 030922bbd08dbbb82f02727326c13529e630f339 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 06:39:50 -0700 Subject: [PATCH 10/58] test(rust): cover pinned toolchain policy guard --- .../tests/test_rust_toolchain_policy.py | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 services/analysis-engine/tests/test_rust_toolchain_policy.py diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy.py b/services/analysis-engine/tests/test_rust_toolchain_policy.py new file mode 100644 index 000000000..934fb87ef --- /dev/null +++ b/services/analysis-engine/tests/test_rust_toolchain_policy.py @@ -0,0 +1,115 @@ +"""Regression tests for the repository Rust toolchain policy guard.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest +from conftest import load_module + + +def _configure_policy_fixture( + module: object, + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + *, + manifest: str, + dependabot: str, + workflow: str, +) -> None: + """Point one loaded verifier module at an isolated repository fixture.""" + toolchain_path = tmp_path / "rust-toolchain.toml" + dependabot_path = tmp_path / ".github" / "dependabot.yml" + workflows_path = tmp_path / ".github" / "workflows" + dependabot_path.parent.mkdir(parents=True, exist_ok=True) + workflows_path.mkdir(parents=True, exist_ok=True) + toolchain_path.write_text(manifest, encoding="utf-8") + dependabot_path.write_text(dependabot, encoding="utf-8") + (workflows_path / "ci.yml").write_text(workflow, encoding="utf-8") + + monkeypatch.setattr(module, "RUST_TOOLCHAIN", toolchain_path) + monkeypatch.setattr(module, "DEPENDABOT", dependabot_path) + monkeypatch.setattr(module, "WORKFLOWS", workflows_path) + + +def _complete_workflow_contract(version: str) -> str: + """Return a minimal workflow fixture containing every reviewed compiler token.""" + return "\n".join( + ( + f"rustup toolchain install {version} --profile minimal", + f"cargo +{version} check", + f"cargo +{version} test", + f"cargo +{version} install cargo-audit --locked", + f"cargo +{version} audit", + f"rustup target add x86_64-unknown-linux-gnu --toolchain {version}", + ) + ) + + +def test_rust_toolchain_policy_accepts_exact_reviewed_contract( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], +) -> None: + """The verifier accepts one exact compiler pin and monitored update lane.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", "verify_rust_toolchain_success" + ) + version = verifier.EXPECTED_TOOLCHAIN + _configure_policy_fixture( + verifier, + monkeypatch, + tmp_path, + manifest=( + "[toolchain]\n" + f'channel = "{version}"\n' + 'profile = "minimal"\n' + 'components = ["rustfmt", "clippy"]\n' + ), + dependabot=( + 'package-ecosystem: "rust-toolchain"\n' + 'target-branch: "develop"\n' + 'interval: "weekly"\n' + ), + workflow=_complete_workflow_contract(version), + ) + + assert verifier.main() == 0 + captured = capsys.readouterr() + assert captured.err == "" + assert captured.out == f"Rust compiler contract is pinned to {version}.\n" + + +def test_rust_toolchain_policy_fails_closed_on_every_contract_drift( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], +) -> None: + """Manifest, Dependabot, floating selectors, and command drift all fail closed.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", "verify_rust_toolchain_failure" + ) + _configure_policy_fixture( + verifier, + monkeypatch, + tmp_path, + manifest='[toolchain]\nchannel = "stable"\nprofile = "default"\n', + dependabot='package-ecosystem: "cargo"\n', + workflow=( + "rustup toolchain install stable\n" + "cargo +stable check\n" + "rustup target add x86_64-unknown-linux-gnu --toolchain stable\n" + ), + ) + + assert verifier.main() == 1 + captured = capsys.readouterr() + assert captured.out == "" + for expected in ( + "must pin channel", + "must retain profile = 'minimal'", + "Dependabot Rust toolchain lane is missing", + "workflow still contains floating Rust selector", + "workflow compiler contract is missing", + ): + assert expected in captured.err From 69c0a2539c49ef35649b6480dfe3629ae46579e9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:02:31 -0700 Subject: [PATCH 11/58] test(rust): reject cross-lane Dependabot evidence --- .../tests/test_rust_toolchain_policy.py | 57 +++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy.py b/services/analysis-engine/tests/test_rust_toolchain_policy.py index 934fb87ef..0f33022f8 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_policy.py +++ b/services/analysis-engine/tests/test_rust_toolchain_policy.py @@ -46,6 +46,19 @@ def _complete_workflow_contract(version: str) -> str: ) +def _complete_dependabot_contract() -> str: + """Return one minimal, complete Rust toolchain Dependabot update lane.""" + return ( + "version: 2\n" + "updates:\n" + ' - package-ecosystem: "rust-toolchain"\n' + ' directory: "/"\n' + ' target-branch: "develop"\n' + " schedule:\n" + ' interval: "weekly"\n' + ) + + def test_rust_toolchain_policy_accepts_exact_reviewed_contract( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, @@ -66,11 +79,7 @@ def test_rust_toolchain_policy_accepts_exact_reviewed_contract( 'profile = "minimal"\n' 'components = ["rustfmt", "clippy"]\n' ), - dependabot=( - 'package-ecosystem: "rust-toolchain"\n' - 'target-branch: "develop"\n' - 'interval: "weekly"\n' - ), + dependabot=_complete_dependabot_contract(), workflow=_complete_workflow_contract(version), ) @@ -80,6 +89,44 @@ def test_rust_toolchain_policy_accepts_exact_reviewed_contract( assert captured.out == f"Rust compiler contract is pinned to {version}.\n" +def test_rust_toolchain_policy_rejects_cross_lane_dependabot_evidence( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], +) -> None: + """Unrelated update lanes cannot satisfy the Rust toolchain lane contract.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", "verify_rust_toolchain_cross_lane" + ) + version = verifier.EXPECTED_TOOLCHAIN + _configure_policy_fixture( + verifier, + monkeypatch, + tmp_path, + manifest=f'[toolchain]\nchannel = "{version}"\nprofile = "minimal"\n', + dependabot=( + "version: 2\n" + "updates:\n" + ' - package-ecosystem: "rust-toolchain"\n' + ' directory: "/wrong"\n' + ' - package-ecosystem: "npm"\n' + ' directory: "/"\n' + ' target-branch: "develop"\n' + " schedule:\n" + ' interval: "weekly"\n' + ), + workflow=_complete_workflow_contract(version), + ) + + assert verifier.main() == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert "Rust toolchain lane is missing" in captured.err + assert "directory" in captured.err + assert "target-branch" in captured.err + assert "interval" in captured.err + + def test_rust_toolchain_policy_fails_closed_on_every_contract_drift( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, From 3ba24baaef67c82bd7575640af3d3aa0272ec42f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:02:59 -0700 Subject: [PATCH 12/58] fix(rust): bind Dependabot policy to toolchain lane --- scripts/checks/verify_rust_toolchain.py | 40 ++++++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/scripts/checks/verify_rust_toolchain.py b/scripts/checks/verify_rust_toolchain.py index 5038b4774..23694cd48 100644 --- a/scripts/checks/verify_rust_toolchain.py +++ b/scripts/checks/verify_rust_toolchain.py @@ -18,12 +18,31 @@ "cargo +stable", "--toolchain stable", ) +DEPENDABOT_LANE_MARKER = ' - package-ecosystem: "rust-toolchain"' +DEPENDABOT_UPDATE_MARKER = " - package-ecosystem:" def _error(message: str) -> None: + """Write one policy violation to stderr.""" print(f"rust-toolchain-contract: {message}", file=sys.stderr) +def _rust_toolchain_dependabot_lane(content: str) -> str | None: + """Return the single Rust toolchain update lane without borrowing sibling fields.""" + lines = content.splitlines() + starts = [index for index, line in enumerate(lines) if line == DEPENDABOT_LANE_MARKER] + if len(starts) != 1: + return None + + start = starts[0] + end = len(lines) + for index in range(start + 1, len(lines)): + if lines[index].startswith(DEPENDABOT_UPDATE_MARKER): + end = index + break + return "\n".join(lines[start:end]) + + def main() -> int: """Validate the root manifest, update lane, and every executable workflow.""" @@ -41,14 +60,19 @@ def main() -> int: failures += 1 dependabot = DEPENDABOT.read_text(encoding="utf-8") - for required in ( - 'package-ecosystem: "rust-toolchain"', - 'target-branch: "develop"', - 'interval: "weekly"', - ): - if required not in dependabot: - _error(f"Dependabot Rust toolchain lane is missing {required!r}") - failures += 1 + dependabot_lane = _rust_toolchain_dependabot_lane(dependabot) + if dependabot_lane is None: + _error("Dependabot Rust toolchain lane is missing or duplicated") + failures += 1 + else: + for required in ( + 'directory: "/"', + 'target-branch: "develop"', + 'interval: "weekly"', + ): + if required not in dependabot_lane: + _error(f"Dependabot Rust toolchain lane is missing {required!r}") + failures += 1 workflow_text = "\n".join( path.read_text(encoding="utf-8") From c951edf76ba8d73f14fd820b7bd58587374781c6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:03:21 -0700 Subject: [PATCH 13/58] docs(rust): correct toolchain authority sources --- docs/doctoring/rust-toolchain-freshness.md | 26 ++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/docs/doctoring/rust-toolchain-freshness.md b/docs/doctoring/rust-toolchain-freshness.md index 685bb8943..ccdfac72e 100644 --- a/docs/doctoring/rust-toolchain-freshness.md +++ b/docs/doctoring/rust-toolchain-freshness.md @@ -13,19 +13,31 @@ This change governs BandScope's reviewed build environment; it does not create a new downstream minimum-supported-Rust promise for reusable crates. GitHub Dependabot monitors the root manifest through the `rust-toolchain` -ecosystem against the protected `develop` branch. A future compiler update must -therefore arrive as a reviewable pull request and pass the unchanged-head -Windows, macOS, analysis-engine, Tauri, release-preflight, audit, coverage, and -supply-chain gates. +ecosystem against the protected `develop` branch. GitHub documents this +integration as a Dependabot version-update capability rather than a Rust +security-update feed. A future compiler update must therefore arrive as a +reviewable pull request and pass the unchanged-head Windows, macOS, +analysis-engine, Tauri, release-preflight, audit, coverage, and supply-chain +gates. GitHub's platform-level default cooldown for Dependabot version updates +is additional noise control; it is not treated as a repository security or +freshness guarantee. `scripts/checks/verify_rust_toolchain.py` runs in the canonical quickcheck and fails when any executable workflow reintroduces `rustup toolchain install -stable`, `cargo +stable`, or `--toolchain stable`. +stable`, `cargo +stable`, or `--toolchain stable`. The same guard binds +`directory`, target branch, and schedule evidence to the actual +`rust-toolchain` Dependabot lane so an unrelated ecosystem entry cannot satisfy +the compiler-update policy. ## References -GitHub. (2026). *Dependabot supports updates for Rust toolchains*. GitHub -Changelog. https://github.blog/changelog/ +GitHub. (2025, August 19). *Dependabot now supports Rust toolchain updates*. +GitHub Changelog. +https://github.blog/changelog/2025-08-19-dependabot-now-supports-rust-toolchain-updates/ + +GitHub. (2026, July 14). *Dependabot version updates introduce default package +cooldown*. GitHub Changelog. +https://github.blog/changelog/2026-07-14-dependabot-version-updates-introduce-default-package-cooldown/ The Rust Release Team. (2026, July 16). *Announcing Rust 1.97.1*. Rust Blog. https://blog.rust-lang.org/2026/07/16/Rust-1.97.1/ From 8c997367ec984e4482a00060a5fcd4002bc5a94b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:36:00 -0700 Subject: [PATCH 14/58] test(rust): reject cross-workflow compiler evidence --- .../tests/test_rust_toolchain_policy.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy.py b/services/analysis-engine/tests/test_rust_toolchain_policy.py index 0f33022f8..3acc825aa 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_policy.py +++ b/services/analysis-engine/tests/test_rust_toolchain_policy.py @@ -160,3 +160,33 @@ def test_rust_toolchain_policy_fails_closed_on_every_contract_drift( "workflow compiler contract is missing", ): assert expected in captured.err + + +def test_rust_toolchain_policy_rejects_compiler_evidence_borrowed_from_sibling_workflow( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], +) -> None: + """A release lane cannot borrow its compiler pin from another workflow file.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", "verify_rust_toolchain_cross_workflow" + ) + version = verifier.EXPECTED_TOOLCHAIN + _configure_policy_fixture( + verifier, + monkeypatch, + tmp_path, + manifest=f'[toolchain]\nchannel = "{version}"\nprofile = "minimal"\n', + dependabot=_complete_dependabot_contract(), + workflow=_complete_workflow_contract(version), + ) + (tmp_path / ".github" / "workflows" / "release.yml").write_text( + "name: release\njobs:\n release-preflight:\n steps:\n - run: echo no-rust-pin\n", + encoding="utf-8", + ) + + assert verifier.main() == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert "release.yml" in captured.err + assert f"rustup toolchain install {version} --profile minimal" in captured.err From cde30845b13ca92d588397580eaa6bb65ae73f07 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:36:50 -0700 Subject: [PATCH 15/58] fix(rust): bind compiler evidence to owning workflows --- scripts/checks/verify_rust_toolchain.py | 56 ++++++++++++++++++------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/scripts/checks/verify_rust_toolchain.py b/scripts/checks/verify_rust_toolchain.py index 23694cd48..df52dbc7c 100644 --- a/scripts/checks/verify_rust_toolchain.py +++ b/scripts/checks/verify_rust_toolchain.py @@ -43,8 +43,31 @@ def _rust_toolchain_dependabot_lane(content: str) -> str | None: return "\n".join(lines[start:end]) +def _required_workflow_commands() -> dict[str, tuple[tuple[str, int], ...]]: + """Return compiler evidence required from each workflow that owns Rust execution.""" + install = f"rustup toolchain install {EXPECTED_TOOLCHAIN} --profile minimal" + target = f"--toolchain {EXPECTED_TOOLCHAIN}" + return { + "ci.yml": ( + (install, 2), + (f"cargo +{EXPECTED_TOOLCHAIN} check", 1), + (f"cargo +{EXPECTED_TOOLCHAIN} test", 1), + ), + "release.yml": ((install, 1),), + "security-audit.yml": ( + (install, 1), + (f"cargo +{EXPECTED_TOOLCHAIN} install cargo-audit --locked", 1), + (f"cargo +{EXPECTED_TOOLCHAIN} audit", 1), + ), + "build-baseline.yml": ( + (install, 4), + (target, 4), + ), + } + + def main() -> int: - """Validate the root manifest, update lane, and every executable workflow.""" + """Validate the root manifest, update lane, and every Rust-owning workflow.""" failures = 0 manifest = tomllib.loads(RUST_TOOLCHAIN.read_text(encoding="utf-8")) @@ -74,27 +97,28 @@ def main() -> int: _error(f"Dependabot Rust toolchain lane is missing {required!r}") failures += 1 - workflow_text = "\n".join( - path.read_text(encoding="utf-8") - for path in sorted((*WORKFLOWS.glob("*.yml"), *WORKFLOWS.glob("*.yaml"))) - ) + workflow_paths = sorted((*WORKFLOWS.glob("*.yml"), *WORKFLOWS.glob("*.yaml"))) + workflow_text = "\n".join(path.read_text(encoding="utf-8") for path in workflow_paths) for pattern in FLOATING_PATTERNS: if pattern in workflow_text: _error(f"workflow still contains floating Rust selector {pattern!r}") failures += 1 - expected_commands = ( - f"rustup toolchain install {EXPECTED_TOOLCHAIN} --profile minimal", - f"cargo +{EXPECTED_TOOLCHAIN} check", - f"cargo +{EXPECTED_TOOLCHAIN} test", - f"cargo +{EXPECTED_TOOLCHAIN} install cargo-audit --locked", - f"cargo +{EXPECTED_TOOLCHAIN} audit", - f"--toolchain {EXPECTED_TOOLCHAIN}", - ) - for command in expected_commands: - if command not in workflow_text: - _error(f"workflow compiler contract is missing {command!r}") + for filename, requirements in _required_workflow_commands().items(): + path = WORKFLOWS / filename + if not path.is_file(): + _error(f"required Rust workflow {filename!r} is missing") failures += 1 + continue + content = path.read_text(encoding="utf-8") + for command, minimum_count in requirements: + actual_count = content.count(command) + if actual_count < minimum_count: + _error( + f"{filename} must contain {command!r} at least {minimum_count} time(s); " + f"found {actual_count}" + ) + failures += 1 if failures: return 1 From 316ef6db98cb8f620c5ded8dfd6da70730f40116 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:37:43 -0700 Subject: [PATCH 16/58] test(rust): model workflow-owned compiler contracts --- .../tests/test_rust_toolchain_policy.py | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy.py b/services/analysis-engine/tests/test_rust_toolchain_policy.py index 3acc825aa..aa693468b 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_policy.py +++ b/services/analysis-engine/tests/test_rust_toolchain_policy.py @@ -8,6 +8,28 @@ from conftest import load_module +def _supporting_workflow_contracts(version: str) -> dict[str, str]: + """Return minimal fixtures for Rust-owning workflows outside ordinary CI.""" + install = f"rustup toolchain install {version} --profile minimal" + return { + "release.yml": install, + "security-audit.yml": "\n".join( + ( + install, + f"cargo +{version} install cargo-audit --locked", + f"cargo +{version} audit", + ) + ), + "build-baseline.yml": "\n".join( + (install,) * 4 + + tuple( + f"rustup target add target-{index} --toolchain {version}" + for index in range(4) + ) + ), + } + + def _configure_policy_fixture( module: object, monkeypatch: pytest.MonkeyPatch, @@ -26,6 +48,9 @@ def _configure_policy_fixture( toolchain_path.write_text(manifest, encoding="utf-8") dependabot_path.write_text(dependabot, encoding="utf-8") (workflows_path / "ci.yml").write_text(workflow, encoding="utf-8") + version = getattr(module, "EXPECTED_TOOLCHAIN") + for filename, content in _supporting_workflow_contracts(version).items(): + (workflows_path / filename).write_text(content, encoding="utf-8") monkeypatch.setattr(module, "RUST_TOOLCHAIN", toolchain_path) monkeypatch.setattr(module, "DEPENDABOT", dependabot_path) @@ -33,15 +58,14 @@ def _configure_policy_fixture( def _complete_workflow_contract(version: str) -> str: - """Return a minimal workflow fixture containing every reviewed compiler token.""" + """Return a minimal CI fixture containing its two reviewed compiler owners.""" + install = f"rustup toolchain install {version} --profile minimal" return "\n".join( ( - f"rustup toolchain install {version} --profile minimal", + install, + install, f"cargo +{version} check", f"cargo +{version} test", - f"cargo +{version} install cargo-audit --locked", - f"cargo +{version} audit", - f"rustup target add x86_64-unknown-linux-gnu --toolchain {version}", ) ) @@ -157,7 +181,7 @@ def test_rust_toolchain_policy_fails_closed_on_every_contract_drift( "must retain profile = 'minimal'", "Dependabot Rust toolchain lane is missing", "workflow still contains floating Rust selector", - "workflow compiler contract is missing", + "ci.yml must contain", ): assert expected in captured.err From 85a349fd0c9e8e9127a511b38078629f475c0d47 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:42:05 -0700 Subject: [PATCH 17/58] test(rust): reject cross-job compiler evidence --- .../tests/test_rust_toolchain_policy.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy.py b/services/analysis-engine/tests/test_rust_toolchain_policy.py index aa693468b..c34369f12 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_policy.py +++ b/services/analysis-engine/tests/test_rust_toolchain_policy.py @@ -214,3 +214,55 @@ def test_rust_toolchain_policy_rejects_compiler_evidence_borrowed_from_sibling_w assert captured.out == "" assert "release.yml" in captured.err assert f"rustup toolchain install {version} --profile minimal" in captured.err + + +def test_rust_toolchain_policy_rejects_compiler_evidence_borrowed_between_native_jobs( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], +) -> None: + """One native packaging job cannot supply compiler evidence for sibling architectures.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", "verify_rust_toolchain_cross_job" + ) + version = verifier.EXPECTED_TOOLCHAIN + _configure_policy_fixture( + verifier, + monkeypatch, + tmp_path, + manifest=f'[toolchain]\nchannel = "{version}"\nprofile = "minimal"\n', + dependabot=_complete_dependabot_contract(), + workflow=_complete_workflow_contract(version), + ) + install = f"rustup toolchain install {version} --profile minimal" + target = f"rustup target add target --toolchain {version}" + (tmp_path / ".github" / "workflows" / "build-baseline.yml").write_text( + "jobs:\n" + " build-windows-native:\n" + " steps:\n" + f" - run: {install}\n" + f" - run: {install}\n" + f" - run: {install}\n" + f" - run: {install}\n" + f" - run: {target}\n" + f" - run: {target}\n" + f" - run: {target}\n" + f" - run: {target}\n" + " build-windows-arm64:\n" + " steps:\n" + " - run: echo no-rust-pin\n" + " build-macos-native:\n" + " steps:\n" + " - run: echo no-rust-pin\n" + " build-macos-arm64:\n" + " steps:\n" + " - run: echo no-rust-pin\n", + encoding="utf-8", + ) + + assert verifier.main() == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert "build-windows-arm64" in captured.err + assert "build-macos-native" in captured.err + assert "build-macos-arm64" in captured.err From 063c588c0972786eb73953b49a0385c14a005191 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:42:56 -0700 Subject: [PATCH 18/58] fix(rust): bind compiler evidence to owning jobs --- scripts/checks/verify_rust_toolchain.py | 79 +++++++++++++++++-------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/scripts/checks/verify_rust_toolchain.py b/scripts/checks/verify_rust_toolchain.py index df52dbc7c..fb6e6a3ea 100644 --- a/scripts/checks/verify_rust_toolchain.py +++ b/scripts/checks/verify_rust_toolchain.py @@ -43,31 +43,56 @@ def _rust_toolchain_dependabot_lane(content: str) -> str | None: return "\n".join(lines[start:end]) -def _required_workflow_commands() -> dict[str, tuple[tuple[str, int], ...]]: - """Return compiler evidence required from each workflow that owns Rust execution.""" +def _workflow_job(content: str, job_name: str) -> str | None: + """Return one exact top-level workflow job so sibling jobs cannot lend evidence.""" + lines = content.splitlines() + marker = f" {job_name}:" + starts = [index for index, line in enumerate(lines) if line == marker] + if len(starts) != 1: + return None + + start = starts[0] + end = len(lines) + for index in range(start + 1, len(lines)): + line = lines[index] + if line.startswith(" ") and not line.startswith(" ") and line.endswith(":"): + end = index + break + return "\n".join(lines[start:end]) + + +def _required_workflow_jobs() -> dict[str, dict[str, tuple[str, ...]]]: + """Return compiler evidence required from each job that owns Rust execution.""" install = f"rustup toolchain install {EXPECTED_TOOLCHAIN} --profile minimal" target = f"--toolchain {EXPECTED_TOOLCHAIN}" return { - "ci.yml": ( - (install, 2), - (f"cargo +{EXPECTED_TOOLCHAIN} check", 1), - (f"cargo +{EXPECTED_TOOLCHAIN} test", 1), - ), - "release.yml": ((install, 1),), - "security-audit.yml": ( - (install, 1), - (f"cargo +{EXPECTED_TOOLCHAIN} install cargo-audit --locked", 1), - (f"cargo +{EXPECTED_TOOLCHAIN} audit", 1), - ), - "build-baseline.yml": ( - (install, 4), - (target, 4), - ), + "ci.yml": { + "verify": (install,), + "rust-check": ( + install, + f"cargo +{EXPECTED_TOOLCHAIN} check", + f"cargo +{EXPECTED_TOOLCHAIN} test", + ), + }, + "release.yml": {"release-preflight": (install,)}, + "security-audit.yml": { + "audit": ( + install, + f"cargo +{EXPECTED_TOOLCHAIN} install cargo-audit --locked", + f"cargo +{EXPECTED_TOOLCHAIN} audit", + ) + }, + "build-baseline.yml": { + "build-windows-native": (install, target), + "build-windows-arm64": (install, target), + "build-macos-native": (install, target), + "build-macos-arm64": (install, target), + }, } def main() -> int: - """Validate the root manifest, update lane, and every Rust-owning workflow.""" + """Validate the root manifest, update lane, and every Rust-owning workflow job.""" failures = 0 manifest = tomllib.loads(RUST_TOOLCHAIN.read_text(encoding="utf-8")) @@ -104,21 +129,23 @@ def main() -> int: _error(f"workflow still contains floating Rust selector {pattern!r}") failures += 1 - for filename, requirements in _required_workflow_commands().items(): + for filename, job_requirements in _required_workflow_jobs().items(): path = WORKFLOWS / filename if not path.is_file(): _error(f"required Rust workflow {filename!r} is missing") failures += 1 continue content = path.read_text(encoding="utf-8") - for command, minimum_count in requirements: - actual_count = content.count(command) - if actual_count < minimum_count: - _error( - f"{filename} must contain {command!r} at least {minimum_count} time(s); " - f"found {actual_count}" - ) + for job_name, requirements in job_requirements.items(): + job = _workflow_job(content, job_name) + if job is None: + _error(f"{filename} is missing unique Rust-owning job {job_name!r}") failures += 1 + continue + for command in requirements: + if command not in job: + _error(f"{filename} job {job_name!r} is missing {command!r}") + failures += 1 if failures: return 1 From 9def786477088dac5c3cb7e0097ab50972d909b9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 07:43:57 -0700 Subject: [PATCH 19/58] test(rust): model job-owned compiler contracts --- .../tests/test_rust_toolchain_policy.py | 89 +++++++++++-------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy.py b/services/analysis-engine/tests/test_rust_toolchain_policy.py index c34369f12..aeb5b61ed 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_policy.py +++ b/services/analysis-engine/tests/test_rust_toolchain_policy.py @@ -8,25 +8,40 @@ from conftest import load_module +def _job(name: str, *commands: str) -> str: + """Return one minimal workflow job containing the supplied shell commands.""" + lines = [f" {name}:", " steps:"] + lines.extend(f" - run: {command}" for command in commands) + return "\n".join(lines) + + def _supporting_workflow_contracts(version: str) -> dict[str, str]: - """Return minimal fixtures for Rust-owning workflows outside ordinary CI.""" + """Return minimal valid fixtures for Rust-owning workflows outside ordinary CI.""" install = f"rustup toolchain install {version} --profile minimal" + target = f"rustup target add target --toolchain {version}" return { - "release.yml": install, - "security-audit.yml": "\n".join( - ( + "release.yml": "jobs:\n" + _job("release-preflight", install) + "\n", + "security-audit.yml": ( + "jobs:\n" + + _job( + "audit", install, f"cargo +{version} install cargo-audit --locked", f"cargo +{version} audit", ) + + "\n" ), - "build-baseline.yml": "\n".join( - (install,) * 4 - + tuple( - f"rustup target add target-{index} --toolchain {version}" - for index in range(4) + "build-baseline.yml": "jobs:\n" + + "\n".join( + _job(job_name, install, target) + for job_name in ( + "build-windows-native", + "build-windows-arm64", + "build-macos-native", + "build-macos-arm64", ) - ), + ) + + "\n", } @@ -58,15 +73,19 @@ def _configure_policy_fixture( def _complete_workflow_contract(version: str) -> str: - """Return a minimal CI fixture containing its two reviewed compiler owners.""" + """Return a minimal valid CI fixture with both Rust-owning jobs.""" install = f"rustup toolchain install {version} --profile minimal" - return "\n".join( - ( - install, + return ( + "jobs:\n" + + _job("verify", install) + + "\n" + + _job( + "rust-check", install, f"cargo +{version} check", f"cargo +{version} test", ) + + "\n" ) @@ -181,7 +200,7 @@ def test_rust_toolchain_policy_fails_closed_on_every_contract_drift( "must retain profile = 'minimal'", "Dependabot Rust toolchain lane is missing", "workflow still contains floating Rust selector", - "ci.yml must contain", + "ci.yml is missing unique Rust-owning job", ): assert expected in captured.err @@ -205,7 +224,7 @@ def test_rust_toolchain_policy_rejects_compiler_evidence_borrowed_from_sibling_w workflow=_complete_workflow_contract(version), ) (tmp_path / ".github" / "workflows" / "release.yml").write_text( - "name: release\njobs:\n release-preflight:\n steps:\n - run: echo no-rust-pin\n", + "jobs:\n" + _job("release-preflight", "echo no-rust-pin") + "\n", encoding="utf-8", ) @@ -213,6 +232,7 @@ def test_rust_toolchain_policy_rejects_compiler_evidence_borrowed_from_sibling_w captured = capsys.readouterr() assert captured.out == "" assert "release.yml" in captured.err + assert "release-preflight" in captured.err assert f"rustup toolchain install {version} --profile minimal" in captured.err @@ -238,25 +258,24 @@ def test_rust_toolchain_policy_rejects_compiler_evidence_borrowed_between_native target = f"rustup target add target --toolchain {version}" (tmp_path / ".github" / "workflows" / "build-baseline.yml").write_text( "jobs:\n" - " build-windows-native:\n" - " steps:\n" - f" - run: {install}\n" - f" - run: {install}\n" - f" - run: {install}\n" - f" - run: {install}\n" - f" - run: {target}\n" - f" - run: {target}\n" - f" - run: {target}\n" - f" - run: {target}\n" - " build-windows-arm64:\n" - " steps:\n" - " - run: echo no-rust-pin\n" - " build-macos-native:\n" - " steps:\n" - " - run: echo no-rust-pin\n" - " build-macos-arm64:\n" - " steps:\n" - " - run: echo no-rust-pin\n", + + _job( + "build-windows-native", + install, + install, + install, + install, + target, + target, + target, + target, + ) + + "\n" + + _job("build-windows-arm64", "echo no-rust-pin") + + "\n" + + _job("build-macos-native", "echo no-rust-pin") + + "\n" + + _job("build-macos-arm64", "echo no-rust-pin") + + "\n", encoding="utf-8", ) From 8b206a7dc40b3749231d34a8e1e5b587d70a2740 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 08:41:33 -0700 Subject: [PATCH 20/58] test(rust): reject non-executing toolchain evidence --- .../test_rust_toolchain_policy_execution.py | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 services/analysis-engine/tests/test_rust_toolchain_policy_execution.py diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy_execution.py b/services/analysis-engine/tests/test_rust_toolchain_policy_execution.py new file mode 100644 index 000000000..4859c0b51 --- /dev/null +++ b/services/analysis-engine/tests/test_rust_toolchain_policy_execution.py @@ -0,0 +1,105 @@ +"""Regression tests for executable Rust toolchain policy evidence.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest +from conftest import load_module + + +def _job(name: str, *commands: str) -> str: + """Return one minimal workflow job with executable run steps.""" + lines = [f" {name}:", " steps:"] + lines.extend(f" - run: {command}" for command in commands) + return "\n".join(lines) + + +def test_rust_toolchain_policy_rejects_required_command_present_only_in_comment( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], +) -> None: + """A YAML comment cannot satisfy a job's compiler-install evidence.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", + "verify_rust_toolchain_nonexecuting_evidence", + ) + version = verifier.EXPECTED_TOOLCHAIN + toolchain_path = tmp_path / "rust-toolchain.toml" + dependabot_path = tmp_path / ".github" / "dependabot.yml" + workflows_path = tmp_path / ".github" / "workflows" + dependabot_path.parent.mkdir(parents=True, exist_ok=True) + workflows_path.mkdir(parents=True, exist_ok=True) + + toolchain_path.write_text( + f'[toolchain]\nchannel = "{version}"\nprofile = "minimal"\n', + encoding="utf-8", + ) + dependabot_path.write_text( + "version: 2\n" + "updates:\n" + ' - package-ecosystem: "rust-toolchain"\n' + ' directory: "/"\n' + ' target-branch: "develop"\n' + " schedule:\n" + ' interval: "weekly"\n', + encoding="utf-8", + ) + + install = f"rustup toolchain install {version} --profile minimal" + (workflows_path / "ci.yml").write_text( + "jobs:\n" + " verify:\n" + " steps:\n" + f" # {install}\n" + " - run: echo no-rust-toolchain-install\n" + + _job( + "rust-check", + install, + f"cargo +{version} check", + f"cargo +{version} test", + ) + + "\n", + encoding="utf-8", + ) + (workflows_path / "release.yml").write_text( + "jobs:\n" + _job("release-preflight", install) + "\n", + encoding="utf-8", + ) + (workflows_path / "security-audit.yml").write_text( + "jobs:\n" + + _job( + "audit", + install, + f"cargo +{version} install cargo-audit --locked", + f"cargo +{version} audit", + ) + + "\n", + encoding="utf-8", + ) + target = f"rustup target add test-target --toolchain {version}" + (workflows_path / "build-baseline.yml").write_text( + "jobs:\n" + + "\n".join( + _job(job_name, install, target) + for job_name in ( + "build-windows-native", + "build-windows-arm64", + "build-macos-native", + "build-macos-arm64", + ) + ) + + "\n", + encoding="utf-8", + ) + + monkeypatch.setattr(verifier, "RUST_TOOLCHAIN", toolchain_path) + monkeypatch.setattr(verifier, "DEPENDABOT", dependabot_path) + monkeypatch.setattr(verifier, "WORKFLOWS", workflows_path) + + assert verifier.main() == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert "ci.yml job 'verify' is missing" in captured.err + assert install in captured.err From 420dfbddd6f6a6e83393b24477869935bb1c10d1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 08:42:45 -0700 Subject: [PATCH 21/58] fix(rust): require executable workflow evidence --- scripts/checks/verify_rust_toolchain.py | 39 ++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/scripts/checks/verify_rust_toolchain.py b/scripts/checks/verify_rust_toolchain.py index fb6e6a3ea..10adec1f0 100644 --- a/scripts/checks/verify_rust_toolchain.py +++ b/scripts/checks/verify_rust_toolchain.py @@ -61,6 +61,43 @@ def _workflow_job(content: str, job_name: str) -> str | None: return "\n".join(lines[start:end]) +def _inline_run_commands(job: str) -> tuple[str, ...]: + """Return executable inline ``run:`` payloads from one workflow job. + + Required compiler evidence deliberately stays on one-line ``run:`` steps. A + comment, step name, environment value, or multiline scalar cannot satisfy + the contract accidentally; changing that representation requires an + explicit verifier update and regression rather than silently broadening the + evidence boundary. + """ + commands: list[str] = [] + for line in job.splitlines(): + stripped = line.strip() + if stripped.startswith("- run:"): + command = stripped.removeprefix("- run:").strip() + elif stripped.startswith("run:"): + command = stripped.removeprefix("run:").strip() + else: + continue + if command and command not in {"|", ">", "|-", ">-"}: + commands.append(command) + return tuple(commands) + + +def _job_runs_required_command(job: str, required: str) -> bool: + """Return whether one executable run step owns the required Rust evidence.""" + commands = _inline_run_commands(job) + if required.startswith("--toolchain "): + return any( + command.startswith("rustup target add ") and required in command + for command in commands + ) + return any( + command == required or command.startswith(f"{required} ") + for command in commands + ) + + def _required_workflow_jobs() -> dict[str, dict[str, tuple[str, ...]]]: """Return compiler evidence required from each job that owns Rust execution.""" install = f"rustup toolchain install {EXPECTED_TOOLCHAIN} --profile minimal" @@ -143,7 +180,7 @@ def main() -> int: failures += 1 continue for command in requirements: - if command not in job: + if not _job_runs_required_command(job, command): _error(f"{filename} job {job_name!r} is missing {command!r}") failures += 1 From 3342efb68f1155badc4d4e57d42e5409faa50f35 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 08:46:22 -0700 Subject: [PATCH 22/58] test(rust): reject commented Dependabot evidence --- ...t_toolchain_policy_dependabot_effective.py | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 services/analysis-engine/tests/test_rust_toolchain_policy_dependabot_effective.py diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy_dependabot_effective.py b/services/analysis-engine/tests/test_rust_toolchain_policy_dependabot_effective.py new file mode 100644 index 000000000..e286a4cc0 --- /dev/null +++ b/services/analysis-engine/tests/test_rust_toolchain_policy_dependabot_effective.py @@ -0,0 +1,108 @@ +"""Regression tests for effective Rust-toolchain Dependabot policy fields.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest +from conftest import load_module + + +def _job(name: str, *commands: str) -> str: + """Return one minimal workflow job with executable run steps.""" + lines = [f" {name}:", " steps:"] + lines.extend(f" - run: {command}" for command in commands) + return "\n".join(lines) + + +def test_rust_toolchain_policy_rejects_dependabot_fields_present_only_in_comments( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], +) -> None: + """Comments inside the Rust lane cannot satisfy effective update policy.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", + "verify_rust_toolchain_commented_dependabot_evidence", + ) + version = verifier.EXPECTED_TOOLCHAIN + toolchain_path = tmp_path / "rust-toolchain.toml" + dependabot_path = tmp_path / ".github" / "dependabot.yml" + workflows_path = tmp_path / ".github" / "workflows" + dependabot_path.parent.mkdir(parents=True, exist_ok=True) + workflows_path.mkdir(parents=True, exist_ok=True) + + toolchain_path.write_text( + f'[toolchain]\nchannel = "{version}"\nprofile = "minimal"\n', + encoding="utf-8", + ) + dependabot_path.write_text( + "version: 2\n" + "updates:\n" + ' - package-ecosystem: "rust-toolchain"\n' + ' # directory: "/"\n' + ' directory: "/wrong"\n' + ' # target-branch: "develop"\n' + ' target-branch: "main"\n' + " schedule:\n" + ' # interval: "weekly"\n' + ' interval: "monthly"\n', + encoding="utf-8", + ) + + install = f"rustup toolchain install {version} --profile minimal" + (workflows_path / "ci.yml").write_text( + "jobs:\n" + + _job("verify", install) + + "\n" + + _job( + "rust-check", + install, + f"cargo +{version} check", + f"cargo +{version} test", + ) + + "\n", + encoding="utf-8", + ) + (workflows_path / "release.yml").write_text( + "jobs:\n" + _job("release-preflight", install) + "\n", + encoding="utf-8", + ) + (workflows_path / "security-audit.yml").write_text( + "jobs:\n" + + _job( + "audit", + install, + f"cargo +{version} install cargo-audit --locked", + f"cargo +{version} audit", + ) + + "\n", + encoding="utf-8", + ) + target = f"rustup target add test-target --toolchain {version}" + (workflows_path / "build-baseline.yml").write_text( + "jobs:\n" + + "\n".join( + _job(job_name, install, target) + for job_name in ( + "build-windows-native", + "build-windows-arm64", + "build-macos-native", + "build-macos-arm64", + ) + ) + + "\n", + encoding="utf-8", + ) + + monkeypatch.setattr(verifier, "RUST_TOOLCHAIN", toolchain_path) + monkeypatch.setattr(verifier, "DEPENDABOT", dependabot_path) + monkeypatch.setattr(verifier, "WORKFLOWS", workflows_path) + + assert verifier.main() == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert "Rust toolchain lane is missing" in captured.err + assert "directory" in captured.err + assert "target-branch" in captured.err + assert "interval" in captured.err From e8981fcbc839903dabc9af66b796462c61fbd270 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 08:46:56 -0700 Subject: [PATCH 23/58] fix(rust): validate effective Dependabot lane fields --- scripts/checks/verify_rust_toolchain.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/checks/verify_rust_toolchain.py b/scripts/checks/verify_rust_toolchain.py index 10adec1f0..783b37e7b 100644 --- a/scripts/checks/verify_rust_toolchain.py +++ b/scripts/checks/verify_rust_toolchain.py @@ -150,13 +150,14 @@ def main() -> int: _error("Dependabot Rust toolchain lane is missing or duplicated") failures += 1 else: - for required in ( - 'directory: "/"', - 'target-branch: "develop"', - 'interval: "weekly"', + lane_lines = set(dependabot_lane.splitlines()) + for label, required_line in ( + ('directory: "/"', ' directory: "/"'), + ('target-branch: "develop"', ' target-branch: "develop"'), + ('interval: "weekly"', ' interval: "weekly"'), ): - if required not in dependabot_lane: - _error(f"Dependabot Rust toolchain lane is missing {required!r}") + if required_line not in lane_lines: + _error(f"Dependabot Rust toolchain lane is missing {label!r}") failures += 1 workflow_paths = sorted((*WORKFLOWS.glob("*.yml"), *WORKFLOWS.glob("*.yaml"))) From 57ab5932af5b29a2ea204eb52d0a06a77dfd0b8e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 12:42:55 -0700 Subject: [PATCH 24/58] test(rust): bind supply-chain audit to pinned toolchain --- ...st_rust_toolchain_supply_chain_contract.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py new file mode 100644 index 000000000..3ce72a0ff --- /dev/null +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -0,0 +1,75 @@ +"""Supply-chain regressions for the repository-pinned Rust audit toolchain.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest +from conftest import load_module + + +PINNED_RUST_AUDIT = "cargo +1.97.1 audit" + + +def _security_audit_workflow(rust_audit_command: str) -> str: + """Return the smallest blocking workflow that exercises all audit families.""" + return f""" +name: security-audit +on: + pull_request: + branches: [develop, main] + push: + branches: [develop, main] +jobs: + audit: + runs-on: ubuntu-latest + steps: + - run: npm audit --workspaces --audit-level=high + - run: pip-audit --local --strict + - run: {rust_audit_command} +""".strip() + + +def _rust_audit_violations( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + rust_audit_command: str, +) -> list[str]: + """Run only the security-audit coverage verifier against one isolated workflow.""" + supply_chain = load_module( + "scripts/checks/verify_supply_chain.py", + f"verify_supply_chain_rust_audit_{rust_audit_command.replace(' ', '_').replace('+', '')}", + ) + workflow_dir = tmp_path / ".github" / "workflows" + workflow_dir.mkdir(parents=True) + (workflow_dir / "security-audit.yml").write_text( + _security_audit_workflow(rust_audit_command), + encoding="utf-8", + ) + monkeypatch.chdir(tmp_path) + + violations: list[str] = [] + supply_chain._verify_security_audit_coverage(violations) + return violations + + +def test_supply_chain_accepts_repository_pinned_rust_audit( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + """The pinned audit command must satisfy the security workflow contract.""" + violations = _rust_audit_violations(monkeypatch, tmp_path, PINNED_RUST_AUDIT) + + assert not any("missing vulnerability audit token" in item for item in violations) + + +def test_supply_chain_rejects_floating_stable_rust_audit( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + """A floating stable selector cannot satisfy the exact Rust audit contract.""" + violations = _rust_audit_violations(monkeypatch, tmp_path, "cargo +stable audit") + + assert ( + "security audit workflow missing vulnerability audit token: " + PINNED_RUST_AUDIT + ) in violations From cdf5d56745a4f34878116bf81868b3a09fb915ea Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 12:47:16 -0700 Subject: [PATCH 25/58] fix(rust): align supply-chain audit with pinned toolchain --- scripts/checks/verify_supply_chain.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/checks/verify_supply_chain.py b/scripts/checks/verify_supply_chain.py index 1cd561e5c..eccd4352e 100644 --- a/scripts/checks/verify_supply_chain.py +++ b/scripts/checks/verify_supply_chain.py @@ -142,6 +142,7 @@ "glib", ) RUST_FASTRAND_YANKED_VERSION = "2.4.0" +RUST_AUDIT_COMMAND = "cargo +1.97.1 audit" RUST_AUDIT_CONFIG = Path("apps/desktop/src-tauri/.cargo/audit.toml") RUST_OSV_SCANNER_CONFIG = Path("apps/desktop/src-tauri/osv-scanner.toml") TRIVY_IGNORE_CONFIG = Path(".trivyignore") @@ -1232,7 +1233,7 @@ def _verify_security_audit_coverage(missing: list[str]) -> None: for token in [ "npm audit --workspaces --audit-level=high", "pip-audit --local --strict", - "cargo +stable audit", + RUST_AUDIT_COMMAND, ]: if audit and not any( command_contains_token_sequence(command, token) for command in audit_run_commands From 35600ddac58d84a9587a8d104dd078e574e21a54 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 14:18:48 -0700 Subject: [PATCH 26/58] fix(ci): satisfy Ruff toolchain test lint --- services/analysis-engine/tests/test_rust_toolchain_policy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy.py b/services/analysis-engine/tests/test_rust_toolchain_policy.py index aeb5b61ed..f42d7ddb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_policy.py +++ b/services/analysis-engine/tests/test_rust_toolchain_policy.py @@ -63,7 +63,7 @@ def _configure_policy_fixture( toolchain_path.write_text(manifest, encoding="utf-8") dependabot_path.write_text(dependabot, encoding="utf-8") (workflows_path / "ci.yml").write_text(workflow, encoding="utf-8") - version = getattr(module, "EXPECTED_TOOLCHAIN") + version = module.EXPECTED_TOOLCHAIN for filename, content in _supporting_workflow_contracts(version).items(): (workflows_path / filename).write_text(content, encoding="utf-8") From 1bf7f7c67a025c65ef5f29e544650895dde8b5f5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 14:19:23 -0700 Subject: [PATCH 27/58] fix(ci): normalize Ruff import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From dd6b8fde54e65ab54a95b49438ff6f8acd1bc5aa Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 15:23:04 -0700 Subject: [PATCH 28/58] fix(tests): satisfy Ruff import ordering --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From 35dd5b528df5529daa62114ed79828c79963361f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 16:18:19 -0700 Subject: [PATCH 29/58] fix(ci): satisfy Ruff import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From 2d3fd1349d81509eb3507dc204e52fcc6e3590c0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 17:00:14 -0700 Subject: [PATCH 30/58] test(rust): align supply-chain import layout --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From d244ee68d90d8363d5e29481de4fb836241dcbef Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 18:10:43 -0700 Subject: [PATCH 31/58] test(rust): fix supply-chain import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From 245486a4722b79784e95739dd86ad29fb30a7f58 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 18:33:05 -0700 Subject: [PATCH 32/58] test(rust): reject masked toolchain evidence --- .../test_rust_toolchain_policy_execution.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy_execution.py b/services/analysis-engine/tests/test_rust_toolchain_policy_execution.py index 4859c0b51..944f7792f 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_policy_execution.py +++ b/services/analysis-engine/tests/test_rust_toolchain_policy_execution.py @@ -103,3 +103,23 @@ def test_rust_toolchain_policy_rejects_required_command_present_only_in_comment( assert captured.out == "" assert "ci.yml job 'verify' is missing" in captured.err assert install in captured.err + + +def test_rust_toolchain_policy_rejects_failure_masking_shell_suffixes() -> None: + """Shell control flow cannot turn a failed required Rust command into evidence.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", + "verify_rust_toolchain_failure_masking", + ) + version = verifier.EXPECTED_TOOLCHAIN + install = f"rustup toolchain install {version} --profile minimal" + check = f"cargo +{version} check" + test = f"cargo +{version} test" + + masked_commands = ( + (install, f"{install} || true"), + (check, f"{check} --manifest-path crate/Cargo.toml --locked | cat"), + (test, f"{test} --manifest-path crate/Cargo.toml --locked ; true"), + ) + for required, masked in masked_commands: + assert not verifier._job_runs_required_command(_job("owner", masked), required) From e476bc981b22a06767d92c43fad981a22c005273 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 18:33:57 -0700 Subject: [PATCH 33/58] fix(rust): reject failure-masked workflow evidence --- scripts/checks/verify_rust_toolchain.py | 29 +++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/scripts/checks/verify_rust_toolchain.py b/scripts/checks/verify_rust_toolchain.py index 783b37e7b..071d93da0 100644 --- a/scripts/checks/verify_rust_toolchain.py +++ b/scripts/checks/verify_rust_toolchain.py @@ -3,6 +3,7 @@ from __future__ import annotations +import shlex import sys import tomllib from pathlib import Path @@ -20,6 +21,7 @@ ) DEPENDABOT_LANE_MARKER = ' - package-ecosystem: "rust-toolchain"' DEPENDABOT_UPDATE_MARKER = " - package-ecosystem:" +SHELL_CONTROL_CHARACTERS = frozenset("|&;") def _error(message: str) -> None: @@ -84,9 +86,32 @@ def _inline_run_commands(job: str) -> tuple[str, ...]: return tuple(commands) +def _is_single_shell_command(command: str) -> bool: + """Return whether a run payload has no shell control operator. + + A required Rust command may carry ordinary arguments such as + ``--manifest-path`` or ``--locked``. It may not be chained, piped, or + backgrounded, because a later command could replace the required command's + exit status and manufacture passing policy evidence. + """ + try: + lexer = shlex.shlex(command, posix=True, punctuation_chars="|&;") + lexer.whitespace_split = True + lexer.commenters = "" + tokens = tuple(lexer) + except ValueError: + return False + return bool(tokens) and not any( + token and all(character in SHELL_CONTROL_CHARACTERS for character in token) + for token in tokens + ) + + def _job_runs_required_command(job: str, required: str) -> bool: - """Return whether one executable run step owns the required Rust evidence.""" - commands = _inline_run_commands(job) + """Return whether one unmasked executable run step owns the Rust evidence.""" + commands = tuple( + command for command in _inline_run_commands(job) if _is_single_shell_command(command) + ) if required.startswith("--toolchain "): return any( command.startswith("rustup target add ") and required in command From a8dbacdade242724b719bda4702448782a7ee8b4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 18:36:54 -0700 Subject: [PATCH 34/58] docs(rust): record unmasked command evidence --- docs/doctoring/rust-toolchain-freshness.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/doctoring/rust-toolchain-freshness.md b/docs/doctoring/rust-toolchain-freshness.md index ccdfac72e..d214a4c3f 100644 --- a/docs/doctoring/rust-toolchain-freshness.md +++ b/docs/doctoring/rust-toolchain-freshness.md @@ -29,6 +29,14 @@ stable`, `cargo +stable`, or `--toolchain stable`. The same guard binds `rust-toolchain` Dependabot lane so an unrelated ecosystem entry cannot satisfy the compiler-update policy. +Required Rust command evidence is also bound to one inline executable `run:` +step whose exit status cannot be replaced by shell chaining, pipelines, or +background control operators. Arguments such as `--manifest-path`, `--locked`, +and an explicit target triple remain valid, but forms such as `|| true`, +`| cat`, or `; true` fail closed. This prevents an unsuccessfully installed, +checked, tested, or audited Rust toolchain from becoming success-shaped policy +evidence merely because a later shell command returns zero. + ## References GitHub. (2025, August 19). *Dependabot now supports Rust toolchain updates*. From 94ea841d9dc873a927e0396e73ecd2b7e49f5f20 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 18:37:22 -0700 Subject: [PATCH 35/58] chore(changelog): record Rust evidence hardening --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eea696893..eec6bfe64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ - Display the analyzed song tempo (BPM) as a badge in the rehearsal workspace. - 각 합주 역할(Role)별 개인 연습 진행도를 0~100% 범위로 기록 및 시각화할 수 있는 연습 진척도(`practiceProgress`) 트래커 기능 추가. UI 컨트롤(슬라이더 및 +/- 버튼)과 한/영 다국어 지원 포함. +### Changed + +- Pin repository-owned Rust build, audit, release, and native packaging evidence to Rust 1.97.1, and fail closed when required Rust commands are hidden in non-executing text, borrowed from another workflow/job, or chained through shell control flow that can mask their exit status. + ## [0.1.3] - 2026-04-29 ### Fixed From 8c53e91a86984b82dc62559e79c66260a1a7dca5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 20:02:08 -0700 Subject: [PATCH 36/58] fix(ci): format Rust toolchain supply-chain test --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From 52099e3e51854a6adae4915725706e23d57b9bdc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 22:03:54 -0700 Subject: [PATCH 37/58] style(tests): satisfy Ruff import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From bbdbadf56ec0f0398cd8d262ce5ce1c024587645 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 19 Aug 2026 23:04:13 -0700 Subject: [PATCH 38/58] test(rust): restore Ruff import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From 35c1f03c85bf1b215dcc18b97821c552286ade1d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 00:40:38 -0700 Subject: [PATCH 39/58] test(rust): remove incidental pytest import from toolchain contract --- .../tests/test_rust_toolchain_supply_chain_contract.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..5fbb71f09 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -4,7 +4,6 @@ from pathlib import Path -import pytest from conftest import load_module @@ -31,7 +30,7 @@ def _security_audit_workflow(rust_audit_command: str) -> str: def _rust_audit_violations( - monkeypatch: pytest.MonkeyPatch, + monkeypatch, tmp_path: Path, rust_audit_command: str, ) -> list[str]: @@ -54,7 +53,7 @@ def _rust_audit_violations( def test_supply_chain_accepts_repository_pinned_rust_audit( - monkeypatch: pytest.MonkeyPatch, + monkeypatch, tmp_path: Path, ) -> None: """The pinned audit command must satisfy the security workflow contract.""" @@ -64,7 +63,7 @@ def test_supply_chain_accepts_repository_pinned_rust_audit( def test_supply_chain_rejects_floating_stable_rust_audit( - monkeypatch: pytest.MonkeyPatch, + monkeypatch, tmp_path: Path, ) -> None: """A floating stable selector cannot satisfy the exact Rust audit contract.""" From 8038fd2c430cb2a2d482a9e834f4634356c6cf3f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 02:09:57 -0700 Subject: [PATCH 40/58] test(rust): restore formatter-clean pytest typing --- .../tests/test_rust_toolchain_supply_chain_contract.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 5fbb71f09..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -4,6 +4,7 @@ from pathlib import Path +import pytest from conftest import load_module @@ -30,7 +31,7 @@ def _security_audit_workflow(rust_audit_command: str) -> str: def _rust_audit_violations( - monkeypatch, + monkeypatch: pytest.MonkeyPatch, tmp_path: Path, rust_audit_command: str, ) -> list[str]: @@ -53,7 +54,7 @@ def _rust_audit_violations( def test_supply_chain_accepts_repository_pinned_rust_audit( - monkeypatch, + monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """The pinned audit command must satisfy the security workflow contract.""" @@ -63,7 +64,7 @@ def test_supply_chain_accepts_repository_pinned_rust_audit( def test_supply_chain_rejects_floating_stable_rust_audit( - monkeypatch, + monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """A floating stable selector cannot satisfy the exact Rust audit contract.""" From 68a54e42a4fb28554d4e4d35731525b855d28c94 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 03:22:29 -0700 Subject: [PATCH 41/58] style(tests): separate local toolchain test import --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From 3369ad2dbbe65f5b4b7f0bede45582a58ad229a5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 05:19:09 -0700 Subject: [PATCH 42/58] style(tests): organize Rust toolchain contract imports --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From a9534919091d0b23fbe317aa27ebc2f65763c468 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 07:37:34 -0700 Subject: [PATCH 43/58] style(tests): align Rust toolchain import groups --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From b0bc4a925c37eefd557e8371a1c6f5fba2e13853 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 10:05:37 -0700 Subject: [PATCH 44/58] test(rust): satisfy Ruff import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From 279710b6a64817e7a92e3540c2fcba74554a4122 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 13:17:01 -0700 Subject: [PATCH 45/58] test(rust): format supply-chain regression imports --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From bda03da267c9d698d098e8204715b0a1d74573d1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 15:20:32 -0700 Subject: [PATCH 46/58] style(test): align rust toolchain imports with Ruff --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From 8553647c3c6f15419e61f0737a40eef53cc462c8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 17:19:18 -0700 Subject: [PATCH 47/58] style(test): separate local conftest import --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From 2f1d013bfea6cf84e94dcb1abb2f507dd0dd4ade Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 19:41:12 -0700 Subject: [PATCH 48/58] test(rust): align supply-chain regression imports --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From cecab72f2df6f343d9a28949c845f5dbb0d50e16 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 23:19:45 -0700 Subject: [PATCH 49/58] test(rust): restore Ruff import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From fb4426b21c47d0f53c485aea1dc43f0eb5d3ccc9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 02:11:44 -0700 Subject: [PATCH 50/58] fix(rust): format supply-chain regression imports --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From 00bee2f6ed17c6b3379b383d67b2be45adb5d6d5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 05:06:39 -0700 Subject: [PATCH 51/58] style(rust-toolchain): satisfy ruff import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From 9fbfbcbc2c470b3e4e8d47d93f1f00a788385d52 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 06:46:47 -0700 Subject: [PATCH 52/58] test(rust-toolchain): reject nested run-shaped evidence --- ...st_toolchain_policy_nested_run_evidence.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 services/analysis-engine/tests/test_rust_toolchain_policy_nested_run_evidence.py diff --git a/services/analysis-engine/tests/test_rust_toolchain_policy_nested_run_evidence.py b/services/analysis-engine/tests/test_rust_toolchain_policy_nested_run_evidence.py new file mode 100644 index 000000000..ce982dbad --- /dev/null +++ b/services/analysis-engine/tests/test_rust_toolchain_policy_nested_run_evidence.py @@ -0,0 +1,27 @@ +"""Regression tests for non-executable run-shaped Rust toolchain evidence.""" + +from __future__ import annotations + +from conftest import load_module + + +def test_rust_toolchain_policy_rejects_required_command_in_nested_env_run_key() -> None: + """A nested ``env.run`` value cannot satisfy executable Rust evidence.""" + verifier = load_module( + "scripts/checks/verify_rust_toolchain.py", + "verify_rust_toolchain_nested_run_evidence", + ) + version = verifier.EXPECTED_TOOLCHAIN + install = f"rustup toolchain install {version} --profile minimal" + job = "\n".join( + ( + " owner:", + " steps:", + " - name: Pretend evidence", + " env:", + f" run: {install}", + " run: echo no-rust-toolchain-install", + ) + ) + + assert not verifier._job_runs_required_command(job, install) From 261fa254444228ad1b132546c69b5e750d61b9e6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 06:48:26 -0700 Subject: [PATCH 53/58] fix(rust-toolchain): bind evidence to actual step run keys --- scripts/checks/verify_rust_toolchain.py | 34 +++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/scripts/checks/verify_rust_toolchain.py b/scripts/checks/verify_rust_toolchain.py index 071d93da0..99d733ac1 100644 --- a/scripts/checks/verify_rust_toolchain.py +++ b/scripts/checks/verify_rust_toolchain.py @@ -67,18 +67,32 @@ def _inline_run_commands(job: str) -> tuple[str, ...]: """Return executable inline ``run:`` payloads from one workflow job. Required compiler evidence deliberately stays on one-line ``run:`` steps. A - comment, step name, environment value, or multiline scalar cannot satisfy - the contract accidentally; changing that representation requires an - explicit verifier update and regression rather than silently broadening the - evidence boundary. + comment, step name, environment value, nested ``with`` value, or multiline + scalar cannot satisfy the contract accidentally; changing that representation + requires an explicit verifier update and regression rather than silently + broadening the evidence boundary. """ + lines = job.splitlines() + step_markers = [index for index, line in enumerate(lines) if line == " steps:"] + if len(step_markers) != 1: + return () + + start = step_markers[0] + 1 + end = len(lines) + for index in range(start, len(lines)): + line = lines[index] + if not line.strip() or line.lstrip().startswith("#"): + continue + if line.startswith(" ") and not line.startswith(" "): + end = index + break + commands: list[str] = [] - for line in job.splitlines(): - stripped = line.strip() - if stripped.startswith("- run:"): - command = stripped.removeprefix("- run:").strip() - elif stripped.startswith("run:"): - command = stripped.removeprefix("run:").strip() + for line in lines[start:end]: + if line.startswith(" - run:"): + command = line.removeprefix(" - run:").strip() + elif line.startswith(" run:"): + command = line.removeprefix(" run:").strip() else: continue if command and command not in {"|", ">", "|-", ">-"}: From cfab395e4882a9bec249fba8ce8839ad762d77b0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 08:12:08 -0700 Subject: [PATCH 54/58] test(ci): format Rust supply-chain regression imports --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From 2aad4e01e6b0da7ca2af287833b6486f26c9944e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 11:12:51 -0700 Subject: [PATCH 55/58] test: format Rust toolchain contract imports --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..c86c28eb0 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from conftest import load_module From 0d9263788f996928d0a5b60fd27c3a395a43614b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 12:13:14 -0700 Subject: [PATCH 56/58] test(rust): apply repository Ruff import grouping --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index c86c28eb0..3ce72a0ff 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -5,7 +5,6 @@ from pathlib import Path import pytest - from conftest import load_module From 98c064e83a0e69d3e5385bef49125c6f136d34d2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 12:19:19 -0700 Subject: [PATCH 57/58] test(rust): remove unnecessary pytest type-only import --- .../tests/test_rust_toolchain_supply_chain_contract.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 3ce72a0ff..5fbb71f09 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -4,7 +4,6 @@ from pathlib import Path -import pytest from conftest import load_module @@ -31,7 +30,7 @@ def _security_audit_workflow(rust_audit_command: str) -> str: def _rust_audit_violations( - monkeypatch: pytest.MonkeyPatch, + monkeypatch, tmp_path: Path, rust_audit_command: str, ) -> list[str]: @@ -54,7 +53,7 @@ def _rust_audit_violations( def test_supply_chain_accepts_repository_pinned_rust_audit( - monkeypatch: pytest.MonkeyPatch, + monkeypatch, tmp_path: Path, ) -> None: """The pinned audit command must satisfy the security workflow contract.""" @@ -64,7 +63,7 @@ def test_supply_chain_accepts_repository_pinned_rust_audit( def test_supply_chain_rejects_floating_stable_rust_audit( - monkeypatch: pytest.MonkeyPatch, + monkeypatch, tmp_path: Path, ) -> None: """A floating stable selector cannot satisfy the exact Rust audit contract.""" From b0f8cf0de9f02ee1bed7a8ee964daed6d2063562 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:36:23 -0700 Subject: [PATCH 58/58] test(rust): satisfy Ruff import block spacing --- .../tests/test_rust_toolchain_supply_chain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py index 5fbb71f09..bcf7641d6 100644 --- a/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py +++ b/services/analysis-engine/tests/test_rust_toolchain_supply_chain_contract.py @@ -6,7 +6,6 @@ from conftest import load_module - PINNED_RUST_AUDIT = "cargo +1.97.1 audit"