* feat(web): export captured scripts for JavaScript application analysis Add capture adapters, conservative source path projection, verified exclusive publication and a shared CLI/MCP workflow. Retain source identities, missing content and competing URL versions in a complete manifest for existing static analysis. Refs: #774 Closes: #799 Assisted-by: Yukari (gensokyo-skills:yukari-boundary-analysis) Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing) * test(web): include script export in independent effect audit Register the new contract family in the independent inventory audit and verify the filesystem, session, network and idempotence metadata of the named export contract. Assisted-by: Yukari (gensokyo-skills:yukari-boundary-analysis) Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing) * fix(web): preserve capture limitation values in export manifests Align the export boundary with passive capture’s string contract instead of rejecting an admitted empty limitation. Cover the publisher boundary and regenerate canonical schemas and identities. Assisted-by: Yukari (gensokyo-skills:yukari-boundary-analysis) Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
114 lines
5.4 KiB
JavaScript
114 lines
5.4 KiB
JavaScript
import { createHash } from "node:crypto";
|
|
import { join } from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
import canonicalize from "canonicalize";
|
|
|
|
const load = (root, path) => import(pathToFileURL(join(root, path)).href);
|
|
|
|
/** Sort tool/provider names alphabetically. */
|
|
export const names = (contracts) =>
|
|
contracts
|
|
.map(({ name }) => name)
|
|
.sort((left, right) => left.localeCompare(right));
|
|
|
|
/** Return the stable digest for a generated catalog projection. */
|
|
export const digest = (value) => {
|
|
const encoded = canonicalize(value);
|
|
if (encoded === undefined)
|
|
throw new TypeError("Catalog projection is not canonical JSON");
|
|
return createHash("sha256").update(encoded).digest("hex");
|
|
};
|
|
|
|
/** Throw when two name lists diverge. */
|
|
export const assertSameNames = (label, actual, expected) => {
|
|
const actualSet = new Set(actual);
|
|
const expectedSet = new Set(expected);
|
|
const missing = [...expectedSet].filter((name) => !actualSet.has(name));
|
|
const extra = [...actualSet].filter((name) => !expectedSet.has(name));
|
|
if (missing.length === 0 && extra.length === 0) return;
|
|
throw new Error(
|
|
`${label} drifted (missing: ${missing.join(", ") || "none"}; extra: ${extra.join(", ") || "none"})`,
|
|
);
|
|
};
|
|
|
|
const SOURCE_PATHS = {
|
|
packageMetadata: "dist/generatedPackageMetadata.js",
|
|
catalogIdentity: "dist/catalogIdentity.js",
|
|
cli: "dist/cli.js",
|
|
toolContracts: "dist/contracts/toolContracts.js",
|
|
officialContracts: "dist/contracts/officialToolContracts.js",
|
|
enhancedContracts: "dist/contracts/enhancedToolContracts.js",
|
|
sessionContracts: "dist/contracts/sessionToolContracts.js",
|
|
nativeContracts: "dist/contracts/nativeToolContracts.js",
|
|
artifactContracts: "dist/contracts/artifactToolContracts.js",
|
|
managedContracts: "dist/contracts/managedToolContracts.js",
|
|
firmwareContracts: "dist/contracts/firmwareToolContracts.js",
|
|
firmwareProvider: "dist/firmware/FirmwareRelease.js",
|
|
androidContracts: "dist/contracts/androidToolContracts.js",
|
|
androidProvider: "dist/android/JadxRelease.js",
|
|
managedWorkflowContracts: "dist/contracts/managedWorkflowToolContracts.js",
|
|
browserContracts: "dist/contracts/browserToolContracts.js",
|
|
browserScenarioContracts: "dist/contracts/browserScenarioToolContracts.js",
|
|
electronContracts: "dist/contracts/electronToolContracts.js",
|
|
javascriptRuntimeObservationContracts:
|
|
"dist/contracts/javascriptRuntimeObservationToolContracts.js",
|
|
applicationContracts: "dist/contracts/applicationToolContracts.js",
|
|
webScriptContracts: "dist/contracts/webScriptToolContracts.js",
|
|
supportedClients: "dist/application/SupportedClients.js",
|
|
hopperProvider: "dist/hopper/HopperProvider.js",
|
|
ghidraProvider: "dist/ghidra/GhidraProvider.js",
|
|
idaProvider: "dist/ida/IdaProviderCapabilities.js",
|
|
nativeProvider: "dist/native/NativeMacOSProvider.js",
|
|
artifactProviders: "dist/application/InvestigationProviders.js",
|
|
browserProvider: "dist/browser/CdpBrowserProvider.js",
|
|
browserScenarioProvider: "dist/browser/PlaywrightBrowserScenarioProvider.js",
|
|
electronProvider: "dist/browser/CdpElectronProvider.js",
|
|
electronActiveProvider: "dist/browser/PlaywrightElectronActiveProvider.js",
|
|
v8InspectorProvider: "dist/browser/V8InspectorProvider.js",
|
|
evidence: "dist/domain/evidence.js",
|
|
evidenceBundle: "dist/domain/evidenceBundle.js",
|
|
evidenceCompletion: "dist/domain/evidenceCompletionLedger.js",
|
|
completionGeneration: "dist/domain/completionLedgerGeneration.js",
|
|
processCapture: "dist/domain/processCapture.js",
|
|
analysisSnapshot: "dist/domain/analysisSnapshot.js",
|
|
artifactGraph: "dist/domain/artifactGraph.js",
|
|
browserObservation: "dist/domain/browserObservation.js",
|
|
browserScenario: "dist/domain/browserScenario.js",
|
|
browserScenarioCapture: "dist/domain/browserScenarioCapture.js",
|
|
browserScenarioDiff: "dist/domain/browserScenarioDiff.js",
|
|
browserSession: "dist/domain/browserSession.js",
|
|
electronObservation: "dist/domain/electronObservation.js",
|
|
electronActiveObservation: "dist/domain/electronActiveObservation.js",
|
|
javascriptRuntimeObservation: "dist/domain/javascriptRuntimeObservation.js",
|
|
webBundleAnalysis: "dist/domain/webBundleAnalysis.js",
|
|
webCaptureDiff: "dist/domain/webCaptureDiff.js",
|
|
managedArtifact: "dist/domain/managedArtifact.js",
|
|
managedComparison: "dist/domain/managedMemberComparison.js",
|
|
managedNativeVerification: "dist/domain/managedNativeVerification.js",
|
|
webMcpDiscovery: "dist/domain/webMcpDiscovery.js",
|
|
webScreenshot: "dist/domain/webScreenshot.js",
|
|
javascriptApplicationGraph: "dist/domain/javascriptApplicationGraph.js",
|
|
javascriptApplicationAnalysis: "dist/domain/javascriptApplicationAnalysis.js",
|
|
javascriptSemanticGraph: "dist/domain/javascriptSemanticGraph.js",
|
|
javascriptSemanticQuery: "dist/domain/javascriptSemanticQuerySchemas.js",
|
|
javascriptSemanticTrace: "dist/domain/javascriptSemanticTraceSchemas.js",
|
|
javascriptFeatureTrace: "dist/domain/javascriptFeatureTraceSchemas.js",
|
|
javascriptVersionComparison:
|
|
"dist/domain/javascriptApplicationVersionComparisonSchemas.js",
|
|
reconstructionVerification:
|
|
"dist/domain/reconstructionVerificationSchemas.js",
|
|
residualUnknown: "dist/domain/residualUnknown.js",
|
|
};
|
|
|
|
/** Load every compiled source module referenced by the catalog. */
|
|
export const loadSources = async (root) =>
|
|
Object.fromEntries(
|
|
await Promise.all(
|
|
Object.entries(SOURCE_PATHS).map(async ([key, path]) => [
|
|
key,
|
|
await load(root, path),
|
|
]),
|
|
),
|
|
);
|