refactor(artifacts): move inventory and extraction into provider owners (#1032)

This commit is contained in:
Ysopwnable
2026-10-08 05:51:14 +08:00
committed by GitHub
parent c6dad93208
commit 6e4535c101
36 changed files with 147 additions and 91 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ graph TD
GHIDRA["src/ghidra/<br/>Ghidra discovery, profile & function analysis<br/>snapshot, Unix/Windows transport, bounded lifecycle"]
IDA["src/ida/<br/>Upstream MCP contract adaptation<br/>live GUI binding or owned headless database"]
IDA_MCP["External ida-pro-mcp<br/>GUI proxy or database supervisor<br/>upstream installation and engine lifecycle"]
AUX["src/artifacts/ + src/native/<br/>disjoint artifact and native capabilities"]
AUX["src/artifacts/ + src/native/<br/>artifact inventory and extraction<br/>format readers and native capabilities"]
BROWSER["src/browser/<br/>CDP / Playwright capture<br/>captured scripts and native module resolution<br/>execution/: coverage, listener and source attribution"]
JS_CODEC["src/javascript/sourceMaps/<br/>pinned upstream map codec<br/>owned heap-limited Node process, complete point evidence"]
INSPECTOR["src/inspector/<br/>passive V8 Inspector discovery and capture<br/>script and target locations"]
+24
View File
@@ -385,6 +385,30 @@ claims. Actual Swift/Xcode, assetutil, native NIB, bundle signing and DMG lifecy
claims require the real Apple lane. Native binary API/value-flow semantics and
shared cross-domain contract aggregates keep their separate owners.
## Artifact inventory and extraction ownership
`src/artifacts/inventory/` owns format classification, reader selection, inventory
policy, canonical scanning and artifact graph construction. The shared artifact
provider and JavaScript reconstruction workflow consume this owner. Snapshot
semantics remain in `src/domain/artifactInventorySnapshot.ts`.
`src/artifacts/extraction/` owns member selection, integrity checks and transactional
materialization through the existing readers and safe output tree. Reader cleanup,
cancellation, rollback, archive containment and caller-visible results retain their
existing behavior. Acquisition guards reject imports from these producer owners
into application workflows, production composition or CLI/MCP adapters.
`src/application/artifacts/ArtifactExtractionDestination.ts` owns the caller's
default temporary output-root choice for both CLI and MCP. The adapters pass this
destination to the existing provider operation; format handling and member writes
remain in the artifact owner.
Add format-specific acquisition behavior beside the inventory readers and exercise
its actual producer representation in filesystem boundary tests. Add caller
workflow behavior in the application owner and verify both adapters. The installed
package lane checks inventory identity and extraction through CLI and MCP; the
real Apple bundle lane separately establishes DMG mount and detach behavior.
## Binary production composition closure
`src/composition/binary.ts` is the shared production owner for deep candidate
+2
View File
@@ -78,6 +78,8 @@ const failedBoundary = (file, target) => {
if (
(file.startsWith("src/artifacts/javascript/") ||
file.startsWith("src/artifacts/apple/") ||
file.startsWith("src/artifacts/inventory/") ||
file.startsWith("src/artifacts/extraction/") ||
/^src\/artifacts\/ArtifactHash\.(?:js|ts)$/u.test(file)) &&
(["application", "composition", "server", "cli", "main"].includes(
targetLayer,
+29 -4
View File
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
import { join } from "node:path";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { readFile, rm } from "node:fs/promises";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
@@ -167,6 +168,7 @@ const verifyMcpInlineArtifactEvidence = async (
mcpOptions,
);
assert.notEqual(opened.isError, true, JSON.stringify(opened));
let outputRoot;
try {
const inspected = await client.callTool(
{ name: "inspect_artifact", arguments: {} },
@@ -212,12 +214,35 @@ const verifyMcpInlineArtifactEvidence = async (
evidence,
);
}
} finally {
const closed = await client.callTool(
{ name: "close_binary", arguments: {} },
const extracted = await client.callTool(
{ name: "extract_artifact", arguments: {} },
mcpOptions,
);
assert.notEqual(closed.isError, true, JSON.stringify(closed));
assert.notEqual(extracted.isError, true, JSON.stringify(extracted));
const extraction = parseEvidence(extracted.structuredContent?.evidence);
assert.deepEqual(
extraction.normalized_result,
extracted.structuredContent?.result,
);
const materialized = extracted.structuredContent?.result;
assert.equal(typeof materialized?.output_root, "string");
outputRoot = materialized.output_root;
assert.equal(materialized.containment_verified, true);
assert.equal(
await readFile(join(outputRoot, "app/main.js"), "utf8"),
"main();",
);
} finally {
try {
const closed = await client.callTool(
{ name: "close_binary", arguments: {} },
mcpOptions,
);
assert.notEqual(closed.isError, true, JSON.stringify(closed));
} finally {
if (outputRoot !== undefined)
await rm(outputRoot, { recursive: true, force: true });
}
}
};
@@ -1,4 +1,4 @@
import type { ArtifactInventorySnapshot } from "../ArtifactInventory.js";
import type { ArtifactInventorySnapshot } from "../../artifacts/inventory/ArtifactInventory.js";
import {
createJavaScriptApplicationGraph,
type JavaScriptApplicationGraph,
@@ -1,4 +1,4 @@
import type { ArtifactInventorySnapshot } from "../ArtifactInventory.js";
import type { ArtifactInventorySnapshot } from "../../artifacts/inventory/ArtifactInventory.js";
import {
completeApplicationCoverage,
partialApplicationCoverage,
@@ -1,4 +1,4 @@
import type { ArtifactInventorySnapshot } from "../ArtifactInventory.js";
import type { ArtifactInventorySnapshot } from "../../artifacts/inventory/ArtifactInventory.js";
import type { ApplicationNode } from "../../domain/javascript/javascriptApplicationGraph.js";
import { completeApplicationCoverage } from "../../domain/javascript/javascriptApplicationEvidenceSchemas.js";
import type { JavaScriptArtifactAnalysis } from "./JavaScriptArtifactAnalysisTypes.js";
@@ -12,7 +12,7 @@ import {
javascriptArtifactReconstructionInputSchema,
type JavaScriptArtifactReconstructionInput,
} from "./JavaScriptArtifactReconstructionInput.js";
import { scanCanonicalArtifactInventory } from "../ArtifactInventory.js";
import { scanCanonicalArtifactInventory } from "../../artifacts/inventory/ArtifactInventory.js";
import { summarizeElectronBoundaries } from "./ElectronBoundaryAnalysis.js";
import { buildJavaScriptSemanticGraph } from "./JavaScriptSemanticGraphBuilder.js";
import type { ProgressReporter } from "../ProgressReporter.js";
+3 -3
View File
@@ -9,8 +9,8 @@ import {
} from "../application/AnalysisProvider.js";
import { inspectBundleKeyedArchive } from "./apple/KeyedArchiveReader.js";
import { basename, dirname } from "node:path";
import { inventoryArtifact } from "../application/ArtifactInventory.js";
import { extractArtifact } from "../application/ArtifactExtraction.js";
import { inventoryArtifact } from "./inventory/ArtifactInventory.js";
import { extractArtifact } from "./extraction/ArtifactExtraction.js";
import { analyzeInterfaceBuilderBundle } from "./apple/InterfaceBuilderAnalysis.js";
import { analyzeAppleAssetCatalogs } from "./apple/AppleAssetCatalogAnalysis.js";
import {
@@ -33,7 +33,7 @@ import {
} from "./ArtifactProviderMetadata.js";
import { createEvidence } from "../domain/evidence.js";
import { createArtifactInspection } from "../domain/artifactInspection.js";
import { resolveArtifactIntegrityPolicy } from "../application/ArtifactInventory/policy.js";
import { resolveArtifactIntegrityPolicy } from "./inventory/policy.js";
/** Read-only inventory and exclusively owned extraction provider. */
export class ArtifactProvider implements AnalysisProvider {
@@ -1,29 +1,29 @@
import { lstat, realpath } from "node:fs/promises";
import { canonicalDigest } from "../domain/comparisonSemantics.js";
import { AsarArtifactReader } from "../artifacts/AsarArtifactReader.js";
import { canonicalDigest } from "../../domain/comparisonSemantics.js";
import { AsarArtifactReader } from "../AsarArtifactReader.js";
import {
ArtifactPathRegistry,
normalizeArtifactPath,
} from "../artifacts/ArtifactPaths.js";
} from "../ArtifactPaths.js";
import {
ArtifactReaderFailure,
type ArtifactEntry,
type ArtifactReader,
} from "../artifacts/ArtifactReader.js";
import { DirectoryArtifactReader } from "../artifacts/DirectoryArtifactReader.js";
import { SafeOutputTree } from "../artifacts/SafeOutputTree.js";
import { ZipArtifactReader } from "../artifacts/ZipArtifactReader.js";
import { MachOSliceArtifactReader } from "../artifacts/MachOSliceArtifactReader.js";
} from "../ArtifactReader.js";
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
import { SafeOutputTree } from "../SafeOutputTree.js";
import { ZipArtifactReader } from "../ZipArtifactReader.js";
import { MachOSliceArtifactReader } from "../MachOSliceArtifactReader.js";
import {
artifactExtractionResultSchema,
type ArtifactExtractionResult,
type ArtifactGraphManifest,
type ArtifactNode,
type ArtifactOccurrence,
} from "../domain/artifactGraph.js";
import type { BinaryTarget } from "../domain/binaryTarget.js";
import { scanArtifactInventory } from "./ArtifactInventory.js";
} from "../../domain/artifactGraph.js";
import type { BinaryTarget } from "../../domain/binaryTarget.js";
import { scanArtifactInventory } from "../inventory/ArtifactInventory.js";
/** Local extraction input with the output root chosen by the adapter. */
export interface ArtifactExtractionInput {
@@ -1,13 +1,13 @@
import { canonicalDigest } from "../domain/comparisonSemantics.js";
import type { ArtifactEntry } from "../artifacts/ArtifactReader.js";
import { canonicalDigest } from "../../domain/comparisonSemantics.js";
import type { ArtifactEntry } from "../ArtifactReader.js";
import type {
ArtifactCommand,
ArtifactEdge,
ArtifactNode,
ArtifactOccurrence,
} from "../domain/artifactGraph.js";
import { zipPackageFormatForPath } from "../domain/zipPackageFormat.js";
import { mzWindowsHeaderOffset, parseDosMzHeader } from "../domain/dosMz.js";
} from "../../domain/artifactGraph.js";
import { zipPackageFormatForPath } from "../../domain/zipPackageFormat.js";
import { mzWindowsHeaderOffset, parseDosMzHeader } from "../../domain/dosMz.js";
/** Mutable internal occurrence used until root-bound IDs are known. */
export interface MutableOccurrence {
@@ -3,22 +3,22 @@ import { realpath } from "node:fs/promises";
import {
artifactInventoryResultSchema,
type ArtifactInventoryResult,
} from "../domain/artifactGraph.js";
import { abortIfNeeded } from "../artifacts/ArtifactHash.js";
import { scanCanonicalArtifactInventory } from "./ArtifactInventory/scanCanonical.js";
} from "../../domain/artifactGraph.js";
import { abortIfNeeded } from "../ArtifactHash.js";
import { scanCanonicalArtifactInventory } from "./scanCanonical.js";
import type {
ArtifactIntegrityPolicy,
ArtifactInventoryOptions,
ArtifactInventorySnapshot,
} from "./ArtifactInventory/types.js";
} from "./types.js";
export { scanCanonicalArtifactInventory } from "./ArtifactInventory/scanCanonical.js";
export { scanCanonicalArtifactInventory } from "./scanCanonical.js";
export type {
ArtifactIntegrityPolicy,
ArtifactInventoryOptions,
ArtifactInventorySnapshot,
} from "./ArtifactInventory/types.js";
} from "./types.js";
/** Inventory one local artifact and return every graph collection inline. */
export const inventoryArtifact = async (
@@ -1,7 +1,7 @@
import { open } from "node:fs/promises";
import { classifyArtifactContent } from "../ArtifactGraphConstruction.js";
import { ARTIFACT_CLASSIFICATION_PREFIX_BYTES } from "../../artifacts/ArtifactHash.js";
import { classifyArtifactContent } from "./ArtifactGraphConstruction.js";
import { ARTIFACT_CLASSIFICATION_PREFIX_BYTES } from "../ArtifactHash.js";
import type { ArtifactNode } from "../../domain/artifactGraph.js";
import {
hasZipSignature,
@@ -1,9 +1,9 @@
import { AsarArtifactReader } from "../../artifacts/AsarArtifactReader.js";
import type { ArtifactReader } from "../../artifacts/ArtifactReader.js";
import { DirectoryArtifactReader } from "../../artifacts/DirectoryArtifactReader.js";
import { MachOSliceArtifactReader } from "../../artifacts/MachOSliceArtifactReader.js";
import { NativeDmgArtifactReader } from "../../artifacts/NativeDmgArtifactReader.js";
import { ZipArtifactReader } from "../../artifacts/ZipArtifactReader.js";
import { AsarArtifactReader } from "../AsarArtifactReader.js";
import type { ArtifactReader } from "../ArtifactReader.js";
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
import { MachOSliceArtifactReader } from "../MachOSliceArtifactReader.js";
import { NativeDmgArtifactReader } from "../NativeDmgArtifactReader.js";
import { ZipArtifactReader } from "../ZipArtifactReader.js";
import type { ArtifactNode } from "../../domain/artifactGraph.js";
export const createReader = async (
@@ -5,7 +5,7 @@ import type { Stats } from "node:fs";
import {
ArtifactReaderFailure,
type ArtifactReader,
} from "../../artifacts/ArtifactReader.js";
} from "../ArtifactReader.js";
import {
artifactInventoryResultSchema,
type ArtifactInventoryResult,
@@ -20,10 +20,10 @@ import {
rekeyOccurrences,
rootOccurrenceFor,
type MutableOccurrence,
} from "../ArtifactGraphConstruction.js";
} from "./ArtifactGraphConstruction.js";
import { canonicalDigest } from "../../domain/comparisonSemantics.js";
import { classifyRoot } from "./classify.js";
import { hashReadable, type HashResult } from "../../artifacts/ArtifactHash.js";
import { hashReadable, type HashResult } from "../ArtifactHash.js";
import { createReader, inventoryLimitations } from "./reader.js";
import {
scanReader,
@@ -3,13 +3,13 @@ import { isAbsolute } from "node:path";
import {
ArtifactPathRegistry,
normalizeArtifactPath,
} from "../../artifacts/ArtifactPaths.js";
} from "../ArtifactPaths.js";
import {
ArtifactReaderFailure,
type ArtifactEntry,
type ArtifactReader,
} from "../../artifacts/ArtifactReader.js";
import { AsarArtifactReader } from "../../artifacts/AsarArtifactReader.js";
} from "../ArtifactReader.js";
import { AsarArtifactReader } from "../AsarArtifactReader.js";
import type { ArtifactNode } from "../../domain/artifactGraph.js";
import {
classifyArtifactContent,
@@ -17,12 +17,12 @@ import {
createOccurrence,
nearestParent,
type MutableOccurrence,
} from "../ArtifactGraphConstruction.js";
} from "./ArtifactGraphConstruction.js";
import {
STRICT_INTEGRITY_POLICY,
type ArtifactIntegrityPolicy,
} from "./types.js";
import { hashReadable } from "../../artifacts/ArtifactHash.js";
import { hashReadable } from "../ArtifactHash.js";
export interface PendingIntegrityContradiction {
readonly logicalPath: string;
+1 -1
View File
@@ -1,7 +1,7 @@
import { z } from "incur";
import { runProviderAnalysis } from "../composition/directAnalysis.js";
import { createArtifactExtractionDestination } from "../application/ArtifactExtractionDestination.js";
import { createArtifactExtractionDestination } from "../application/artifacts/ArtifactExtractionDestination.js";
import { logCliCommand } from "../cliLogging.js";
import { CLI_COMMANDS } from "../cliCommandNames.js";
import type { Logger } from "../logger.js";
+1 -1
View File
@@ -14,7 +14,7 @@ import { mcpProgressReporter } from "./mcpProgress.js";
import { logToolExecution } from "./toolLogging.js";
import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
import { toCallToolResult } from "./toolResult.js";
import { createArtifactExtractionDestination } from "../application/ArtifactExtractionDestination.js";
import { createArtifactExtractionDestination } from "../application/artifacts/ArtifactExtractionDestination.js";
interface EvidenceToolRegistration {
readonly logger: Logger;
@@ -3,7 +3,7 @@ import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { inventoryArtifact } from "../../../src/application/ArtifactInventory.js";
import { inventoryArtifact } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import { compareArtifacts } from "../../../src/domain/artifactComparison.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
@@ -5,7 +5,7 @@ import { TextReader, Uint8ArrayWriter, ZipWriter } from "@zip.js/zip.js";
import { describe, expect, it } from "vitest";
import { canonicalDigest } from "../../../src/domain/comparisonSemantics.js";
import { inventoryArtifact } from "../../../src/application/ArtifactInventory.js";
import { inventoryArtifact } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import { compareArtifacts } from "../../../src/domain/artifactComparison.js";
import type { ArtifactInventoryResult } from "../../../src/domain/artifactGraph.js";
import { createEvidence } from "../../../src/domain/evidence.js";
@@ -4,7 +4,7 @@ import { join } from "node:path";
import { createPackage } from "@electron/asar";
import { describe, expect, it } from "vitest";
import { inventoryArtifact } from "../../../src/application/ArtifactInventory.js";
import { inventoryArtifact } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import {
artifactOccurrenceAt,
artifactParentPaths,
@@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { scanArtifactInventory } from "../../../src/application/ArtifactInventory.js";
import { scanArtifactInventory } from "../../../src/artifacts/inventory/ArtifactInventory.js";
describe("artifact inventory snapshot", () => {
it("retains the complete scan after the source directory changes", async () => {
@@ -3,10 +3,10 @@ import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { classifyArtifactContent } from "../../../src/application/ArtifactGraphConstruction.js";
import { classifyRoot } from "../../../src/application/ArtifactInventory/classify.js";
import { classifyArtifactContent } from "../../../src/artifacts/inventory/ArtifactGraphConstruction.js";
import { classifyRoot } from "../../../src/artifacts/inventory/classify.js";
import { ARTIFACT_CLASSIFICATION_PREFIX_BYTES } from "../../../src/artifacts/ArtifactHash.js";
import { scanCanonicalArtifactInventory } from "../../../src/application/ArtifactInventory/scanCanonical.js";
import { scanCanonicalArtifactInventory } from "../../../src/artifacts/inventory/scanCanonical.js";
import { targetFormatSchema } from "../../../src/contracts/toolOutputSchemaPrimitives.js";
import { artifactInventoryResultSchema } from "../../../src/domain/artifactGraph.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
@@ -11,7 +11,7 @@ import {
} from "@zip.js/zip.js";
import { describe, expect, it } from "vitest";
import { inventoryArtifact } from "../../../src/application/ArtifactInventory.js";
import { inventoryArtifact } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import {
artifactOccurrenceAt,
artifactParentPaths,
@@ -5,7 +5,7 @@ import { buffer } from "node:stream/consumers";
import { createPackage, listPackage, uncache } from "@electron/asar";
import { describe, expect, it } from "vitest";
import { inventoryArtifact } from "../../../src/application/ArtifactInventory.js";
import { inventoryArtifact } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import { AsarArtifactReader } from "../../../src/artifacts/AsarArtifactReader.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
@@ -14,7 +14,7 @@ import { Readable } from "node:stream";
import { buffer } from "node:stream/consumers";
import { createPackageWithOptions } from "@electron/asar";
import { describe, expect, it } from "vitest";
import { scanArtifactInventory } from "../../../src/application/ArtifactInventory.js";
import { scanArtifactInventory } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import { AsarArtifactReader } from "../../../src/artifacts/AsarArtifactReader.js";
import {
closeAsarHandle,
@@ -4,7 +4,7 @@ import { join } from "node:path";
import { createPackage } from "@electron/asar";
import { describe, expect, it } from "vitest";
import { scanArtifactInventory } from "../../../src/application/ArtifactInventory.js";
import { scanArtifactInventory } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import { readJavaScriptArtifactFiles } from "../../../src/artifacts/javascript/JavaScriptArtifactFiles.js";
import { AsarArtifactReader } from "../../../src/artifacts/AsarArtifactReader.js";
import { DirectoryArtifactReader } from "../../../src/artifacts/DirectoryArtifactReader.js";
@@ -8,7 +8,7 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { readJavaScriptArtifactFiles } from "../../../src/artifacts/javascript/JavaScriptArtifactFiles.js";
import { reconstructJavaScriptArtifact } from "../../../src/application/javascript/JavaScriptArtifactReconstruction.js";
import { scanArtifactInventory } from "../../../src/application/ArtifactInventory.js";
import { scanArtifactInventory } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import {
type ArtifactEntry,
type ArtifactReader,
@@ -3,7 +3,7 @@ import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { classifyRoot } from "../../../src/application/ArtifactInventory/classify.js";
import { classifyRoot } from "../../../src/artifacts/inventory/classify.js";
import { parseBinaryTarget } from "../../../src/application/BinaryTargetResolver.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
@@ -6,7 +6,7 @@ import { describe, expect, it } from "vitest";
import { fragmentInventoryEvidence } from "../../fixtures/artifactEvidence.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { inventoryArtifact } from "../../../src/application/ArtifactInventory.js";
import { inventoryArtifact } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import { artifactInventoryResultSchema } from "../../../src/domain/artifactGraph.js";
import {
artifactComparisonResultSchema,
@@ -7,7 +7,7 @@ import { expect, it } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { reconstructJavaScriptArtifact } from "../../../src/application/javascript/JavaScriptArtifactReconstruction.js";
import { scanArtifactInventory } from "../../../src/application/ArtifactInventory.js";
import { scanArtifactInventory } from "../../../src/artifacts/inventory/ArtifactInventory.js";
import { parseJavaScriptApplicationGraph } from "../../../src/domain/javascript/javascriptApplicationGraph.js";
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
import { createJavaScriptSemanticGraph } from "../../../src/domain/javascript/javascriptSemanticGraph.js";
+29 -24
View File
@@ -76,7 +76,7 @@ describe("incremental module import boundaries", () => {
["src/contracts/probe.ts", "../composition/android.js", false],
[
"src/artifacts/javascript/probe.ts",
"../../application/ArtifactInventory.js",
"../../application/javascript/JavaScriptArtifactReconstruction.js",
false,
],
[
@@ -87,7 +87,7 @@ describe("incremental module import boundaries", () => {
["src/artifacts/javascript/probe.ts", "../../cli.js", false],
[
"src/artifacts/ArtifactHash.ts",
"../application/ArtifactInventory/hash.js",
"../application/artifacts/ArtifactExtractionDestination.js",
false,
],
[
@@ -111,11 +111,7 @@ describe("incremental module import boundaries", () => {
"../../artifacts/javascript/JavaScriptArtifactReader.js",
true,
],
[
"src/application/ArtifactInventory/probe.ts",
"../../artifacts/AsarArtifactReader.js",
true,
],
["src/artifacts/inventory/probe.ts", "../AsarArtifactReader.js", true],
["src/domain/probe.test.ts", "../composition/firmware.js", false],
["src/application/probe.ts", "../android/JadxProvider.js", false],
["src/application/probe.ts", "../composition/android.js", false],
@@ -329,21 +325,30 @@ describe("test lane import boundaries", () => {
});
});
describe("Apple artifact producer ownership", () => {
it.each([
["../../application/Workflow.js", false],
["../../composition/android.js", false],
["../../cli.js", false],
["../../domain/apple/plistValue.js", true],
["../DirectoryArtifactReader.js", true],
])("checks the producer dependency %s", (dependency, allowed) => {
const violations = inspectModuleBoundaries(
"src/artifacts/apple/probe.ts",
`import type { Value } from ${JSON.stringify(dependency)};`,
process.cwd(),
);
describe.each(["apple", "inventory", "extraction"])(
"%s artifact producer ownership",
(owner) => {
it.each([
["../../application/Workflow.js", false],
["../../composition/android.js", false],
["../../cli.js", false],
["../../server/registerEvidenceTools.js", false],
["../../main.ts", false],
["../../domain/apple/plistValue.js", true],
["../../domain/artifactInventorySnapshot.js", true],
["../../contracts/artifactGraph.js", true],
["../DirectoryArtifactReader.js", true],
["../ArtifactHash.js", true],
])("checks the producer dependency %s", (dependency, allowed) => {
const violations = inspectModuleBoundaries(
`src/artifacts/${owner}/probe.ts`,
`import type { Value } from ${JSON.stringify(dependency)};`,
process.cwd(),
);
expect(violations.length === 0).toBe(allowed);
if (!allowed) expect(violations[0]?.boundary).toBe("artifact-acquisition");
});
});
expect(violations.length === 0).toBe(allowed);
if (!allowed)
expect(violations[0]?.boundary).toBe("artifact-acquisition");
});
},
);