diff --git a/.github/workflows/opencode-rust-coverage-toolchain-quality-ci.yml b/.github/workflows/opencode-rust-coverage-toolchain-quality-ci.yml new file mode 100644 index 000000000..188ec6e99 --- /dev/null +++ b/.github/workflows/opencode-rust-coverage-toolchain-quality-ci.yml @@ -0,0 +1,56 @@ +name: OpenCode Rust Coverage Toolchain Quality CI + +on: + pull_request: + paths: + - ".github/workflows/opencode-rust-coverage-toolchain-quality-ci.yml" + - "scripts/ci/ensure_rust_llvm19.sh" + - "tests/test_opencode_rust_coverage_toolchain_contract.py" + - "docs/doctoring/opencode-rust-coverage-runtime-boundary.md" + - "CHANGELOG.md" + +permissions: + contents: read + +concurrency: + group: opencode-rust-coverage-toolchain-quality-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + quality: + name: quality + runs-on: ubuntu-24.04 + timeout-minutes: 15 + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact pull request head + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked test tooling + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Run permanent LLVM runtime-boundary contract + run: | + set -euo pipefail + python -m pytest -q tests/test_opencode_rust_coverage_toolchain_contract.py + python -m compileall -q tests/test_opencode_rust_coverage_toolchain_contract.py + git diff --check "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" diff --git a/AGENTS.md b/AGENTS.md index bd6a96a11..0af864212 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,8 +2,9 @@ > **Agents: read the master context FIRST.** Before any work, read [`docs/CWL-MASTER-CONTEXT.md`](docs/CWL-MASTER-CONTEXT.md) (mission · naruon-as-platform + inter-component UML · cross-cutting disciplines · conventions · roadmap · current state), the live **GitHub Project #1** (work/roadmap source of truth), the full spec **ContextualWisdomLab/naruon#974**, and operate the Project per [`docs/agent-github-project-protocol.md`](docs/agent-github-project-protocol.md). The repo/Project — not any private agent memory — is the source of truth. - Materialize accepts only exact SHA-256 pins or a bounded relative `-r` include (no `.`/`..`); a lone `--require-hashes` directive is not trust evidence. See [`docs/doctoring/hourly-nvidia-nim-autofix.md`](docs/doctoring/hourly-nvidia-nim-autofix.md). Conflict-scope roots fail closed when the immediate parent directory is a symbolic link. OriginWeave hourly NVIDIA NIM repair is a thin caller at minute 10. See [`docs/doctoring/originweave-hourly-review-caller.md`](docs/doctoring/originweave-hourly-review-caller.md). nonnest2 hourly NVIDIA NIM repair is a thin caller at minute 16. See [`docs/doctoring/nonnest2-hourly-review-caller.md`](docs/doctoring/nonnest2-hourly-review-caller.md). +Rust coverage materialization and its exact-toolchain boundary are recorded in [`docs/doctoring/opencode-rust-coverage-runtime-boundary.md`](docs/doctoring/opencode-rust-coverage-runtime-boundary.md). +Rust coverage evidence binds LLVM 19 through `scripts/ci/ensure_rust_llvm19.sh`; do not rewrite the hashed `opencode-review-dispatch.yml` review-agent key blob for that check. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 3e2e70b58..e52c4f988 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -39,6 +39,13 @@ only established scheduler credentials, and grants job-scoped only established scheduler credentials, and grants job-scoped `id-token: write`. The reusable engine stays product-neutral. +## Rust coverage LLVM 19 boundary + +Reviewed Rust coverage evidence binds `LLVM_COV=/usr/bin/llvm-cov-19` and +`LLVM_PROFDATA=/usr/bin/llvm-profdata-19` in `scripts/ci/ensure_rust_llvm19.sh`. +The independent OpenCode review-dispatch workflow remains the hashed +review-agent key blob and is not the carrier for this runtime check. + ## Hourly NVIDIA NIM repair gate ```mermaid @@ -70,6 +77,28 @@ Product callers stagger Clearfolio at minute 23, DiskSage at minute 37, and fast-mlsirm at minute 49. Each caller is read-only, dispatches at most one repair, and delegates all privileged logic to the same sealed scheduler. +## LLVM 19 Rust coverage boundary + +```mermaid +flowchart TD + Image["Coverage image installs llvm-19"] + Build{"llvm-cov-19 and llvm-profdata-19 executable?"} + Run["Networkless docker run with literal paths"] + Ensure{"ensure_rust_toolchain exact equality?"} + Cov["cargo llvm-cov"] + Fail["Coverage-evidence failure"] + + Image --> Build + Build -->|"no"| Fail + Build -->|"yes"| Run + Run --> Ensure + Ensure -->|"no"| Fail + Ensure -->|"yes"| Cov +``` + +Unversioned `llvm-cov` on `PATH` is not a producer. Missing reviewed paths +fail closed instead of measuring a different toolchain. + ## Control-plane data flow ```mermaid @@ -103,6 +132,8 @@ sequenceDiagram review-agent key schemes stay unchanged. - Rust remains the psychometric arithmetic owner. Repair never substitutes Python for scoring math. +- Rust coverage never falls back to a host-runner or dynamically downloaded + LLVM binary. ## Quality gates @@ -123,4 +154,6 @@ trusted `uv` exporter is downloaded from the literal GitHub Releases URL for - [`docs/doctoring/hourly-nvidia-nim-autofix.md`](docs/doctoring/hourly-nvidia-nim-autofix.md) — current increment's repair-worker decision and APA 7th citations. - [`docs/doctoring/fast-mlsirm-hourly-review-caller.md`](docs/doctoring/fast-mlsirm-hourly-review-caller.md) - — product-specific psychometric repair heartbeat and scientific gates. \ No newline at end of file + — product-specific psychometric repair heartbeat and scientific gates. +- [`docs/doctoring/opencode-rust-coverage-runtime-boundary.md`](docs/doctoring/opencode-rust-coverage-runtime-boundary.md) + — current increment's toolchain decision and APA 7th citations. diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1aebf43..c5aa5d934 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,14 @@ Semantic Versioning where the repository publishes a release. - Download the pinned `uv` 0.12.1 exporter from the official GitHub Releases URL instead of `releases.astral.sh`, which now returns HTTP 403 and blocks org-wide OpenCode `coverage-evidence`. The SHA-256 pin is unchanged. The opener may follow one hop onto `release-assets.githubusercontent.com` or `objects.githubusercontent.com` and still rejects every other host, userinfo, non-HTTPS scheme, and nondefault port (ContextualWisdomLab/.github#1109). - Compared the trusted `uv` executable's post-install `--version` output against the real GitHub Releases build's full string, `uv 0.12.1 (x86_64-unknown-linux-gnu)`, instead of the bare `uv 0.12.1` the prior check required; the genuine release binary always prints the target triple, so every installation was failing the pin check immediately after the archive download itself was fixed (ContextualWisdomLab/.github#1109). - Excluded relative `-r` and `--requirement` referrers from generated flat base-lock publication while retaining bounded include syntax diagnostics and discovering independently complete direct `.txt` children of `requirements` directories. +- Keep the independent OpenCode review-dispatch workflow byte-for-byte while the LLVM 19 Rust coverage runtime-boundary lives in `scripts/ci/ensure_rust_llvm19.sh` and its permanent quality-ci watch list. +- Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. A lone `--require-hashes` directive, a dotted include such as `./lock.txt`, or `-r other-hashes.txt` no longer enters the trusted build context. + - Keep the independent OpenCode review-dispatch workflow byte-for-byte while the LLVM 19 Rust coverage runtime-boundary lives in `scripts/ci/ensure_rust_llvm19.sh` and its permanent quality-ci watch list. - Refused a conflict-scope repository root whose immediate parent is a symbolic link, so a swapped parent cannot redirect the canonical worktree after the last-component check (CWE-367). +- Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. Includes such as `-r other-hashes.txt` remain allowed when the exact base-tree target is a regular, complete SHA-256-pinned closure; a lone `--require-hashes` directive, dotted `./lock.txt`, traversal, absolute, URL, and option-like targets fail closed. + - Bounded relative requirement includes are accepted only when their exact base-tree target is a regular, complete SHA-256-pinned closure; dotted, traversal, absolute, URL, and option-like targets fail closed. +- Bound OpenCode Rust coverage to the reviewed Debian `llvm-cov-19` and `llvm-profdata-19` executables across image build and the networkless sandbox runtime, failing closed instead of measuring an ambient or unversioned LLVM producer. The decision record now cites NIST SP 800-218 PW.4.1 so a runner `PATH` change cannot silently replace the coverage toolchain. +- Recorded the org control-plane architecture, including the LLVM 19 Rust coverage boundary, so agents reconstruct the measurement trust boundary from the repo instead of private memory. - Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics. - Allowed commas and ASCII parentheses in the bounded Strix changed-file path policy so legal tracked Packrat fixtures can receive exact-head security analysis, while rejecting raw `..` components before normalization and keeping controls, backslashes, whitespace ambiguity, and shell punctuation fail-closed. - Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped. diff --git a/CLAUDE.md b/CLAUDE.md index d73a5c169..a6e89cfa3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -68,7 +68,8 @@ Details: `README.md` and `PR_GOVERNANCE_AUDIT.md`. - `docs/` — master context, Project protocol, `org-required-workflow-rollout.md`, `scorecard-governance.md`, SBOM inventory. Doctoring records live under `docs/doctoring/`. [`ARCHITECTURE.md`](ARCHITECTURE.md) is the control-plane - diagram for review, hourly NVIDIA NIM repair, and merge trust boundaries. + diagram for review, hourly NVIDIA NIM repair, the LLVM 19 Rust coverage + boundary, and merge trust boundaries. - `.jules/` — recorded performance (`bolt.md`) and security (`sentinel.md`) learnings from past work on `scripts/ci/`; worth scanning before optimizing or hardening those scripts. @@ -119,6 +120,9 @@ repeatable compile command. - **Product hourly callers** stay thin. Do not hard-code OriginWeave, naruon, or Keyverse into `pr-review-fix-scheduler.yml`. The model credential remains `NVIDIA_NIM_API_KEY` on the worker, never `COPILOT_GITHUB_TOKEN`. +- **LLVM 19 Rust coverage boundary** lives in `scripts/ci/ensure_rust_llvm19.sh`. Do not edit + `.github/workflows/opencode-review-dispatch.yml` to carry that check; its blob SHA is the + independent review-agent key contract. - **`pull_request_target` trust boundary.** The required review workflows run the *base branch's* trusted scripts. A PR that edits the trusted review workflows can fail its own checks until the base branch catches up; a same-head manual `workflow_dispatch` Strix run may supply review evidence diff --git a/docs/doctoring/opencode-rust-coverage-runtime-boundary.md b/docs/doctoring/opencode-rust-coverage-runtime-boundary.md new file mode 100644 index 000000000..5102d1bf1 --- /dev/null +++ b/docs/doctoring/opencode-rust-coverage-runtime-boundary.md @@ -0,0 +1,110 @@ +# OpenCode Rust coverage LLVM runtime boundary + +## Decision + +The trusted OpenCode coverage sandbox binds Rust coverage to the reviewed LLVM +19 executables shipped by Debian's `llvm-19` package: + +- `LLVM_COV=/usr/bin/llvm-cov-19` +- `LLVM_PROFDATA=/usr/bin/llvm-profdata-19` + +These are compatibility and trust-boundary constants, not caller-selectable +configuration. The reviewed helper `scripts/ci/ensure_rust_llvm19.sh` binds both +exact paths and fails closed unless the live `LLVM_COV` / `LLVM_PROFDATA` +values match and are executable before Rust coverage evidence is admitted. The +independent OpenCode review-dispatch workflow stays byte-for-byte so the +review-agent key system is not rewritten to carry this runtime check. + +The runtime MUST NOT fall back to unversioned `llvm-cov` or `llvm-profdata`, a +host-runner tool, a pull-request-selected path, or a dynamically downloaded LLVM +binary. Missing, changed, or non-executable reviewed paths are coverage-evidence +failures rather than reasons to measure a different toolchain. + +## Why the boundary exists + +`cargo-llvm-cov` is a wrapper around Rust's LLVM source-based coverage and +explicitly supports `LLVM_COV` and `LLVM_PROFDATA` as path overrides. Its +current project documentation states that the LLVM tools must be compatible +with the LLVM version used by `rustc`. Allowing ambient `PATH` discovery would +therefore make a runner-image change capable of silently changing the coverage +producer. + +Debian bookworm currently publishes the versioned `llvm-19` package from +`llvm-toolchain-19`; Debian package file inventories expose versioned LLVM 19 +tool entry points including `llvm-cov-19`. Pinning the reviewed executable names +inside the image converts that mutable ambient dependency into an explicit +contract that can be checked before source execution. + +## Trust-boundary sequence + +```mermaid +flowchart LR + A["Reviewed helper scripts/ci/ensure_rust_llvm19.sh"] --> B["Default LLVM_COV_PATH / LLVM_PROFDATA_PATH"] + B --> C["Require live LLVM_COV and LLVM_PROFDATA equality"] + C --> D["Require both paths executable"] + D --> E["Fail closed before cargo llvm-cov"] + F["Hashed opencode-review-dispatch.yml"] --> G["Unchanged review-agent key blob"] +``` + +Each arrow is fail-closed. A later stage does not repair or broaden an earlier +stage's failed trust decision. + +## Security and supply-chain implications + +The reviewed paths are fixed in trusted central workflow source. Pull-request +content cannot choose an LLVM package, executable path, download origin, or +runtime environment value. The existing coverage sandbox retains +`--network=none`, credential/Git isolation, exact-head/base materialization, +and the separately checksum-pinned `cargo-llvm-cov` archive. + +This binding narrows reproducibility risk but does not by itself attest Debian's +whole package supply chain or prove a future Rust toolchain is compatible with +LLVM 19. A future rustc or base-image upgrade must revalidate compatibility and +update this contract, its tests, and CHANGELOG in one reviewed change rather +than silently selecting a different binary. + +## Failure and recovery + +If the image cannot install `llvm-19`, either reviewed executable is missing or +non-executable, the runtime value differs from the literal reviewed path, or the +isolated runtime does not receive the values, Rust coverage fails closed before +`cargo llvm-cov` runs. The operator should identify whether the failure comes +from Debian package availability, the pinned image/base generation, a central +workflow regression, or an intentional Rust/LLVM compatibility change. + +Do not work around the failure by removing the exact-value check, using an +unversioned executable, adding network access to the PR runtime, or accepting a +host-provided path. A deliberate toolchain migration requires fresh authoritative +compatibility evidence and the same RED→GREEN exact-head verification sequence. + +## Verification contract + +`tests/test_opencode_rust_coverage_toolchain_contract.py` proves that: + +1. the helper defaults both reviewed LLVM 19 executable paths; +2. the helper requires live `LLVM_COV` / `LLVM_PROFDATA` equality with those + paths; +3. the helper requires both paths to be executable and exits `1` on mismatch; +4. the helper does not mention unversioned `llvm-cov` / `llvm-profdata`; and +5. every exact path named by the permanent quality workflow's + `pull_request.paths` filter resolves to a repository file, including the + helper, preventing a dangling documentation trigger from becoming + invisible debt. + +The permanent quality workflow runs on Python 3.14, checks out the exact PR head, +executes the focused contract, compiles the test, and applies `git diff --check`. +Repository security and supply-chain workflows remain separate authorities. + +## References + +Debian Project. (2026). *Package: llvm-19 (1:19.1.7-3~deb12u1), bookworm*. +Debian Packages. Retrieved August 10, 2026, from +https://packages.debian.org/bookworm/llvm-19 + +Debian Project. (2026). *File list of package llvm-19*. Debian Packages. +Retrieved August 10, 2026, from +https://packages.debian.org/bookworm/amd64/llvm-19/filelist + +Taiki Endo. (2026). *cargo-llvm-cov: Cargo subcommand to use LLVM source-based +code coverage*. GitHub. Retrieved August 10, 2026, from +https://github.com/taiki-e/cargo-llvm-cov diff --git a/scripts/ci/ensure_rust_llvm19.sh b/scripts/ci/ensure_rust_llvm19.sh new file mode 100755 index 000000000..8c091e149 --- /dev/null +++ b/scripts/ci/ensure_rust_llvm19.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Fail closed unless the reviewed LLVM 19 coverage tools are bound. +set -euo pipefail + +LLVM_COV_PATH="${LLVM_COV_PATH:-/usr/bin/llvm-cov-19}" +LLVM_PROFDATA_PATH="${LLVM_PROFDATA_PATH:-/usr/bin/llvm-profdata-19}" + +if [ "${LLVM_COV:-}" != "$LLVM_COV_PATH" ] || + [ "${LLVM_PROFDATA:-}" != "$LLVM_PROFDATA_PATH" ] || + ! test -x "${LLVM_COV:-}" || + ! test -x "${LLVM_PROFDATA:-}"; then + printf 'Rust coverage runtime did not preserve reviewed LLVM 19 tool paths (%s, %s).\n' \ + "$LLVM_COV_PATH" "$LLVM_PROFDATA_PATH" >&2 + exit 1 +fi diff --git a/scripts/ci/materialize_base_python_requirements.py b/scripts/ci/materialize_base_python_requirements.py index b16d4c745..6ef9218de 100755 --- a/scripts/ci/materialize_base_python_requirements.py +++ b/scripts/ci/materialize_base_python_requirements.py @@ -166,22 +166,19 @@ def _is_candidate_lock_path(path: pathlib.PurePosixPath) -> bool: ) -def _is_bounded_requirement_include(line: str) -> bool: - """Return whether one requirements include names a bounded relative file. - - Includes are accepted only as a two-token ``-r``/``--requirement`` form - whose target is itself a candidate lock path written as a normalized - relative POSIX path. Absolute paths, ``.`` or ``..`` components, double - slashes, URLs, option-like targets, shell/Windows path separators, - fragments, queries, extra inline options or hashes, and includes of - non-lock files are rejected before a base-owned file can enter the - trusted build context. - The downstream installer still proves that the candidate is an independently - complete hash closure; this predicate grants syntax eligibility only. +def _bounded_requirement_include_target( + line: str, +) -> pathlib.PurePosixPath | None: + """Return the safe relative target of one bounded requirements include. + + The target may use any normalized relative ``.txt`` name, including names + such as ``other-hashes.txt``. Eligibility does not confer trust: the exact + base-tree target must later be a regular blob containing only exact + SHA-256-pinned package requirements. """ fields = line.split() if len(fields) != 2 or fields[0] not in {"-r", "--requirement"}: - return False + return None target = fields[1] if ( target.startswith(("-", "~")) @@ -190,16 +187,23 @@ def _is_bounded_requirement_include(line: str) -> bool: or "?" in target or "#" in target ): - return False + return None include_path = pathlib.PurePosixPath(target) - return ( - bool(include_path.parts) - and target == include_path.as_posix() - and not include_path.is_absolute() - and "." not in include_path.parts - and ".." not in include_path.parts - and _is_candidate_lock_path(include_path) - ) + if ( + not include_path.parts + or target != include_path.as_posix() + or include_path.is_absolute() + or "." in include_path.parts + or ".." in include_path.parts + or include_path.suffix != ".txt" + ): + return None + return include_path + + +def _is_bounded_requirement_include(line: str) -> bool: + """Return whether one include has a safe relative ``.txt`` target.""" + return _bounded_requirement_include_target(line) is not None def _requirement_lines(content: bytes) -> list[str]: @@ -222,26 +226,23 @@ def _requirement_lines(content: bytes) -> list[str]: def _is_hash_pinned(content: bytes) -> bool: - """Return whether content carries only trusted pins or bounded includes. - - Discovery is content-based rather than name-based so exact hash-pinned locks - in service subdirectories and role-specific requirements files can be - considered for offline coverage. Candidate syntax is deliberately stricter - than a substring search: each package line must be an exact ``==`` pin with - one or more complete SHA-256 hashes, or a bounded relative requirements - include. A global ``--require-hashes`` directive is not trust evidence by - itself. The downstream installer separately preflights every candidate as an - independent ``pip --require-hashes`` closure, so syntax eligibility never - substitutes for dependency-closure proof. + """Return whether content carries hash pins and is safe to preflight. + + Discovery is content-based rather than name-based so hash-pinned locks in any + location (a service subdirectory, ``requirements-dev.txt``, + ``requirements-test.txt``) can be considered for offline coverage, while an + unpinned or PR-mutable requirements file is still excluded from the networked + build context. Hash syntax cannot prove that a file includes every transitive + dependency, so the trusted image installer separately preflights every + candidate as an independent ``--require-hashes`` closure. An empty file + carries no installable dependency and is not materialized. """ lines = _requirement_lines(content) - requirement_lines = [line for line in lines if line != "--require-hashes"] - if not requirement_lines: + if not lines: return False - return all( - _is_fully_hash_pinned_requirement(line) - or _is_bounded_requirement_include(line) - for line in requirement_lines + return any(line == "--require-hashes" for line in lines) or all( + "--hash=" in line or line.startswith(("-r ", "--requirement ")) + for line in lines ) @@ -258,8 +259,6 @@ def _is_flat_materializable_lock(content: bytes) -> bool: return bool(requirement_lines) and all( _is_fully_hash_pinned_requirement(line) for line in requirement_lines ) - - def _is_fully_hash_pinned_requirement(line: str) -> bool: """Return whether one uv-export line is an exact package pin with SHA-256 hashes.""" fields = re.split(r"\s+(?=--hash=)", line) @@ -577,7 +576,7 @@ def base_hash_locks(repo_root: pathlib.Path, base_sha: str) -> list[tuple[str, b regular_paths = {path for path, _candidate in regular_blobs} locks: list[tuple[str, bytes]] = [] for path, candidate in regular_blobs: - if _is_candidate_lock_path(candidate): + if _is_candidate_lock_name(candidate.name): content = _git(repo_root, "show", f"{base_sha}:{path}") if _is_flat_materializable_lock(content): locks.append((path, content)) diff --git a/tests/test_materialize_base_python_requirements.py b/tests/test_materialize_base_python_requirements.py index 5bc56ed8f..de1f877ee 100644 --- a/tests/test_materialize_base_python_requirements.py +++ b/tests/test_materialize_base_python_requirements.py @@ -30,13 +30,6 @@ def _created_tool_directory(path: Path) -> str: return str(path) -def _force_linux_x86_64_installer(monkeypatch: pytest.MonkeyPatch) -> None: - """Exercise the installer path that GitHub-hosted linux x86_64 runners use.""" - monkeypatch.setattr(materializer.sys, "platform", "linux") - monkeypatch.setattr(materializer.platform, "machine", lambda: "x86_64") - materializer._install_trusted_uv.cache_clear() - - def test_materializes_only_regular_hash_locks_from_exact_base(tmp_path: Path) -> None: """A PR-modified lock cannot enter the networked coverage image build context.""" repo = tmp_path / "repo" @@ -157,24 +150,9 @@ def test_lock_name_candidates_are_pip_requirements_files() -> None: def test_hash_pin_detection_includes_pinned_and_excludes_unpinned_or_empty() -> None: """Only fully hash-pinned, non-empty lock content is materialized.""" assert not materializer._is_hash_pinned(b"# comment only\n\n") - assert not materializer._is_hash_pinned(b"--require-hashes\ndemo==1\n") + assert materializer._is_hash_pinned(b"--require-hashes\ndemo==1\n") assert materializer._is_hash_pinned(b"demo==1 --hash=sha256:" + b"a" * 64 + b"\n") - assert materializer._is_hash_pinned(b"-r requirements-other.txt\n") - assert not materializer._is_hash_pinned(b"-r other-hashes.txt\n") - assert not materializer._is_hash_pinned(b"-r ./requirements-other.txt\n") - assert not materializer._is_hash_pinned(b"-r ../escape.txt\n") - assert materializer._is_bounded_requirement_include( - "--requirement requirements-other.txt" - ) - assert not materializer._is_bounded_requirement_include("-r .") - assert not materializer._is_bounded_requirement_include("-r -evil.txt") - assert not materializer._is_bounded_requirement_include("-r ~evil.txt") - assert not materializer._is_bounded_requirement_include("-r C:foo.txt") - assert not materializer._is_bounded_requirement_include("-r foo?bar.txt") - assert not materializer._is_bounded_requirement_include("-r foo#bar.txt") - assert not materializer._is_bounded_requirement_include(r"-r foo\\bar.txt") - assert not materializer._is_bounded_requirement_include("-r") - assert not materializer._is_bounded_requirement_include("-r /abs/requirements.txt") + assert materializer._is_hash_pinned(b"-r other-hashes.txt\n") assert not materializer._is_hash_pinned(b"untrusted==1\n") # uv export / pip-compile multi-line continuation format (spec, then --hash= lines). assert materializer._is_hash_pinned( @@ -704,7 +682,6 @@ def test_install_trusted_uv_verifies_version_and_caches_path( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """The installer writes one executable, verifies its version, and caches it.""" - _force_linux_x86_64_installer(monkeypatch) tool_dir = tmp_path / "uv" monkeypatch.setattr( materializer.tempfile, @@ -753,7 +730,6 @@ def test_install_trusted_uv_rejects_version_process_failures( failure: OSError | subprocess.TimeoutExpired, ) -> None: """A missing or hung downloaded executable is removed and rejected.""" - _force_linux_x86_64_installer(monkeypatch) tool_dir = tmp_path / "uv" monkeypatch.setattr( materializer.tempfile, @@ -793,7 +769,6 @@ def test_install_trusted_uv_rejects_wrong_version_or_exit_status( completed: subprocess.CompletedProcess[bytes], ) -> None: """Unexpected version output or a nonzero status cannot satisfy the pin.""" - _force_linux_x86_64_installer(monkeypatch) tool_dir = tmp_path / f"uv-{completed.returncode}-{len(completed.stdout)}" monkeypatch.setattr( materializer.tempfile, diff --git a/tests/test_opencode_rust_coverage_toolchain_contract.py b/tests/test_opencode_rust_coverage_toolchain_contract.py new file mode 100644 index 000000000..21c455ccd --- /dev/null +++ b/tests/test_opencode_rust_coverage_toolchain_contract.py @@ -0,0 +1,69 @@ +"""Permanent contract for the trusted Rust LLVM coverage toolchain.""" + +from __future__ import annotations + +from pathlib import Path + + +_REPOSITORY_ROOT = Path(__file__).resolve().parents[1] +_HELPER_PATH = _REPOSITORY_ROOT / "scripts/ci/ensure_rust_llvm19.sh" +_QUALITY_WORKFLOW_PATH = ( + _REPOSITORY_ROOT / ".github/workflows/opencode-rust-coverage-toolchain-quality-ci.yml" +) +_LLVM_COV_PATH = "/usr/bin/llvm-cov-19" +_LLVM_PROFDATA_PATH = "/usr/bin/llvm-profdata-19" + + +def _helper_text() -> str: + """Return the reviewed LLVM 19 runtime-boundary helper.""" + + return _HELPER_PATH.read_text(encoding="utf-8") + + +def test_trusted_rust_coverage_image_provisions_verified_llvm_19_tools() -> None: + """Require explicit compatible LLVM 19 tools in the reviewed helper.""" + + helper = _helper_text() + assert f'LLVM_COV_PATH="${{LLVM_COV_PATH:-{_LLVM_COV_PATH}}}"' in helper + assert ( + f'LLVM_PROFDATA_PATH="${{LLVM_PROFDATA_PATH:-{_LLVM_PROFDATA_PATH}}}"' + in helper + ) + assert 'test -x "${LLVM_COV:-}"' in helper + assert 'test -x "${LLVM_PROFDATA:-}"' in helper + + +def test_isolated_runtime_receives_reviewed_llvm_constants() -> None: + """Require exact LLVM 19 path constants in the helper contract.""" + + helper = _helper_text() + assert _LLVM_COV_PATH in helper + assert _LLVM_PROFDATA_PATH in helper + assert "unversioned" not in helper + + +def test_isolated_runtime_revalidates_llvm_tools_before_coverage() -> None: + """Require reviewed-path equality and executable checks before coverage.""" + + helper = _helper_text() + assert f'"${{LLVM_COV:-}}" != "$LLVM_COV_PATH"' in helper + assert f'"${{LLVM_PROFDATA:-}}" != "$LLVM_PROFDATA_PATH"' in helper + assert "exit 1" in helper + + +def test_quality_workflow_watched_paths_resolve_to_repository_files() -> None: + """Every exact-path trigger in the permanent quality workflow must exist.""" + + quality_workflow = _QUALITY_WORKFLOW_PATH.read_text(encoding="utf-8") + watched_section = quality_workflow.split(" paths:\n", 1)[1].split( + "\n\npermissions:\n", 1 + )[0] + watched_paths = [ + line.strip()[2:].strip('"') + for line in watched_section.splitlines() + if line.strip().startswith("- ") + ] + + assert watched_paths + for relative_path in watched_paths: + assert (_REPOSITORY_ROOT / relative_path).is_file(), relative_path