Conversation
PP-2963 **Release: Security fixes and logic tests**
- Add optional version-plugin that writes a VERSION JSON with SHA256 file hashes - Expose MiAPI.internalPageName from loaded page metadata - Extend normalizeVitePPDevConfig with versionPlugin options (default on) - Align getViteConfig with InlineConfig and Vite 8 / Rolldown (banner types, CSS options) - Use bundler moduleResolution and refresh dependencies (cac, ejs, jsdom, vitest, Next 16, etc.) - Ignore coverage/ in git
- Add tailwind.css entry and adjust PostCSS for Next sample projects - Bump lockfiles and add overrides (file-type, flatted, undici) for zero audit issues - Sync pp-dev config and styles with updated toolchain
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
tests/unit/plugin/version-plugin.spec.ts (1)
65-69: Unused variable and inconsistent import usage.
- Line 65 declares
versionFilebut it's never used - this appears to be leftover from development.- Line 66 uses
require('fs').readdirSync(outDir)instead of importingreaddirSyncat the top alongside other fs functions (lines 3-9).♻️ Proposed cleanup
First, add
readdirSyncto imports at the top:import { existsSync, mkdtempSync, mkdirSync, readFileSync, + readdirSync, rmSync, writeFileSync, } from 'fs';Then update the test:
- const versionFile = join(outDir, 'VERSION-v1.2.3-'); - const files = require('fs').readdirSync(outDir); + const files = readdirSync(outDir);Apply the same
require('fs').readdirSync→readdirSyncchange throughout the file (lines 103, 125, 136, 161, 187, 211, 234).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/plugin/version-plugin.spec.ts` around lines 65 - 69, Remove the unused local variable versionFile (it's dead code) and replace all inline require('fs').readdirSync(...) calls with the imported readdirSync function: add readdirSync to the existing fs imports at the top of the file alongside other fs functions, then change every occurrence of require('fs').readdirSync(outDir) (and similar patterns elsewhere in the spec) to readdirSync(outDir); ensure no other require('fs') usages remain in this test file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@package.json`:
- Around line 109-110: The dependency "vite-plugin-image-optimizer" may be
incompatible with Vite 8; before merging, either run a local compatibility test
with the current Vite version (vite ^8.0.1) or pin/replace the plugin: reproduce
a dev build and production build (vite dev and vite build) with the plugin
enabled, check for build errors or warnings referencing the plugin, and if
failures occur, revert to a Vite-verified plugin version or remove/replace
"vite-plugin-image-optimizer" in package.json (or lock to a Vite-6/7-compatible
Vite version) until official Vite 8 support is confirmed.
In `@src/plugins/version-plugin.ts`:
- Around line 43-48: The computeChecksum function is incorrectly passing 'hex'
to createHash().update which decodes the concatenated hex strings; change the
call in computeChecksum so update() is invoked without the 'hex' encoding (hash
the literal hashesConcatenated string as UTF‑8) so the final
createHash(...).update(hashesConcatenated).digest('hex') computes the intended
checksum from the concatenated sha256OfContent values.
In `@tests/test-nextjs-cjs/package.json`:
- Around line 31-38: Update the Vite override in the package.json "overrides"
block to either match the root and test-commonjs version or document the reason
for downgrading: either change the "vite": "^6.4.1" entry to "vite": "8.0.1" to
align versions, or add an inline JSON comment (or a surrounding README note)
explaining why this test app requires Vite ^6.4.1 (e.g., Next.js 16 CJS
compatibility), and ensure the change targets the "overrides" object in
tests/test-nextjs-cjs/package.json so the intent is clear to future maintainers.
In `@tests/unit/plugin/plugin.normalize.spec.ts`:
- Around line 230-262: Remove the duplicated "describe('versionPlugin
Normalization')" test block by deleting the redundant block that repeats
assertions for normalizeVitePPDevConfig (the one using versionPluginOpts/opts);
keep the original block (which asserts versionPlugin false/true/object) and
ensure only a single describe for versionPlugin Normalization remains that
continues to reference normalizeVitePPDevConfig and the versionPlugin test
cases.
---
Nitpick comments:
In `@tests/unit/plugin/version-plugin.spec.ts`:
- Around line 65-69: Remove the unused local variable versionFile (it's dead
code) and replace all inline require('fs').readdirSync(...) calls with the
imported readdirSync function: add readdirSync to the existing fs imports at the
top of the file alongside other fs functions, then change every occurrence of
require('fs').readdirSync(outDir) (and similar patterns elsewhere in the spec)
to readdirSync(outDir); ensure no other require('fs') usages remain in this test
file.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b7f61c30-25c9-4079-9c8f-b00eb92383d5
⛔ Files ignored due to path filters (4)
package-lock.jsonis excluded by!**/package-lock.jsontests/test-commonjs/package-lock.jsonis excluded by!**/package-lock.jsontests/test-nextjs-cjs/package-lock.jsonis excluded by!**/package-lock.jsontests/test-nextjs/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (26)
.gitignorepackage.jsonsrc/banner/header.tssrc/index.tssrc/lib/pp.middleware.tssrc/plugin.tssrc/plugins/index.tssrc/plugins/version-plugin.tstests/test-commonjs/package.jsontests/test-commonjs/pp-dev.config.tstests/test-nextjs-cjs/package.jsontests/test-nextjs-cjs/postcss.config.jstests/test-nextjs-cjs/pp-dev.config.jstests/test-nextjs-cjs/src/pages/_app.tsxtests/test-nextjs-cjs/src/styles/global.scsstests/test-nextjs-cjs/src/styles/tailwind.csstests/test-nextjs/package.jsontests/test-nextjs/postcss.config.cjstests/test-nextjs/pp-dev.config.tstests/test-nextjs/src/pages/_app.tsxtests/test-nextjs/src/styles/global.scsstests/test-nextjs/src/styles/tailwind.csstests/test-nextjs/tsconfig.jsontests/unit/plugin/plugin.normalize.spec.tstests/unit/plugin/version-plugin.spec.tstsconfig.json
💤 Files with no reviewable changes (2)
- tests/test-nextjs/src/styles/global.scss
- tests/test-nextjs-cjs/src/styles/global.scss
| "vite": "^8.0.1", | ||
| "vite-plugin-image-optimizer": "^2.0.3", |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
vite-plugin-image-optimizer 2.0 Vite 8 compatibility
💡 Result:
vite-plugin-image-optimizer version 2.0 (including 2.0.3, latest as of Oct 2025) is not confirmed compatible with Vite 8. The plugin specifies peer dependency "vite >=5" and was last updated in Oct 2025 with dev dependency "vite ^6.4.1". Vite 8 (released March 2026) introduces breaking changes including Rolldown as the new bundler with full Rollup plugin API compatibility. No explicit Vite 8 support, changelog entries, or issues confirming compatibility were found. The repository shows activity as recent as March 2026 (last push), but no Vite 8-specific updates. It may work due to API compatibility, but lacks official confirmation. Test in your environment or monitor for updates.
Citations:
- 1: https://www.npmjs.com/package/vite-plugin-image-optimizer
- 2: https://registry.npmjs.org/vite-plugin-image-optimizer
- 3: https://github.com/FatehAK/vite-plugin-image-optimizer/releases
- 4: https://github.com/fatehak/vite-plugin-image-optimizer
- 5: Support Vite 6+ FatehAK/vite-plugin-image-optimizer#47
- 6: https://vite.dev/blog/announcing-vite8
vite-plugin-image-optimizer@^2.0.3 has no confirmed Vite 8 support—test before merging.
The plugin's last verified version is Vite 6.4.1 (from Oct 2025 dev dependencies). While the peer dependency allows Vite >=5, no explicit Vite 8 support, changelog updates, or compatibility confirmation exist. Given Vite 8's breaking changes (Rolldown bundler replacement), test this plugin in your environment or delay merging until official Vite 8 support is confirmed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@package.json` around lines 109 - 110, The dependency
"vite-plugin-image-optimizer" may be incompatible with Vite 8; before merging,
either run a local compatibility test with the current Vite version (vite
^8.0.1) or pin/replace the plugin: reproduce a dev build and production build
(vite dev and vite build) with the plugin enabled, check for build errors or
warnings referencing the plugin, and if failures occur, revert to a
Vite-verified plugin version or remove/replace "vite-plugin-image-optimizer" in
package.json (or lock to a Vite-6/7-compatible Vite version) until official Vite
8 support is confirmed.
| function computeChecksum(files: Record<string, string>): string { | ||
| const sortedPaths = Object.keys(files).sort(); | ||
| const hashesConcatenated = sortedPaths.map((p) => files[p]).join(''); | ||
|
|
||
| return createHash('sha256').update(hashesConcatenated, 'hex').digest('hex'); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Node.js crypto createHash update encoding parameter behavior
💡 Result:
The Node.js crypto.createHash(algorithm) returns a Hash object. The hash.update(data[, inputEncoding]) method updates the hash content with the given data. Key behavior of the inputEncoding parameter (optional second argument): - If data is a Buffer, TypedArray, or DataView, inputEncoding is ignored, and the raw bytes are used directly. - If data is a string: - If inputEncoding is provided (e.g., 'utf8', 'hex', 'base64', 'latin1'), the string is decoded from that encoding to bytes. - If inputEncoding is omitted, 'utf8' is used as the default. This has been the behavior since around Node.js v6 (changed from legacy 'binary' default in older versions like v0.x). Examples from official docs show hash.update('string') implicitly using UTF-8. Code example: const crypto = require('node:crypto'); const hash = crypto.createHash('sha256'); hash.update('hello', 'utf8'); // Explicit UTF-8 hash.update('world'); // Implicit UTF-8 console.log(hash.digest('hex')); For binary data, pass a Buffer: hash.update(Buffer.from(binaryData)); Historical note: Pre-v6 versions defaulted to 'binary' (latin1-like), causing issues with Unicode (e.g., "Kiełbasa" mangled). Modern Node.js (v25+) uses UTF-8 default for strings.
Citations:
- 1: https://nodejs.org/api/crypto.html
- 2: https://bun.com/reference/node/crypto/Hash/update
- 3: https://w3schools.com/nodejs/ref_hash.asp
- 4: https://docs.deno.com/api/node/crypto/~/Hash
- 5: https://nodejs.org/docs/latest-carbon/api/crypto.html
🏁 Script executed:
# First, check the full file to understand the context
cat -n src/plugins/version-plugin.ts | head -60Repository: mi-examples/pp-dev
Length of output: 2222
🏁 Script executed:
# Look for tests or usage of computeChecksum function
rg -n "computeChecksum" --type typescriptRepository: mi-examples/pp-dev
Length of output: 96
🏁 Script executed:
# Check the sha256OfContent function to confirm it returns hex strings
rg -n "sha256OfContent" --type typescript -A 5Repository: mi-examples/pp-dev
Length of output: 96
🏁 Script executed:
# Search for computeChecksum usage
rg -n "computeChecksum" .Repository: mi-examples/pp-dev
Length of output: 244
🏁 Script executed:
# Search for version manifest tests
rg -n "VersionManifest\|checksum" . --type-list | head -5Repository: mi-examples/pp-dev
Length of output: 451
🏁 Script executed:
# Look for any comments or tests around the plugin
rg -n "version-plugin\|versionPlugin" . | head -20Repository: mi-examples/pp-dev
Length of output: 44
🏁 Script executed:
# Check if there are test files for this plugin
find . -name "*.test.*" -o -name "*.spec.*" | grep -i versionRepository: mi-examples/pp-dev
Length of output: 104
🏁 Script executed:
cat -n tests/unit/plugin/version-plugin.spec.tsRepository: mi-examples/pp-dev
Length of output: 10554
Remove the 'hex' encoding from update()—this decodes hex strings to binary, which is incorrect.
Line 47 passes 'hex' as the encoding parameter to update(). Since hashesConcatenated contains literal hex string characters (from the concatenated sha256OfContent results), the 'hex' encoding causes Node.js to interpret each pair of hex digits as a byte value, decoding the string to binary before hashing.
This produces incorrect checksums. The correct approach is to hash the concatenated hex string directly:
return createHash('sha256').update(hashesConcatenated).digest('hex');This will use the default UTF-8 encoding and hash the string as-is, which is the intended behavior for a checksum computed from hex-encoded file hashes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/plugins/version-plugin.ts` around lines 43 - 48, The computeChecksum
function is incorrectly passing 'hex' to createHash().update which decodes the
concatenated hex strings; change the call in computeChecksum so update() is
invoked without the 'hex' encoding (hash the literal hashesConcatenated string
as UTF‑8) so the final createHash(...).update(hashesConcatenated).digest('hex')
computes the intended checksum from the concatenated sha256OfContent values.
| "overrides": { | ||
| "file-type": "^21.3.1", | ||
| "file-type": "^21.3.3", | ||
| "flatted": ">=3.4.2", | ||
| "minimatch": "10.2.4", | ||
| "undici": ">=6.24.0", | ||
| "vite": "^6.4.1", | ||
| "esbuild": "^0.25.0", | ||
| "minimatch": "10.2.4" | ||
| "esbuild": "^0.25.0" | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if other test apps have similar Vite version overrides
rg '"vite"' tests/*/package.json -A1 -B1Repository: mi-examples/pp-dev
Length of output: 395
🏁 Script executed:
#!/bin/bash
# Check root package.json for Vite version
rg '"vite"' package.json -A1 -B1
# Check if there are any comments around Vite in test-nextjs-cjs
cat tests/test-nextjs-cjs/package.json | head -50Repository: mi-examples/pp-dev
Length of output: 1097
Add a comment explaining the Vite 6.4.1 override or align with Vite 8.0.1.
This test app deliberately overrides Vite to ^6.4.1 while the root package.json and test-commonjs both use Vite 8.0.1. Either document why the downgrade is required (e.g., Next.js 16 CJS compatibility issue) with an inline comment, or update to match Vite 8.0.1.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/test-nextjs-cjs/package.json` around lines 31 - 38, Update the Vite
override in the package.json "overrides" block to either match the root and
test-commonjs version or document the reason for downgrading: either change the
"vite": "^6.4.1" entry to "vite": "8.0.1" to align versions, or add an inline
JSON comment (or a surrounding README note) explaining why this test app
requires Vite ^6.4.1 (e.g., Next.js 16 CJS compatibility), and ensure the change
targets the "overrides" object in tests/test-nextjs-cjs/package.json so the
intent is clear to future maintainers.
| describe('versionPlugin Normalization', () => { | ||
| it('should normalize versionPlugin: false to false', () => { | ||
| const config = normalizeVitePPDevConfig({ | ||
| templateName: 'test', | ||
| versionPlugin: false, | ||
| }); | ||
|
|
||
| expect(config.versionPlugin).toBe(false); | ||
| }); | ||
|
|
||
| it('should preserve versionPlugin: true as passed (spread overwrites normalization)', () => { | ||
| const config = normalizeVitePPDevConfig({ | ||
| templateName: 'test', | ||
| versionPlugin: true, | ||
| }); | ||
|
|
||
| expect(config.versionPlugin).toBe(true); | ||
| }); | ||
|
|
||
| it('should pass through versionPlugin object options', () => { | ||
| const versionPluginOpts = { | ||
| versionFileTemplate: 'CUSTOM-{packageversion}.json', | ||
| enabled: false, | ||
| }; | ||
|
|
||
| const config = normalizeVitePPDevConfig({ | ||
| templateName: 'test', | ||
| versionPlugin: versionPluginOpts, | ||
| }); | ||
|
|
||
| expect(config.versionPlugin).toEqual(versionPluginOpts); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Remove duplicate test block.
This describe('versionPlugin Normalization') block (lines 230-262) is a duplicate of the one at lines 146-191. The tests are nearly identical with minor naming differences (opts vs versionPluginOpts). This causes test redundancy and potential maintenance confusion.
🗑️ Proposed fix: Remove duplicate block
- describe('versionPlugin Normalization', () => {
- it('should normalize versionPlugin: false to false', () => {
- const config = normalizeVitePPDevConfig({
- templateName: 'test',
- versionPlugin: false,
- });
-
- expect(config.versionPlugin).toBe(false);
- });
-
- it('should preserve versionPlugin: true as passed (spread overwrites normalization)', () => {
- const config = normalizeVitePPDevConfig({
- templateName: 'test',
- versionPlugin: true,
- });
-
- expect(config.versionPlugin).toBe(true);
- });
-
- it('should pass through versionPlugin object options', () => {
- const versionPluginOpts = {
- versionFileTemplate: 'CUSTOM-{packageversion}.json',
- enabled: false,
- };
-
- const config = normalizeVitePPDevConfig({
- templateName: 'test',
- versionPlugin: versionPluginOpts,
- });
-
- expect(config.versionPlugin).toEqual(versionPluginOpts);
- });
- });
-📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| describe('versionPlugin Normalization', () => { | |
| it('should normalize versionPlugin: false to false', () => { | |
| const config = normalizeVitePPDevConfig({ | |
| templateName: 'test', | |
| versionPlugin: false, | |
| }); | |
| expect(config.versionPlugin).toBe(false); | |
| }); | |
| it('should preserve versionPlugin: true as passed (spread overwrites normalization)', () => { | |
| const config = normalizeVitePPDevConfig({ | |
| templateName: 'test', | |
| versionPlugin: true, | |
| }); | |
| expect(config.versionPlugin).toBe(true); | |
| }); | |
| it('should pass through versionPlugin object options', () => { | |
| const versionPluginOpts = { | |
| versionFileTemplate: 'CUSTOM-{packageversion}.json', | |
| enabled: false, | |
| }; | |
| const config = normalizeVitePPDevConfig({ | |
| templateName: 'test', | |
| versionPlugin: versionPluginOpts, | |
| }); | |
| expect(config.versionPlugin).toEqual(versionPluginOpts); | |
| }); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/unit/plugin/plugin.normalize.spec.ts` around lines 230 - 262, Remove
the duplicated "describe('versionPlugin Normalization')" test block by deleting
the redundant block that repeats assertions for normalizeVitePPDevConfig (the
one using versionPluginOpts/opts); keep the original block (which asserts
versionPlugin false/true/object) and ensure only a single describe for
versionPlugin Normalization remains that continues to reference
normalizeVitePPDevConfig and the versionPlugin test cases.
…ding createHash().update() expects string encoding for the data; passing 'hex' was incorrect for joined hex digest strings.
Pull request: merge
pp-2859→developTitle
feat: version manifest plugin, Vite 8 upgrade, and sample-app refresh (PP-2859)
Summary
This branch adds an optional version manifest build step that emits a JSON file with package version, build date, and SHA-256 checksums of output files. It also upgrades the toolchain to Vite 8 (Rolldown-backed types, dependency bumps), tightens TypeScript resolution for modern
package.jsonexports, and refreshes the test sample apps (Tailwind entry, PostCSS, lockfiles, npm audit overrides).What changed
Version manifest plugin
versionPluginin pp-dev config) writes aVERSION-v{version}-{date}.jsonmanifest under the build output directory.versionPlugin?: boolean | { versionFileTemplate?, enabled? }(seenormalizeVitePPDevConfig).MiAPInow exposesinternalPageNamefrom loaded page metadata (used in plugin-related flows).Vite 8 and tooling
vite-plugin-image-optimizer, Vitest 4, Next 16 in dev, etc.).tsconfig.json:moduleResolutionset tobundlerso TypeScript resolves packages that only exposeexports(fixesvite/ Rolldown type resolution under Rollup build).src/banner/header.ts: banner callback typed withRenderedChunkfromrolldownsobuild.rollupOptions.output.bannermatches Vite 8 / Rolldown.getViteConfig: returnsPromise<InlineConfig>without unsafe cast; removes obsoletecss.scss/api: 'modern'block (Vite 8CSSOptions+ default Sass pipeline).Repository hygiene
.gitignore: ignorecoverage/.package.json: dependency refreshes and overrides (e.g.file-type,undici) for security alignment.Test sample apps (
tests/test-commonjs,tests/test-nextjs,tests/test-nextjs-cjs)overrides(file-type,flatted,undici) sonpm auditis clean.tailwind.cssentry and PostCSS / style tweaks aligned with the updated stack.Commits (this branch)
feat: version manifest plugin and upgrade to Vite 8test: refresh sample apps, Tailwind entry, and npm audit overridesHow to test
npm installat repo rootnpm run build(ornpm run build:nodeas in your CI)npm run test:unittests/test-nextjs/tests/test-nextjs-cjs(npm run dev/npm run build) afternpm installin that folderRisk / rollout notes
versionPlugin: falsein pp-dev config.Checklist (edit before merge)
developSummary by CodeRabbit
New Features
versionPluginconfiguration option supporting customizable file templates and enable/disable control.Improvements
@tailwindcss/postcssplugin.Chores
Tests