Skip to content

fix(hardening): prerelease peer versions, asset-stub escaping, Flow-strip guard#71

Open
danfry1 wants to merge 2 commits into
mainfrom
fix/validation-asset-hardening
Open

fix(hardening): prerelease peer versions, asset-stub escaping, Flow-strip guard#71
danfry1 wants to merge 2 commits into
mainfrom
fix/validation-asset-hardening

Conversation

@danfry1

@danfry1 danfry1 commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Problem

Three unrelated hardening gaps, all found in a code audit:

  1. Prerelease peer versions hard-failed validation at startup. satisfiesMinimum split versions on . only, so a prerelease sharing the minimum's major.minor — e.g. vitest 4.0.0-beta.3 against the 4.0.0 floor — parsed with NaN in the patch slot and failed the check, throwing the unsupported-peer error for exactly the early-adopter installs that run betas/RCs.
  2. Mock-engine asset stubs diverged from the native loader. The extension match was case-sensitive (LOGO.PNG fell through and broke parsing) while the native loader lowercases; user-supplied assetExts weren't regex-escaped (png|js would asset-stub every .js file); the stubbed basename was raw-interpolated into the emitted module, so a filename containing a quote emitted broken JS.
  3. A Flow-strip parse failure killed the whole transform pipeline. The @flow content filter is a heuristic — the marker can appear inside a string or comment of a file flow-remove-types cannot parse; that parse error previously propagated out of the transform hook.

Change

  • Version comparison strips prerelease/build metadata first (semver ignores build metadata for precedence). A prerelease of the minimum itself is accepted — rejecting it would re-break the beta cohort, and vite/vitest don't publish patch-level prereleases, so the theoretical security-floor bypass doesn't occur on npm (trade-off documented in-code and pinned by tests).
  • Asset extension matching is case-insensitive with escaped extensions, and the basename is JSON-stringified — now matching the native loader's semantics on all three counts.
  • Unparseable files pass through the Flow-strip untouched (a genuine Flow file that fails here fails Vite's own parse next with a clearer error); the skip warns under diagnostics with the file id.

Review

Independently adversarially reviewed pre-PR: the new tests were verified to fail against main's source (real regressions, not tautologies), the native-loader parity claims were checked against loader.mjs, and the prerelease-of-minimum trade-off was assessed against npm publishing reality. Review findings (diagnostics warning, overstated bug description, property-based assertion) are incorporated.

Full gate: mock suite (incl. 16 new tests), native suites, crosscheck 75/75, lint/format/typecheck clean.

danfry1 added 2 commits July 2, 2026 22:44
…trip guard

- validate.ts: strip prerelease/build metadata before version comparison —
  "4.0.0-beta.3" parsed to [4, NaN, …] and failed the minimum check, throwing
  the unsupported-peer startup error for installs running betas/RCs (exactly
  the early-adopter cohort). A prerelease of the minimum itself is accepted.
- plugin.ts asset stubs: case-insensitive extension matching (the native
  loader already lowercases; the engines must agree on what is an asset),
  regex-escaped user-supplied assetExts entries, and JSON-stringified
  basenames so filenames containing quotes emit valid JS (mirrors the native
  loader, which already stringifies).
- plugin.ts Flow-strip: the "@flow" content filter is a heuristic — the
  marker can appear inside a string or comment of a file flow-remove-types
  cannot parse; that parse error previously propagated and killed the whole
  transform pipeline. Unparseable files now pass through untouched (a genuine
  Flow file that fails here would fail Vite's own parse next with a clearer
  error).
…-bug description, property-based test assertions

Pre-PR review findings: the silent catch now warns under diagnostics with the
file id (a genuine Flow file the stripper chokes on otherwise surfaces only as
a downstream Vite parse error with no hint the strip was attempted); the
comment/changeset overstated the old parse bug (NaN landed in the patch slot,
so only prereleases sharing the minimum's major.minor failed, not all
prereleases); the quote-escaping test now asserts the emitted literal
round-trips rather than mirroring the implementation expression.
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.

1 participant