import { CLEAN_LEAKS, NO_GRAPHS, NO_INVENTORY, NO_LEAK_SET, NO_SEEDS, SOURCES_SUFFIX, TOKENS_SUFFIX, WROTE, } from "#configuration/strings/derivation.strings"; import { DERIVE_DESCRIBE, LEAK_SUMMARY } from "#configuration/strings/contract.strings"; import { DERIVE_FLAG, PRIVATE_ALLOWANCES, PRIVATE_TERMS } from "#configuration/constants/leak.constants"; import { conclude, refuse, say } from "#core/reporters/derivation.reporter"; import { deriveLeakSet, leakTarget, readLeakSet, workspaceRoots } from "#core/loaders/leak.loader"; import { hasFlag, resolveArgv } from "@govlab/argv"; import { inventoryTarget, readInventory } from "#core/loaders/inventory.loader"; import { machinePaths, publishedPaths, readPublished } from "#core/loaders/leak.output.loader"; import { readSeeds, seedsTarget } from "#core/loaders/seed.loader"; import { validatePayload, validatePublished } from "#core/validators/leak.validator"; import type { Finding } from "#types/derivation.types"; import { LEAK_COMMAND } from "#configuration/constants/contract.constants"; import { PAYLOAD_MISSING } from "#configuration/strings/coverage.strings"; import { defineCheck } from "@govlab/context/check"; import { loadContentGraphs } from "#core/loaders/coverage.loader"; import { persistJson } from "#core/persistence/report.persistence"; import { privateTermScanner } from "#core/matchers/leak.matcher"; import { readPagePayload } from "#core/loaders/payload.loader"; defineCheck({ detects: ["architecture:personal-data-oversharing"], enforces: ["architecture:privacy-by-design"] }); const argv = resolveArgv({ command: LEAK_COMMAND, flags: [{ describe: DERIVE_DESCRIBE, name: DERIVE_FLAG, takesValue: false }], summary: LEAK_SUMMARY, }); const derive = async function derive(): Promise { const inventory = readInventory(); if (inventory === null) { refuse(`${NO_INVENTORY}${inventoryTarget()}`); } const seeds = readSeeds(); if (seeds === null) { refuse(`${NO_SEEDS}${seedsTarget()}`); } const leaks = deriveLeakSet(inventory, seeds); const target = leakTarget(); await persistJson(target, leaks); say( `${WROTE}${target}: ${String(leaks.tokens.length)}${TOKENS_SUFFIX}${String(leaks.sources.length)}${SOURCES_SUFFIX}`, ); }; const validate = async function validate(): Promise { const leaks = readLeakSet(); if (leaks === null) { refuse(`${NO_LEAK_SET}${leakTarget()}`); } const graphs = await loadContentGraphs(); if (graphs.length === 0) { say(NO_GRAPHS); } const roots = workspaceRoots(); const findings: Finding[] = []; for (const graph of graphs) { const payload = readPagePayload(graph.page); if (payload === null) { findings.push({ file: graph.page, message: `${PAYLOAD_MISSING}${graph.page}` }); continue; } findings.push(...validatePayload(payload, leaks, roots)); } const scan = privateTermScanner(PRIVATE_TERMS, PRIVATE_ALLOWANCES); const machine = machinePaths(); for (const path of publishedPaths()) { findings.push(...validatePublished(readPublished(path), scan, machine)); } conclude(LEAK_COMMAND, findings, CLEAN_LEAKS); }; await (hasFlag(argv, DERIVE_FLAG) ? derive() : validate());