fix(update): preserve proxy on npm cache failures - #533
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
Addressed the CodeRabbit outside-diff cache-traversal finding in commit 1490ca9. The preflight now fails closed after 50,000 discovered entries or 10 seconds, with injectable budgets and checks around stat, directory reads, and entry iteration. Regressions cover both limits; the current 15,718-entry cache passes in about 317ms, and the retained 36,202-entry incident cache still rejects promptly on ownership mismatch. |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
CodeRabbit follow-up is in 314eb53. I also adopted the outside-diff PID-helper consolidation because it keeps all replacement-process safety decisions on one implementation while preserving the direct path PID for killProxy. I did not add the optional errorIssue factory: that suggestion is presentation-only, the current error variants are already covered by the structured result contract, and avoiding an unrelated refactor keeps this incident fix focused. Verification: 55 focused tests passed; the full pre-push gate passed 4,964 tests, typecheck, GUI lint, and privacy scan. |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
Addressed the CodeRabbit outside-diff recovery-tree deadline finding in a28d6f8. Candidate tree validation now runs in a short-lived worker process, while the GUI update worker enforces the entire scan with a 5-second spawn timeout and SIGKILL. A blocking worker regression uses a 250ms budget and verifies fail-closed return within 2 seconds; existing valid, retired, in-tree symlink, out-of-tree symlink, and candidate-bound cases still pass. Verification: 74 focused tests passed, and the full pre-push gate passed 5,074 tests / 24,933 assertions, typecheck, GUI lint, and privacy scan. |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
@Ingwannu Follow-up head a28d6f8 is pushed after the latest Codex and CodeRabbit findings. The exact staged diff passed the local guard, 74 focused tests, and two full pre-push gates with 5,074 tests / 24,933 assertions, typecheck, GUI lint, and privacy scan. The new fork workflow runs are awaiting maintainer approval: Cross-platform CI https://github.com/lidge-jun/opencodex/actions/runs/30262870035 and React Doctor https://github.com/lidge-jun/opencodex/actions/runs/30262869987. Please approve these exact-head runs when convenient. This requests CI execution only; the PR remains open and unmerged while the fresh automated reviews complete. |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
@Ingwannu The follow-up head
The local pre-push gate passed 5,078 tests with typecheck, GUI lint, and privacy scan. I will keep monitoring the exact-head reviews and CI after approval. |
Two read-only audit lenses returned 30 contradictions; the verified ones are applied here and recorded in 006_corrections.md. Factual corrections: - claude-code#1124 closed 2025-05-16, not 2025-08-10 - 13 open enhancement issues, not 11 - #529 is merged, so issue #42 phase 2 is done - #418 has no PR behind it; it was miscounted as in-flight - #528 does not contain #424's current head, so it needs a rebase - #527's retarget is manual and independent of #526 Framing corrections: - stale-needs-info.yml is absent from the default branch, so bundle C had no real deadline - the debug switch #543's reporter asked for already exists - whether #545 is our defect is answerable from code, not owner judgment - #491 is an OAuth credential change, so it is a security boundary rather than a warm-up; #533 and #447 keep their security classification too Structure: bundle G added for roadmap honesty, bundle F rescoped to the security boundary, #498 split out of bundle B, cycle order rebuilt, and the loop archetype corrected to decision-elicitation.
This comment was marked as outdated.
This comment was marked as outdated.
Review — bugs, edge cases, leaks & securityUpdated verdict: changes requested. The original review found the security posture deliberately fail-closed and broadly sound, with one residual availability concern. A follow-up review of the current head found two additional real blockers that should be fixed before merge. Security
Bugs and edge cases
Leaks and resource hygiene
Non-blocking notes
RecommendationFix the two blocking issues first:
Then either document that clean nonzero installer failures require manual recovery, or add a narrowly proven |
|
Maintainer takeover follow-up opened as #557 against It addresses the two high blockers from the latest review on this PR:
I am leaving this PR open/draft and not merging the takeover PR automatically because the remaining nonzero-installer recovery policy is updater/security-adjacent and needs maintainer review. |
|
Follow-up on the takeover PR #557. Its first CI run failed on Cause: expect(launchersDuringInstall[0]?.endsWith("/bin/ocx.mjs")).toBe(true);The value under test comes from
If you prefer to keep this PR as the merge vehicle, please cherry-pick the same assertion fix here — otherwise Windows CI will keep failing on this branch. |
|
@lidge-jun When there is no near reply i would suggest we just maintainer-takeover this one so we can fix it for the users. |
|
Thanks for the follow-up. I confirm that #557 should be the sole merge vehicle, so I will not cherry-pick the Windows assertion fix back into #533 or continue parallel changes here. I have reviewed #557 and support keeping nonzero installer failures fail-closed with a documented manual recovery path. Please proceed with the maintainer takeover. GitHub currently reports #557 as conflicting with the latest Once #557 is merged, #533 can be closed as superseded. Please retain attribution to #533 and @WZBbiao; the attribution request in #557 still stands. |
Summary
SIGKILL, and persisted failure text contains neither cache/entry paths nor Unix account identifiers.node launcher --versioncheck before attempting fallback.Incident
A real GUI update from 2.7.33 to 2.7.41 reproduced the failure. The updater stopped the proxy, then
npm install -gfailed withEACCESbecause the configured~/.npmcache contained hundreds of entries owned by a different Unix account. npm had already moved the previous package into a hidden transaction directory, leaving a partial install, and the failed update path exited without restoring the service.The preserved incident cache is rejected by this preflight for an ownership mismatch, while the current user-owned cache passes.
Verification
135 pass,0 fail)bun run typecheckbun run prepushand the repository pre-push hook (5059 pass,0 fail, 382 files; typecheck, GUI lint, and privacy scan passed)npm pack --dry-run --ignore-scripts --jsonconfirmed the preflight and installer-process runtime/type files are included in the 337-entry packageSIGTERMis terminated by the parent deadlineSecurity Review
This change touches the dependency-installation boundary. The preflight runs the configured npm executable with fixed
config get cachearguments, then runs the packaged scanner through the current Node/Bun executable with fixed arguments,shell: false, bounded stdin, a 10-second timeout, andSIGKILL. The scanner canonicalizes only the configured cache-root symlink, performs bounded read-onlylstat/directory traversal, and never follows nested symlinks or mutates cache contents. Failed-install recovery considers at most two current/newest packages and accepts them only when the package root, manifest, and launcher are owned by the current UID or root, are not symlinks, and the launcher is contained in a regular package directory whose manifest has the expected package name and pre-update version. Maintainer security review is explicitly requested for the process boundary, path handling, retired-package validation, PID identity checks, and fail-closed behavior.Checklist
Summary by CodeRabbit
ocx update, aborting before the proxy is stopped when ownership can’t be verified.ocx updateCLI docs (including translations) to describe the new pre-check.