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
104 changes: 86 additions & 18 deletions .github/workflows/opencode-review-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1232,10 +1232,25 @@ jobs:
}

javascript_test_script_collects_coverage() {
jq -e '(.scripts.test // "") | test("(^|[[:space:]])--coverage([.=[:space:]]|$)|c8([[:space:]]|$)|nyc([[:space:]]|$)")' \
jq -e '(.scripts.test // "") | test("(^|[[:space:]])--coverage([.=[:space:]]|$)|c8([[:space:]]|$)|nyc([[:space:]]|$)|istanbul([[:space:]]|$)")' \
package.json >/dev/null 2>&1
}

javascript_test_runner_accepts_coverage_flag() {
jq -e '
(.scripts.test // "") as $test
| ((.devDependencies // {}) + (.dependencies // {})) as $dependencies
| ($test | test("(^|[[:space:]])jest([[:space:]]|$)"))
or (
($test | test("(^|[[:space:]])vitest([[:space:]]|$)"))
and (
($dependencies | has("@vitest/coverage-v8"))
or ($dependencies | has("@vitest/coverage-istanbul"))
)
)
' package.json >/dev/null 2>&1
}

declared_package_manager() {
if [ -f package.json ]; then
jq -r '.packageManager // "" | split("@")[0]' package.json 2>/dev/null || true
Expand Down Expand Up @@ -1480,6 +1495,36 @@ jobs:
writable_pnpm_store_dir="$destination"
}

pnpm_supports_trust_lockfile() {
local pnpm_version
local pnpm_major
local pnpm_minor
pnpm_version="$(corepack pnpm --version 2>/dev/null || printf '0')"
pnpm_major="${pnpm_version%%.*}"
case "$pnpm_version" in
*.*)
pnpm_minor="${pnpm_version#*.}"
pnpm_minor="${pnpm_minor%%.*}"
;;
*)
pnpm_minor=0
;;
esac
case "$pnpm_major" in
''|*[!0-9]*) pnpm_major=0 ;;
esac
case "$pnpm_minor" in
''|*[!0-9]*) pnpm_minor=0 ;;
esac
if [ "$pnpm_major" -gt 11 ]; then
return 0
fi
if [ "$pnpm_major" -eq 11 ] && [ "$pnpm_minor" -ge 3 ]; then
return 0
fi
Comment thread
seonghobae marked this conversation as resolved.
return 1
}
Comment thread
seonghobae marked this conversation as resolved.

install_package_dependencies() {
local package_runner="$1"
case "$package_runner" in
Expand Down Expand Up @@ -1514,13 +1559,22 @@ jobs:
pnpm)
trusted_pnpm_lock_matches_base
prepare_writable_pnpm_store
Comment thread
seonghobae marked this conversation as resolved.
run_and_capture "JavaScript/TypeScript dependencies (pnpm offline install, lifecycle hooks disabled)" \
corepack pnpm install \
--offline \
--frozen-lockfile \
--trust-lockfile \
--ignore-scripts \
--store-dir "$writable_pnpm_store_dir"
if pnpm_supports_trust_lockfile; then
run_and_capture "JavaScript/TypeScript dependencies (pnpm offline install, lifecycle hooks disabled)" \
corepack pnpm install \
--offline \
--frozen-lockfile \
--trust-lockfile \
--ignore-scripts \
--store-dir "$writable_pnpm_store_dir"
else
run_and_capture "JavaScript/TypeScript dependencies (pnpm offline install, lifecycle hooks disabled)" \
corepack pnpm install \
--offline \
--frozen-lockfile \
--ignore-scripts \
--store-dir "$writable_pnpm_store_dir"
fi
;;
yarn)
run_and_capture "JavaScript/TypeScript dependencies (yarn install, lifecycle hooks disabled)" yarn install --immutable --mode=skip-builds
Expand Down Expand Up @@ -2023,20 +2077,34 @@ jobs:
run_package_script_and_capture "JavaScript/TypeScript coverage script" "$package_runner" coverage
javascript_coverage_ran=1
elif jq -e '.scripts.test // empty' package.json >/dev/null; then
if javascript_test_script_collects_coverage; then
case "$package_runner" in
npm) run_and_capture "JavaScript/TypeScript test coverage" npm test ;;
pnpm) run_and_capture "JavaScript/TypeScript test coverage" corepack pnpm test ;;
yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test ;;
esac
if javascript_test_script_collects_coverage || javascript_test_runner_accepts_coverage_flag; then
if javascript_test_script_collects_coverage; then
case "$package_runner" in
npm) run_and_capture "JavaScript/TypeScript test coverage" npm test ;;
pnpm) run_and_capture "JavaScript/TypeScript test coverage" corepack pnpm test ;;
yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test ;;
esac
else
case "$package_runner" in
npm) run_and_capture "JavaScript/TypeScript test coverage" npm test -- --coverage ;;
pnpm) run_and_capture "JavaScript/TypeScript test coverage" corepack pnpm run test --coverage ;;
yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test --coverage ;;
esac
fi
javascript_coverage_ran=1
else
case "$package_runner" in
npm) run_and_capture "JavaScript/TypeScript test coverage" npm test -- --coverage ;;
pnpm) run_and_capture "JavaScript/TypeScript test coverage" corepack pnpm run test --coverage ;;
yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test --coverage ;;
npm) run_and_capture "JavaScript/TypeScript tests (coverage provider not declared)" npm test ;;
pnpm) run_and_capture "JavaScript/TypeScript tests (coverage provider not declared)" corepack pnpm test ;;
yarn) run_and_capture "JavaScript/TypeScript tests (coverage provider not declared)" yarn test ;;
esac
append "### JavaScript/TypeScript coverage threshold"
append ""
append "- Result: FAIL"
append "- Reason: package.json defines a test script but no compatible coverage provider or coverage-collecting test script. The networkless sandbox ran the tests without inventing an instrumenter, but plain tests cannot satisfy the required frontend coverage gate. Add a lock-pinned provider and a repository-owned coverage command."
append ""
failures=$((failures + 1))
fi
Comment thread
seonghobae marked this conversation as resolved.
Comment thread
seonghobae marked this conversation as resolved.
javascript_coverage_ran=1
else
append "### JavaScript/TypeScript test coverage"
append ""
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ Semantic Versioning where the repository publishes a release.
during materialization and then rejecting every version except pnpm 11.5.3;
route generic coverage and docstring package scripts through the same
Corepack boundary instead of invoking a removed bare `pnpm` binary.
- Keep `--trust-lockfile` only for pnpm 11.3 and newer
(`trustLockfile` landed in pnpm 11.3). pnpm 9, 10, and 11.0–11.2 reject
that flag and previously failed LineageWeave JavaScript coverage before
tests could run. Jest test scripts still receive `--coverage` because Jest
documents a native coverage flag.
- Run declared JavaScript test scripts without synthesizing `--coverage` when
the package does not declare a compatible coverage command, but keep the
coverage result failed until the repository adds a lock-pinned provider and
owned coverage command. A generic `c8`, `nyc`, or Istanbul dependency no
longer makes an unrelated test runner receive an unsupported flag.
- Fix OpenCode coverage evidence for exact-base, organization-owned Python VCS
dependencies without weakening registry hashes or the networkless PR sandbox,
reject namespace, ambiguous, linked, native-extension, and installed-metadata
Expand Down
88 changes: 88 additions & 0 deletions docs/doctoring/opencode-pnpm-lock-compat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# OpenCode coverage pnpm lock compatibility

검토 기준일: **2026-08-23**

## Decision

OpenCode coverage-evidence honors the repository-owned `packageManager`
pin through Corepack. `--trust-lockfile` is valid only on pnpm 11.3 and
newer (`trustLockfile` landed in pnpm 11.3; Kochan, 2026). pnpm 11.0,
11.1, and 11.2 still reject the flag. Exact trusted-base lock matching
remains mandatory before any offline install. The sandbox never invents a
JavaScript coverage instrumenter when the package did not declare one,
except that a bare `jest` test script still receives Jest's documented
`--coverage` flag and a Vitest script receives it only when a compatible
Vitest coverage provider is lock-pinned.

This keeps LineageWeave and other pnpm 9.x products measurable after
Corepack started activating the repository pin instead of a central
pnpm 11.5.3 binary. A paying reviewer of lineage reconstruction would
otherwise see every frontend head blocked on `Unknown option:
'trust-lockfile'` and, after that, on `vitest --coverage` without
`@vitest/coverage-v8`.

## Root-cause analysis

1. Coverage images now activate the exact `packageManager` from the
validated base (for LineageWeave, `pnpm@9.15.9`).
2. The install command still passed `--trust-lockfile`, a pnpm 11.3 flag.
pnpm 9, pnpm 10, and pnpm 11.0–11.2 exit before reading the store.
3. After a successful install, coverage appended `--coverage` to `vitest run`
even when no coverage provider was declared, so tests never became
evidence.

The lock-matching gate is unchanged: a PR-added or PR-mutated
`pnpm-lock.yaml` is still refused. `--offline`, `--frozen-lockfile`,
`--ignore-scripts`, and the writable clone of `/opt/pnpm-store` remain
required. Python still never runs `uv sync --project`.

## Remediation

- When `corepack pnpm --version` reports 11.3 or newer (major greater
than 11, or major 11 with minor 3 or greater), keep `--trust-lockfile`
so registry attestation lookups stay suppressed for an exact
trusted-base lock (Kochan, 2026; pnpm, n.d.).
- When the version is below 11.3, omit that flag. pnpm 9, 10, and
11.0–11.2 already treat `--frozen-lockfile` plus `--offline` as the
integrity boundary.
- When `package.json` has a test script but no coverage script or compatible
coverage-collecting runner, run the tests without synthesizing an undeclared
instrumenter and fail the coverage result with the next action: add a
lock-pinned provider and repository-owned coverage command. Plain passing
tests are not 100% frontend coverage evidence.
- A bare Jest script receives `--coverage` because Jest documents that native
flag (Jest, n.d.). Vitest receives `--coverage` only with
`@vitest/coverage-v8` or `@vitest/coverage-istanbul`. A generic `c8`, `nyc`,
or Istanbul dependency is not proof that an arbitrary runner accepts the
flag; those collectors count only when the test script actually invokes
them.

Independent OpenCode, Strix, and Noema review remain authorization
gates. This change does not approve, merge, or weaken hash-pinned
Python or npm installs.

## APA 7th references

GitHub, Inc. (n.d.). *Using a package.json file to specify the package
manager*. GitHub Docs. Retrieved August 23, 2026, from
https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry

MITRE. (2026). *CWE-494: Download of code without integrity check*.
https://cwe.mitre.org/data/definitions/494.html

National Institute of Standards and Technology. (2022). *Secure software
development framework (SSDF) version 1.1: Recommendations for mitigating
the risk of software vulnerabilities* (NIST Special Publication 800-218).
https://doi.org/10.6028/NIST.SP.800-218

Jest. (n.d.). *Jest CLI options: --coverage*. Jest Docs. Retrieved
August 23, 2026, from https://jestjs.io/docs/cli#--coverageboolean

Kochan, Z. (2026, May 24). *pnpm 11.3*. pnpm Blog.
https://pnpm.io/blog/releases/11.3

pnpm. (n.d.). *pnpm install*. pnpm Docs. Retrieved August 23, 2026, from
https://pnpm.io/cli/install

Vitest. (n.d.). *Coverage*. Vitest Docs. Retrieved August 23, 2026, from
https://vitest.dev/guide/coverage
5 changes: 5 additions & 0 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,11 @@ assert_file_contains "$REPO_ROOT/scripts/ci/run_opencode_review_model_pool.sh" '
assert_file_contains "$workflow_file" '"$COVERAGE_SOURCE_WORKDIR/$relative_lock"' "coverage hashes nested pnpm locks from the validated worktree root"
assert_file_not_contains "$workflow_file" 'hash-object --no-filters -- "$relative_lock"' "coverage does not double-prefix nested package lock paths from the package working directory"
assert_file_contains "$workflow_file" "--trust-lockfile" "coverage suppresses registry attestation lookups only for an exact trusted-base lock"
assert_file_contains "$workflow_file" "pnpm_supports_trust_lockfile()" "coverage gates --trust-lockfile on a helper that parses major and minor"
assert_file_contains "$workflow_file" '[ "$pnpm_major" -eq 11 ] && [ "$pnpm_minor" -ge 3 ]' "coverage omits --trust-lockfile on pnpm versions before 11.3"
assert_file_contains "$workflow_file" "javascript_test_runner_accepts_coverage_flag()" "coverage adds a native flag only for a compatible Jest or provider-backed Vitest runner"
assert_file_not_contains "$workflow_file" "javascript_coverage_provider_declared()" "coverage does not infer runner compatibility from an unused generic provider dependency"
assert_file_contains "$workflow_file" "plain tests cannot satisfy the required frontend coverage gate" "coverage fails closed when a package has no compatible coverage command"
assert_file_contains "$workflow_file" "prepare_writable_pnpm_store()" "coverage prepares a sandbox-writable clone of the trusted pnpm store"
assert_file_contains "$workflow_file" 'destination="$(mktemp -d /tmp/opencode-pnpm-store.XXXXXX)"' "coverage creates the writable pnpm store at an unpredictable root-owned path"
assert_file_contains "$workflow_file" 'cp -R /opt/pnpm-store/. "$destination/"' "coverage clones packages from the trusted image seed"
Expand Down
Loading
Loading