refactor(apple): group artifact producers and verification (#952)
* refactor(apple): group artifact producers and verification * test(apple): run affected native plist CLI regressions
This commit is contained in:
parent
a6ba772c08
commit
ef1a0cc65a
|
|
@ -311,7 +311,7 @@ jobs:
|
|||
- name: Real binary metadata and Interface Builder integration
|
||||
run: npm run verify:apple-dispatch && npm run verify:interface-builder
|
||||
- name: Native plist CLI selection regressions
|
||||
run: npm run test:focused -- tests/boundary/cli/nativePlistCli.test.ts
|
||||
run: npm run test:focused -- tests/boundary/cli/nativePlistCli.test.ts tests/boundary/cli/nativePlistPrototypeKeyCli.test.ts tests/boundary/cli/nativePlistSelectionFailureCli.test.ts
|
||||
|
||||
reconstruction-readiness:
|
||||
name: Reconstruction readiness
|
||||
|
|
|
|||
|
|
@ -356,3 +356,32 @@ repository-root default. Both point to `_reference/firmware-integration/generate
|
|||
when invoked through the documented npm commands. Optional ext4/Ghidra lanes keep
|
||||
their own prerequisites. Source-fixture generation and synthetic producer tests
|
||||
do not establish real Binwalk/Unblob analysis or another host's execution support.
|
||||
|
||||
## Apple artifact capability ownership
|
||||
|
||||
`src/domain/apple/` owns Apple application anatomy/projection, asset catalog
|
||||
facts, Interface Builder graphs, keyed archive semantics and plist values.
|
||||
`src/application/apple/AppleApplicationService.ts` retains the shared workflow
|
||||
that projects authenticated IPA/macOS inventory Evidence.
|
||||
|
||||
`src/artifacts/apple/` owns the actual producer boundary: directory acquisition,
|
||||
assetutil invocation, plist/NIB decoding, encoded view-parent interpretation and
|
||||
keyed archive inspection. These helpers are used by ArtifactProvider, retain
|
||||
its existing typed analysis boundary, injected assetutil seam and original reader
|
||||
cleanup, and do not require a new port for each helper. Producer code no longer
|
||||
lives in the application layer. Guards reject application/composition/caller
|
||||
imports from this owner while admitting pure facts and shared artifact readers.
|
||||
Adapter-source tests retain their assertions in the existing forked adapter lane.
|
||||
|
||||
`scripts/verify/apple/` groups archive, asset catalog, Interface Builder,
|
||||
Objective-C/Swift dispatch and macOS bundle verification. The macOS bundle fixture
|
||||
builder lives in `scripts/fixtures/apple/`; NIB byte fixtures stay beside their
|
||||
artifact decoder. Existing format-specific conformance sources and goldens keep
|
||||
their locations, and relocated verifiers resolve them against their own file
|
||||
URLs. Public npm entrypoints and CLI/MCP contracts stay stable; generated-document
|
||||
cache inputs include the relocated runtime scripts and fixture builder.
|
||||
|
||||
Portable decoder and injected producer tests establish their format/boundary
|
||||
claims. Actual Swift/Xcode, assetutil, native NIB, bundle signing and DMG lifecycle
|
||||
claims require the real Apple lane. Native binary API/value-flow semantics and
|
||||
shared cross-domain contract aggregates keep their separate owners.
|
||||
|
|
|
|||
|
|
@ -89,6 +89,12 @@ then checks that `inspect-artifact` plus `project-apple-application-graph`
|
|||
report the same bundle anatomy for all three through the CLI, with stdio MCP
|
||||
parity. It also checks that the DMG is detached afterwards. It runs in macOS CI.
|
||||
|
||||
Apple artifact verifiers live in `scripts/verify/apple/`, with the macOS bundle
|
||||
builder under `scripts/fixtures/apple/` and NIB byte fixtures beside the decoder
|
||||
in `src/artifacts/apple/`. The npm entrypoints are unchanged. Format-specific
|
||||
Swift/XIB/asset sources and goldens retain their locations; real Apple workflows
|
||||
resolve them from the verifier file URL and run in the macOS CI lane.
|
||||
|
||||
MCP SDK transport tests with recording providers remain integration tests.
|
||||
They are useful for schema drift and failure projection but do not prove that
|
||||
Hopper, Ghidra or another substituted engine works. `verify:package` proves
|
||||
|
|
|
|||
10
package.json
10
package.json
|
|
@ -121,17 +121,17 @@
|
|||
"typecheck": "tsc --noEmit",
|
||||
"verify:test-temp-hygiene": "npm run build:cached && node scripts/verify-test-temp-hygiene.mjs",
|
||||
"verify:hopper": "npm run verify:fixtures && npm run build:cached && node scripts/verify-real-hopper.mjs",
|
||||
"verify:apple-dispatch": "npm run build:cached && node scripts/verify-apple-dispatch.mjs",
|
||||
"verify:apple-dispatch": "npm run build:cached && node scripts/verify/apple/dispatch.mjs",
|
||||
"verify:native-ui": "npm run build:cached && node scripts/verify-native-ui.mjs",
|
||||
"verify:keyed-archive": "npm run build:cached && node scripts/verify-keyed-archive.mjs",
|
||||
"verify:macos-bundle": "npm run build:cached && node scripts/verify-macos-bundle.mjs",
|
||||
"verify:keyed-archive": "npm run build:cached && node scripts/verify/apple/keyed-archive.mjs",
|
||||
"verify:macos-bundle": "npm run build:cached && node scripts/verify/apple/macos-bundle.mjs",
|
||||
"verify:ghidra": "npm run build:cached && node scripts/verify-real-ghidra.mjs",
|
||||
"verify:ida": "npm run build:cached && node scripts/verify-real-ida.mjs",
|
||||
"verify:ghidra:switch": "npm run build:cached && node scripts/verify-real-ghidra-switch.mjs",
|
||||
"verify:ghidra:dos": "npm run build:cached && node scripts/verify-real-ghidra-dos.mjs",
|
||||
"verify:ghidra:com": "npm run build:cached && node scripts/verify-real-ghidra-com.mjs",
|
||||
"verify:ghidra:aarch64-jump-table": "npm run build:cached && node scripts/verify-real-ghidra.mjs --aarch64-jump-table",
|
||||
"verify:interface-builder": "npm run build:cached && node scripts/verify-interface-builder.mjs",
|
||||
"verify:interface-builder": "npm run build:cached && node scripts/verify/apple/interface-builder.mjs",
|
||||
"verify:ghidra:cross-format": "npm run build:cached && node scripts/verify-real-ghidra.mjs --cross-format",
|
||||
"verify:ghidra:windows": "npm run build:cached && npm run build:ghidra-windows-fixture && node scripts/verify-real-ghidra-windows.mjs",
|
||||
"verify:browser": "npm run build:cached && node scripts/verify-real-browser.mjs",
|
||||
|
|
@ -171,7 +171,7 @@
|
|||
"docs:error-schema": "npm run build:cached && node scripts/generate-error-schema.mjs",
|
||||
"prepack": "node scripts/prepack.mjs",
|
||||
"prepare": "node scripts/prepare.mjs",
|
||||
"verify:asset-catalog": "npm run build:cached && node scripts/verify-asset-catalog.mjs",
|
||||
"verify:asset-catalog": "npm run build:cached && node scripts/verify/apple/asset-catalog.mjs",
|
||||
"verify:native-ui:permissions": "npm run build:cached && node scripts/verify-native-ui.mjs --allow-permission-denial",
|
||||
"test:focused": "node scripts/run-development-tests.mjs focused",
|
||||
"build:windows-native": "node scripts/build-windows-native.mjs",
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ const failedBoundary = (file, target) => {
|
|||
return "provider-construction";
|
||||
if (
|
||||
(file.startsWith("src/artifacts/javascript/") ||
|
||||
file.startsWith("src/artifacts/apple/") ||
|
||||
/^src\/artifacts\/ArtifactHash\.(?:js|ts)$/u.test(file)) &&
|
||||
(["application", "composition", "server", "cli", "main"].includes(
|
||||
targetLayer,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
artifactCli,
|
||||
artifactMcpResult,
|
||||
withArtifactMcp,
|
||||
} from "./lib/artifact-e2e.mjs";
|
||||
} from "../../lib/artifact-e2e.mjs";
|
||||
|
||||
if (process.platform !== "darwin")
|
||||
throw new Error(
|
||||
|
|
@ -30,7 +30,7 @@ try {
|
|||
"clang",
|
||||
fileURLToPath(
|
||||
new URL(
|
||||
"../tests/conformance/interface-builder/fixture.c",
|
||||
"../../../tests/conformance/interface-builder/fixture.c",
|
||||
import.meta.url,
|
||||
),
|
||||
),
|
||||
|
|
@ -44,7 +44,10 @@ try {
|
|||
await exec("/usr/bin/xcrun", [
|
||||
"actool",
|
||||
fileURLToPath(
|
||||
new URL("../tests/conformance/native/Assets.xcassets", import.meta.url),
|
||||
new URL(
|
||||
"../../../tests/conformance/native/Assets.xcassets",
|
||||
import.meta.url,
|
||||
),
|
||||
),
|
||||
"--compile",
|
||||
resources,
|
||||
|
|
@ -4,8 +4,8 @@ import { tmpdir } from "node:os";
|
|||
import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
import { parseBinaryTarget } from "../dist/application/BinaryTargetResolver.js";
|
||||
import { inspectAppleDispatchMetadata } from "../dist/native/AppleDispatchMetadata.js";
|
||||
import { parseBinaryTarget } from "../../../dist/application/BinaryTargetResolver.js";
|
||||
import { inspectAppleDispatchMetadata } from "../../../dist/native/AppleDispatchMetadata.js";
|
||||
|
||||
if (process.platform !== "darwin")
|
||||
throw new Error(
|
||||
|
|
@ -14,7 +14,7 @@ if (process.platform !== "darwin")
|
|||
const exec = promisify(execFile);
|
||||
const source = (name) =>
|
||||
fileURLToPath(
|
||||
new URL(`../tests/conformance/native/${name}`, import.meta.url),
|
||||
new URL(`../../../tests/conformance/native/${name}`, import.meta.url),
|
||||
);
|
||||
|
||||
/** Both link modes: legacy LC_DYLD_INFO binds and the default chained fixups. */
|
||||
|
|
@ -8,8 +8,8 @@ import { join } from "node:path";
|
|||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
import { parseBinaryTarget } from "../dist/application/BinaryTargetResolver.js";
|
||||
import { ArtifactProvider } from "../dist/artifacts/ArtifactProvider.js";
|
||||
import { parseBinaryTarget } from "../../../dist/application/BinaryTargetResolver.js";
|
||||
import { ArtifactProvider } from "../../../dist/artifacts/ArtifactProvider.js";
|
||||
|
||||
const exec = promisify(execFile);
|
||||
const fixtureRoot = await mkdtemp(join(tmpdir(), "rea-interface-builder-"));
|
||||
|
|
@ -18,7 +18,7 @@ const resourcesPath = join(appPath, "Contents", "Resources");
|
|||
const executablePath = join(appPath, "Contents", "MacOS", "Fixture");
|
||||
const nibPath = join(resourcesPath, "Main.nib");
|
||||
const sourceRoot = fileURLToPath(
|
||||
new URL("../tests/conformance/interface-builder/", import.meta.url),
|
||||
new URL("../../../tests/conformance/interface-builder/", import.meta.url),
|
||||
);
|
||||
|
||||
try {
|
||||
|
|
@ -10,7 +10,7 @@ import {
|
|||
artifactCli,
|
||||
artifactMcpResult,
|
||||
withArtifactMcp,
|
||||
} from "./lib/artifact-e2e.mjs";
|
||||
} from "../../lib/artifact-e2e.mjs";
|
||||
|
||||
if (process.platform !== "darwin")
|
||||
throw new Error(
|
||||
|
|
@ -25,7 +25,7 @@ try {
|
|||
join(root, "modules"),
|
||||
fileURLToPath(
|
||||
new URL(
|
||||
"../tests/conformance/native/keyed-archive.swift",
|
||||
"../../../tests/conformance/native/keyed-archive.swift",
|
||||
import.meta.url,
|
||||
),
|
||||
),
|
||||
|
|
@ -66,7 +66,7 @@ try {
|
|||
const expected = JSON.parse(
|
||||
await readFile(
|
||||
new URL(
|
||||
"../tests/fixtures/golden/keyed-archive/graph.json",
|
||||
"../../../tests/fixtures/golden/keyed-archive/graph.json",
|
||||
import.meta.url,
|
||||
),
|
||||
"utf8",
|
||||
|
|
@ -124,7 +124,7 @@ try {
|
|||
join(root, "modules"),
|
||||
fileURLToPath(
|
||||
new URL(
|
||||
"../tests/conformance/native/keyed-archive-uid-root.swift",
|
||||
"../../../tests/conformance/native/keyed-archive-uid-root.swift",
|
||||
import.meta.url,
|
||||
),
|
||||
),
|
||||
|
|
@ -9,11 +9,11 @@ import {
|
|||
artifactCliEvidence,
|
||||
artifactMcpResult,
|
||||
withArtifactMcp,
|
||||
} from "./lib/artifact-e2e.mjs";
|
||||
} from "../../lib/artifact-e2e.mjs";
|
||||
import {
|
||||
buildMacosBundleFixture,
|
||||
preflightMacosBundleFixture,
|
||||
} from "./lib/macos-bundle-fixture.mjs";
|
||||
} from "../../fixtures/apple/macos-bundle.mjs";
|
||||
|
||||
const exec = promisify(execFile);
|
||||
|
||||
|
|
@ -3,7 +3,7 @@ import { z } from "zod";
|
|||
import type { AnalysisOperationPort } from "./AnalysisProvider.js";
|
||||
import type { EnhancedResult } from "./EnhancedToolTypes.js";
|
||||
import type { enhancedInputSchemas } from "../contracts/enhancedInputs.js";
|
||||
import { interfaceBuilderAnalysisSchema } from "../domain/interfaceBuilderGraph.js";
|
||||
import { interfaceBuilderAnalysisSchema } from "../domain/apple/interfaceBuilderGraph.js";
|
||||
import {
|
||||
nativeInvestigationGraphSchema,
|
||||
nativeInvestigationTraceSchema,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import type { AnalysisError } from "../domain/analysisErrorBase.js";
|
||||
import type { Evidence } from "../domain/evidence.js";
|
||||
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
|
||||
import type { Evidence } from "../../domain/evidence.js";
|
||||
import {
|
||||
appleApplicationProjectionInputSchema,
|
||||
projectAppleApplication,
|
||||
} from "../domain/appleApplication.js";
|
||||
import type { Result } from "../domain/result.js";
|
||||
import { APPLE_APPLICATION_PROVIDER } from "./InvestigationProviders.js";
|
||||
import { projectInventoryEvidence } from "./InventoryProjectionEvidence.js";
|
||||
} from "../../domain/apple/appleApplication.js";
|
||||
import type { Result } from "../../domain/result.js";
|
||||
import { APPLE_APPLICATION_PROVIDER } from "../InvestigationProviders.js";
|
||||
import { projectInventoryEvidence } from "../InventoryProjectionEvidence.js";
|
||||
|
||||
const OPERATION = "project_apple_application_graph" as const;
|
||||
|
||||
|
|
@ -7,12 +7,12 @@ import {
|
|||
type ProviderIdentity,
|
||||
type ExecutionOptions,
|
||||
} from "../application/AnalysisProvider.js";
|
||||
import { inspectBundleKeyedArchive } from "./KeyedArchiveReader.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 { analyzeInterfaceBuilderBundle } from "../application/InterfaceBuilderAnalysis.js";
|
||||
import { analyzeAppleAssetCatalogs } from "../application/AppleAssetCatalogAnalysis.js";
|
||||
import { analyzeInterfaceBuilderBundle } from "./apple/InterfaceBuilderAnalysis.js";
|
||||
import { analyzeAppleAssetCatalogs } from "./apple/AppleAssetCatalogAnalysis.js";
|
||||
import {
|
||||
ARTIFACT_ANALYSIS_OPERATIONS,
|
||||
artifactInventoryInputSchema,
|
||||
|
|
@ -24,7 +24,7 @@ import { AnalysisCapabilityUnavailableError } from "../domain/analysisErrorCore.
|
|||
import { ArtifactOperationError } from "../domain/artifactOperationError.js";
|
||||
import { type AnalysisError } from "../domain/analysisErrorBase.js";
|
||||
import type { JsonValue } from "../domain/jsonValue.js";
|
||||
import { interfaceBuilderLimitsSchema } from "../domain/interfaceBuilderGraph.js";
|
||||
import { interfaceBuilderLimitsSchema } from "../domain/apple/interfaceBuilderGraph.js";
|
||||
import { err, ok } from "../domain/result.js";
|
||||
import { ArtifactReaderFailure } from "./ArtifactReader.js";
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { createHash } from "node:crypto";
|
||||
import { lstat } from "node:fs/promises";
|
||||
import { DirectoryArtifactReader } from "../artifacts/DirectoryArtifactReader.js";
|
||||
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
||||
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
|
||||
import { ArtifactReaderFailure } from "../ArtifactReader.js";
|
||||
import { analyzeInterfaceBuilderBundle } from "./InterfaceBuilderAnalysis.js";
|
||||
import {
|
||||
appleAssetCatalogInputSchema,
|
||||
parseAppleAssetCatalogRecords,
|
||||
projectAppleAssetCatalogPage,
|
||||
} from "../domain/appleAssetCatalog.js";
|
||||
import { execFileOutput } from "../process/ExecFileOutput.js";
|
||||
} from "../../domain/apple/appleAssetCatalog.js";
|
||||
import { execFileOutput } from "../../process/ExecFileOutput.js";
|
||||
|
||||
const ASSETUTIL = "/usr/bin/assetutil";
|
||||
const MAX_CATALOG_BYTES = 64 * 1024 * 1024;
|
||||
|
|
@ -105,7 +105,7 @@ export const analyzeAppleAssetCatalogs = async (input: {
|
|||
|
||||
const inspectAssetCatalogEntry = async (input: {
|
||||
readonly reader: DirectoryArtifactReader;
|
||||
readonly entry: import("../artifacts/ArtifactReader.js").ArtifactEntry;
|
||||
readonly entry: import("../ArtifactReader.js").ArtifactEntry;
|
||||
readonly runAssetUtil: (
|
||||
path: string,
|
||||
signal?: AbortSignal,
|
||||
|
|
@ -237,7 +237,7 @@ const runAssetUtil = async (
|
|||
|
||||
const digestBounded = async (
|
||||
reader: DirectoryArtifactReader,
|
||||
entry: import("../artifacts/ArtifactReader.js").ArtifactEntry,
|
||||
entry: import("../ArtifactReader.js").ArtifactEntry,
|
||||
signal?: AbortSignal,
|
||||
): Promise<string> => {
|
||||
if (entry.declaredSize === null || entry.declaredSize > MAX_CATALOG_BYTES)
|
||||
|
|
@ -1,28 +1,25 @@
|
|||
import { createHash } from "node:crypto";
|
||||
import { parseBinary } from "plist";
|
||||
|
||||
import { DirectoryArtifactReader } from "../artifacts/DirectoryArtifactReader.js";
|
||||
import { projectPlistValue } from "../domain/plistValue.js";
|
||||
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
|
||||
import { projectPlistValue } from "../../domain/apple/plistValue.js";
|
||||
import {
|
||||
omittedPrototypeKeysLimitation,
|
||||
parseXmlPropertyList,
|
||||
} from "../domain/propertyListKeys.js";
|
||||
import {
|
||||
decodeNibArchive,
|
||||
type NibArchiveDocument,
|
||||
} from "../artifacts/NibArchive.js";
|
||||
import type { ArtifactEntry } from "../artifacts/ArtifactReader.js";
|
||||
} from "../../domain/propertyListKeys.js";
|
||||
import { decodeNibArchive, type NibArchiveDocument } from "./NibArchive.js";
|
||||
import type { ArtifactEntry } from "../ArtifactReader.js";
|
||||
import {
|
||||
buildInterfaceBuilderAnalysis,
|
||||
interfaceBuilderLimitsSchema,
|
||||
type InterfaceBuilderDocumentInput,
|
||||
} from "../domain/interfaceBuilderGraph.js";
|
||||
} from "../../domain/apple/interfaceBuilderGraph.js";
|
||||
import {
|
||||
mergeNibHierarchies,
|
||||
projectNibViewHierarchy,
|
||||
type NibHierarchyNode,
|
||||
} from "./NibViewHierarchy.js";
|
||||
import { jsonValueSchema, type JsonValue } from "../domain/jsonValue.js";
|
||||
import { jsonValueSchema, type JsonValue } from "../../domain/jsonValue.js";
|
||||
|
||||
const MAX_DOCUMENT_BYTES = 64 * 1024 * 1024;
|
||||
|
||||
|
|
@ -2,19 +2,19 @@ import { createHash } from "node:crypto";
|
|||
import { TextDecoder } from "node:util";
|
||||
import { parseBinary } from "plist";
|
||||
import { z } from "zod";
|
||||
import type { JsonValue } from "../domain/jsonValue.js";
|
||||
import { projectPlistValue } from "../domain/plistValue.js";
|
||||
import type { JsonValue } from "../../domain/jsonValue.js";
|
||||
import { projectPlistValue } from "../../domain/apple/plistValue.js";
|
||||
import {
|
||||
omittedPrototypeKeysLimitation,
|
||||
parseXmlPropertyList,
|
||||
} from "../domain/propertyListKeys.js";
|
||||
} from "../../domain/propertyListKeys.js";
|
||||
import {
|
||||
keyedArchiveInputSchema,
|
||||
keyedArchiveResultSchema,
|
||||
projectKeyedArchive,
|
||||
} from "../domain/keyedArchive.js";
|
||||
import { DirectoryArtifactReader } from "./DirectoryArtifactReader.js";
|
||||
import { ArtifactReaderFailure } from "./ArtifactReader.js";
|
||||
} from "../../domain/apple/keyedArchive.js";
|
||||
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
|
||||
import { ArtifactReaderFailure } from "../ArtifactReader.js";
|
||||
|
||||
const MAX_BYTES = 64 * 1024 * 1024;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import type { JsonValue } from "../domain/jsonValue.js";
|
||||
import type { JsonValue } from "../../domain/jsonValue.js";
|
||||
import { TextDecoder } from "node:util";
|
||||
|
||||
const MAGIC = Buffer.from("NIBArchive", "ascii");
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import type { NibArchiveDocument } from "../artifacts/NibArchive.js";
|
||||
import type { JsonValue } from "../domain/jsonValue.js";
|
||||
import type { NibArchiveDocument } from "./NibArchive.js";
|
||||
import type { JsonValue } from "../../domain/jsonValue.js";
|
||||
|
||||
export type NibHierarchyNode = {
|
||||
objectID: string;
|
||||
|
|
@ -2,7 +2,7 @@ import { reconstructionCoverageEvaluationInputSchema } from "../domain/reconstru
|
|||
import { Cli, z } from "incur";
|
||||
|
||||
import { projectAndroidApplicationEvidence } from "../application/android/AndroidApplicationService.js";
|
||||
import { projectAppleApplicationEvidence } from "../application/AppleApplicationService.js";
|
||||
import { projectAppleApplicationEvidence } from "../application/apple/AppleApplicationService.js";
|
||||
import {
|
||||
compareApplicationVersionsEvidenceValidated,
|
||||
compareJavaScriptExportShapesEvidenceValidated,
|
||||
|
|
@ -19,7 +19,7 @@ import { AnalysisInputError } from "../domain/analysisErrorCore.js";
|
|||
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
|
||||
import { type AnalysisError } from "../domain/analysisErrorBase.js";
|
||||
import { androidApplicationProjectionInputSchema } from "../domain/android/androidApplication.js";
|
||||
import { appleApplicationProjectionInputSchema } from "../domain/appleApplication.js";
|
||||
import { appleApplicationProjectionInputSchema } from "../domain/apple/appleApplication.js";
|
||||
import { jsonValueSchema, type JsonValue } from "../domain/jsonValue.js";
|
||||
import type { Logger } from "../logger.js";
|
||||
import { traceApplicationFeatureInputSchema } from "../domain/javascript/javascriptFeatureTraceSchemas.js";
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import {
|
|||
import {
|
||||
appleApplicationProjectionInputSchema,
|
||||
appleApplicationProjectionResultSchema,
|
||||
} from "../domain/appleApplication.js";
|
||||
} from "../domain/apple/appleApplication.js";
|
||||
import type { ToolContract } from "./toolContracts.js";
|
||||
import { toolContractMetadata } from "./toolEffects.js";
|
||||
import { evidenceResultOf } from "./toolOutputSchemas.js";
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import { artifactOutputSchemas } from "./toolOutputSchemas.js";
|
|||
import { jsonValueSchema } from "../domain/jsonValue.js";
|
||||
import { toolContractMetadata } from "./toolEffects.js";
|
||||
import { requireOutputSchema } from "./toolOutputSchemaPrimitives.js";
|
||||
import { appleAssetCatalogInputSchema } from "../domain/appleAssetCatalog.js";
|
||||
import { keyedArchiveInputSchema } from "../domain/keyedArchive.js";
|
||||
import { appleAssetCatalogInputSchema } from "../domain/apple/appleAssetCatalog.js";
|
||||
import { keyedArchiveInputSchema } from "../domain/apple/keyedArchive.js";
|
||||
/** Exact caller boundary for deterministic artifact inventory. */
|
||||
export const artifactInventoryInputSchema = z.strictObject({
|
||||
integrity_policy: z.enum(["fail", "record-and-continue"]).default("fail"),
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ import {
|
|||
} from "../domain/nativeInspection.js";
|
||||
import { artifactExtractionResultSchema } from "../domain/artifactGraph.js";
|
||||
import { artifactInspectionResultSchema } from "../domain/artifactInspection.js";
|
||||
import { interfaceBuilderAnalysisSchema } from "../domain/interfaceBuilderGraph.js";
|
||||
import { keyedArchiveResultSchema } from "../domain/keyedArchive.js";
|
||||
import { appleAssetCatalogResultSchema } from "../domain/appleAssetCatalog.js";
|
||||
import { interfaceBuilderAnalysisSchema } from "../domain/apple/interfaceBuilderGraph.js";
|
||||
import { keyedArchiveResultSchema } from "../domain/apple/keyedArchive.js";
|
||||
import { appleAssetCatalogResultSchema } from "../domain/apple/appleAssetCatalog.js";
|
||||
import {
|
||||
managedArtifactInspectionSchema,
|
||||
managedMemberInspectionSchema,
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { createHash } from "node:crypto";
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { projectAppleApplication } from "./appleApplication.js";
|
||||
import { canonicalDigest } from "./comparisonSemantics.js";
|
||||
import { createEvidence, type Evidence } from "./evidence.js";
|
||||
import { jsonValueSchema } from "./jsonValue.js";
|
||||
import { canonicalDigest } from "../comparisonSemantics.js";
|
||||
import { createEvidence, type Evidence } from "../evidence.js";
|
||||
import { jsonValueSchema } from "../jsonValue.js";
|
||||
|
||||
type EntryKind = "file" | "directory" | "symlink";
|
||||
type RootFormat = "ipa" | "zip" | "dmg" | "directory" | "asar";
|
||||
|
|
@ -14,10 +14,10 @@ import {
|
|||
platformsOf,
|
||||
type AppleInventoryEntry,
|
||||
} from "./appleBundleAnatomy.js";
|
||||
import { parseArtifactInventoryEvidence } from "./artifactInventoryEvidence.js";
|
||||
import { evidenceSchema } from "./evidence.js";
|
||||
import { digestSchema } from "./../domain/digests.js";
|
||||
import { prefixedDigestSchema } from "./../domain/digests.js";
|
||||
import { parseArtifactInventoryEvidence } from "../artifactInventoryEvidence.js";
|
||||
import { evidenceSchema } from "../evidence.js";
|
||||
import { digestSchema } from "../digests.js";
|
||||
import { prefixedDigestSchema } from "../digests.js";
|
||||
|
||||
const evidenceIdSchema = prefixedDigestSchema("ev");
|
||||
const pathSchema = z.string().min(1);
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { z } from "zod";
|
||||
|
||||
import { jsonValueSchema } from "./jsonValue.js";
|
||||
import { AnalysisOutputError } from "./analysisErrorCore.js";
|
||||
import { jsonValueSchema } from "../jsonValue.js";
|
||||
import { AnalysisOutputError } from "../analysisErrorCore.js";
|
||||
|
||||
/** Caller-controlled page bounds for compiled Apple asset metadata. */
|
||||
export const appleAssetCatalogInputSchema = z.strictObject({
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from "zod";
|
||||
|
||||
import { digestSchema, prefixedDigestSchema } from "./digests.js";
|
||||
import { digestSchema, prefixedDigestSchema } from "../digests.js";
|
||||
|
||||
const pathSchema = z.string().min(1);
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ import {
|
|||
nativeInvestigationGraphSchema,
|
||||
nativeInvestigationNodeSchema,
|
||||
nativeInvestigationTraceLimitsSchema,
|
||||
} from "./nativeInvestigationGraph.js";
|
||||
} from "../nativeInvestigationGraph.js";
|
||||
|
||||
export { parseInterfaceBuilderRecords } from "./interfaceBuilderKeyedArchive.js";
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from "zod";
|
||||
|
||||
import { jsonValueSchema } from "./jsonValue.js";
|
||||
import { jsonValueSchema } from "../jsonValue.js";
|
||||
|
||||
const recordSchema = z.record(z.string(), z.unknown());
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from "zod";
|
||||
import { jsonValueSchema, type JsonValue } from "./jsonValue.js";
|
||||
import { jsonValueSchema, type JsonValue } from "../jsonValue.js";
|
||||
|
||||
/** Select one archive within the active bundle and optionally one named root. */
|
||||
export const keyedArchiveInputSchema = z.strictObject({
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from "zod";
|
||||
|
||||
import type { JsonValue } from "./jsonValue.js";
|
||||
import type { JsonValue } from "../jsonValue.js";
|
||||
|
||||
const MAX_PLIST_DEPTH = 128;
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ import {
|
|||
import {
|
||||
buildInterfaceBuilderAnalysis,
|
||||
interfaceBuilderLimitsSchema,
|
||||
} from "./interfaceBuilderGraph.js";
|
||||
} from "./apple/interfaceBuilderGraph.js";
|
||||
|
||||
const evidence = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type { JsonValue } from "../../domain/jsonValue.js";
|
|||
import {
|
||||
projectPlistValue,
|
||||
type ProjectedPlistValue,
|
||||
} from "../../domain/plistValue.js";
|
||||
} from "../../domain/apple/plistValue.js";
|
||||
import {
|
||||
omitPrototypeKeys,
|
||||
omittedPrototypeKeysLimitation,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { McpServer } from "@modelcontextprotocol/server";
|
||||
|
||||
import { projectAndroidApplicationEvidence } from "../../application/android/AndroidApplicationService.js";
|
||||
import { projectAppleApplicationEvidence } from "../../application/AppleApplicationService.js";
|
||||
import { projectAppleApplicationEvidence } from "../../application/apple/AppleApplicationService.js";
|
||||
import {
|
||||
APPLICATION_TOOL_CONTRACTS,
|
||||
applicationToolContract,
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import { promisify } from "node:util";
|
|||
import { buildBinary } from "plist";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { analyzeInterfaceBuilderBundle } from "../../../src/application/InterfaceBuilderAnalysis.js";
|
||||
import { encodeNibArchiveFixture } from "../../../src/artifacts/NibArchive.fixture.js";
|
||||
import { analyzeInterfaceBuilderBundle } from "../../../src/artifacts/apple/InterfaceBuilderAnalysis.js";
|
||||
import { encodeNibArchiveFixture } from "../../../src/artifacts/apple/NibArchive.fixture.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
|
||||
const compile = promisify(execFile);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { decodeKeyedArchiveBytes } from "../../../src/artifacts/KeyedArchiveReader.js";
|
||||
import { decodeKeyedArchiveBytes } from "../../../src/artifacts/apple/KeyedArchiveReader.js";
|
||||
import {
|
||||
parseAppleAssetCatalogRecords,
|
||||
projectAppleAssetCatalogPage,
|
||||
} from "../../../src/domain/appleAssetCatalog.js";
|
||||
} from "../../../src/domain/apple/appleAssetCatalog.js";
|
||||
|
||||
const golden = (path: string) =>
|
||||
new URL(`../../fixtures/golden/${path}`, import.meta.url);
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import { promisify } from "node:util";
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { decodeNibArchive } from "../../../src/artifacts/NibArchive.js";
|
||||
import { analyzeInterfaceBuilderBundle } from "../../../src/application/InterfaceBuilderAnalysis.js";
|
||||
import { decodeNibArchive } from "../../../src/artifacts/apple/NibArchive.js";
|
||||
import { analyzeInterfaceBuilderBundle } from "../../../src/artifacts/apple/InterfaceBuilderAnalysis.js";
|
||||
|
||||
const compile = promisify(execFile);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { expect, it } from "vitest";
|
|||
import { z } from "zod";
|
||||
import { parseConfig } from "../../../src/config.js";
|
||||
import { createBinarySession } from "../../../src/application/runtime.js";
|
||||
import { keyedArchiveResultSchema } from "../../../src/domain/keyedArchive.js";
|
||||
import { keyedArchiveResultSchema } from "../../../src/domain/apple/keyedArchive.js";
|
||||
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { createTestBinarySession } from "../../fixtures/binarySession.js";
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { join } from "node:path";
|
|||
import { buildBinary, parse } from "plist";
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import { inspectBundleKeyedArchive } from "../../../../src/artifacts/KeyedArchiveReader.js";
|
||||
import { inspectBundleKeyedArchive } from "../../../../src/artifacts/apple/KeyedArchiveReader.js";
|
||||
import { nativeFixture } from "../../../fixtures/nativeCommands.js";
|
||||
import { createTestTempDirectory } from "../../../fixtures/temporaryDirectory.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ import {
|
|||
requireSuccessfulProjection,
|
||||
} from "../../support/applicationSessionFixture.js";
|
||||
|
||||
import { projectAppleApplicationEvidence } from "../../../src/application/AppleApplicationService.js";
|
||||
import { projectAppleApplicationEvidence } from "../../../src/application/apple/AppleApplicationService.js";
|
||||
import { runProviderAnalysis } from "../../../src/application/DirectAnalysis.js";
|
||||
import { appleApplicationProjectionResultSchema } from "../../../src/domain/appleApplication.js";
|
||||
import { appleApplicationProjectionResultSchema } from "../../../src/domain/apple/appleApplication.js";
|
||||
import { parseEvidence } from "../../../src/domain/evidence.js";
|
||||
|
||||
// Real ZIP entries cross the former component and bridge-candidate limits.
|
||||
|
|
|
|||
|
|
@ -272,3 +272,22 @@ describe("test lane import boundaries", () => {
|
|||
if (!allowed) expect(result.stdout).toContain("no-restricted-imports");
|
||||
});
|
||||
});
|
||||
|
||||
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(),
|
||||
);
|
||||
|
||||
expect(violations.length === 0).toBe(allowed);
|
||||
if (!allowed) expect(violations[0]?.boundary).toBe("artifact-acquisition");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@
|
|||
"scripts/lib/*.mjs",
|
||||
"scripts/verify/managed/*.mjs",
|
||||
"scripts/fixtures/managed/*.mjs",
|
||||
"scripts/verify/apple/*.mjs",
|
||||
"scripts/fixtures/apple/*.mjs",
|
||||
"src/generated*.ts",
|
||||
"src/contracts/**/*.ts",
|
||||
"docs/**",
|
||||
|
|
|
|||
Loading…
Reference in New Issue