121 lines
4.6 KiB
TypeScript
121 lines
4.6 KiB
TypeScript
import { mkdir, readFile, readdir } from "node:fs/promises";
|
|
|
|
import { diagnosticsReportArtifactSchema } from "./contracts/release-artifacts.ts";
|
|
import { writeValidatedJsonArtifact } from "./lib/validated-json-artifact.ts";
|
|
import path from "node:path";
|
|
|
|
import { DIAGNOSTIC_EVENT_REGISTRY } from "../src/contracts/diagnostics.ts";
|
|
import { TELEMETRY_REGISTRY } from "../src/contracts/telemetry.ts";
|
|
|
|
const fixtureMode = process.argv.includes("--fixture");
|
|
const failures: string[] = [];
|
|
const extensions = /\.(?:ts|tsx|mts|cts)$/;
|
|
|
|
async function filesBelow(directory: string): Promise<string[]> {
|
|
const result: string[] = [];
|
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
const target = path.join(directory, entry.name);
|
|
if (entry.isDirectory()) result.push(...(await filesBelow(target)));
|
|
else if (extensions.test(entry.name)) result.push(target);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const telemetryProducerFiles: Readonly<Record<string, string>> = {
|
|
"app.boot.failed": "src/adapters/diagnostics/bounded-diagnostics.ts",
|
|
"api.request.failed": "src/adapters/http/client.ts",
|
|
"ui.render.failed": "src/application/create-application.ts",
|
|
"release.mismatch.detected": "src/application/create-application.ts",
|
|
"telemetry.delivery.dropped":
|
|
"src/adapters/telemetry/best-effort-telemetry.ts",
|
|
};
|
|
const diagnosticProducerFiles: Readonly<Record<string, string>> = {
|
|
"app.boot.failed": "src/adapters/diagnostics/bounded-diagnostics.ts",
|
|
"http.request.completed": "src/adapters/http/client.ts",
|
|
"cache.operation.failed":
|
|
"src/adapters/query-cache/tanstack-query-cache.ts",
|
|
"storage.operation.failed":
|
|
"src/adapters/storage/browser-storage-adapter.ts",
|
|
"route.changed": "src/application/create-application.ts",
|
|
"ui.render.failed": "src/application/create-application.ts",
|
|
"release.mismatch.detected": "src/application/create-application.ts",
|
|
"telemetry.delivery.dropped": "src/bootstrap/runtime-adapters.ts",
|
|
};
|
|
|
|
if (!fixtureMode) {
|
|
for (const eventName of Object.keys(TELEMETRY_REGISTRY)) {
|
|
const producer = telemetryProducerFiles[eventName];
|
|
if (!producer) {
|
|
failures.push(`telemetry event has no declared producer: ${eventName}`);
|
|
continue;
|
|
}
|
|
const source = await readFile(producer, "utf8");
|
|
if (!source.includes(`"${eventName}"`)) {
|
|
failures.push(`telemetry producer is not executable: ${eventName}`);
|
|
}
|
|
}
|
|
for (const eventId of Object.keys(DIAGNOSTIC_EVENT_REGISTRY)) {
|
|
const producer = diagnosticProducerFiles[eventId];
|
|
if (!producer) {
|
|
failures.push(`diagnostic event has no declared producer: ${eventId}`);
|
|
continue;
|
|
}
|
|
const source = await readFile(producer, "utf8");
|
|
if (!source.includes(`"${eventId}"`)) {
|
|
failures.push(`diagnostic producer is not executable: ${eventId}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
const sources = fixtureMode
|
|
? await filesBelow("tests/fixtures/diagnostics/forbidden")
|
|
: await filesBelow("src");
|
|
const sensitiveContext =
|
|
/\b(?:authorization|cookie|access_token|refresh_token|request_body|response_body|raw_url|query_string|email|user_name)\b/i;
|
|
for (const file of sources) {
|
|
const source = await readFile(file, "utf8");
|
|
if (file.includes("contracts/telemetry.ts")) continue;
|
|
if (source.includes("console.")) {
|
|
failures.push(`direct console diagnostics bypass in ${file}`);
|
|
}
|
|
const calls = source.match(
|
|
/(?:\.record\(\{|\.emit\()[\s\S]{0,700}?(?:\}\)|\}\);)/g,
|
|
) ?? [];
|
|
if (calls.some((call) => sensitiveContext.test(call))) {
|
|
failures.push(`sensitive diagnostic or telemetry context in ${file}`);
|
|
}
|
|
if (
|
|
file.includes("tests/fixtures/diagnostics/forbidden") &&
|
|
source.includes("UNKNOWN_DIAGNOSTIC_EVENT")
|
|
) {
|
|
failures.push(`unknown diagnostic event in ${file}`);
|
|
}
|
|
}
|
|
|
|
const report = diagnosticsReportArtifactSchema.parse({
|
|
schemaVersion: 1,
|
|
mode: fixtureMode ? "negative-fixture" : "source",
|
|
telemetryEventCount: Object.keys(TELEMETRY_REGISTRY).length,
|
|
diagnosticEventCount: Object.keys(DIAGNOSTIC_EVENT_REGISTRY).length,
|
|
checkedFiles: sources.length,
|
|
failures,
|
|
passed: failures.length === 0,
|
|
});
|
|
await mkdir("artifacts/quality", { recursive: true });
|
|
await writeValidatedJsonArtifact({
|
|
path: fixtureMode
|
|
? "artifacts/quality/diagnostics-fixture.json"
|
|
: "artifacts/quality/diagnostics.json",
|
|
schema: diagnosticsReportArtifactSchema,
|
|
value: report,
|
|
});
|
|
if (failures.length > 0) {
|
|
process.stderr.write(
|
|
`Diagnostics contract failed:\n${failures.join("\n")}\n`,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
process.stdout.write(
|
|
`Diagnostics contract: ${report.diagnosticEventCount} diagnostics and ${report.telemetryEventCount} telemetry producers PASS\n`,
|
|
);
|