Version: 2.0.0+ Created: 2025-09-30 Total Time Estimate: 8-12 hours with AI assistance (1-2 days) Status: Planning Phase
This roadmap outlines a comprehensive plan to achieve enterprise-grade security, reliability, and test coverage for the vite-plugin-component-debugger. The plan includes 51 specific tasks across 8 categories.
Current Status:
- ✅ 113/113 tests passing
- ✅ Basic security measures implemented (ReDoS protection, transformer validation, path traversal prevention)
- ✅ Risk Level: 🟢 LOW
Target Status:
- 🎯 100% code coverage
- 🎯 Comprehensive fuzzing tests
- 🎯 Memory leak detection
- 🎯 Performance regression tests
- 🎯 Browser compatibility tests
- 🎯 Formal threat model
- 🎯 Penetration testing complete
- 🎯 Risk Level: 🟢 ZERO
Critical security and reliability tasks that should be done first.
Important improvements for production readiness.
Nice-to-have enhancements and edge case handling.
- Priority: 🔴 HIGH
- Time Estimate: 45-60 minutes with AI
- Dependencies: None
- Tools Needed:
@jazzer.js/core(fuzzing framework)fast-check(property-based testing)jsfuzz(JavaScript fuzzer)
Installation:
pnpm add -D @jazzer.js/core fast-checkSteps:
- Create
src/__tests__/fuzzing/babel-parser.fuzz.test.ts - Generate malformed JSX/TSX code samples (unclosed tags, invalid attributes, broken syntax)
- Fuzz test with deeply nested JSX (1000+ levels)
- Test Unicode edge cases (emoji in component names, RTL text, zero-width characters)
- Test extremely long identifiers (10KB+ component names)
- Test binary/null bytes in code strings
Success Criteria:
- Plugin gracefully handles all malformed input without crashes
- No uncaught exceptions in 100,000+ fuzz iterations
- Maximum memory usage stays below 500MB per test
Implementation:
// src/__tests__/fuzzing/babel-parser.fuzz.test.ts
import { describe, it, expect } from "vitest";
import { componentDebugger } from "../../plugin";
import fc from "fast-check";
describe("Babel Parser Fuzzing", () => {
it("should handle malformed JSX without crashing", async () => {
await fc.assert(
fc.asyncProperty(fc.string({ minLength: 1, maxLength: 10000 }), async (randomCode) => {
const plugin = componentDebugger();
try {
// Should not throw, should return null or valid result
const result = await plugin.transform?.(randomCode, "fuzz.tsx");
expect(result === null || typeof result === "object").toBe(true);
} catch (error) {
// Parsing errors are acceptable, crashes are not
expect(error).toBeDefined();
}
}),
{ numRuns: 10000 }
);
});
it("should handle deeply nested JSX", async () => {
const depths = [10, 50, 100, 500, 1000];
for (const depth of depths) {
const code = "<div>" + "<span>".repeat(depth) + "test" + "</span>".repeat(depth) + "</div>";
const plugin = componentDebugger();
const result = await plugin.transform?.(code, "deep.tsx");
// Should complete within reasonable time
expect(result).toBeDefined();
}
});
it("should handle Unicode edge cases", async () => {
const unicodeCases = [
"<Component😀 />", // Emoji in name
"<div>مرحبا</div>", // Arabic RTL
"<div>你好</div>", // Chinese
"<div>\u200B\u200C\u200D</div>", // Zero-width chars
];
for (const code of unicodeCases) {
const plugin = componentDebugger();
const result = await plugin.transform?.(code, "unicode.tsx");
expect(result).toBeDefined();
}
});
});- Priority: 🔴 HIGH
- Time Estimate: 30-45 minutes with AI
- Dependencies: Task 1.1
- Tools Needed:
fast-check,minimatch(already installed)
Steps:
- Create
src/__tests__/fuzzing/glob-patterns.fuzz.test.ts - Fuzz test with ReDoS attack patterns (catastrophic backtracking)
- Test patterns exceeding MAX_PATTERN_LENGTH (200 chars)
- Test patterns with MAX_WILDCARD_COUNT+ wildcards (>10)
- Test path traversal attempts (
../../../etc/passwd,..\\..\\windows\\system32) - Test null bytes in paths (
path\0with\0nulls) - Verify performance: no pattern should take >100ms to match
Success Criteria:
- All ReDoS patterns timeout gracefully with warnings
- Path traversal attacks blocked
- No glob pattern causes >100ms execution time
Implementation:
// src/__tests__/fuzzing/glob-patterns.fuzz.test.ts
import { describe, it, expect } from "vitest";
import { componentDebugger } from "../../plugin";
import fc from "fast-check";
describe("Glob Pattern Fuzzing", () => {
it("should reject ReDoS attack patterns", async () => {
const redosPatterns = [
"(a+)+b",
"(a*)*b",
"([a-zA-Z]+)*",
"*".repeat(50) + "test",
"**/**/**/**/**/**/**/**/**/**/**",
];
for (const pattern of redosPatterns) {
const plugin = componentDebugger({
includePaths: [pattern],
});
const code = "<div>test</div>";
const startTime = Date.now();
await plugin.transform?.(code, "test.tsx");
const duration = Date.now() - startTime;
// Should complete quickly or skip pattern
expect(duration).toBeLessThan(1000);
}
});
it("should prevent path traversal in exportStats", async () => {
const traversalPaths = [
"../../../etc/passwd",
"..\\..\\..\\windows\\system32\\config\\sam",
"/etc/shadow",
"C:\\Windows\\System32\\config\\SAM",
];
for (const path of traversalPaths) {
const plugin = componentDebugger({ exportStats: path });
const code = "<div>test</div>";
await plugin.transform?.(code, "test.tsx");
// buildEnd should prevent writing outside project
plugin.buildEnd?.();
// Verify file wasn't created (manual check or filesystem mock)
}
});
it("should handle extremely long patterns", async () => {
const longPattern = "a/".repeat(200) + "*.tsx";
const plugin = componentDebugger({ includePaths: [longPattern] });
const code = "<div>test</div>";
// Should warn and skip pattern
await plugin.transform?.(code, "test.tsx");
});
});- Priority: 🟡 MEDIUM
- Time Estimate: 20-30 minutes with AI
- Dependencies: Task 1.1
- Tools Needed:
fast-check
Steps:
- Create
src/__tests__/fuzzing/transformers.fuzz.test.ts - Fuzz transformers with non-string returns (objects, null, undefined, symbols)
- Test transformers that throw errors
- Test transformers with infinite loops (timeout protection)
- Test transformers returning extremely long strings (>1MB)
- Test transformers with prototype pollution attempts
Success Criteria:
- Plugin handles invalid transformer returns gracefully
- Errors in transformers don't crash the build
- Resource limits enforced (MAX_ATTR_LENGTH)
Implementation:
// src/__tests__/fuzzing/transformers.fuzz.test.ts
import { describe, it, expect } from "vitest";
import { componentDebugger } from "../../plugin";
describe("Transformer Fuzzing", () => {
it("should handle transformers returning non-strings", async () => {
const badTransformers = [
{ id: () => null as any },
{ id: () => undefined as any },
{ id: () => ({ malicious: "object" } as any) },
{ id: () => 123 as any },
{ id: () => Symbol("test") as any },
{ id: () => [] as any },
{ id: () => true as any },
];
for (const transformers of badTransformers) {
const plugin = componentDebugger({ transformers });
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
// Should not crash, should warn and use original value
expect(result).toBeDefined();
}
});
it("should handle transformers that throw", async () => {
const plugin = componentDebugger({
transformers: {
id: () => {
throw new Error("Malicious transformer");
},
name: () => {
throw new TypeError("Bad type");
},
path: () => {
throw new ReferenceError("Not defined");
},
},
});
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
// Should catch error and continue with original value
expect(result).toBeDefined();
});
it("should handle transformers returning huge strings", async () => {
const plugin = componentDebugger({
transformers: {
id: () => "x".repeat(10 * 1024 * 1024), // 10MB string
},
});
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
// Should handle or truncate
expect(result).toBeDefined();
});
});- Priority: 🟡 MEDIUM
- Time Estimate: 20-30 minutes with AI
- Dependencies: Task 1.3
- Tools Needed:
fast-check
Steps:
- Create
src/__tests__/fuzzing/callbacks.fuzz.test.ts - Test callbacks that throw errors
- Test callbacks with infinite loops
- Test shouldTag returning non-boolean values
- Test customAttributes returning dangerous keys (
__proto__,constructor) - Test customAttributes returning non-string values
- Test customAttributes returning huge objects (>50 attributes)
Success Criteria:
- Callbacks errors logged but don't crash build
- Prototype pollution attempts blocked
- Resource limits enforced (MAX_CUSTOM_ATTRS: 50)
Implementation:
// src/__tests__/fuzzing/callbacks.fuzz.test.ts
import { describe, it, expect } from "vitest";
import { componentDebugger } from "../../plugin";
describe("Callback Fuzzing", () => {
it("should handle shouldTag throwing errors", async () => {
const plugin = componentDebugger({
shouldTag: () => {
throw new Error("Bad callback");
},
});
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
// Should catch error and continue processing
expect(result).toBeDefined();
});
it("should handle shouldTag returning non-boolean", async () => {
const badReturns = [
() => "yes" as any,
() => 1 as any,
() => null as any,
() => undefined as any,
() => ({} as any),
];
for (const shouldTag of badReturns) {
const plugin = componentDebugger({ shouldTag });
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
expect(result).toBeDefined();
}
});
it("should block prototype pollution in customAttributes", async () => {
const plugin = componentDebugger({
customAttributes: () => ({
__proto__: "malicious",
constructor: "evil",
prototype: "bad",
safe: "good",
}),
});
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
if (result && typeof result === "object" && "code" in result) {
// Should only include 'safe' attribute
expect(result.code).toContain("safe");
expect(result.code).not.toContain("__proto__");
expect(result.code).not.toContain("constructor");
}
});
it("should limit number of custom attributes", async () => {
const plugin = componentDebugger({
customAttributes: () => {
const attrs: Record<string, string> = {};
for (let i = 0; i < 100; i++) {
attrs[`attr-${i}`] = `value-${i}`;
}
return attrs;
},
});
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
// Should warn and limit to 50
expect(result).toBeDefined();
});
});- Priority: 🟡 MEDIUM
- Time Estimate: 1 day
- Dependencies: None
- Tools Needed:
fast-check
Steps:
- Create
src/__tests__/fuzzing/config-options.fuzz.test.ts - Test invalid depth values (negative, >MAX_DEPTH_LIMIT, NaN, Infinity)
- Test conflicting options (minDepth > maxDepth)
- Test invalid extension arrays (non-strings, empty strings)
- Test invalid preset names
- Test invalid metadataEncoding values
Success Criteria:
- All invalid configs handled with warnings
- Defaults applied when invalid values provided
- No crashes on bad configuration
Implementation:
// src/__tests__/fuzzing/config-options.fuzz.test.ts
import { describe, it, expect } from "vitest";
import { componentDebugger } from "../../plugin";
describe("Configuration Fuzzing", () => {
it("should handle invalid depth values", () => {
const invalidDepths = [
{ maxDepth: -1 },
{ maxDepth: 999 },
{ maxDepth: NaN },
{ maxDepth: Infinity },
{ maxDepth: -Infinity },
{ minDepth: -5 },
{ minDepth: 100, maxDepth: 10 }, // minDepth > maxDepth
];
for (const config of invalidDepths) {
expect(() => componentDebugger(config)).not.toThrow();
// Should apply defaults or swap values
}
});
it("should handle invalid preset names", () => {
const invalidPresets = [
"invalid-preset",
"MINIMAL", // Wrong case
"",
null as any,
123 as any,
];
for (const preset of invalidPresets) {
expect(() => componentDebugger({ preset: preset as any })).not.toThrow();
}
});
it("should handle invalid metadataEncoding", () => {
const invalidEncodings = [
"invalid",
"JSON", // Wrong case
null as any,
123 as any,
];
for (const encoding of invalidEncodings) {
expect(() =>
componentDebugger({
metadataEncoding: encoding as any,
})
).not.toThrow();
}
});
it("should handle invalid extensions array", () => {
const invalidExtensions = [[123, 456] as any, [""], [null] as any, "not-an-array" as any];
for (const extensions of invalidExtensions) {
expect(() =>
componentDebugger({
extensions: extensions as any,
})
).not.toThrow();
}
});
});- Priority: 🔴 HIGH
- Time Estimate: 2 hours
- Dependencies: None
- Tools Needed:
@vitest/coverage-v8,vitest
Installation:
pnpm add -D @vitest/coverage-v8Steps:
- Create
vitest.config.ts:
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
coverage: {
provider: "v8",
reporter: ["text", "json", "html", "lcov"],
include: ["src/**/*.ts"],
exclude: ["src/__tests__/**", "src/**/*.test.ts", "src/**/*.spec.ts"],
all: true,
lines: 100,
functions: 100,
branches: 100,
statements: 100,
thresholds: {
lines: 100,
functions: 100,
branches: 100,
statements: 100,
},
},
},
});- Add script to
package.json:
{
"scripts": {
"test:coverage": "vitest --coverage --run"
}
}- Run coverage:
pnpm test:coverage - Identify uncovered lines/branches
Success Criteria: Coverage report generated successfully
- Priority: 🔴 HIGH
- Time Estimate: 30-45 minutes with AI
- Dependencies: Task 2.1
- Tools Needed: Vitest
Steps:
- Create
src/__tests__/error-paths/plugin-errors.test.ts - Test Babel parser throwing on invalid syntax
- Test magic-string errors (invalid source positions)
- Test file I/O errors in exportStats (permission denied, disk full)
- Test malformed AST nodes (missing loc, missing name)
- Test callback errors (onTransform, onComplete throwing)
- Test edge case: code with no newlines
- Test edge case: code with only newlines
- Test edge case: empty file
- Test edge case: file with only comments
Success Criteria:
- All error branches in plugin.ts covered
- Error handling verified
- No silent failures
Implementation:
// src/__tests__/error-paths/plugin-errors.test.ts
import { describe, it, expect, vi } from "vitest";
import { componentDebugger } from "../../plugin";
describe("Plugin Error Paths", () => {
it("should handle babel parse errors gracefully", async () => {
const plugin = componentDebugger();
const invalidCode = "<div unclosed";
const result = await plugin.transform?.(invalidCode, "test.tsx");
// Should return null and log error
expect(result).toBeNull();
});
it("should handle callback errors in onTransform", async () => {
const errorCallback = vi.fn(() => {
throw new Error("onTransform failed");
});
const plugin = componentDebugger({ onTransform: errorCallback });
const code = "<div>test</div>";
await plugin.transform?.(code, "test.tsx");
expect(errorCallback).toHaveBeenCalled();
// Should log error but continue
});
it("should handle missing location info in AST nodes", async () => {
const plugin = componentDebugger({ debug: true });
// Code that might produce nodes without location info
const code = "<div />";
const result = await plugin.transform?.(code, "test.tsx");
expect(result).toBeDefined();
});
it("should handle exportStats file write errors", async () => {
const plugin = componentDebugger({
exportStats: "/root/forbidden/path.json", // Permission denied
});
const code = "<div>test</div>";
await plugin.transform?.(code, "test.tsx");
// Should log error, not crash
expect(() => plugin.buildEnd?.()).not.toThrow();
});
it("should handle empty file", async () => {
const plugin = componentDebugger();
const result = await plugin.transform?.("", "empty.tsx");
expect(result).toBeNull();
});
it("should handle file with only comments", async () => {
const plugin = componentDebugger();
const code = "// Just a comment\n/* Another comment */";
const result = await plugin.transform?.(code, "comments.tsx");
expect(result).toBeNull();
});
it("should handle code with no newlines", async () => {
const plugin = componentDebugger();
const code = "<div><span>test</span></div>";
const result = await plugin.transform?.(code, "single-line.tsx");
expect(result).toBeDefined();
});
});- Priority: 🔴 HIGH
- Time Estimate: 20-30 minutes with AI
- Dependencies: Task 2.1
- Tools Needed: Vitest
Steps:
- Create
src/__tests__/error-paths/generate-attributes.test.ts - Test all encoding modes (json, base64, none)
- Test metadata exceeding MAX_METADATA_SIZE (10KB)
- Test HTML escaping edge cases (
<script>,&, quotes) - Test groupAttributes mode
- Test all attribute inclusion/exclusion combinations
- Test source map hints
- Test custom attributes with dangerous keys filtered out
- Test custom attributes exceeding MAX_CUSTOM_ATTRS (50)
- Test attribute values exceeding MAX_ATTR_LENGTH (1000)
Success Criteria: All branches in generateAttributes covered
Implementation:
// src/__tests__/error-paths/generate-attributes.test.ts
import { describe, it, expect } from "vitest";
import { componentDebugger } from "../../plugin";
describe("Generate Attributes Edge Cases", () => {
it("should truncate large metadata", async () => {
const largeProps = { data: "x".repeat(20000) };
const plugin = componentDebugger({
includeProps: true,
customAttributes: () => largeProps,
});
const code = '<div className="test">content</div>';
const result = await plugin.transform?.(code, "test.tsx");
if (result && typeof result === "object" && "code" in result) {
// Should contain truncation notice
expect(result.code).toContain("truncated");
}
});
it("should handle all metadata encoding modes", async () => {
const encodings: Array<"json" | "base64" | "none"> = ["json", "base64", "none"];
for (const encoding of encodings) {
const plugin = componentDebugger({
includeProps: true,
metadataEncoding: encoding,
});
const code = '<div className="test">content</div>';
const result = await plugin.transform?.(code, "test.tsx");
expect(result).toBeDefined();
}
});
it("should properly escape HTML characters", async () => {
const plugin = componentDebugger({
customAttributes: () => ({
xss: '<script>alert("XSS")</script>',
amp: "A & B",
quote: 'He said "hello"',
apostrophe: "It's working",
lt: "<div>",
gt: "a > b",
}),
});
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
if (result && typeof result === "object" && "code" in result) {
expect(result.code).toContain("<script>");
expect(result.code).toContain("&");
expect(result.code).toContain(""");
expect(result.code).toContain("'");
}
});
it("should handle groupAttributes mode", async () => {
const plugin = componentDebugger({
groupAttributes: true,
includeAttributes: ["id", "name", "line"],
metadataEncoding: "base64",
});
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
if (result && typeof result === "object" && "code" in result) {
// Should have single data-dev attribute
expect(result.code).toContain("data-dev=");
expect(result.code).not.toContain("data-dev-id=");
}
});
it("should test all inclusion/exclusion combinations", async () => {
const configs = [
{ includeAttributes: ["id"] },
{ includeAttributes: ["id", "name"] },
{ excludeAttributes: ["metadata"] },
{ excludeAttributes: ["file", "component"] },
{ includeAttributes: ["id"], excludeAttributes: ["metadata"] },
];
for (const config of configs) {
const plugin = componentDebugger(config);
const code = "<div>test</div>";
const result = await plugin.transform?.(code, "test.tsx");
expect(result).toBeDefined();
}
});
});- Priority: 🟡 MEDIUM
- Time Estimate: 1 day
- Dependencies: Task 2.1
- Tools Needed: Vitest
Steps:
- Create
src/__tests__/utils/utility-functions.test.ts - Test shouldExcludeElement with all code paths
- Test extractTextContent with nested JSX, expressions, empty content
- Test matchesPatterns with empty patterns, invalid patterns, dot files
- Test applyPreset with all presets and override behavior
Success Criteria: 100% coverage of utility functions
- Priority: 🟢 LOW
- Time Estimate: 1 day
- Dependencies: Task 2.1
- Tools Needed: Vitest, jsdom or happy-dom
Steps:
- Install:
pnpm add -D happy-dom - Create
src/__tests__/utils/component-debugger-utils.test.ts - Test all exported functions (getComponentInfo, findAllComponents, etc.)
- Mock DOM environment with tagged elements
- Test error handling in metadata parsing
- Test browser API interactions
Success Criteria: 100% coverage of component-debugger.ts
- Priority: 🔴 HIGH
- Time Estimate: 45-60 minutes with AI
- Dependencies: None
- Tools Needed:
vite,tmp
Installation:
pnpm add -D tmpSteps:
- Create
src/__tests__/integration/vite-build.test.ts - Set up temp project with real vite.config.ts
- Test full development build
- Test full production build
- Test HMR (Hot Module Replacement)
- Test with various React versions (17, 18, 19)
- Test plugin order (before/after React plugin)
- Verify generated HTML has correct attributes
- Verify source maps are correct
Success Criteria:
- Plugin works in real Vite builds
- Attributes present in built HTML
- Source maps accurate
- No build performance regression (>10% slower)
- Priority: 🔴 HIGH
- Time Estimate: 3 days
- Dependencies: Task 3.1
- Tools Needed:
@playwright/test,playwright
Installation:
pnpm add -D @playwright/test
pnpm exec playwright installSteps:
- Create
src/__tests__/e2e/browser.spec.ts - Create
playwright.config.ts - Start dev server with plugin enabled
- Use Playwright to verify DOM attributes
- Test component highlighting utility
- Test data extraction utilities in browser
- Verify line numbers match source files
- Test with different browsers (Chromium, Firefox, WebKit)
Success Criteria:
- All attributes visible in browser DOM
- Line numbers accurate
- Utilities work in browser context
Configuration:
// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";
export default defineConfig({
testDir: "./src/__tests__/e2e",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: "html",
use: {
baseURL: "http://localhost:5173",
trace: "on-first-retry",
},
projects: [
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
{ name: "firefox", use: { ...devices["Desktop Firefox"] } },
{ name: "webkit", use: { ...devices["Desktop Safari"] } },
],
webServer: {
command: "pnpm run dev",
url: "http://localhost:5173",
reuseExistingServer: !process.env.CI,
},
});- Priority: 🟡 MEDIUM
- Time Estimate: 60-90 minutes with AI
- Dependencies: Task 3.1
- Tools Needed: Various React versions, Next.js, Remix
Steps:
- Create test projects for each framework
- Test React 17 (no automatic JSX runtime)
- Test React 18 (automatic JSX runtime)
- Test React 19 (latest features)
- Test Next.js App Router
- Test Next.js Pages Router
- Test Remix
- Verify SSR doesn't break
- Verify client-side hydration works
Success Criteria:
- Plugin works across all framework versions
- No SSR errors
- Hydration successful
- Priority: 🟢 LOW
- Time Estimate: 2 days
- Dependencies: Task 3.1
- Tools Needed: pnpm workspaces
Steps:
- Create test monorepo with multiple packages
- Test with pnpm workspaces
- Test with npm workspaces
- Test with Yarn workspaces
- Verify relative paths work across packages
- Test symlinked dependencies
Success Criteria:
- Plugin resolves paths correctly in monorepos
- No duplicate processing
- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: Task 3.1
- Tools Needed: GitHub Actions
Steps:
- Update
.github/workflows/ci.ymlto run integration tests - Test builds in CI environment
- Test across different Node versions (18, 20, 22)
- Test on different OS (Ubuntu, macOS, Windows)
- Verify no flaky tests
- Add integration test coverage reporting
Success Criteria:
- Integration tests pass in CI
- No platform-specific failures
Implementation:
# .github/workflows/integration.yml
name: Integration Tests
on: [push, pull_request]
jobs:
integration:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [18, 20, 22]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: "pnpm"
- run: pnpm install
- run: pnpm test:integration- Priority: 🔴 HIGH
- Time Estimate: 1 day
- Dependencies: None
- Tools Needed:
memlab,@clinicjs/clinic
Installation:
pnpm add -D memlab @clinicjs/clinicSteps:
- Create memory profiling scripts
- Set up heap snapshot capture
- Configure automated leak detection
Success Criteria: Tools installed and configured
Package.json scripts:
{
"scripts": {
"test:memory": "node --expose-gc --max-old-space-size=512 ./scripts/memory-test.js",
"profile:memory": "clinic heapprofiler -- node ./scripts/profile-plugin.js"
}
}- Priority: 🔴 HIGH
- Time Estimate: 3 days
- Dependencies: Task 4.1
- Tools Needed: memlab, Vitest
Steps:
- Create
scripts/memory-test.js - Process 10,000 files in a loop
- Monitor heap size growth
- Take heap snapshots before/after
- Analyze retained objects (MagicString, AST nodes, closures)
- Check for detached DOM nodes
- Verify garbage collection occurs
Success Criteria:
- Heap size stabilizes after GC
- No unbounded growth
- Memory usage < 200MB for 10,000 files
Implementation:
// scripts/memory-test.js
const { componentDebugger } = require("./dist/index.js");
const v8 = require("v8");
async function testMemoryLeak() {
const plugin = componentDebugger();
const testCode = "<div><span>Test</span></div>";
const initialHeap = v8.getHeapStatistics().used_heap_size;
// Process 10,000 files
for (let i = 0; i < 10000; i++) {
await plugin.transform?.(testCode, `file-${i}.tsx`);
if (i % 1000 === 0) {
global.gc?.(); // Force GC if --expose-gc flag set
const currentHeap = v8.getHeapStatistics().used_heap_size;
const growth = ((currentHeap - initialHeap) / 1024 / 1024).toFixed(2);
console.log(`Processed ${i} files, heap growth: ${growth}MB`);
}
}
global.gc?.();
const finalHeap = v8.getHeapStatistics().used_heap_size;
const totalGrowth = ((finalHeap - initialHeap) / 1024 / 1024).toFixed(2);
console.log(`\nTotal heap growth after 10,000 files: ${totalGrowth}MB`);
if (parseFloat(totalGrowth) > 200) {
console.error("❌ Memory leak detected! Heap growth exceeds 200MB");
process.exit(1);
}
console.log("✅ No memory leaks detected");
}
testMemoryLeak().catch(console.error);- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: Task 4.1
- Tools Needed: memlab, happy-dom
Steps:
- Test component-debugger.ts browser utilities
- Test enableComponentHighlighting for listener cleanup
- Test observeComponentRenders for observer cleanup
- Verify cleanup functions remove all listeners
- Test repeated enable/disable cycles
Success Criteria:
- All listeners removed on cleanup
- No retained event handlers
- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: Task 4.1, Task 3.1
- Tools Needed: memlab, Vite
Steps:
- Start Vite dev server with plugin
- Simulate file changes (HMR) for 1 hour
- Monitor heap size over time
- Check for accumulating transform results
- Verify stats object doesn't grow unbounded
Success Criteria:
- Heap stable during long-running server
- No accumulation of transform results
- Priority: 🟢 LOW
- Time Estimate: 1 day
- Dependencies: Task 4.2, Task 4.3, Task 4.4
- Tools Needed: GitHub Actions
Steps:
- Update
.github/workflows/ci.yml - Add memory leak test job
- Configure timeout (30 minutes max)
- Upload heap snapshots as artifacts
Success Criteria: Memory tests run in CI
- Priority: 🔴 HIGH
- Time Estimate: 2 days
- Dependencies: None
- Tools Needed:
tinybench
Installation:
pnpm add -D tinybenchSteps:
- Create
src/__tests__/benchmarks/baseline.bench.ts - Benchmark transform performance (small/medium/large files)
- Benchmark different file sizes (1KB, 10KB, 100KB, 1MB)
- Benchmark different JSX complexity (flat, nested, deeply nested)
- Measure Babel parse time vs. attribute injection time
- Store baseline results in
benchmarks/baseline.json
Success Criteria:
- Baseline metrics captured
- Benchmarks reproducible
Implementation:
// src/__tests__/benchmarks/baseline.bench.ts
import { bench, describe } from "vitest";
import { componentDebugger } from "../../plugin";
describe("Performance Baselines", () => {
const smallCode = "<div>Hello</div>";
const mediumCode = "<div>" + "<span>Test</span>".repeat(100) + "</div>";
const largeCode = "<div>" + "<span>Test</span>".repeat(1000) + "</div>";
bench("transform small file (< 1KB)", async () => {
const plugin = componentDebugger();
await plugin.transform?.(smallCode, "small.tsx");
});
bench("transform medium file (10KB)", async () => {
const plugin = componentDebugger();
await plugin.transform?.(mediumCode, "medium.tsx");
});
bench("transform large file (100KB)", async () => {
const plugin = componentDebugger();
await plugin.transform?.(largeCode, "large.tsx");
});
bench("disabled plugin (should be near-zero overhead)", async () => {
const plugin = componentDebugger({ enabled: false });
await plugin.transform?.(mediumCode, "disabled.tsx");
});
});- Priority: 🔴 HIGH
- Time Estimate: 3 days
- Dependencies: Task 5.1
- Tools Needed:
tinybench, custom scripts
Steps:
- Create
scripts/performance-regression-check.js - Run benchmarks on each commit
- Compare against baseline (max 10% regression allowed)
- Generate performance report
- Fail CI if regression > 10%
- Store historical performance data
Success Criteria:
- Automated detection of >10% slowdowns
- Historical tracking enabled
- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: Task 5.1, Task 3.1
- Tools Needed: Vite, hyperfine
Steps:
- Create test projects of varying sizes
- Measure build time with plugin enabled vs. disabled
- Test cold start vs. warm cache
- Test HMR update speed
- Verify plugin overhead < 5% of total build time
Success Criteria:
- Plugin adds <5% to build time
- HMR not significantly impacted
- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: Task 5.1
- Tools Needed: Test codebase generator
Steps:
- Generate synthetic codebase (10,000 components)
- Test transform performance at scale
- Measure memory usage with large codebase
- Test stats aggregation performance
- Verify no exponential slowdowns
Success Criteria:
- Linear time complexity maintained
- Memory usage proportional to file size
- Priority: 🟡 MEDIUM
- Time Estimate: 1 day
- Dependencies: Task 5.2
- Tools Needed: GitHub Actions
Steps:
- Add benchmark job to
.github/workflows/ci.yml - Run on every PR
- Comment results on PR
- Block merge if regression > 10%
Success Criteria: Performance tests run in CI
- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: Task 3.2
- Tools Needed:
@playwright/test
Steps:
- Configure Playwright for multiple browsers
- Set up test matrix (Chrome, Firefox, Safari, Edge)
- Configure mobile browsers (iOS Safari, Chrome Android)
Success Criteria: Tests run on all major browsers
- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: Task 6.1
- Tools Needed: Playwright
Steps:
- Test
datasetAPI across browsers - Test getAttribute/setAttribute
- Test querySelector with data attributes
- Test special characters in attribute values
- Test very long attribute values (>1KB)
- Test non-ASCII characters
Success Criteria:
- All browsers support data attributes correctly
- No encoding issues
- Priority: 🟢 LOW
- Time Estimate: 2 days
- Dependencies: Task 6.1
- Tools Needed: Playwright
Steps:
- Test getComponentInfo in all browsers
- Test enableComponentHighlighting visual rendering
- Test MutationObserver support
- Test clipboard API
- Verify tooltip positioning
Success Criteria:
- All utilities work across browsers
- Graceful degradation for unsupported features
- Priority: 🟢 LOW
- Time Estimate: 1 day
- Dependencies: Task 6.1
- Tools Needed: BrowserStack (optional)
Steps:
- Test in older Safari versions (12-13)
- Identify polyfills needed
- Document browser support matrix
- Add graceful degradation
Success Criteria:
- Clear browser support documented
- Polyfills identified
- Priority: 🟡 MEDIUM
- Time Estimate: 1 day
- Dependencies: Task 6.1, Task 6.2
- Tools Needed: GitHub Actions, Playwright
Steps:
- Add Playwright test job to CI
- Run on all configured browsers
- Upload test results and screenshots
Success Criteria: Browser tests run in CI
- Priority: 🔴 HIGH
- Time Estimate: 1 day
- Dependencies: None
- Tools Needed: Threat modeling framework (STRIDE)
Steps:
- List all plugin assets
- Identify trust boundaries
- Map data flow
- Identify threat actors
- Create data flow diagram
Success Criteria:
- Complete asset inventory
- Trust boundaries documented
Assets:
- Source code files
- User configuration
- Babel AST
- Transformed output
- Statistics files
- NPM package
Trust Boundaries:
- User configuration (untrusted)
- Source code files (partially trusted)
- File system operations
- Callback functions (untrusted)
- Glob patterns (untrusted)
- Priority: 🔴 HIGH
- Time Estimate: 2 days
- Dependencies: Task 7.1
- Tools Needed: STRIDE framework
Steps:
- Analyze Spoofing threats
- Analyze Tampering threats
- Analyze Repudiation threats
- Analyze Information Disclosure threats
- Analyze Denial of Service threats
- Analyze Elevation of Privilege threats
- Document all threats
- Rate by severity
Success Criteria:
- Complete STRIDE analysis
- Threats prioritized
STRIDE Categories:
Spoofing (S)
- S1: Fake data-dev attributes in source
- S2: Package spoofing on npm
Tampering (T)
- T1: Malicious transformer modifying output
- T2: Path traversal in exportStats (✅ mitigated)
Repudiation (R)
- R1: No audit trail for callbacks
Information Disclosure (I)
- I1: Sensitive props in metadata
- I2: File paths revealing structure
Denial of Service (D)
- D1: ReDoS via glob patterns (✅ mitigated)
- D2: Memory exhaustion (✅ mitigated)
- D3: Infinite loop in callbacks
Elevation of Privilege (E)
- E1: Arbitrary code via callbacks
- E2: Prototype pollution (✅ mitigated)
- Priority: 🔴 HIGH
- Time Estimate: 1 day
- Dependencies: Task 7.2
- Tools Needed: Markdown
Steps:
- Create
SECURITY.mddocument - List all attack vectors
- Document mitigations
- Document known vulnerabilities
- Provide security best practices
- Add responsible disclosure policy
Success Criteria: Complete security documentation
Template:
# SECURITY.md
## Security Policy
### Supported Versions
- 2.x: Full security support
- 1.x: Critical fixes only
### Known Security Considerations
#### 1. User-Provided Callbacks (CRITICAL)
**Risk**: Arbitrary code execution
**Mitigation**: Callbacks run in build process
**Best Practice**: Never use untrusted callbacks
#### 2. Metadata Information Disclosure (HIGH)
**Risk**: Props may contain sensitive data
**Mitigation**: Set `includeProps: false` in production
**Best Practice**: Review metadata before enabling
### Reporting Vulnerabilities
Email: security@tonyebrown.com
Response time: 48 hours- Priority: 🔴 HIGH
- Time Estimate: 3 days
- Dependencies: Task 7.2, Task 7.3
- Tools Needed: None
Steps:
- Prioritize unmitigated threats
- Design mitigations for top 5 threats
- Implement mitigations (if feasible)
- Add security hardening options
- Document trade-offs
Success Criteria:
- Mitigations implemented or documented
- Security hardening options available
New Security Options:
export interface TagOptions {
/**
* Security: Timeout for user callbacks (ms)
* @default 5000
*/
callbackTimeout?: number;
/**
* Security: Enable audit logging
* @default false
*/
auditLog?: boolean;
/**
* Security: Sanitize metadata keys
* @default ['password', 'token', 'secret', 'apiKey']
*/
sanitizeMetadata?: string[];
}- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: None
- Tools Needed:
npm audit,snyk
Steps:
- Run
pnpm audit - Review dependency tree
- Check for known CVEs
- Set up Dependabot
- Add audit to CI pipeline
Success Criteria:
- No high/critical vulnerabilities
- Automated scanning enabled
GitHub Actions:
# .github/workflows/security.yml
name: Security Audit
on:
push:
pull_request:
schedule:
- cron: "0 0 * * 0" # Weekly
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- run: pnpm audit --audit-level=moderateDependabot:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10- Priority: 🟡 MEDIUM
- Time Estimate: 1 day
- Dependencies: None
- Tools Needed: Docker
Steps:
- Create isolated Docker container
- Set up test application
- Create malicious test payloads
- Document methodology
Success Criteria: Testing environment ready
- Priority: 🔴 HIGH
- Time Estimate: 3 days
- Dependencies: Task 8.1
- Tools Needed: Custom scripts
Steps:
- Test XSS via metadata
- Test script injection via customAttributes
- Test eval() exploitation
- Test template injection
- Test JSX injection
- Verify HTML escaping
Success Criteria:
- No code injection vulnerabilities
- All user input properly escaped
- Priority: 🔴 HIGH
- Time Estimate: 2 days
- Dependencies: Task 8.1
- Tools Needed: File system mocking
Steps:
- Test directory traversal in exportStats
- Test symlink attacks
- Test absolute path exploits
- Test Windows path tricks
- Test null byte injection
- Verify path normalization
Success Criteria: All path traversal attempts blocked
- Priority: 🔴 HIGH
- Time Estimate: 2 days
- Dependencies: Task 8.1
- Tools Needed: Custom scripts
Steps:
- Test ReDoS with catastrophic backtracking
- Test billion laughs attack
- Test zip bomb (deeply nested JSX)
- Test resource exhaustion
- Test algorithmic complexity attacks
- Verify timeouts and limits
Success Criteria: All DoS attempts mitigated
- Priority: 🟡 MEDIUM
- Time Estimate: 2 days
- Dependencies: Task 8.1
- Tools Needed: Custom malicious packages
Steps:
- Simulate compromised dependency
- Test with malicious AST
- Test with malicious glob matcher
- Verify no implicit trust
- Add runtime validation
Success Criteria:
- Plugin resilient to compromised dependencies
- Validation checks in place
| Week | Focus | Tasks |
|---|---|---|
| 1-2 | Foundation | Coverage tooling, Babel fuzzing, Glob fuzzing |
| 3-4 | Robustness | Error path coverage in plugin.ts and utils |
| 5-6 | Integration | Real Vite builds, E2E browser tests |
| 7-8 | Performance | Memory leak detection, Performance baselines |
| 9-10 | Security | Threat modeling, STRIDE analysis |
| 11-12 | Attacks | Penetration testing (injection, traversal, DoS) |
| 13-14 | Polish | Medium priority tasks, CI integration |
| 15 | Finalization | Low priority tasks, documentation |
Task 2.1 (Coverage) ──> Tasks 2.2, 2.3, 2.4, 2.5
Task 3.1 (Vite) ──> Tasks 3.2, 3.3, 4.4, 5.3
Task 4.1 (Memory) ──> Tasks 4.2, 4.3, 4.4, 4.5
Task 5.1 (Baseline) ──> Tasks 5.2, 5.3, 5.4, 5.5
Task 7.1 (Assets) ──> Tasks 7.2, 7.3, 7.4
Task 8.1 (Pentest) ──> Tasks 8.2, 8.3, 8.4, 8.5
- Target: 100% lines, branches, functions, statements
- Current: ~90% (estimate)
- Measurement:
pnpm test:coverage
- Target: 🟢 ZERO risk
- Current: 🟢 LOW risk
- Measurement: STRIDE analysis complete, all threats mitigated
- Target: <5% build time overhead, <200MB memory for 10K files
- Current: Unknown
- Measurement: Benchmark suite
- Target: No crashes in 100K+ fuzz iterations
- Current: Unknown
- Measurement: Fuzz test suite
- Target: Works in Chrome, Firefox, Safari, Edge (latest 2 versions)
- Current: Likely works, not tested
- Measurement: Playwright E2E tests
1. Install Coverage Tooling (2 hours)
pnpm add -D @vitest/coverage-v8
# Create vitest.config.ts
pnpm test:coverage2. Babel Parser Fuzzing (3 days)
pnpm add -D fast-check @jazzer.js/core
# Create src/__tests__/fuzzing/babel-parser.fuzz.test.ts3. Glob Pattern Fuzzing (2 days)
# Create src/__tests__/fuzzing/glob-patterns.fuzz.test.ts
# Test ReDoS patterns- Fuzzing:
fast-check,@jazzer.js/core,jsfuzz - Coverage:
@vitest/coverage-v8 - Integration:
@playwright/test,tmp - Memory:
memlab,@clinicjs/clinic - Performance:
tinybench,hyperfine - Security:
npm audit,snyk,socket.dev
This roadmap should be reviewed and updated:
- After completing each major category
- When new security threats are discovered
- When dependencies are upgraded
- Quarterly for relevance
Last Updated: 2025-09-30 Status: Planning Phase - Updated for AI-Assisted Development Next Review: After first 3 tasks completion (expected within 2-3 hours)
Total Time with AI Assistance: 8-12 hours (1-2 days)
- ✅ Task 1.1: AST Parser Fuzzing - 45-60 minutes
- ✅ Task 1.2: Glob Pattern Fuzzing - 30-45 minutes
- ✅ Task 1.3: Transformer Fuzzing - 20-30 minutes
- ✅ Task 1.4: Callback Fuzzing - 20-30 minutes
- ✅ Task 1.5: Configuration Fuzzing - 15-20 minutes
- ✅ Task 2.1: Coverage Setup - 2 hours
- ✅ Task 2.2: Error Path Coverage - 30-45 minutes
- ✅ Task 2.3: Edge Case Coverage - 20-30 minutes
- ✅ Task 3.1: Integration Tests - 45-60 minutes
- ✅ Task 3.2: Browser Tests - 60-90 minutes
- ✅ Memory & Performance Profiling - 30-45 minutes
- ✅ Remaining integration tests - 60-90 minutes
- ✅ Security auditing & documentation - 30-60 minutes
- ✅ CI/CD setup & final validation - 30-45 minutes
Key AI Advantages:
- Automated test generation and boilerplate code
- Instant fuzzing pattern creation
- Parallel task execution capabilities
- Real-time error detection and fixes
- Comprehensive edge case identification
- Auto-generated documentation and examples
This represents a 90%+ time reduction from traditional manual development!