Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 80 additions & 42 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,75 @@ jobs:
mkdir -p "$sandbox_result_dir"
chmod 0700 "$sandbox_result_dir"

# Build the coverage tool image before the pull-request tree is
# mounted anywhere. The networked build context contains only this
# trusted Dockerfile plus the reviewed, hash-pinned CI requirements
# from the default-branch checkout; it never contains PR-controlled
# source, dependency manifests, credentials, or runner command files.
coverage_tool_image="opencode-coverage-tools:${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
coverage_build_dir="${RUNNER_TEMP}/opencode-coverage-tool-build"
trusted_ci_requirements="${GITHUB_WORKSPACE}/requirements-opencode-review-ci-hashes.txt"
if [ ! -f "$trusted_ci_requirements" ] || [ -L "$trusted_ci_requirements" ]; then
echo "::error::Trusted coverage requirements must be a regular non-symlink file."
exit 1
fi
sudo rm -rf "$coverage_build_dir"
mkdir -p "$coverage_build_dir"
chmod 0700 "$coverage_build_dir"
install -m 0644 "$trusted_ci_requirements" \
"$coverage_build_dir/requirements-opencode-review-ci-hashes.txt"
cat >"$coverage_build_dir/Dockerfile" <<'DOCKERFILE'
FROM docker.io/library/ubuntu@sha256:52df9b1ee71626e0088f7d400d5c6b5f7bb916f8f0c82b474289a4ece6cf3faf
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
ca-certificates \
cargo \
curl \
git \
jq \
libcurl4-openssl-dev \
libssl-dev \
libxml2-dev \
mesa-vulkan-drivers \
libvulkan1 \
nodejs \
npm \
pkg-config \
python3 \
python3-pip \
python3-venv \
r-base \
r-cran-covr \
r-cran-testthat \
rustc \
util-linux \
vulkan-tools \
&& rm -rf /var/lib/apt/lists/*
RUN curl --proto '=https' --tlsv1.2 -fsSLo /tmp/cargo-llvm-cov.tar.gz \
https://github.com/taiki-e/cargo-llvm-cov/releases/download/v0.8.7/cargo-llvm-cov-x86_64-unknown-linux-musl.tar.gz \
&& echo '967b5cc996c29d8baa52bbb4595ef1f53af35255af8e2036ddbc6468d7b523c7 /tmp/cargo-llvm-cov.tar.gz' | sha256sum -c - \
&& tar -xzf /tmp/cargo-llvm-cov.tar.gz -C /usr/local/bin cargo-llvm-cov \
&& chmod 0755 /usr/local/bin/cargo-llvm-cov \
&& rm -f /tmp/cargo-llvm-cov.tar.gz
COPY requirements-opencode-review-ci-hashes.txt /tmp/requirements-opencode-review-ci-hashes.txt
RUN python3 -m pip install \
--break-system-packages \
--disable-pip-version-check \
--require-hashes \
--only-binary=:all: \
-r /tmp/requirements-opencode-review-ci-hashes.txt \
&& rm -f /tmp/requirements-opencode-review-ci-hashes.txt
DOCKERFILE
if ! docker build --pull --no-cache --network=default \
--tag "$coverage_tool_image" \
--file "$coverage_build_dir/Dockerfile" \
"$coverage_build_dir"; then
echo "::error::Trusted coverage tool image build failed before PR execution."
exit 1
fi
sudo rm -rf "$coverage_build_dir"

sandbox_status=0
docker run --rm --init --network=none \
--name "opencode-coverage-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" \
Expand Down Expand Up @@ -573,7 +642,7 @@ jobs:
--env RUNNER_TEMP=/secure-output \
--env GITHUB_OUTPUT=/secure-output/github-output \
--env GITHUB_STEP_SUMMARY=/secure-output/step-summary \
docker.io/library/ubuntu@sha256:52df9b1ee71626e0088f7d400d5c6b5f7bb916f8f0c82b474289a4ece6cf3faf \
"$coverage_tool_image" \
/bin/bash /trusted-measure-step.sh || sandbox_status=$?

sandbox_output="${sandbox_result_dir}/github-output"
Expand All @@ -596,35 +665,6 @@ jobs:
exit 0
fi

export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install --no-install-recommends -y \
ca-certificates \
cargo \
curl \
git \
jq \
libcurl4-openssl-dev \
libssl-dev \
libxml2-dev \
nodejs \
npm \
python3 \
python3-pip \
python3-venv \
r-base \
r-cran-covr \
r-cran-testthat \
rustc \
util-linux
rm -rf /var/lib/apt/lists/*
python3 -m pip install \
--break-system-packages \
--disable-pip-version-check \
--require-hashes \
--only-binary=:all: \
-r /trusted/requirements-opencode-review-ci-hashes.txt

# Use a fixed nobody-like identity that cannot traverse the host-owned
# /out bind mount. This prevents even a daemonized test process from
# racing trusted result publication.
Expand Down Expand Up @@ -1291,8 +1331,7 @@ jobs:
if command -v Rscript >/dev/null 2>&1 && dpkg -s libcurl4-openssl-dev libssl-dev libxml2-dev >/dev/null 2>&1; then
return 0
fi
run_and_capture "R runtime and signed distribution coverage packages" \
bash -c 'sudo apt-get update && sudo apt-get install -y r-base r-cran-covr r-cran-testthat libcurl4-openssl-dev libssl-dev libxml2-dev'
return 1
}

run_r_test_coverage() {
Expand Down Expand Up @@ -1349,10 +1388,6 @@ jobs:
# coverage command still runs and reports any uncovered GPU lines
# exactly as before, so Rust repositories without GPU code are
# unaffected and no gate is weakened.
if ! ls /usr/share/vulkan/icd.d/lvp_icd*.json >/dev/null 2>&1; then
run_and_capture "Software Vulkan adapter (Mesa lavapipe) for GPGPU coverage" \
bash -c 'sudo apt-get update && sudo apt-get install -y --no-install-recommends mesa-vulkan-drivers libvulkan1 vulkan-tools || true'
fi
if ls /usr/share/vulkan/icd.d/lvp_icd*.json >/dev/null 2>&1; then
lvp_icd="$(ls /usr/share/vulkan/icd.d/lvp_icd*.json | head -n1)"
export VK_ICD_FILENAMES="$lvp_icd"
Expand Down Expand Up @@ -1384,10 +1419,6 @@ jobs:
if ! find . -name tauri.conf.json -not -path '*/node_modules/*' -not -path '*/target/*' -print -quit 2>/dev/null | grep -q .; then
return 0
fi
if ! pkg-config --exists webkit2gtk-4.1 2>/dev/null; then
run_and_capture "Tauri Linux system libraries (WebKitGTK/GTK3) for desktop coverage" \
bash -c 'sudo apt-get update && sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev || true'
fi
if pkg-config --exists webkit2gtk-4.1 2>/dev/null; then
append "### Tauri desktop coverage dependencies"
append ""
Expand All @@ -1414,8 +1445,15 @@ jobs:
failures=$((failures + 1))
return 1
fi
if [ ! -x /work/.opencode-sandbox-home/.cargo/bin/cargo-llvm-cov ]; then
run_and_capture "Rust coverage tooling (cargo-llvm-cov 0.8.7)" cargo install cargo-llvm-cov --version 0.8.7 --locked
if ! command -v cargo-llvm-cov >/dev/null 2>&1; then
append "### Rust coverage toolchain"
append ""
append "- Result: FAIL"
append "- Reason: the trusted offline coverage image is missing cargo-llvm-cov 0.8.7."
append "- Fix: rebuild the trusted coverage image before rerunning current-head evidence."
append ""
failures=$((failures + 1))
return 1
fi
ensure_rust_gpu_adapter
ensure_rust_desktop_deps
Expand Down
10 changes: 7 additions & 3 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() {
assert_file_contains "$workflow_file" 'R_LIBS_USER="/work/.opencode-r-library"' "opencode R coverage isolates the package library inside the untrusted worktree"
assert_file_not_contains "$workflow_file" 'install.packages(' "opencode R coverage never installs PR-selected mutable packages"
assert_file_contains "$workflow_file" "libcurl4-openssl-dev libssl-dev libxml2-dev" "opencode R coverage installs system headers required by covr dependencies"
assert_file_contains "$workflow_file" "r-cran-covr r-cran-testthat" "opencode R coverage uses signed distribution packages instead of mutable CRAN resolution"
assert_file_contains "$workflow_file" "r-cran-covr" "opencode R coverage uses the signed distribution covr package instead of mutable CRAN resolution"
assert_file_contains "$workflow_file" "r-cran-testthat" "opencode R coverage uses the signed distribution testthat package instead of mutable CRAN resolution"
assert_file_contains "$workflow_file" "R package testthat suite" "opencode R package coverage requires package testthat evidence"
assert_file_contains "$workflow_file" "testthat unavailable in coverage runner; deferring to required peer R CMD check evidence." "opencode R package tests defer only when testthat cannot be installed in the coverage runner"
assert_file_contains "$workflow_file" "covr package_coverage unavailable after package tests; treating missing-line report as advisory." "opencode R package coverage does not block on covr installation reproduction after tests pass"
Expand Down Expand Up @@ -862,7 +863,9 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() {
assert_file_contains "$workflow_file" "Coverage merge tree could not be materialized" "coverage evidence logs an actionable merge-tree failure reason"
assert_file_contains "$workflow_file" "--require-hashes" "coverage tooling installs from a hash-pinned lock"
assert_file_contains "$workflow_file" "--only-binary=:all:" "coverage tooling installs only binary packages from the pinned lock"
assert_file_contains "$workflow_file" "-r /trusted/requirements-opencode-review-ci-hashes.txt" "coverage sandbox installs the trusted hash lock rather than PR-controlled requirements"
assert_file_contains "$workflow_file" 'trusted_ci_requirements="${GITHUB_WORKSPACE}/requirements-opencode-review-ci-hashes.txt"' "coverage tooling sources its hash lock from the trusted default-branch checkout"
assert_file_contains "$workflow_file" '"$coverage_build_dir/requirements-opencode-review-ci-hashes.txt"' "coverage tooling copies the trusted hash lock into the isolated build context"
assert_file_contains "$workflow_file" "-r /tmp/requirements-opencode-review-ci-hashes.txt" "coverage image installs the trusted hash lock rather than PR-controlled requirements"
assert_file_contains "$workflow_file" 'GITHUB_ENV=/dev/null' "PR-controlled coverage commands cannot write runner environment command files"
assert_file_contains "$workflow_file" 'GITHUB_PATH=/dev/null' "PR-controlled coverage commands cannot extend later-step PATH"
assert_file_contains "$workflow_file" 'GITHUB_OUTPUT=/dev/null' "PR-controlled coverage commands cannot forge trusted step outputs"
Expand Down Expand Up @@ -896,7 +899,8 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() {
assert_file_contains "$GATE_SCRIPT" 'STRIX_EXECUTABLE_PATH must be outside the untrusted scan target' "Strix executable cannot come from the scan target"
assert_file_not_contains "$GATE_SCRIPT" 'shutil.which("strix")' "Strix gate never resolves its credential-bearing executable through inherited PATH"
assert_file_not_contains "$workflow_file" "https://sh.rustup.rs" "coverage refuses a mutable Rust network installer"
assert_file_contains "$workflow_file" "cargo install cargo-llvm-cov --version 0.8.7 --locked" "coverage pins cargo-llvm-cov"
assert_file_contains "$workflow_file" "cargo-llvm-cov-x86_64-unknown-linux-musl.tar.gz" "coverage pins the official cargo-llvm-cov 0.8.7 Linux asset"
assert_file_contains "$workflow_file" "967b5cc996c29d8baa52bbb4595ef1f53af35255af8e2036ddbc6468d7b523c7" "coverage verifies the official cargo-llvm-cov 0.8.7 asset digest"
assert_file_contains "$workflow_file" "Run merge scheduler after approval" "opencode approval runs the merge scheduler after current-head review publication"
assert_file_contains "$workflow_file" "python3 scripts/ci/pr_review_merge_scheduler.py" "opencode approval directly executes the trusted central merge scheduler when required workflows are not repo-local dispatch targets"
assert_file_contains "$workflow_file" "--require-opencode-app" "opencode approval reuse and post-publication follow-up reject GitHub Actions-authored review evidence"
Expand Down
21 changes: 20 additions & 1 deletion tests/test_opencode_agent_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,14 @@ def test_opencode_target_coverage_materializes_only_after_authorized_dispatch():
assert "docker.io/library/ubuntu@sha256:" in measure_step
assert "apt-get install --no-install-recommends -y" in measure_step
assert "--require-hashes" in measure_step
assert 'coverage_tool_image="opencode-coverage-tools:${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"' in measure_step
assert "The networked build context contains only this" in measure_step
assert 'install -m 0644 "$trusted_ci_requirements"' in measure_step
assert "docker build --pull --no-cache --network=default" in measure_step
assert '"$coverage_build_dir"' in measure_step
assert measure_step.index("docker build --pull --no-cache") < measure_step.index(
"docker run --rm --init --network=none"
)
assert "--cap-drop ALL" in measure_step
# Docker already creates a private PID namespace by default. Passing the
# unsupported literal `private` makes hosted-runner Docker exit 125 before
Expand Down Expand Up @@ -367,6 +375,12 @@ def test_opencode_target_coverage_materializes_only_after_authorized_dispatch():
)
assert "CARGO_HOME=/work/.opencode-sandbox-home/.cargo" in measure_step
assert "docker run --rm --init --network=none" in measure_step
sandbox_runtime = measure_step.split(
" export OPENCODE_SANDBOX_UID=65532", 1
)[1]
assert "apt-get" not in sandbox_runtime
assert "cargo install" not in sandbox_runtime
assert "command -v cargo-llvm-cov" in sandbox_runtime
assert (
'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"'
in measure_step
Expand Down Expand Up @@ -1647,7 +1661,12 @@ def test_opencode_privileged_review_security_boundaries_are_fail_closed():
assert "yarn install --immutable --mode=skip-builds" in coverage_job
assert 'corepack prepare "${runner}@latest"' not in coverage_job
assert "https://sh.rustup.rs" not in coverage_job
assert "cargo install cargo-llvm-cov --version 0.8.7 --locked" in coverage_job
assert "cargo-llvm-cov-x86_64-unknown-linux-musl.tar.gz" in coverage_job
assert (
"967b5cc996c29d8baa52bbb4595ef1f53af35255af8e2036ddbc6468d7b523c7"
in coverage_job
)
assert "sha256sum -c -" in coverage_job
assert "install.packages(" not in coverage_job

target_condition = target_job.split(" runs-on:", 1)[0]
Expand Down
Loading