From 2620e91a35962e49ee8d052720b2533c4f32e30b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 22:39:07 +0900 Subject: [PATCH 1/4] fix(coverage): install npm workspaces from root lock --- .../workflows/opencode-review-dispatch.yml | 38 ++++++++++++++- CHANGELOG.md | 3 ++ tests/test_opencode_agent_contract.py | 48 +++++++++++++++++++ ...t_pr_review_autofix_nvidia_nim_contract.py | 2 +- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/.github/workflows/opencode-review-dispatch.yml b/.github/workflows/opencode-review-dispatch.yml index 553111b542..bc2ed91451 100644 --- a/.github/workflows/opencode-review-dispatch.yml +++ b/.github/workflows/opencode-review-dispatch.yml @@ -1404,6 +1404,38 @@ jobs: writable_npm_cache_dir="" writable_pnpm_store_dir="" + npm_lock_project_dir() { + local candidate_dir="$PWD" + + case "$candidate_dir" in + "$COVERAGE_SOURCE_WORKDIR"|"$COVERAGE_SOURCE_WORKDIR"/*) ;; + *) + echo "::error::npm package directory escaped the validated coverage worktree." + return 1 + ;; + esac + + while true; do + if [ -f "$candidate_dir/npm-shrinkwrap.json" ] \ + && [ ! -L "$candidate_dir/npm-shrinkwrap.json" ]; then + printf '%s\n' "$candidate_dir" + return 0 + fi + if [ -f "$candidate_dir/package-lock.json" ] \ + && [ ! -L "$candidate_dir/package-lock.json" ]; then + printf '%s\n' "$candidate_dir" + return 0 + fi + if [ "$candidate_dir" = "$COVERAGE_SOURCE_WORKDIR" ]; then + break + fi + candidate_dir="$(dirname "$candidate_dir")" + done + + echo "::error::No regular non-symlink npm lock was found at the package or validated workspace root." + return 1 + } + trusted_npm_lock_is_materialized() { local relative_dir local lock_name @@ -1613,9 +1645,11 @@ jobs: install_package_dependencies() { local package_runner="$1" + local npm_project_dir case "$package_runner" in npm) - if [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then + if npm_project_dir="$(npm_lock_project_dir)"; then + pushd "$npm_project_dir" >/dev/null if ! trusted_npm_lock_is_materialized || ! prepare_writable_npm_cache; then append "### JavaScript/TypeScript dependencies (npm)" append "" @@ -1623,6 +1657,7 @@ jobs: append "- Reason: the current npm lock is not hash-bounded to the validated base or HEAD, or the trusted npm cache is unavailable." append "" failures=$((failures + 1)) + popd >/dev/null return 0 fi run_and_capture "JavaScript/TypeScript dependencies (npm offline ci, lifecycle hooks disabled)" \ @@ -1632,6 +1667,7 @@ jobs: --cache "$writable_npm_cache_dir" \ --no-audit \ --no-fund + popd >/dev/null else append "### JavaScript/TypeScript dependencies (npm)" append "" diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eab104fc2..cab8e790cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ this file. The format follows Keep a Changelog, and versioned releases follow Semantic Versioning where the repository publishes a release. ## [Unreleased] +- Run npm workspace coverage installs from the nearest validated ancestor lock + while keeping tests scoped to the changed package; regular non-symlink lock + files remain hash-bounded by the existing materialization manifest. - Skip trusted base Python lock materialization for exact-head reviews with no Python source or dependency-manifest changes, while preserving the fail-closed wheel-only path when Python coverage is relevant. diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index 79fdba39aa..d979bfbc0a 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -627,6 +627,9 @@ def test_opencode_target_coverage_materializes_only_after_authorized_dispatch(): assert "corepack pnpm fetch" in measure_step assert "--store-dir /opt/pnpm-store" in measure_step assert "chmod -R a+rX /opt/corepack /opt/npm-cache /opt/pnpm-store" in measure_step + assert "npm_lock_project_dir() {" in measure_step + assert 'pushd "$npm_project_dir" >/dev/null' in measure_step + assert "No regular non-symlink npm lock was found at the package or validated workspace root." in measure_step assert "trusted_npm_lock_is_materialized()" in measure_step assert ( 'head_blob="$(trusted_git rev-parse "${PR_HEAD_SHA}:${relative_lock}"' @@ -1540,6 +1543,51 @@ def test_opencode_coverage_discovers_changed_nested_javascript_package(tmp_path) assert result.stdout.splitlines() == ["ADFS 연동 라이브러리/Node.JS/Node App"] +def test_opencode_coverage_resolves_ancestor_npm_lock_for_workspace_package(tmp_path): + """Workspace coverage installs from the root lock while testing the nested package.""" + bash = shutil.which("bash") + if bash is None: + pytest.skip("bash is required for the extracted workflow function regression test") + + workflow = Path(".github/workflows/opencode-review-dispatch.yml").read_text( + encoding="utf-8" + ) + measure_start = workflow.index( + " - name: Measure test and docstring evidence\n" + ) + measure_end = workflow.index("\n - name:", measure_start + 1) + measure_step = workflow[measure_start:measure_end] + helper_start = measure_step.index(" npm_lock_project_dir() {\n") + helper_end = measure_step.index( + "\n\n trusted_npm_lock_is_materialized()", helper_start + ) + shell = "\n".join( + ( + "set -euo pipefail", + textwrap.dedent(measure_step[helper_start:helper_end]), + "npm_lock_project_dir", + ) + ) + + repo = tmp_path / "repo" + package = repo / "apps" / "desktop" + package.mkdir(parents=True) + (repo / "package-lock.json").write_text("{}\n", encoding="utf-8") + env = os.environ.copy() + env["COVERAGE_SOURCE_WORKDIR"] = str(repo) + result = subprocess.run( + [bash, "-c", shell], + cwd=package, + env=env, + capture_output=True, + text=True, + timeout=10, + ) + + assert result.returncode == 0, result.stderr + assert result.stdout.splitlines() == [str(repo)] + + def test_opencode_runtime_pin_supports_reasoning_options(): """Keep OpenCode runtime new enough to apply model-level reasoning settings.""" review_workflow = Path(".github/workflows/opencode-review-dispatch.yml").read_text( diff --git a/tests/test_pr_review_autofix_nvidia_nim_contract.py b/tests/test_pr_review_autofix_nvidia_nim_contract.py index 986dd24ff3..22986b9796 100644 --- a/tests/test_pr_review_autofix_nvidia_nim_contract.py +++ b/tests/test_pr_review_autofix_nvidia_nim_contract.py @@ -19,7 +19,7 @@ DOCTORING_RECORD = Path("docs/doctoring/hourly-nvidia-nim-autofix.md") CHANGELOG = Path("CHANGELOG.md") REVIEW_DISPATCH_WORKFLOW = Path(".github/workflows/opencode-review-dispatch.yml") -REVIEW_DISPATCH_BLOB_SHA = "553111b54287c56a78833f8463b2a75e646ae208" +REVIEW_DISPATCH_BLOB_SHA = "bc2ed91451fbb322632bcbe6dbaa1e7c5adacb62" def _workflow_text(path: Path) -> str: From 091453f80f901d5d6fb67fa07d3e1a0947bfac0c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 22:43:20 +0900 Subject: [PATCH 2/4] test(coverage): guard npm workspace boundary errors --- .github/workflows/opencode-review-dispatch.yml | 4 ++-- tests/test_opencode_agent_contract.py | 13 +++++++++++++ tests/test_pr_review_autofix_nvidia_nim_contract.py | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/opencode-review-dispatch.yml b/.github/workflows/opencode-review-dispatch.yml index bc2ed91451..3eae3b0e65 100644 --- a/.github/workflows/opencode-review-dispatch.yml +++ b/.github/workflows/opencode-review-dispatch.yml @@ -1410,7 +1410,7 @@ jobs: case "$candidate_dir" in "$COVERAGE_SOURCE_WORKDIR"|"$COVERAGE_SOURCE_WORKDIR"/*) ;; *) - echo "::error::npm package directory escaped the validated coverage worktree." + echo "::error::npm package directory escaped the validated coverage worktree." >&2 return 1 ;; esac @@ -1432,7 +1432,7 @@ jobs: candidate_dir="$(dirname "$candidate_dir")" done - echo "::error::No regular non-symlink npm lock was found at the package or validated workspace root." + echo "::error::No regular non-symlink npm lock was found at the package or validated workspace root." >&2 return 1 } diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index d979bfbc0a..b8d2de7f55 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -1587,6 +1587,19 @@ def test_opencode_coverage_resolves_ancestor_npm_lock_for_workspace_package(tmp_ assert result.returncode == 0, result.stderr assert result.stdout.splitlines() == [str(repo)] + outside = tmp_path / "outside" + outside.mkdir() + escaped = subprocess.run( + [bash, "-c", shell], + cwd=outside, + env=env, + capture_output=True, + text=True, + timeout=10, + ) + assert escaped.returncode != 0 + assert "escaped the validated coverage worktree" in escaped.stderr + def test_opencode_runtime_pin_supports_reasoning_options(): """Keep OpenCode runtime new enough to apply model-level reasoning settings.""" diff --git a/tests/test_pr_review_autofix_nvidia_nim_contract.py b/tests/test_pr_review_autofix_nvidia_nim_contract.py index 22986b9796..5ad33c5136 100644 --- a/tests/test_pr_review_autofix_nvidia_nim_contract.py +++ b/tests/test_pr_review_autofix_nvidia_nim_contract.py @@ -19,7 +19,7 @@ DOCTORING_RECORD = Path("docs/doctoring/hourly-nvidia-nim-autofix.md") CHANGELOG = Path("CHANGELOG.md") REVIEW_DISPATCH_WORKFLOW = Path(".github/workflows/opencode-review-dispatch.yml") -REVIEW_DISPATCH_BLOB_SHA = "bc2ed91451fbb322632bcbe6dbaa1e7c5adacb62" +REVIEW_DISPATCH_BLOB_SHA = "3eae3b0e65c4fde57b4c6e8223663728ae0af960" def _workflow_text(path: Path) -> str: From bc965eae494a4574a893e052eb86ab7c5b341e45 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 31 Aug 2026 23:45:04 +0900 Subject: [PATCH 3/4] fix(ci): match only job-level bootstrap conditions --- scripts/ci/test_strix_quick_gate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index 76bb69a5b1..271fd0c23b 100644 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -100,7 +100,7 @@ required_workflow_bootstrap_has_if() { local bootstrap_file="$1" awk '/^ required-workflow-bootstrap:$/{p=1; print; next} p && /^ [A-Za-z0-9_-]+:/{exit} p' "$bootstrap_file" | - grep '^[[:space:]]*if:' >/dev/null + grep '^ if:' >/dev/null } seal_opencode_test_artifacts() { From e09206b15f245c1053bbfbed6135be1edf1e7475 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 00:04:49 +0900 Subject: [PATCH 4/4] fix(noema): isolate cancelled review triggers --- .github/workflows/noema-review.yml | 4 ++++ tests/test_required_workflow_queue_contract.py | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/noema-review.yml b/.github/workflows/noema-review.yml index 064c4e5aee..c0016afe4e 100644 --- a/.github/workflows/noema-review.yml +++ b/.github/workflows/noema-review.yml @@ -22,6 +22,10 @@ concurrency: noema-review-${{ github.event.pull_request.base.repo.full_name || github.event.client_payload.target_repository || github.repository }}-${{ + github.event_name == 'workflow_run' + && github.event.workflow_run.conclusion == 'cancelled' + && github.run_id + || github.event.pull_request.number || github.event.workflow_run.pull_requests[0].number || github.event.client_payload.pr_number || github.run_id }} diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index b3eac37fac..dbbdd79625 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -489,11 +489,14 @@ def test_required_workflow_trusted_source_refs_are_not_input_controlled() -> Non assert "GITHUB_CONTEXT_JSON: ${{ toJSON(github) }}" in workflow -def test_noema_triggers_serialize_one_review_per_pull_request() -> None: - """Serialize every Noema trigger type for one pull request.""" +def test_noema_triggers_serialize_actionable_reviews_per_pull_request() -> None: + """Serialize actionable Noema triggers without letting cancelled runs evict them.""" workflow = workflow_text("noema-review.yml") concurrency_contract = workflow.split("permissions:", 1)[0] + assert "github.event_name == 'workflow_run'" in concurrency_contract + assert "github.event.workflow_run.conclusion == 'cancelled'" in concurrency_contract + assert "&& github.run_id" in concurrency_contract assert "github.event.pull_request.number || github.event.workflow_run.pull_requests[0].number" in concurrency_contract assert "github.event.client_payload.pr_number" in concurrency_contract assert "github.event_name }}" not in concurrency_contract