FABLE_CLEANUP: fix(core): 20-day audit fixes for the core engine - #1012
Merged
Conversation
…ache hardening, NUL de-binarification Co-Authored-By: Aiden Bai <aiden.bai05@gmail.com>
Contributor
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
commit: |
…ixes - cap darwin spawn argv at 800k: macOS ARG_MAX is 1 MiB (argv + envp together) and an argv that passes the guard but crosses the OS limit makes spawn throw E2BIG synchronously, escaping Effect — the #924 crash class the guard exists to prevent; the guard regression test now also overflows every platform's cap - record the security scan's fail-open on `securityScanFailed` and thread it InspectOutput -> CachedScanPayload -> wide event (`securityScan.failed`), mirroring `supplyChainOverlapTimedOut`; failed passes are never cached, and the fail-open path is now pinned by a regression test - pin the uid suffix in the tmp cache-dir test (the prefix match passed with or without the fix) - deslop: NODE_VERSION_PROBE_TIMEOUT_MS moves to constants.ts, flatten the drop-reason nested ternary, collapse persist()'s keptHashes loop, inline the tmp cache dir name, tighten the hasOwn comment; annotate LINT_PHASE_TIMEOUT_MS's now-per-batch sizing assumption - changeset for the audit-fix release notes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e-core # Conflicts: # packages/react-doctor/src/cli/utils/scan-result-cache.ts # packages/react-doctor/src/inspect.ts
rayhanadev
approved these changes
Jul 2, 2026
rayhanadev
added a commit
that referenced
this pull request
Jul 2, 2026
…-duration
Resolved spawn-batches.ts: main reworked the split-retry budget to lazy
per-batch anchoring (splitBudget: { deadlineMs } param, better drop-reason
messages); this branch added the --max-duration isPastDeadline() skip and the
scannedFileCount subtraction. Combined both — my deadline check sits atop
main's new signature, and the call site passes { deadlineMs: null } while still
subtracting deadline-skipped files from the scanned count.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Core-engine slice of the 20-day deep-audit fixes from #999 (split into 4 PRs).
spawn-batches.ts): the 180s split budget was anchored at pass start (healthy lint time consumed it, so a batch failing after minute 3 was dropped whole with zero split attempts) and was pass-wide (one bad batch starved later batches). Drop reasons now name the actual limit + depth that fired.REACT_DOCTOR_SUPPLY_CHAIN_TIMEOUT_MSnow actually raises the budget: the configured value is threaded intocheckSupplyChain's inner cap, which stayed pinned at the 90s constant (the env var could previously only lower the effective budget).fixGroupIdno longer rides the Score API payload (contract drift vs. "request shape identical").file-lint-cachepersist()fails open on a corrupt sibling ruleset bucket ({"rulesets":{"x":null}}previously crashed every warm scan until the file was hand-deleted)./tmpfallback cache dir is uid-scoped — the predictable world-writable path let another local user pre-create it and plant cached diagnostics.compute-ruleset-hash.tsandrun-oxlint.ts(literal U+0000 made git/ripgrep treat the files as binary) →\u0000escape sequences. The cache keys are byte-identical; three of the four ruleset-hash separators are too, but the fourth was a stray literal space and is now NUL like its siblings — so the ruleset hash changes and the per-file lint cache takes a one-time miss on upgrade (fail-open: one slower scan, then warm again).isSafeGitRevisionbefore reachinggit merge-baseargv (repo-controlledorigin/HEADsymref).Effect.tryPromise+orElseSucceed) instead of defecting through the unconditionalFiber.joinand sinking the scan.--scope linesto file scope on large PRs on Linux/macOS.type/severitylookups guardObject.prototypemembers ("constructor"off the wire read a Function and bypassedsanitizeTerminalText).CheckDeadCodeOptions.userConfigremoved.Follow-up commit (
c22fb9ba, from adversarial review of this PR):spawnthrowE2BIGsynchronously (outside Node's async-error whitelist), escaping Effect uncatchably — the exact Unguarded subprocess spawn on the scan path aborts the run (ENAMETOOLONG / ENOTDIR / spawn UNKNOWN; regression of #46) #924 crash class the guard exists to prevent. The guard test now also overflows every platform's cap.securityScan.failedtelemetry — the security-scan fail-open above previously made a failed pass indistinguishable from a clean one; it's now recorded onInspectOutput.securityScanFailedand threaded through the cached scan payload to the Sentry wide event, mirroringsupplyChainOverlapTimedOut(failed passes are never cached). Pinned by a regression test.startsWithassertion passed with or without the uid suffix; it now asserts thereact-doctor-cache-<scope>basename.NODE_VERSION_PROBE_TIMEOUT_MSmoved toconstants.ts, drop-reason nested ternary flattened,persist()'s kept-hashes loop collapsed, comment tightening;LINT_PHASE_TIMEOUT_MS's sizing note updated for per-batch budgets. Plus a changeset (react-doctor/@react-doctor/corepatch).New regression tests: per-batch split budget, supply-chain timeout threading, score-payload field stripping, corrupt cache bucket, security-scan fail-open, all-platform argv-cap overflow.
Part of splitting #999. Siblings: rules, CLI, and action/CI PRs.
Link to Devin session: https://app.devin.ai/sessions/023f6cac087a40558f73fca03773c180
Requested by: @aidenybai
Note
Medium Risk
Touches scan orchestration, subprocess spawning, on-disk caches, and security-sensitive supply-chain parsing; behavior is mostly fail-open with regression tests, but argv caps and one-time lint cache invalidation can change large-PR diff scope and first-run lint performance.
Overview
Core-engine reliability and security from the 20-day audit: scan orchestration, lint spawning, caches, git argv, and telemetry.
Lint binary-split recovery is scoped per top-level batch with the split deadline anchored at the first splittable failure (not pass start), so healthy lint time no longer eats the budget and one bad batch cannot starve later batches. Drop reasons now name whether the depth cap or time budget fired.
Spawn argv guards are platform-sized (Windows 24k, macOS 800k, POSIX 1.5M) so large
--scope linesgit diffs are not silently downgraded on Linux/macOS while avoiding synchronousE2BIGon Darwin.Security scan I/O errors fail open (skip the pass) instead of defecting through
Fiber.joinand failing the whole scan;securityScan.failedis threaded through inspect output, scan cache eligibility, and Sentry wide events (mirroring supply-chain overlap timeout).Per-file lint cache: corrupt sibling ruleset buckets no longer crash
persist(); ruleset hash uses the oxlint child Node version (nvm fallback); cache keys use\u0000separators (one-time cache miss on upgrade)./tmpfallback cache paths are uid-scoped against cross-user poisoning.Supply-chain:
REACT_DOCTOR_SUPPLY_CHAIN_TIMEOUT_MSis threaded into the check’s inner wall-clock cap (can raise, not only lower). Socket alerttype/severitylookups useObject.hasOwnso wire values like"constructor"cannot hitObject.prototype.Score API payloads strip
fixGroupIdwith other local-only fields. Auto-detected default branch is validated before git argv. Dead-code no longer forwards unuseduserConfigto deslop. Foreign-disable near-miss hints say add the qualified rule id rather than replace tokens.Reviewed by Cursor Bugbot for commit d614cb3. Bugbot is set up for automated code reviews on this repo. Configure here.