Skip to content

fix(coverage): resolve npm workspace lock owners - #703

Open
seonghobae wants to merge 45 commits into
mainfrom
fix/npm-workspace-coverage-root
Open

fix(coverage): resolve npm workspace lock owners#703
seonghobae wants to merge 45 commits into
mainfrom
fix/npm-workspace-coverage-root

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

What

Add a fail-closed resolver for nested npm workspace packages and wire it into the central OpenCode coverage sandbox. A selected package such as apps/desktop can now install from its nearest validated npm workspace lock owner instead of requiring an invalid duplicate lockfile beside every workspace package.

Why

BandScope correctly owns one root npm workspace lock. The previous central coverage path selected apps/desktop, attempted isolated installation there, failed to materialize Vitest, and consequently blocked every current-head approval. The final implementation resolves and validates the ancestor lock owner before running a lifecycle-disabled, networkless workspace-scoped npm ci.

Security boundary

  • Resolve ownership from the exact validated HEAD tree and matching worktree.
  • Require an npm v2/v3 lock with an exact packages entry.
  • Match anchored workspace patterns while rejecting path traversal, unsafe glob syntax, control characters, and symlinks.
  • Hash worktree files with Git path-aware normalization.
  • Require an exact validated base-or-HEAD materialization receipt.
  • Keep npm installation offline, lifecycle-disabled, audit-disabled, and bounded to the selected workspace.
  • Pass the npm command as structured argv rather than interpolated shell code.
  • Keep the recursive workspace matcher in one bounded module-level cache.
  • Leave no PR-specific bootstrap workflow or self-modifying helper in the final tree.

Verification

The exact final state was reconstructed, reviewed, and tested before being committed directly:

  • 75 focused resolver and hardening tests passed.
  • Resolver statement coverage: 206/206, 100%.
  • Resolver docstring coverage: 100%.
  • Python compile and Ruff checks passed for the resolver and shared fixture helpers.
  • A real temporary npm workspace fixture resolved apps/desktop to the repository root (.).
  • Tests use shared deterministic Git/JSON fixture helpers and portable shutil.rmtree cleanup.
  • git diff --check passed.
  • The final PR contains only canonical workflows, dependency locks, resolver code, and permanent contract tests.
  • The Strix CI lock is refreshed to aiohttp==3.14.3 and cryptography==50.0.0 to remove current high-severity audit blockers.

Product impact

This removes the organization-level coverage deadlock for BandScope and other modular npm workspace repositories while preserving standalone package selection and centralized governance.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ae0d4eb-4a4c-48c4-b2b2-661b1d8f8766

📥 Commits

Reviewing files that changed from the base of the PR and between ecc6134 and 6b43ac5.

📒 Files selected for processing (8)
  • .github/workflows/opencode-review-dispatch.yml
  • requirements-strix-ci-hashes.txt
  • requirements-strix-ci.txt
  • scripts/ci/npm_workspace_install_root.py
  • tests/npm_workspace_test_support.py
  • tests/test_npm_workspace_install_root.py
  • tests/test_npm_workspace_install_root_hardening.py
  • tests/test_opencode_agent_contract.py
📝 Walkthrough

Walkthrough

npm workspace 설치 루트 해석기와 hardening 테스트를 추가했습니다. 부트스트랩 스크립트는 검증된 workspace 루트에서 오프라인 설치를 수행합니다. 관련 계약 테스트와 일회성 GitHub Actions 워크플로도 추가했습니다.

Changes

npm workspace 설치 루트 검증

Layer / File(s) Summary
설치 루트 해석 및 보안 검증
scripts/ci/npm_workspace_install_root.py
Git revision, manifest, lockfile, workspace 패턴, 경로 및 심볼릭 링크를 검증한 뒤 가장 가까운 유효 설치 루트를 반환합니다. CLI는 안전한 상대 경로만 출력합니다.
해석기 계약 및 hardening 검증
tests/test_npm_workspace_install_root.py, tests/test_npm_workspace_install_root_hardening.py, .github/workflows/pr703-focused-tests.yml
정상 workspace와 lockfile 선택을 검증합니다. 잘못된 JSON, revision, 경로, glob, lockfile, worktree 상태를 거부합니다. 테스트 워크플로는 100% 라인 및 docstring 커버리지를 검사합니다.

부트스트랩 설치 연결

Layer / File(s) Summary
부트스트랩 설치 흐름 연결
scripts/ci/bootstrap_patch_workflow.py
중앙 워크플로에 resolver 호출, SHA 및 lockfile 신뢰 검사를 추가합니다. 검증된 workspace 루트에서 npm ci --offline --ignore-scripts를 실행합니다.
일회성 부트스트랩 실행 및 결과 반영
.github/workflows/bootstrap-npm-workspace-wiring.yml
조건부로 패치를 실행하고 Python, 임시 workspace, diff, 삭제 상태를 검증합니다. 성공 시 변경 사항을 push하고 실패 시 제한된 진단을 커밋한 뒤 작업을 실패 처리합니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant bootstrap_patch_workflow
  participant npm_workspace_install_root
  participant Git
  participant npm
  GitHubActions->>bootstrap_patch_workflow: 패치 스크립트 실행
  bootstrap_patch_workflow->>npm_workspace_install_root: 패키지 및 base/head SHA 전달
  npm_workspace_install_root->>Git: manifest, lockfile, revision 검증
  npm_workspace_install_root-->>bootstrap_patch_workflow: workspace 설치 루트 반환
  bootstrap_patch_workflow->>npm: 검증된 루트에서 오프라인 npm ci 실행
  GitHubActions->>GitHubActions: 결과 및 diff 검증
  GitHubActions->>Git: 성공 변경 또는 실패 진단 push
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 중첩 npm workspace 패키지의 lock owner 해석이라는 주요 변경 사항을 명확하게 요약합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/npm-workspace-coverage-root

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

@jules Please finish this focused central coverage fix on the current branch.

Wire scripts/ci/npm_workspace_install_root.py into .github/workflows/opencode-review-dispatch.yml without weakening any trust boundary:

  1. In install_package_dependencies() for npm, resolve the selected package's install root with the trusted helper using --repo-root "$COVERAGE_SOURCE_WORKDIR" --package-dir "$PWD".
  2. Make trusted_npm_lock_is_materialized() accept that resolved absolute install root, derive the repository-relative lock path from it, and preserve the current HEAD blob/hash-bounded manifest checks.
  3. Run lifecycle-disabled offline npm ci from the resolved lock owner, while continuing to run the package's test/coverage script from the originally selected nested package directory.
  4. Fail closed when no validated local/ancestor workspace lock owns the package. Do not add a package-local duplicate lock, use network fallback, run lifecycle hooks, or relax path/symlink/hash checks.
  5. Add the new resolver and its test file to the central fallback changed-file allowlist.
  6. Update tests/test_opencode_agent_contract.py and any shell/security contract tests for the workspace-root invocation.

The intended verified command shape is equivalent to:

npm_install_root_relative="$(python3 -I "$GITHUB_WORKSPACE/scripts/ci/npm_workspace_install_root.py" --repo-root "$COVERAGE_SOURCE_WORKDIR" --package-dir "$PWD")"
# map `.` or a safe relative result beneath COVERAGE_SOURCE_WORKDIR
trusted_npm_lock_is_materialized "$npm_install_root"
run_and_capture "JavaScript/TypeScript dependencies (npm workspace-root offline ci, lifecycle hooks disabled)" \
  bash -c 'cd "$1" && npm ci --offline --ignore-scripts --cache "$2" --no-audit --no-fund' \
  bash "$npm_install_root" "$writable_npm_cache_dir"

Verify the resolver at 100% line coverage and docstring coverage, the full relevant pytest contract set, Bash syntax of extracted workflow run blocks, and git diff --check, then push the focused changes.

Copy link
Copy Markdown
Contributor Author

@jules While completing the workflow wiring, also close these resolver trust/correctness gaps on the same branch:

  • Do not use Python fnmatch directly for npm workspace patterns because * can match / and over-authorize deeper packages. Implement repository-path segment semantics: * matches one segment, ** may match multiple segments, and reject unsupported/ambiguous patterns fail-closed. Add positive and negative nested-path tests.
  • Reject symlinks in every existing path component from repo_root through package_dir and through the selected lock-owner manifest/lock, not only a symlink at the final package directory. Add an ancestor-symlink escape test.
  • Fix the test fixture helper so an explicit empty workspace list/object is preserved instead of being replaced by defaults (workspaces if workspaces is not None else ...). Add an empty-declaration rejection case.
  • Validate lockfile shape/version conservatively and ensure the exact workspace package entry is a JSON object. If both npm-shrinkwrap.json and package-lock.json exist, apply npm's deterministic precedence and test it.
  • Keep all paths repository-relative/canonical, reject newline/control characters in CLI output, and verify the workflow maps ./relative output beneath the validated coverage tree before use.

Keep the PR focused on the resolver, workflow integration, contracts/tests, and one accurate 2026 journal entry.

Copy link
Copy Markdown
Contributor Author

@jules Complete this PR now rather than leaving the resolver unwired.

Required implementation:

  1. In .github/workflows/opencode-review-dispatch.yml, resolve each selected npm package directory through scripts/ci/npm_workspace_install_root.py before dependency installation.
  2. Validate the resolved lock-owner path against the trusted worktree, current PR_HEAD_SHA, and /opt/javascript-package-locks/manifest.json; do not weaken the existing registry/integrity or non-symlink checks.
  3. Run npm ci --offline --ignore-scripts from the validated lock owner. For a nested workspace, target only the selected package with --workspace <repo-relative-package-dir>; retain standalone-package behavior.
  4. Use the same resolver for Tauri frontend dependency installation/build so apps/desktop/src-tauri can build from the root workspace lock.
  5. Add contract tests covering BandScope's root workspaces: ["apps/*", "packages/*"] + apps/desktop layout, a standalone npm package, workspace mismatch, missing lock packages entry, symlink/path escape, and unchanged local-lock behavior.
  6. Rebase/merge current main (5983b41ace75040c1d81818171ca7d0f3653254e) first so the recently merged uv-lock coverage support remains intact.
  7. Run the focused resolver tests, workflow/contract tests, 100% line coverage for the changed Python modules, 100% docstrings, and git diff --check.

Keep the patch fail-closed and limited to the central coverage path. Push the completed implementation to this PR branch.

@seonghobae
seonghobae enabled auto-merge (squash) August 3, 2026 02:33

Copy link
Copy Markdown
Contributor Author

One fail-closed bug remains in the current resolver head 8d1da716c2e4bac968df16a525bc3ecd002d1d6e: PurePosixPath.match() is suffix-oriented rather than repository-root anchored. For example, PurePosixPath("foo/apps/desktop").match("apps/*") is true, so an ancestor declaring only apps/* could incorrectly claim foo/apps/desktop if the lock map contains that exact path.

Replace _is_declared_workspace with an anchored, path-segment-aware matcher: ordinary *, ?, and character classes must stay within one segment; ** may consume zero or more complete segments; the entire package path must be consumed from the first segment. Add regression tests proving apps/* accepts apps/desktop but rejects both foo/apps/desktop and apps/team/desktop, while apps/**/desktop accepts the intended nested form. Keep negated and traversal patterns rejected. Please include this in the same workflow-wiring commit and retain 100% resolver coverage.

Copy link
Copy Markdown
Contributor Author

A second compatibility/security-contract issue is visible in the current resolver: _validated_lock() requires the npm lock blob to be identical at base and HEAD, and ancestor manifests are also required to be identical. That regresses the existing bounded-HEAD npm contract in materialize_base_javascript_packages.py, which intentionally validates changed HEAD locks (registry.npmjs.org-only, SHA-512 integrity, safe links), materializes them, and records revision_sha=head_sha plus the exact lock_blob in /opt/javascript-package-locks/manifest.json.

The workspace resolver should establish ownership from the live-validated HEAD tree/worktree and return the lock-owner path; the workflow's existing trusted_npm_lock_is_materialized(resolved_root) must remain the authority that accepts only an exact manifest entry from either validated base or validated HEAD. Do not reject legitimate dependency-update PRs merely because package-lock.json or the workspace declaration changed. Add tests for: unchanged base lock, bounded changed HEAD lock, PR-added workspace package already represented by the HEAD lock map, and rejection when the resolved lock lacks the exact base/HEAD manifest receipt. Preserve the no-network/ignore-scripts boundary.

Copy link
Copy Markdown
Contributor Author

@jules Complete this PR into its final reviewable state. Run scripts/ci/bootstrap_patch_workflow.py against the current branch, verify the intended opencode-review-dispatch.yml and contract-test wiring, remove the temporary bootstrap workflow/script and any PR-number-specific focused workflow that should not land on main, run the focused resolver/coverage/docstring tests plus relevant central workflow contracts, and push the minimal final commit. Do not leave a self-modifying bootstrap path in the merge diff.

Copy link
Copy Markdown
Contributor Author

@jules The branch now has the resolver and focused tests, but the actual central workflow wiring is still absent from the PR diff. Please apply the existing scripts/ci/bootstrap_patch_workflow.py transformation directly on this branch, update .github/workflows/opencode-review-dispatch.yml and tests/test_opencode_agent_contract.py, remove the temporary bootstrap workflow/script and focused branch-only workflow, run the full relevant contract suite with 100% resolver coverage/docstrings plus workflow shell syntax and git diff --check, then push the final focused diff.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (7)
tests/test_npm_workspace_install_root_hardening.py (2)

15-67: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

테스트 헬퍼가 중복됩니다.

_git, _write_json, _committests/test_npm_workspace_install_root.py의 동일한 헬퍼와 중복됩니다. 두 픽스처 구현이 시간이 지나며 달라질 수 있습니다. 헬퍼를 tests/conftest.py의 공유 픽스처나 작은 헬퍼 모듈로 이동하십시오.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_npm_workspace_install_root_hardening.py` around lines 15 - 67,
Remove the duplicated _git, _write_json, and _commit helpers from this test
module and reuse shared implementations from tests/conftest.py or a small helper
module, updating _workspace_repo and its callers to use them while preserving
existing fixture behavior.

193-193: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

rm -rf 서브프로세스 대신 shutil.rmtree를 사용하십시오.

이 호출은 외부 rm 실행 파일에 의존합니다. Windows 개발 환경에서는 실패합니다. 또한 Ruff가 S603과 S607로 표시합니다. 표준 라이브러리 shutil.rmtree가 동일한 작업을 이식 가능하게 수행합니다.

♻️ 제안 리팩터링
 import json
+import shutil
 import subprocess
-    subprocess.run(["rm", "-rf", str(repo / "apps")], check=True)
+    shutil.rmtree(repo / "apps")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_npm_workspace_install_root_hardening.py` at line 193, Replace the
subprocess-based recursive deletion in the test with the standard-library
shutil.rmtree call, updating imports as needed. Preserve deletion of the repo /
"apps" directory and its current test behavior without invoking an external rm
executable.

Source: Linters/SAST tools

scripts/ci/npm_workspace_install_root.py (2)

195-218: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

루프 내부에서 lru_cache 데코레이터를 정의하지 마십시오.

matches는 루프 반복마다 새로 정의됩니다. 이 함수는 자유 변수 pattern_parts를 캡처합니다. Ruff는 이를 B023으로 표시합니다. 현재는 함수가 정의된 반복 안에서만 호출되므로 동작은 정확합니다. 그러나 이 구조는 향후 리팩터링에서 늦은 바인딩 버그를 유발할 수 있습니다. 또한 반복마다 새 캐시 객체를 생성합니다.

매처를 모듈 수준 헬퍼로 추출하고 인자를 튜플로 전달하십시오. 그러면 캐시를 패턴 간에 재사용할 수 있고 B023 경고도 사라집니다.

♻️ 제안 리팩터링
+@lru_cache(maxsize=4096)
+def _segments_match(
+    path_parts: tuple[str, ...],
+    pattern_parts: tuple[str, ...],
+) -> bool:
+    """Match anchored single-segment globs and recursive ``**`` tokens."""
+    if not pattern_parts:
+        return not path_parts
+    token = pattern_parts[0]
+    if token == "**":
+        return _segments_match(path_parts, pattern_parts[1:]) or (
+            bool(path_parts) and _segments_match(path_parts[1:], pattern_parts)
+        )
+    if not path_parts:
+        return False
+    return fnmatch.fnmatchcase(path_parts[0], token) and _segments_match(
+        path_parts[1:],
+        pattern_parts[1:],
+    )
+
+
 def _is_declared_workspace(relative_package: PurePosixPath, patterns: list[str]) -> bool:
     """Return whether a path fully matches one anchored workspace pattern."""
     path_parts = relative_package.parts
-
-    for pattern in patterns:
-        pattern_parts = tuple(pattern.split("/"))
-
-        `@lru_cache`(maxsize=None)
-        def matches(path_index: int, pattern_index: int) -> bool:
-            ...
-
-        if matches(0, 0):
-            return True
-    return False
+    return any(
+        _segments_match(path_parts, tuple(pattern.split("/"))) for pattern in patterns
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/npm_workspace_install_root.py` around lines 195 - 218, Move the
nested matches function out of the patterns loop into a module-level cached
helper, passing path_parts and pattern_parts as explicit tuple arguments. Update
the loop to call this helper for each pattern, preserving the existing anchored
glob and recursive ** matching behavior while allowing the cache to be reused
across patterns and eliminating the B023 warning.

Source: Linters/SAST tools


334-337: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

중복 조건을 단순화하십시오.

PurePosixPath("")PurePosixPath(".")로 정규화됩니다. 따라서 parent != PurePosixPath("") 조건의 두 분기가 동일한 값 PurePosixPath(".")를 만듭니다. 이 조건은 동작에 영향을 주지 않습니다. 조건을 제거하면 상위 경로 탐색 의도가 명확해집니다.

♻️ 제안 리팩터링
         if candidate == PurePosixPath("."):
             break
-        parent = candidate.parent
-        candidate = parent if parent != PurePosixPath("") else PurePosixPath(".")
+        candidate = candidate.parent
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/npm_workspace_install_root.py` around lines 334 - 337, Update the
parent-path assignment in the candidate traversal loop to remove the redundant
PurePosixPath("") conditional. After the existing candidate ==
PurePosixPath(".") termination check, assign candidate directly to
candidate.parent while preserving the current traversal behavior.
tests/test_npm_workspace_install_root.py (1)

480-487: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

module.PurePosixPath 대신 직접 임포트를 사용하십시오.

이 테스트는 프로덕션 모듈의 임포트 재노출에 의존합니다. npm_workspace_install_root.pyPurePosixPath 임포트를 제거하거나 이름을 바꾸면, 실제 동작 변경이 없어도 테스트가 실패합니다. 이 파일은 이미 pathlib에서 Path를 임포트합니다. PurePosixPath도 같은 방식으로 임포트하십시오.

♻️ 제안 리팩터링
-from pathlib import Path
+from pathlib import Path, PurePosixPath
         module._tree_blob(
             tmp_path,
             "a" * 40,
-            module.PurePosixPath("package.json"),
+            PurePosixPath("package.json"),
             "fixture manifest",
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_npm_workspace_install_root.py` around lines 480 - 487, Update the
test invoking _tree_blob to use a directly imported PurePosixPath from pathlib
instead of module.PurePosixPath. Add PurePosixPath alongside the existing Path
import and pass it directly, removing the dependency on the production module’s
re-export.
.github/workflows/pr703-focused-tests.yml (1)

42-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Python 버전을 명시적으로 설정하십시오.

이 파일은 bootstrap_patch_workflow.py가 성공하면 삭제하는 일회성 워크플로이므로 별도 중앙 워크플로로 이관할 대상이 아닙니다. 그러나 현재 ubuntu-latest의 기본 python3에 의존합니다. actions/setup-python을 추가하고 python-version: "3.12"를 설정하십시오. bootstrap-npm-workspace-wiring.yml에도 동일한 설정을 적용하십시오.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pr703-focused-tests.yml around lines 42 - 62, Explicitly
configure Python 3.12 in the workflow by adding actions/setup-python with
python-version set to "3.12" before the Python-based steps, and apply the same
setup to bootstrap-npm-workspace-wiring.yml. Keep the existing test and coverage
commands unchanged.
.github/workflows/bootstrap-npm-workspace-wiring.yml (1)

64-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

실패 로그를 저장소에 커밋하지 말고 job summary로 보내세요.

현재 실패 로그는 .github/bootstrap-npm-workspace-failure.log 로 기록되고, 이후 단계가 이를 브랜치에 push합니다. 이 파일은 저장소에 잔여 아티팩트로 남습니다. $GITHUB_STEP_SUMMARY 또는 업로드 아티팩트를 사용하세요.

♻️ 제안 변경
           if [ "$patch_rc" -ne 0 ]; then
             {
               echo "bootstrap_patch_workflow.py failed with exit code $patch_rc"
               echo
               sed -n '1,200p' "$RUNNER_TEMP/bootstrap-patch.log"
-            } > .github/bootstrap-npm-workspace-failure.log
+            } >>"$GITHUB_STEP_SUMMARY"
           fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/bootstrap-npm-workspace-wiring.yml around lines 64 - 70,
Update the failure-handling block around patch_rc in the workflow to stop
writing bootstrap failures to .github/bootstrap-npm-workspace-failure.log, which
is later committed and pushed. Send the existing failure message and contents of
$RUNNER_TEMP/bootstrap-patch.log to $GITHUB_STEP_SUMMARY instead, preserving the
diagnostic details without leaving a repository artifact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/bootstrap-npm-workspace-wiring.yml:
- Line 124: Update the condition in the workflow’s patch result check to pass
steps.patch.outputs.patch_rc through the step’s env configuration, then
reference the resulting shell environment variable inside the if statement
instead of interpolating the GitHub Actions expression directly.

In @.github/workflows/pr703-focused-tests.yml:
- Around line 1-25: Move the resolver tests and coverage gate from the
PR-specific workflow into the repository’s central test workflow, preserving
their required triggers and checks. Then delete the temporary workflow defined
by “PR 703 Focused Resolver Tests,” including its PR-specific branch and path
configuration, so no one-off bootstrap or workflow remains under
.github/workflows.

In `@scripts/ci/bootstrap_patch_workflow.py`:
- Around line 278-289: Remove the one-time self-modifying bootstrap path: run
scripts/ci/bootstrap_patch_workflow.py locally, commit its generated final
contents into .github/workflows/opencode-review-dispatch.yml and
tests/test_opencode_agent_contract.py, then delete
scripts/ci/bootstrap_patch_workflow.py. Also delete
.github/workflows/bootstrap-npm-workspace-wiring.yml, including its contents:
write permission and branch-push behavior.

In `@scripts/ci/npm_workspace_install_root.py`:
- Around line 113-126: Update _worktree_blob to hash the worktree file with
Git’s path-aware normalization by passing the repository-relative relative_path
via --path to hash-object, instead of using --no-filters. Preserve the existing
regular-file validation and expected-blob comparison.

---

Nitpick comments:
In @.github/workflows/bootstrap-npm-workspace-wiring.yml:
- Around line 64-70: Update the failure-handling block around patch_rc in the
workflow to stop writing bootstrap failures to
.github/bootstrap-npm-workspace-failure.log, which is later committed and
pushed. Send the existing failure message and contents of
$RUNNER_TEMP/bootstrap-patch.log to $GITHUB_STEP_SUMMARY instead, preserving the
diagnostic details without leaving a repository artifact.

In @.github/workflows/pr703-focused-tests.yml:
- Around line 42-62: Explicitly configure Python 3.12 in the workflow by adding
actions/setup-python with python-version set to "3.12" before the Python-based
steps, and apply the same setup to bootstrap-npm-workspace-wiring.yml. Keep the
existing test and coverage commands unchanged.

In `@scripts/ci/npm_workspace_install_root.py`:
- Around line 195-218: Move the nested matches function out of the patterns loop
into a module-level cached helper, passing path_parts and pattern_parts as
explicit tuple arguments. Update the loop to call this helper for each pattern,
preserving the existing anchored glob and recursive ** matching behavior while
allowing the cache to be reused across patterns and eliminating the B023
warning.
- Around line 334-337: Update the parent-path assignment in the candidate
traversal loop to remove the redundant PurePosixPath("") conditional. After the
existing candidate == PurePosixPath(".") termination check, assign candidate
directly to candidate.parent while preserving the current traversal behavior.

In `@tests/test_npm_workspace_install_root_hardening.py`:
- Around line 15-67: Remove the duplicated _git, _write_json, and _commit
helpers from this test module and reuse shared implementations from
tests/conftest.py or a small helper module, updating _workspace_repo and its
callers to use them while preserving existing fixture behavior.
- Line 193: Replace the subprocess-based recursive deletion in the test with the
standard-library shutil.rmtree call, updating imports as needed. Preserve
deletion of the repo / "apps" directory and its current test behavior without
invoking an external rm executable.

In `@tests/test_npm_workspace_install_root.py`:
- Around line 480-487: Update the test invoking _tree_blob to use a directly
imported PurePosixPath from pathlib instead of module.PurePosixPath. Add
PurePosixPath alongside the existing Path import and pass it directly, removing
the dependency on the production module’s re-export.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9607ef19-06dd-4eed-b62e-96958f32cc8d

📥 Commits

Reviewing files that changed from the base of the PR and between 5983b41 and ecc6134.

📒 Files selected for processing (6)
  • .github/workflows/bootstrap-npm-workspace-wiring.yml
  • .github/workflows/pr703-focused-tests.yml
  • scripts/ci/bootstrap_patch_workflow.py
  • scripts/ci/npm_workspace_install_root.py
  • tests/test_npm_workspace_install_root.py
  • tests/test_npm_workspace_install_root_hardening.py

Comment thread .github/workflows/bootstrap-npm-workspace-wiring.yml Outdated
Comment thread .github/workflows/pr703-focused-tests.yml Outdated
Comment thread scripts/ci/bootstrap_patch_workflow.py Outdated
Comment thread scripts/ci/npm_workspace_install_root.py
@opencode-agent
opencode-agent Bot disabled auto-merge August 3, 2026 04:02

Copy link
Copy Markdown
Contributor Author

@coderabbitai autofix

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

The agent ran but didn't make any changes. The issues may already be fixed or require manual intervention.

Copy link
Copy Markdown
Contributor Author

@jules Finalize this PR directly on the current branch. Replace the temporary self-modifying bootstrap with the actual central workflow and contract changes it was meant to produce; delete .github/workflows/bootstrap-npm-workspace-wiring.yml, .github/workflows/pr703-focused-tests.yml, and scripts/ci/bootstrap_patch_workflow.py. Address all current unresolved review findings, including passing the bootstrap return code through env rather than direct expression interpolation if any bootstrap remains, integrating resolver tests into the normal central test/coverage contract, and making _worktree_blob use path-aware Git clean hashing (git hash-object --path=<repo-relative-path> -- <file>) instead of --no-filters. Preserve fail-closed path, workspace, lock receipt, and symlink checks. Run the focused resolver tests, central workflow contracts, 100% line/docstring coverage, actionlint, and diff checks; push the minimized final diff and resolve only findings actually addressed.

Comment thread .github/workflows/bootstrap-npm-workspace-wiring.yml Fixed
Comment thread .github/workflows/pr703-final-repair.yml Fixed
@opencode-agent
opencode-agent Bot force-pushed the fix/npm-workspace-coverage-root branch from 2175296 to 309ed34 Compare August 3, 2026 17:21
Comment thread .github/workflows/pr703-final-repair.yml Fixed
@seonghobae
seonghobae enabled auto-merge (squash) August 4, 2026 03:43
@seonghobae
seonghobae marked this pull request as draft August 4, 2026 04:41
auto-merge was automatically disabled August 4, 2026 04:41

Pull request was converted to draft

@seonghobae
seonghobae marked this pull request as ready for review August 4, 2026 04:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants