Files
WRNexusJS/packages/cli/src/report.ts
T
Clintchiz 586a6db8ff
Quality / quality (ubuntu-latest) (push) Failing after 21s
Quality / quality (windows-latest) (push) Canceled after 0s
release: WRNexusJS 0.8.0
2026-08-02 23:18:51 +05:30

128 lines
5.0 KiB
TypeScript

import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { basename, join, relative, resolve } from "node:path";
import { diagnose } from "@wrnexus/compiler";
import { currentCliVersion } from "./update-notifier.ts";
const SENSITIVE_KEY =
/(?:secret|token|password|passwd|credential|api[-_]?key|private[-_]?key|cookie|authorization|session|dsn|database[-_]?url)/i;
function sanitizeText(value: string): string {
return value
.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "[REDACTED_EMAIL]")
.replace(/\b(?:\d{1,3}\.){3}\d{1,3}\b/g, "[REDACTED_IP]")
.replace(/https?:\/\/[^\s"'`/]+/gi, (origin) =>
/localhost|127\.0\.0\.1|example\.(?:com|test|org)/i.test(origin)
? origin
: "https://[REDACTED_DOMAIN]",
)
.replace(/\b(?:sk|pk|wrn|ghp|xox[baprs])[_-][A-Za-z0-9_-]{12,}\b/g, "[REDACTED_TOKEN]")
.replace(
/((?:secret|token|password|apiKey|authorization|cookie)\s*[:=]\s*)(["'`])[^"'`]*\2/gi,
"$1$2[REDACTED]$2",
)
.slice(0, 512 * 1024);
}
function sanitizeValue(value: unknown, key = ""): unknown {
if (SENSITIVE_KEY.test(key)) return "[REDACTED]";
if (typeof value === "string") return sanitizeText(value);
if (Array.isArray(value)) return value.slice(0, 200).map((item) => sanitizeValue(item));
if (value && typeof value === "object")
return Object.fromEntries(
Object.entries(value)
.slice(0, 500)
.map(([name, item]) => [name, sanitizeValue(item, name)]),
);
return value;
}
function packageVersions(root: string) {
const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
};
return Object.fromEntries(
Object.entries({ ...manifest.dependencies, ...manifest.devDependencies }).sort(
([left], [right]) => left.localeCompare(right),
),
);
}
export interface ReproductionReportOptions {
file?: string;
error?: string;
output?: string;
command?: string[];
}
export function generateReproductionReport(
appRoot: string,
options: ReproductionReportOptions = {},
) {
const root = resolve(appRoot);
const selected = options.file ? resolve(root, options.file) : undefined;
if (
selected &&
(!relative(root, selected) ||
relative(root, selected).startsWith("..") ||
!existsSync(selected))
)
throw new Error("WRN-REPORT-FILE: selected source must exist inside the application.");
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
const output = resolve(root, options.output ?? join(".wrnexus", "reports", stamp));
if (!relative(root, output) || relative(root, output).startsWith(".."))
throw new Error("WRN-REPORT-OUTPUT: output must stay inside the application.");
mkdirSync(output, { recursive: true });
let source: string | undefined;
let diagnostics: unknown[] = [];
if (selected) {
source = readFileSync(selected, "utf8");
diagnostics = selected.endsWith(".wrn")
? diagnose(source, { file: basename(selected), accessibility: true })
: [];
writeFileSync(
join(output, `sanitized-${basename(selected)}`),
`${sanitizeText(source)}\n`,
"utf8",
);
}
const configNames = ["wrnexus.config.ts", "wrnexus.config.js", "wrnexus.config.mjs"];
const configFile = configNames.map((name) => join(root, name)).find(existsSync);
const commands = options.command?.length
? options.command
: [
"bun install --frozen-lockfile",
selected ? "bunx wrnexus typecheck ." : "bunx wrnexus doctor .",
"bunx wrnexus build .",
];
const report = sanitizeValue({
schemaVersion: 1,
frameworkVersion: currentCliVersion(),
runtime: { bun: Bun.version, platform: process.platform, architecture: process.arch },
source: selected ? relative(root, selected).replace(/\\/g, "/") : undefined,
diagnostics,
dependencies: packageVersions(root),
config: configFile ? sanitizeText(readFileSync(configFile, "utf8")) : undefined,
error: options.error,
commands,
});
const reportFile = join(output, "report.json");
writeFileSync(reportFile, `${JSON.stringify(report, null, 2)}\n`, "utf8");
writeFileSync(
join(output, "README.md"),
`# Sanitized WRNexus reproduction\n\nGenerated by WRNexus ${currentCliVersion()}. Review the bundle before sharing. Values matching secrets, credentials, emails, IPs and non-public domains are redacted.\n\n## Reproduce\n\n${commands.map((command) => `- \`${command}\``).join("\n")}\n`,
"utf8",
);
return {
directory: output,
reportFile,
sourceFile: selected ? join(output, `sanitized-${basename(selected)}`) : undefined,
};
}
export function runReport(appRoot: string, args: string[]) {
const option = (name: string) =>
args.find((value) => value.startsWith(`--${name}=`))?.slice(name.length + 3);
const result = generateReproductionReport(appRoot, {
file: option("file"),
error: option("error"),
output: option("output"),
});
console.log(`✓ Sanitized reproduction bundle: ${result.directory}`);
return result;
}