release: WRNexusJS 0.7.0
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
import console from "node:console";
|
||||
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import process from "node:process";
|
||||
|
||||
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
let warned = 0;
|
||||
const failures = [];
|
||||
|
||||
function check(name, condition, detail = "") {
|
||||
if (condition) {
|
||||
passed += 1;
|
||||
console.log(` ok ${name}`);
|
||||
return;
|
||||
}
|
||||
failed += 1;
|
||||
failures.push(detail ? `${name}: ${detail}` : name);
|
||||
console.error(` FAIL ${name}${detail ? ` — ${detail}` : ""}`);
|
||||
}
|
||||
|
||||
function warn(name, detail = "") {
|
||||
warned += 1;
|
||||
console.warn(` warn ${name}${detail ? ` — ${detail}` : ""}`);
|
||||
}
|
||||
|
||||
function text(path) {
|
||||
return readFileSync(join(root, path), "utf8");
|
||||
}
|
||||
|
||||
function has(path, pattern) {
|
||||
const value = text(path);
|
||||
return typeof pattern === "string" ? value.includes(pattern) : pattern.test(value);
|
||||
}
|
||||
|
||||
const packageDirs = readdirSync(join(root, "packages"), { withFileTypes: true })
|
||||
.filter(
|
||||
(entry) =>
|
||||
entry.isDirectory() && existsSync(join(root, "packages", entry.name, "package.json")),
|
||||
)
|
||||
.map((entry) => entry.name);
|
||||
const manifests = packageDirs
|
||||
.map((dir) => ({
|
||||
dir,
|
||||
manifest: JSON.parse(text(`packages/${dir}/package.json`)),
|
||||
}))
|
||||
.filter(({ manifest }) => manifest.name?.startsWith("@wrnexus/"));
|
||||
|
||||
check("root version is 0.7.0", JSON.parse(text("package.json")).version === "0.7.0");
|
||||
const temporaryTypecheckFiles = ["focus-shims.d.ts", "tsconfig.focus.json"].filter((path) =>
|
||||
existsSync(join(root, path)),
|
||||
);
|
||||
const rootTsconfig = JSON.parse(text("tsconfig.json"));
|
||||
const rootExcludes = new Set(rootTsconfig.exclude ?? []);
|
||||
check(
|
||||
"root typecheck excludes temporary focused files",
|
||||
rootExcludes.has("focus-shims.d.ts") &&
|
||||
rootExcludes.has("tsconfig.focus.json") &&
|
||||
rootExcludes.has("**/focus-shims.d.ts") &&
|
||||
rootExcludes.has("**/tsconfig.focus.json"),
|
||||
"Keep the temporary focused typecheck files outside the root TypeScript program.",
|
||||
);
|
||||
if (temporaryTypecheckFiles.length > 0) {
|
||||
warn(
|
||||
"temporary focused typecheck files are local leftovers",
|
||||
`${temporaryTypecheckFiles.join(", ")} will be removed by: bun run repair:workspace`,
|
||||
);
|
||||
}
|
||||
check(
|
||||
"lint and formatting ignore temporary focused files",
|
||||
has("eslint.config.js", '"focus-shims.d.ts"') &&
|
||||
has("eslint.config.js", '"tsconfig.focus.json"') &&
|
||||
has(".prettierignore", "focus-shims.d.ts") &&
|
||||
has(".prettierignore", "tsconfig.focus.json"),
|
||||
"Temporary focused helpers must not create lint or formatting cascades before workspace repair.",
|
||||
);
|
||||
check(
|
||||
"all framework package versions align",
|
||||
manifests.every(({ manifest }) => manifest.version === "0.7.0"),
|
||||
[...new Set(manifests.map(({ manifest }) => manifest.version))].join(", "),
|
||||
);
|
||||
for (const name of ["security", "cache", "image", "observability", "benchmark"]) {
|
||||
check(
|
||||
`@wrnexus/${name} package exists`,
|
||||
existsSync(join(root, "packages", name, "src", "index.ts")),
|
||||
);
|
||||
}
|
||||
|
||||
check(
|
||||
"context-aware URL sanitizer is wired into compiler",
|
||||
has("packages/compiler/src/codegen.ts", "sanitizeUrlAttribute"),
|
||||
);
|
||||
check(
|
||||
"URL security checks avoid lint-blocked control-character regexes",
|
||||
has("packages/compiler/src/codegen.ts", "stripAsciiControlAndSpace") &&
|
||||
has("packages/security/src/url.ts", "hasAsciiControlOrSpace") &&
|
||||
has("packages/syntax/src/diagnostics.ts", "stripAsciiControlAndSpace") &&
|
||||
!has("packages/compiler/src/codegen.ts", /\\u0000-\\u0020/) &&
|
||||
!has("packages/security/src/url.ts", /\\u0000-\\u0020/) &&
|
||||
!has("packages/syntax/src/diagnostics.ts", /\\u0000-\\u0020/),
|
||||
"Use character-code checks instead of control-character regular expressions.",
|
||||
);
|
||||
check(
|
||||
"trusted HTML requires an explicit policy",
|
||||
has("packages/security/src/trusted-html.ts", "createTrustedHtml"),
|
||||
);
|
||||
check(
|
||||
"reactive URL updates are sanitized",
|
||||
has("packages/csr/src/reactive-runtime.ts", "sanitizeReactiveUrl"),
|
||||
);
|
||||
check(
|
||||
"SSR store state uses secure serialization",
|
||||
has("packages/ssr/src/store-context.ts", "serializeForHtml"),
|
||||
);
|
||||
check("prototype pollution keys are rejected", has("packages/security/src/object.ts", "__proto__"));
|
||||
check(
|
||||
"SSRF helper blocks private networks",
|
||||
has("packages/security/src/fetch.ts", "isPrivateAddress"),
|
||||
);
|
||||
check(
|
||||
"CSRF checks Origin and Fetch Metadata",
|
||||
has("packages/core/src/csrf.ts", /sec-fetch-site|validateOrigin/),
|
||||
);
|
||||
check(
|
||||
"security headers include CSP and isolation",
|
||||
has("packages/core/src/headers.ts", "Origin-Agent-Cluster"),
|
||||
);
|
||||
check(
|
||||
"request limits are automatic runtime middleware",
|
||||
has("packages/dev-server/src/runtime.ts", "requestHardening"),
|
||||
);
|
||||
check(
|
||||
"gateway enforces request limits",
|
||||
has("packages/dev-server/src/gateway.ts", "GatewayRequestLimits"),
|
||||
);
|
||||
check(
|
||||
"gateway enforces WebSocket limits",
|
||||
has("packages/dev-server/src/gateway.ts", "maxQueuedMessages"),
|
||||
);
|
||||
check(
|
||||
"realtime enforces per-room security",
|
||||
has("packages/core/src/realtime.ts", "RealtimeSecurityOptions"),
|
||||
);
|
||||
check(
|
||||
"database instrumentation detects N+1 patterns",
|
||||
has("packages/db/src/performance.ts", "WRN-DB-DUPLICATE-QUERY"),
|
||||
);
|
||||
check(
|
||||
"CSS performance audit is available",
|
||||
has("packages/styles/src/audit.ts", "WRN-CSS-TRANSITION-ALL"),
|
||||
);
|
||||
check(
|
||||
"static runtime analysis is exported",
|
||||
has("packages/compiler/src/analysis.ts", "analyzeRuntimeRequirements"),
|
||||
);
|
||||
check(
|
||||
"static pages default to zero framework JavaScript",
|
||||
has("packages/dev-server/src/runtime.ts", 'navigation.mode ?? "auto"') &&
|
||||
has("packages/dev-server/src/runtime.ts", "scripts.length > 0"),
|
||||
);
|
||||
check(
|
||||
"Brotli delivery is preferred",
|
||||
has("packages/dev-server/src/runtime.ts", "brotliCompressSync"),
|
||||
);
|
||||
check(
|
||||
"Happy DOM validation events and elements use one DOM type system",
|
||||
has("packages/validation/test/validation.test.ts", "type Event as HappyDOMEvent") &&
|
||||
has(
|
||||
"packages/validation/test/validation.test.ts",
|
||||
"type HTMLInputElement as HappyDOMHTMLInputElement",
|
||||
) &&
|
||||
has(
|
||||
"packages/validation/test/validation.test.ts",
|
||||
"type HTMLFormElement as HappyDOMHTMLFormElement",
|
||||
) &&
|
||||
has(
|
||||
"packages/validation/test/validation.test.ts",
|
||||
"function windowEvent(win: Window, type: string, init?: IEventInit): HappyDOMEvent",
|
||||
) &&
|
||||
!has(
|
||||
"packages/validation/test/validation.test.ts",
|
||||
/as unknown as (?:HTMLInputElement|HTMLFormElement|HTMLElement)/,
|
||||
),
|
||||
"Use Happy DOM Event and element types together; do not mix them with browser DOM globals.",
|
||||
);
|
||||
check(
|
||||
"DevToolbar security checks include CSRF",
|
||||
has("packages/dev-toolbar/src/rules/security.ts", "security/missing-csrf"),
|
||||
);
|
||||
check(
|
||||
"DevToolbar performance checks include hydration",
|
||||
has("packages/dev-toolbar/src/rules/performance.ts", "performance/hydration-count"),
|
||||
);
|
||||
check("release migration includes 0.7.0", has("packages/cli/src/update.ts", 'version: "0.7.0"'));
|
||||
check(
|
||||
"21-point implementation matrix exists",
|
||||
existsSync(join(root, "docs", "SECURITY-PERFORMANCE-0.7.md")),
|
||||
);
|
||||
check(
|
||||
"production audit script exists",
|
||||
existsSync(join(root, "scripts", "security-performance-audit.mjs")),
|
||||
);
|
||||
check(
|
||||
"workspace repair command exists",
|
||||
existsSync(join(root, "scripts", "repair-workspace.mjs")) &&
|
||||
existsSync(join(root, "scripts", "test-workspace-repair.mjs")) &&
|
||||
JSON.parse(text("package.json")).scripts?.["repair:workspace"] ===
|
||||
"node scripts/repair-workspace.mjs" &&
|
||||
JSON.parse(text("package.json")).scripts?.["check:workspace"] ===
|
||||
"node scripts/repair-workspace.mjs --check" &&
|
||||
has("scripts/release.ts", "check:workspace"),
|
||||
);
|
||||
check(
|
||||
"security audit scans Git-tracked release files",
|
||||
has("scripts/security-performance-audit.mjs", 'execFileSync("git", ["ls-files", "-z"]') &&
|
||||
has("scripts/security-performance-audit.mjs", "SEC-NO-TRACKED-SECRET-FILES"),
|
||||
);
|
||||
check("SBOM generator exists", existsSync(join(root, "scripts", "generate-sbom.mjs")));
|
||||
check(
|
||||
"SBOM includes transitive bun.lock packages",
|
||||
has("scripts/generate-sbom.mjs", "lock.packages"),
|
||||
);
|
||||
check(
|
||||
"SBOM parse errors preserve their original cause",
|
||||
has("scripts/generate-sbom.mjs", "{ cause: error }") &&
|
||||
has("scripts/test-workspace-repair.mjs", 'import process from "node:process"'),
|
||||
);
|
||||
check(
|
||||
"staged packages are secret-scanned and hashed",
|
||||
has("scripts/publish-packages.ts", "validateAndHashStage") &&
|
||||
has("scripts/publish-packages.ts", "PACKAGE-INTEGRITY.json"),
|
||||
);
|
||||
check("benchmark runner exists", existsSync(join(root, "scripts", "benchmark-framework.mjs")));
|
||||
check("release gate formats generated UI references", has("scripts/release.ts", "--write"));
|
||||
|
||||
console.log(`\n${passed} passed`);
|
||||
console.log(`${warned} warnings`);
|
||||
console.log(`${failed} failed`);
|
||||
if (failed) {
|
||||
console.error("\nFailures:");
|
||||
for (const failure of failures) console.error(`- ${failure}`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
Reference in New Issue
Block a user