mirror of
https://github.com/morluto/rea.git
synced 2026-11-13 02:02:36 +00:00
refactor(artifacts): consolidate inventory into inspection
This commit is contained in:
1 parent
a66e43a99d
commit
0fe96d92df
28 files changed
+375
-280
No files matched your search
@@ -2,7 +2,7 @@ import type { BinaryTarget } from "../domain/binaryTarget.js";
|
||||
import type { OfficialToolName } from "../contracts/toolContracts.js";
|
||||
import type { EnhancedToolName } from "../contracts/enhancedInputs.js";
|
||||
import type { NativeToolName } from "../contracts/nativeToolContracts.js";
|
||||
import type { ArtifactToolName } from "../contracts/artifactToolContracts.js";
|
||||
import type { ArtifactAnalysisOperation } from "../contracts/artifactToolContracts.js";
|
||||
import type { ManagedToolName } from "../contracts/managedToolContracts.js";
|
||||
import type { AnalysisError } from "../domain/errors.js";
|
||||
import type { AnalysisProfileCommitment } from "../domain/analysisProfile.js";
|
||||
@@ -25,7 +25,7 @@ export type AnalysisOperation =
|
||||
| OfficialToolName
|
||||
| EnhancedToolName
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| "health";
|
||||
|
||||
|
||||
@@ -126,19 +126,23 @@ export const resolveCompareApplicationVersionsRequestValidated = (
|
||||
input: CompareApplicationVersionsRequest,
|
||||
lookup?: EvidenceLookup,
|
||||
): Result<ComparisonInput, AnalysisError> => {
|
||||
const left = graphEvidence(
|
||||
"left" in input
|
||||
? { application: input.left }
|
||||
: { application_evidence_id: input.left_evidence_id },
|
||||
lookup,
|
||||
);
|
||||
const leftReference = input.left ?? input.left_evidence_id;
|
||||
if (leftReference === undefined)
|
||||
return err(
|
||||
new AnalysisInputError("compare_application_versions", undefined, [
|
||||
{ path: ["left"], reason: "missing_argument" },
|
||||
]),
|
||||
);
|
||||
const left = resolveApplicationGraphReference(leftReference, lookup);
|
||||
if (!left.ok) return left;
|
||||
const right = graphEvidence(
|
||||
"right" in input
|
||||
? { application: input.right }
|
||||
: { application_evidence_id: input.right_evidence_id },
|
||||
lookup,
|
||||
);
|
||||
const rightReference = input.right ?? input.right_evidence_id;
|
||||
if (rightReference === undefined)
|
||||
return err(
|
||||
new AnalysisInputError("compare_application_versions", undefined, [
|
||||
{ path: ["right"], reason: "missing_argument" },
|
||||
]),
|
||||
);
|
||||
const right = resolveApplicationGraphReference(rightReference, lookup);
|
||||
if (!right.ok) return right;
|
||||
const leftNative = resolveEvidenceReferences(
|
||||
lookup,
|
||||
@@ -265,6 +269,14 @@ const graphEvidence = (
|
||||
return resolved.ok ? ok(resolved.value[0]) : resolved;
|
||||
};
|
||||
|
||||
const resolveApplicationGraphReference = (
|
||||
reference: Evidence | string,
|
||||
lookup: EvidenceLookup | undefined,
|
||||
) =>
|
||||
typeof reference === "string"
|
||||
? graphEvidence({ application_evidence_id: reference }, lookup)
|
||||
: graphEvidence({ application: reference }, lookup);
|
||||
|
||||
const invalid = <Value>(
|
||||
operation: string,
|
||||
cause: z.ZodError,
|
||||
|
||||
@@ -37,6 +37,7 @@ export const binarySessionStatus = ({
|
||||
const provider = providerSummary(configuredProvider);
|
||||
const providers = router.providerIdentities(route).map(providerSummary);
|
||||
const capabilities = [...(route.capabilities?.values() ?? [])]
|
||||
.filter(({ operation }) => operation !== "inventory_artifact")
|
||||
.sort((left, right) => left.operation.localeCompare(right.operation))
|
||||
.map((descriptor) => {
|
||||
const unavailable = runtimeUnavailability.get(descriptor.operation);
|
||||
@@ -66,6 +67,7 @@ export const binarySessionStatus = ({
|
||||
selected: candidate.selected,
|
||||
capabilities: candidate.capabilities
|
||||
.slice()
|
||||
.filter(({ operation }) => operation !== "inventory_artifact")
|
||||
.sort((left, right) => left.operation.localeCompare(right.operation))
|
||||
.map(capabilityStatus),
|
||||
}));
|
||||
|
||||
@@ -7,7 +7,7 @@ import { silentLogger, type Logger } from "../logger.js";
|
||||
import { createEvidence } from "../domain/evidence.js";
|
||||
import type { Evidence } from "../domain/evidence.js";
|
||||
import type { NativeToolName } from "../contracts/nativeToolContracts.js";
|
||||
import type { ArtifactToolName } from "../contracts/artifactToolContracts.js";
|
||||
import type { ArtifactAnalysisOperation } from "../contracts/artifactToolContracts.js";
|
||||
import type { ManagedToolName } from "../contracts/managedToolContracts.js";
|
||||
import {
|
||||
EvidenceIntegrityError,
|
||||
@@ -92,7 +92,7 @@ export const runDirectAnalysis = async (
|
||||
export const runProviderAnalysis = async (
|
||||
...[path, tool, arguments_, logger = silentLogger, signal]: readonly [
|
||||
path: string,
|
||||
tool: NativeToolName | ArtifactToolName | ManagedToolName,
|
||||
tool: NativeToolName | ArtifactAnalysisOperation | ManagedToolName,
|
||||
arguments_: Readonly<Record<string, JsonValue>>,
|
||||
logger?: Logger,
|
||||
signal?: AbortSignal,
|
||||
@@ -110,7 +110,7 @@ const authorizeAnalysis = async (
|
||||
authority: PermissionAuthority,
|
||||
tool:
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| DirectAnalysisTool,
|
||||
arguments_: Readonly<Record<string, JsonValue>>,
|
||||
@@ -170,7 +170,7 @@ const authorizeSnapshotAccess = async (
|
||||
authority: PermissionAuthority,
|
||||
tool:
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| DirectAnalysisTool,
|
||||
snapshotPath: string | undefined,
|
||||
@@ -196,7 +196,7 @@ const authorizeAnalysisRun = async (input: {
|
||||
readonly suppliedAuthority: PermissionAuthority | undefined;
|
||||
readonly tool:
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| DirectAnalysisTool;
|
||||
readonly arguments: Readonly<Record<string, JsonValue>>;
|
||||
@@ -226,7 +226,7 @@ const runAnalysis = async (
|
||||
path: string,
|
||||
tool:
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| DirectAnalysisTool,
|
||||
arguments_: Readonly<Record<string, JsonValue>>,
|
||||
@@ -316,7 +316,7 @@ const executeAnalysisTool = async (input: {
|
||||
readonly openedTarget: BinaryTarget;
|
||||
readonly tool:
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| DirectAnalysisTool;
|
||||
readonly arguments: Readonly<Record<string, JsonValue>>;
|
||||
@@ -421,7 +421,7 @@ const replayProviderFor = (
|
||||
session: ReturnType<typeof createBinarySession>,
|
||||
tool:
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| DirectAnalysisTool,
|
||||
) =>
|
||||
@@ -433,7 +433,7 @@ const analysisProfileForEvidence = (
|
||||
session: ReturnType<typeof createBinarySession>,
|
||||
tool:
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| DirectAnalysisTool,
|
||||
): AnalysisProfileCommitment | undefined => {
|
||||
@@ -445,7 +445,7 @@ const analysisProfileForEvidence = (
|
||||
const isWorkflowEvidenceTool = (
|
||||
tool:
|
||||
| NativeToolName
|
||||
| ArtifactToolName
|
||||
| ArtifactAnalysisOperation
|
||||
| ManagedToolName
|
||||
| DirectAnalysisTool,
|
||||
): boolean =>
|
||||
|
||||
@@ -10,11 +10,10 @@ import {
|
||||
import { inventoryArtifactFully } from "../application/ArtifactInventory.js";
|
||||
import { extractArtifact } from "../application/ArtifactExtraction.js";
|
||||
import {
|
||||
ARTIFACT_TOOL_CONTRACTS,
|
||||
artifactInspectionInputSchema,
|
||||
ARTIFACT_ANALYSIS_OPERATIONS,
|
||||
artifactInventoryInputSchema,
|
||||
artifactExtractionExecutionSchema,
|
||||
type ArtifactToolName,
|
||||
type ArtifactAnalysisOperation,
|
||||
} from "../contracts/artifactToolContracts.js";
|
||||
import type { BinaryTarget } from "../domain/binaryTarget.js";
|
||||
import {
|
||||
@@ -46,10 +45,10 @@ export class ArtifactProvider implements AnalysisProvider {
|
||||
) {}
|
||||
|
||||
readonly #capabilities: readonly CapabilityDescriptor[] = Object.freeze(
|
||||
ARTIFACT_TOOL_CONTRACTS.map((contract) =>
|
||||
ARTIFACT_ANALYSIS_OPERATIONS.map((operation) =>
|
||||
Object.freeze({
|
||||
provider: IDENTITY,
|
||||
operation: contract.name,
|
||||
operation,
|
||||
available: true as const,
|
||||
reason: null,
|
||||
effects: Object.freeze({
|
||||
@@ -57,7 +56,7 @@ export class ArtifactProvider implements AnalysisProvider {
|
||||
launchesProcess: true,
|
||||
mayShowUi: false,
|
||||
mayAccessNetwork: false,
|
||||
mayWriteFilesystem: contract.name === "extract_artifact",
|
||||
mayWriteFilesystem: operation === "extract_artifact",
|
||||
changesPermissions: false,
|
||||
requiresRoot: false,
|
||||
}),
|
||||
@@ -169,7 +168,7 @@ class ArtifactClient implements AnalysisClient {
|
||||
parameters: Readonly<Record<string, JsonValue>>,
|
||||
options?: ExecutionOptions,
|
||||
) {
|
||||
const parsed = artifactInspectionInputSchema.parse(parameters);
|
||||
const parsed = artifactInventoryInputSchema.parse(parameters);
|
||||
const inventoryParameters = artifactInventoryInputSchema.parse({
|
||||
native_mount_approved: parsed.native_mount_approved,
|
||||
integrity_policy: parsed.integrity_policy,
|
||||
@@ -256,11 +255,13 @@ const DEFAULT_ARTIFACT_LIMITS: ArtifactLimits = {
|
||||
|
||||
const isArtifactOperation = (
|
||||
operation: AnalysisOperation,
|
||||
): operation is ArtifactToolName =>
|
||||
ARTIFACT_TOOL_CONTRACTS.some(({ name }) => name === operation);
|
||||
): operation is ArtifactAnalysisOperation =>
|
||||
ARTIFACT_ANALYSIS_OPERATIONS.includes(
|
||||
operation as (typeof ARTIFACT_ANALYSIS_OPERATIONS)[number],
|
||||
);
|
||||
|
||||
const translateFailure = (
|
||||
operation: ArtifactToolName,
|
||||
operation: ArtifactAnalysisOperation,
|
||||
cause: unknown,
|
||||
): AnalysisError => {
|
||||
if (cause instanceof ArtifactReaderFailure)
|
||||
|
||||
+30
-46
@@ -11,52 +11,10 @@ export const registerArtifactCommands = (
|
||||
cli: CliInstance,
|
||||
logger: Logger,
|
||||
): void => {
|
||||
registerInventoryCommand(cli, logger);
|
||||
registerInspectionCommand(cli, logger);
|
||||
registerExtractionCommand(cli, logger);
|
||||
};
|
||||
|
||||
const registerInventoryCommand = (cli: CliInstance, logger: Logger): void => {
|
||||
cli.command(CLI_COMMANDS.inventoryArtifact, {
|
||||
description: "Build a complete deterministic artifact graph",
|
||||
args: z.object({
|
||||
path: z.string().describe("Application or package path"),
|
||||
}),
|
||||
options: z.object({
|
||||
integrityPolicy: z
|
||||
.enum(["fail", "record-and-continue"])
|
||||
.default("fail")
|
||||
.describe("Behavior when declared artifact integrity does not match"),
|
||||
integrityContinueApproved: z
|
||||
.boolean()
|
||||
.default(false)
|
||||
.describe("Approve continuing after recorded integrity mismatches"),
|
||||
nativeMountApproved: z
|
||||
.boolean()
|
||||
.default(false)
|
||||
.describe("Approve read-only native mounting when required"),
|
||||
}),
|
||||
alias: {
|
||||
integrityPolicy: "integrity-policy",
|
||||
integrityContinueApproved: "integrity-continue-approved",
|
||||
nativeMountApproved: "native-mount-approved",
|
||||
},
|
||||
run: ({ args, options }) =>
|
||||
logCliCommand(logger, "inventory-artifact", () =>
|
||||
runProviderAnalysis(
|
||||
args.path,
|
||||
"inventory_artifact",
|
||||
{
|
||||
integrity_policy: options.integrityPolicy,
|
||||
integrity_continue_approved: options.integrityContinueApproved,
|
||||
native_mount_approved: options.nativeMountApproved,
|
||||
},
|
||||
logger,
|
||||
),
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
const registerExtractionCommand = (cli: CliInstance, logger: Logger): void => {
|
||||
cli.command(CLI_COMMANDS.extractArtifact, {
|
||||
description: "Extract explicitly selected artifact occurrences safely",
|
||||
@@ -67,7 +25,6 @@ const registerExtractionCommand = (cli: CliInstance, logger: Logger): void => {
|
||||
occurrenceIds: z
|
||||
.array(z.string().regex(/^occ_[a-f0-9]{64}$/u))
|
||||
.min(1)
|
||||
.max(500)
|
||||
.describe("Exact artifact occurrence IDs selected for extraction"),
|
||||
}),
|
||||
alias: { occurrenceIds: "occurrence-ids" },
|
||||
@@ -93,10 +50,37 @@ const registerInspectionCommand = (cli: CliInstance, logger: Logger): void => {
|
||||
args: z.object({
|
||||
path: z.string().describe("Application or package path"),
|
||||
}),
|
||||
options: z.object({}),
|
||||
run: ({ args }) =>
|
||||
options: z.object({
|
||||
integrityPolicy: z
|
||||
.enum(["fail", "record-and-continue"])
|
||||
.default("fail")
|
||||
.describe("Behavior when declared artifact integrity does not match"),
|
||||
integrityContinueApproved: z
|
||||
.boolean()
|
||||
.default(false)
|
||||
.describe("Approve continuing after recorded integrity mismatches"),
|
||||
nativeMountApproved: z
|
||||
.boolean()
|
||||
.default(false)
|
||||
.describe("Approve read-only native mounting when required"),
|
||||
}),
|
||||
alias: {
|
||||
integrityPolicy: "integrity-policy",
|
||||
integrityContinueApproved: "integrity-continue-approved",
|
||||
nativeMountApproved: "native-mount-approved",
|
||||
},
|
||||
run: ({ args, options }) =>
|
||||
logCliCommand(logger, "inspect-artifact", () =>
|
||||
runProviderAnalysis(args.path, "inspect_artifact", {}, logger),
|
||||
runProviderAnalysis(
|
||||
args.path,
|
||||
"inspect_artifact",
|
||||
{
|
||||
integrity_policy: options.integrityPolicy,
|
||||
integrity_continue_approved: options.integrityContinueApproved,
|
||||
native_mount_approved: options.nativeMountApproved,
|
||||
},
|
||||
logger,
|
||||
),
|
||||
),
|
||||
});
|
||||
};
|
||||
@@ -35,18 +35,8 @@ export const artifactExtractionInputSchema = z.object({
|
||||
export const artifactExtractionExecutionSchema =
|
||||
artifactExtractionInputSchema.extend({ output_root: z.string().min(1) });
|
||||
|
||||
/** Bounded provider-neutral inspection using one atomic inventory substep. */
|
||||
const artifactInspectionFacts = {
|
||||
native_mount_approved: z.boolean().default(false),
|
||||
} as const;
|
||||
export const artifactInspectionInputSchema = z.union([
|
||||
z.object({ ...artifactInspectionFacts, ...integrityInput.fail }),
|
||||
z.object({ ...artifactInspectionFacts, ...integrityInput.continue }),
|
||||
]);
|
||||
|
||||
const exampleInputSchema = z.record(z.string(), jsonValueSchema);
|
||||
const examples: Readonly<Record<string, Readonly<Record<string, unknown>>>> = {
|
||||
inventory_artifact: {},
|
||||
inspect_artifact: {},
|
||||
extract_artifact: {
|
||||
occurrence_ids: [`occ_${"0".repeat(64)}`],
|
||||
@@ -80,15 +70,10 @@ const artifact = <
|
||||
|
||||
/** Artifact-graph inventory and safe extraction contracts. */
|
||||
export const ARTIFACT_TOOL_CONTRACTS = [
|
||||
artifact(
|
||||
"inventory_artifact",
|
||||
"After open_binary binds a local archive, application package, or other artifact—or when one is already active—inventory the complete content-addressed artifact graph in one call. This tool accepts no path; in a target-free session open the target first. It does not extract or mount by default.",
|
||||
artifactInventoryInputSchema,
|
||||
),
|
||||
artifact(
|
||||
"inspect_artifact",
|
||||
"After open_binary binds a local archive, application package, or other artifact—or when one is already active—inspect the complete artifact inventory in one cancellable substep. This tool accepts no path; in a target-free session open the target first. Returns the full substep Evidence, observations, derived relationships, hypotheses, contradictions, unexplored branches, limitations, and format-specific next probes. Any substep failure fails the whole call.",
|
||||
artifactInspectionInputSchema,
|
||||
"Inspect an active archive or application package in one call. Returns the complete content-addressed artifact graph, source Evidence, observations, relationships, integrity contradictions, hypotheses, unexplored branches, limitations, and next probes inline. It does not extract files; use extract_artifact for selected occurrences.",
|
||||
artifactInventoryInputSchema,
|
||||
),
|
||||
artifact(
|
||||
"extract_artifact",
|
||||
@@ -97,5 +82,12 @@ export const ARTIFACT_TOOL_CONTRACTS = [
|
||||
),
|
||||
] as const satisfies readonly ToolContract[];
|
||||
|
||||
/** Names of provider-neutral artifact graph operations. */
|
||||
export type ArtifactToolName = (typeof ARTIFACT_TOOL_CONTRACTS)[number]["name"];
|
||||
/** Provider operations; inventory remains an internal primitive of inspection. */
|
||||
export const ARTIFACT_ANALYSIS_OPERATIONS = [
|
||||
"inventory_artifact",
|
||||
...ARTIFACT_TOOL_CONTRACTS.map(({ name }) => name),
|
||||
] as const;
|
||||
|
||||
/** Provider-level operations including the inventory primitive used internally. */
|
||||
export type ArtifactAnalysisOperation =
|
||||
(typeof ARTIFACT_ANALYSIS_OPERATIONS)[number];
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
type IntegrityContradiction,
|
||||
} from "./artifactGraph.js";
|
||||
import { parseEvidence, type Evidence } from "./evidence.js";
|
||||
import { artifactInspectionResultSchema } from "./artifactInspection.js";
|
||||
|
||||
/** Complete or partially assembled inventory used by comparison workflows. */
|
||||
export interface InventorySet {
|
||||
@@ -34,17 +35,25 @@ export const parseArtifactInventoryEvidence = (
|
||||
assembleInventorySet(
|
||||
(Array.isArray(input) ? input : [input]).map((value) => {
|
||||
const evidence = parseEvidence(value);
|
||||
if (evidence.operation !== "inventory_artifact")
|
||||
const inventoryEvidence =
|
||||
evidence.operation === "inventory_artifact"
|
||||
? evidence
|
||||
: evidence.operation === "inspect_artifact"
|
||||
? artifactInspectionResultSchema.parse(evidence.normalized_result)
|
||||
.substeps[0]?.evidence
|
||||
: undefined;
|
||||
if (inventoryEvidence === undefined)
|
||||
throw new TypeError(
|
||||
"Artifact comparison requires inventory_artifact Evidence",
|
||||
"Artifact comparison requires inspect_artifact Evidence",
|
||||
);
|
||||
const inventory = artifactInventoryResultSchema.parse(
|
||||
evidence.normalized_result,
|
||||
inventoryEvidence.normalized_result,
|
||||
);
|
||||
if (
|
||||
evidence.subject === null ||
|
||||
evidence.subject.digest.sha256 !== inventory.manifest.root_sha256 ||
|
||||
evidence.subject.format !== inventory.manifest.root_format
|
||||
inventoryEvidence.subject === null ||
|
||||
inventoryEvidence.subject.digest.sha256 !==
|
||||
inventory.manifest.root_sha256 ||
|
||||
inventoryEvidence.subject.format !== inventory.manifest.root_format
|
||||
)
|
||||
throw new TypeError(
|
||||
"Artifact inventory Evidence subject does not match its root digest",
|
||||
|
||||
@@ -30,7 +30,7 @@ interface GeneratedPayload {
|
||||
}
|
||||
|
||||
const GENERATED_PAYLOAD_JSON =
|
||||
'{"auxiliaryProviders":[{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory is macOS-only and requires per-call approval plus operator policy; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inventory_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory is macOS-only and requires per-call approval plus operator policy; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inspect_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory is macOS-only and requires per-call approval plus operator policy; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"extract_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null}],"identity":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"}},{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"inspect_macho","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"inspect_signature","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"inspect_plist","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"list_architectures","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"demangle_swift","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null}],"identity":{"id":"native-macos","name":"macOS native inspection utilities","version":null}},{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":false,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["This capability inventories PE/CLI identity only; inspect_managed_members admits bounded metadata members, signatures, and CIL anchors.","It never loads the target assembly, resolves dependencies through a CLR, decompiles C#, or executes target code."],"operation":"inspect_managed_artifact","provider":{"id":"rea-dotnet-static","name":"REA managed static analysis provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":false,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesysLine truncated
|
||||
'{"auxiliaryProviders":[{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory is macOS-only and requires per-call approval plus operator policy; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inventory_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory is macOS-only and requires per-call approval plus operator policy; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inspect_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory is macOS-only and requires per-call approval plus operator policy; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"extract_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null}],"identity":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"}},{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"inspect_macho","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"inspect_signature","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"inspect_plist","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"list_architectures","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"demangle_swift","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null}],"identity":{"id":"native-macos","name":"macOS native inspection utilities","version":null}},{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":false,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["This capability inventories PE/CLI identity only; inspect_managed_members admits bounded metadata members, signatures, and CIL anchors.","It never loads the target assembly, resolves dependencies through a CLR, decompiles C#, or executes target code."],"operation":"inspect_managed_artifact","provider":{"id":"rea-dotnet-static","name":"REA managed static analysis provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":false,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesysLine truncated
|
||||
const generatedPayload: unknown = JSON.parse(GENERATED_PAYLOAD_JSON);
|
||||
if (!isGeneratedPayload(generatedPayload))
|
||||
throw new TypeError("Generated MCP catalog payload is invalid");
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { AnalysisOperationPort } from "../application/AnalysisProvider.js";
|
||||
import type { BinarySessionPort } from "../application/BinarySession.js";
|
||||
import type { PromptCompletionKind } from "../contracts/promptContracts.js";
|
||||
import { artifactInventoryResultSchema } from "../domain/artifactGraph.js";
|
||||
import { artifactInspectionResultSchema } from "../domain/artifactInspection.js";
|
||||
import { processCaptureSchema } from "../domain/processCapture.js";
|
||||
|
||||
const documentListSchema = z.array(z.string().min(1));
|
||||
@@ -145,10 +146,21 @@ const evidenceValues = (
|
||||
if (kind === "evidence") return [evidence.evidence_id];
|
||||
if (kind === "capture")
|
||||
return isProcessCaptureEvidence(evidence) ? [evidence.evidence_id] : [];
|
||||
if (evidence.operation !== "inventory_artifact") return [];
|
||||
const inventory = artifactInventoryResultSchema.safeParse(
|
||||
evidence.normalized_result,
|
||||
);
|
||||
const inventoryResult =
|
||||
evidence.operation === "inventory_artifact"
|
||||
? evidence.normalized_result
|
||||
: evidence.operation === "inspect_artifact"
|
||||
? (() => {
|
||||
const inspection = artifactInspectionResultSchema.safeParse(
|
||||
evidence.normalized_result,
|
||||
);
|
||||
return inspection.success
|
||||
? inspection.data.substeps[0]?.evidence.normalized_result
|
||||
: undefined;
|
||||
})()
|
||||
: undefined;
|
||||
if (inventoryResult === undefined) return [];
|
||||
const inventory = artifactInventoryResultSchema.safeParse(inventoryResult);
|
||||
if (!inventory.success) return [];
|
||||
if (kind === "manifest") return [inventory.data.manifest.manifest_id];
|
||||
return inventory.data.occurrences.map(({ occurrence_id: id }) => id);
|
||||
|
||||
@@ -24,7 +24,7 @@ export const registerArtifactComparisonTool = (
|
||||
toolRegistrationOptions(contract),
|
||||
async (input, context) => {
|
||||
const expected = {
|
||||
operation: "inventory_artifact",
|
||||
operation: ["inspect_artifact", "inventory_artifact"],
|
||||
predicate: "rea.analysis/v2",
|
||||
};
|
||||
const left = resolveSessionEvidenceIds(
|
||||
|
||||
@@ -13,9 +13,16 @@ type EvidenceAuthorityResult = Result<Evidence[], EvidenceIntegrityError>;
|
||||
export const resolveSessionEvidenceIds = (
|
||||
session: BinarySessionPort,
|
||||
evidenceIds: readonly string[],
|
||||
expected: { readonly operation: string; readonly predicate: string },
|
||||
expected: {
|
||||
readonly operation: string | readonly string[];
|
||||
readonly predicate: string;
|
||||
},
|
||||
): EvidenceAuthorityResult => {
|
||||
const records: Evidence[] = [];
|
||||
const expectedOperations = Array.isArray(expected.operation)
|
||||
? expected.operation
|
||||
: [expected.operation];
|
||||
const expectedOperationLabel = expectedOperations.join(" or ");
|
||||
for (const evidenceId of evidenceIds) {
|
||||
const record = session.evidenceById(evidenceId);
|
||||
if (record === undefined)
|
||||
@@ -23,16 +30,16 @@ export const resolveSessionEvidenceIds = (
|
||||
new EvidenceReferenceError(
|
||||
evidenceId,
|
||||
"missing",
|
||||
expected.operation,
|
||||
expectedOperationLabel,
|
||||
null,
|
||||
),
|
||||
);
|
||||
if (record.operation !== expected.operation)
|
||||
if (!expectedOperations.includes(record.operation))
|
||||
return err(
|
||||
new EvidenceReferenceError(
|
||||
evidenceId,
|
||||
"wrong_operation",
|
||||
expected.operation,
|
||||
expectedOperationLabel,
|
||||
record.operation,
|
||||
),
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user