* feat(javascript): recover readable modules with Wakaru Integrate pinned upstream source behind a typed optional recovery port, preserve source identity and producer provenance, and publish verified artifacts for existing JavaScript analysis through CLI and MCP. Add focused real-tool CI with genuine bundler fixtures and bounded resource, cancellation, cleanup, schema and packaged-artifact checks. Assisted-by: Yukari (gensokyo-skills:yukari-boundary-analysis) Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing) * fix(javascript): align recovery catalog and browser verification Share canonical Wakaru provider identity, describe CLI mode options, and format the new workflow test. Disconnect the real page transport after its observation readiness progress instead of a fixed delay. Assisted-by: Yukari (gensokyo-skills:yukari-boundary-analysis) Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing) * refactor(javascript): consume the investigation evidence writer Verify that the SDK recovery handler records complete Evidence through the newly shared investigation owner. Assisted-by: Yukari (gensokyo-skills:yukari-boundary-analysis) * chore(test): account for isolated recovery fixture compilers * fix(javascript): validate recovery paths before acquiring the engine Return field-specific invalid_format diagnostics for relative paths and verify compiled CLI/MCP parity even when the optional engine is unavailable. Assisted-by: Yukari (gensokyo-skills:yukari-boundary-analysis) Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
117 lines
5.6 KiB
JavaScript
117 lines
5.6 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",
|
|
javascriptRecoveryContracts:
|
|
"dist/contracts/javascriptRecoveryToolContracts.js",
|
|
javascriptRecoveryProvider: "dist/javascript/recovery/WakaruRelease.js",
|
|
supportedClients: "dist/application/SupportedClients.js",
|
|
hopperProvider: "dist/hopper/HopperProvider.js",
|
|
ghidraProvider: "dist/ghidra/GhidraProvider.js",
|
|
idaProvider: "dist/ida/IdaProviderCapabilities.js",
|
|
nativeProvider: "dist/native/NativeMacOSProviderMetadata.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),
|
|
]),
|
|
),
|
|
);
|