initial code
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createHash, webcrypto } from "node:crypto";
|
||||
import { readFileSync, readdirSync, statSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import {
|
||||
DataContractError,
|
||||
REQUIRED_ASSETS,
|
||||
SCHEMA_VERSION,
|
||||
loadDashboardData,
|
||||
validateAssetSet,
|
||||
} from "../js/data.js";
|
||||
|
||||
const DASHBOARD_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const PUBLIC_DATA = path.join(DASHBOARD_ROOT, "public", "data");
|
||||
|
||||
function json(filename) {
|
||||
return JSON.parse(readFileSync(path.join(PUBLIC_DATA, filename), "utf8"));
|
||||
}
|
||||
|
||||
function assetSet() {
|
||||
return Object.fromEntries(
|
||||
Object.entries(REQUIRED_ASSETS).map(([name, filename]) => [name, json(filename)]),
|
||||
);
|
||||
}
|
||||
|
||||
function publicDataFetch(overrides = new Map()) {
|
||||
return async (requestUrl) => {
|
||||
const filename = path.basename(new URL(String(requestUrl)).pathname);
|
||||
const source = path.join(PUBLIC_DATA, filename);
|
||||
let bytes;
|
||||
try {
|
||||
bytes = overrides.has(filename) ? overrides.get(filename) : readFileSync(source);
|
||||
} catch {
|
||||
return { ok: false, async arrayBuffer() { return new ArrayBuffer(0); } };
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
async arrayBuffer() {
|
||||
return Uint8Array.from(bytes).buffer;
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function filesRecursively(directory) {
|
||||
return readdirSync(directory).flatMap((name) => {
|
||||
const target = path.join(directory, name);
|
||||
return statSync(target).isDirectory() ? filesRecursively(target) : [target];
|
||||
});
|
||||
}
|
||||
|
||||
test("static shell exposes four semantic navigable views", () => {
|
||||
const html = readFileSync(path.join(DASHBOARD_ROOT, "index.html"), "utf8");
|
||||
assert.match(html, /<header\b/);
|
||||
assert.match(html, /<nav\b[^>]*aria-label="Dashboard views"/);
|
||||
assert.match(html, /<main\b/);
|
||||
assert.match(html, /<footer\b/);
|
||||
for (const route of ["overview", "reliability", "estimator", "methods"]) {
|
||||
assert.match(html, new RegExp(`data-route="${route}"`));
|
||||
assert.match(html, new RegExp(`data-view="${route}"`));
|
||||
}
|
||||
assert.match(html, /2025 development-sample holdout was evaluated once/i);
|
||||
assert.match(html, /<strong>One-time holdout<\/strong><small>Already evaluated<\/small>/);
|
||||
assert.doesNotMatch(html, /<strong>Locked test<\/strong>|<small>Final evaluation<\/small>/);
|
||||
});
|
||||
|
||||
test("estimator remains disabled and contains no identifying input", () => {
|
||||
const html = readFileSync(path.join(DASHBOARD_ROOT, "index.html"), "utf8");
|
||||
const estimator = html.match(/<section class="view" id="view-estimator"[\s\S]*?<\/section>/)?.[0];
|
||||
assert.ok(estimator, "estimator section is present");
|
||||
assert.match(estimator, /<fieldset disabled>/);
|
||||
const controlAttributes = [...estimator.matchAll(/<(?:input|select|textarea)\b([^>]*)>/g)].map(
|
||||
(match) => match[1],
|
||||
);
|
||||
for (const attributes of controlAttributes) {
|
||||
assert.doesNotMatch(
|
||||
attributes,
|
||||
/(?:name|id)\s*=\s*["'][^"']*(?:vin|plate|address|station|free.?text|zip)[^"']*["']/i,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("all required generated assets satisfy the browser contract", () => {
|
||||
const validated = validateAssetSet(assetSet());
|
||||
assert.equal(validated.manifest.schema_version, SCHEMA_VERSION);
|
||||
assert.equal(validated.manifest.development_preview, true);
|
||||
assert.equal(validated.manifest.population_estimate_allowed, false);
|
||||
assert.equal(validated.manifest.definitions.locked_test_metrics_published, false);
|
||||
assert.match(validated.manifest.release_id, /^[0-9a-f]{64}$/);
|
||||
assert.ok(validated.manifest.model_versions.length > 0);
|
||||
assert.deepEqual(
|
||||
validated.filters.partitions,
|
||||
["train", "tune", "calibrate"],
|
||||
);
|
||||
assert.ok(validated.overview.rows.length > 0);
|
||||
});
|
||||
|
||||
test("browser loader verifies every raw asset digest before rendering", async () => {
|
||||
const validated = await loadDashboardData({
|
||||
basePath: "http://dashboard.test/public/data/",
|
||||
fetchImplementation: publicDataFetch(),
|
||||
cryptoImplementation: webcrypto,
|
||||
});
|
||||
assert.equal(validated.manifest.schema_version, SCHEMA_VERSION);
|
||||
|
||||
const changedOverview = Buffer.concat([
|
||||
readFileSync(path.join(PUBLIC_DATA, REQUIRED_ASSETS.overview)),
|
||||
Buffer.from("\n"),
|
||||
]);
|
||||
await assert.rejects(
|
||||
loadDashboardData({
|
||||
basePath: "http://dashboard.test/public/data/",
|
||||
fetchImplementation: publicDataFetch(
|
||||
new Map([[REQUIRED_ASSETS.overview, changedOverview]]),
|
||||
),
|
||||
cryptoImplementation: webcrypto,
|
||||
}),
|
||||
(error) =>
|
||||
error instanceof DataContractError &&
|
||||
/Integrity verification failed for overview_period_county\.json/.test(error.message),
|
||||
);
|
||||
});
|
||||
|
||||
test("sha256 manifest covers and matches every approved data asset", () => {
|
||||
const manifest = json(REQUIRED_ASSETS.shaManifest);
|
||||
const expectedNames = Object.entries(REQUIRED_ASSETS)
|
||||
.filter(([name]) => name !== "shaManifest")
|
||||
.map(([, filename]) => filename)
|
||||
.sort();
|
||||
assert.deepEqual(
|
||||
manifest.files.map((file) => file.name).sort(),
|
||||
expectedNames,
|
||||
);
|
||||
for (const entry of manifest.files) {
|
||||
const digest = createHash("sha256")
|
||||
.update(readFileSync(path.join(PUBLIC_DATA, entry.name)))
|
||||
.digest("hex");
|
||||
assert.equal(digest, entry.sha256, `${entry.name} digest`);
|
||||
}
|
||||
});
|
||||
|
||||
test("contract fails closed for missing, inconsistent, or sensitive data", () => {
|
||||
const missing = assetSet();
|
||||
delete missing.overview;
|
||||
assert.throws(() => validateAssetSet(missing), DataContractError);
|
||||
|
||||
const inconsistent = assetSet();
|
||||
inconsistent.ageRisk.population_estimate_allowed = true;
|
||||
assert.throws(() => validateAssetSet(inconsistent), DataContractError);
|
||||
|
||||
const sensitive = assetSet();
|
||||
sensitive.scorecards.rows[0].vehicle_token = "not-public";
|
||||
assert.throws(() => validateAssetSet(sensitive), DataContractError);
|
||||
|
||||
const extraRowField = assetSet();
|
||||
extraRowField.overview.rows[0].note = "unapproved";
|
||||
assert.throws(() => validateAssetSet(extraRowField), DataContractError);
|
||||
|
||||
const lockedMetrics = assetSet();
|
||||
lockedMetrics.manifest.definitions.locked_test_metrics_published = true;
|
||||
assert.throws(() => validateAssetSet(lockedMetrics), DataContractError);
|
||||
|
||||
const extraPartition = assetSet();
|
||||
extraPartition.filters.partitions.push("locked_test");
|
||||
assert.throws(() => validateAssetSet(extraPartition), DataContractError);
|
||||
|
||||
const unsortedVersions = assetSet();
|
||||
unsortedVersions.manifest.model_versions = ["z_v1", "a_v1"];
|
||||
assert.throws(() => validateAssetSet(unsortedVersions), DataContractError);
|
||||
|
||||
const belowSuppression = assetSet();
|
||||
belowSuppression.overview.rows[0].support_rounded =
|
||||
belowSuppression.manifest.definitions.suppression_min_support - 1;
|
||||
assert.throws(() => validateAssetSet(belowSuppression), DataContractError);
|
||||
|
||||
const incorrectlyRounded = assetSet();
|
||||
incorrectlyRounded.coverage.rows[0].support_rounded += 1;
|
||||
assert.throws(() => validateAssetSet(incorrectlyRounded), DataContractError);
|
||||
});
|
||||
|
||||
test("dashboard source has no external runtime dependency or credential marker", () => {
|
||||
const sourceFiles = filesRecursively(DASHBOARD_ROOT).filter(
|
||||
(filename) =>
|
||||
!filename.includes(`${path.sep}public${path.sep}data${path.sep}`) &&
|
||||
!filename.includes(`${path.sep}tests${path.sep}`) &&
|
||||
/\.(?:html|css|js|mjs)$/.test(filename),
|
||||
);
|
||||
for (const filename of sourceFiles) {
|
||||
const source = readFileSync(filename, "utf8");
|
||||
assert.doesNotMatch(source, /(?:postgres(?:ql)?:\/\/|PGPASSWORD|PGHOST|countydata\.)/i);
|
||||
assert.doesNotMatch(source, /<script[^>]+src=["']https?:|@import\s+url\(["']?https?:/i);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user