mirror of
https://github.com/morluto/rea.git
synced 2026-11-05 14:26:07 +00:00
* feat(artifacts): read Godot PCK packs Add a Godot Engine PCK artifact reader for standalone packs and packs embedded behind an executable trailer (formats 2 and 3). Members are uncompressed byte ranges verified against their declared MD5 on read. Encrypted directories, sparse bundles, patch removal entries, unknown flags and format 1 fail closed as unavailable; encrypted members are reported without being read. inspect-artifact and extract-artifact recognize standalone packs by their GDPC magic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(artifacts): bound Godot PCK metadata and own member streams Cap member paths at 4096 bytes and the retained directory at 64 MiB before allocation. Read members with positional chunk reads through pipeline so cancellation is typed, abandoned consumers release their source, and the shared descriptor stays reader-owned. Retain the root descriptor for godot-pck inventory, as for ZIP and universal Mach-O. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(artifacts): complete Godot PCK facts, integrity and selected views * fix(artifacts): preserve atomic-root inventory Evidence * fix(artifacts): bound aggregate PCK member expansion --------- Co-authored-by: Samucahub <151155051+Samucahub@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
307 lines
9.1 KiB
TypeScript
307 lines
9.1 KiB
TypeScript
import {
|
|
artifactIdForContent,
|
|
occurrenceIdForLocation,
|
|
artifactEdgeId,
|
|
artifactGraphDigest,
|
|
artifactManifestId,
|
|
} from "../artifactIdentity.js";
|
|
import { afterEach, expect, it, vi } from "vitest";
|
|
import { ARTIFACT_COMPARISON_EXAMPLE } from "../../contracts/artifactComparisonExample.js";
|
|
import { artifactInventoryResultSchema } from "../artifactGraph.js";
|
|
import { freezeJsonSnapshot } from "../immutableJson.js";
|
|
import {
|
|
artifactInventoryViewRequestSchema,
|
|
projectArtifactInventoryView,
|
|
} from "./artifactInventoryView.js";
|
|
import type { AnalysisViewParent } from "./analysisView.js";
|
|
|
|
const carrier = ARTIFACT_COMPARISON_EXAMPLE.left;
|
|
const freshInventory = () => {
|
|
const inventory = artifactInventoryResultSchema.parse(
|
|
carrier.normalized_result,
|
|
);
|
|
const root = inventory.occurrences[0]!;
|
|
const rootNode = inventory.nodes[0]!;
|
|
root.artifact_kind = "container";
|
|
root.artifact_format = "zip";
|
|
rootNode.format = "zip";
|
|
const sha256 = "1".repeat(64);
|
|
const child = {
|
|
...root,
|
|
occurrence_id: occurrenceIdForLocation({
|
|
rootArtifactId: rootNode.artifact_id,
|
|
logicalPath: "child.txt",
|
|
entryKind: "file",
|
|
}),
|
|
artifact_id: artifactIdForContent(sha256),
|
|
parent_occurrence_id: root.occurrence_id,
|
|
logical_path: "child.txt",
|
|
artifact_kind: "resource" as const,
|
|
artifact_format: "file" as const,
|
|
declared_size: 2,
|
|
limitations: [...root.limitations],
|
|
};
|
|
inventory.nodes.push({
|
|
...rootNode,
|
|
artifact_id: child.artifact_id,
|
|
sha256,
|
|
format: "file",
|
|
size: 2,
|
|
content_state: "embedded",
|
|
limitations: [...rootNode.limitations],
|
|
});
|
|
inventory.nodes.sort((left, right) =>
|
|
left.artifact_id < right.artifact_id
|
|
? -1
|
|
: left.artifact_id > right.artifact_id
|
|
? 1
|
|
: 0,
|
|
);
|
|
inventory.occurrences.push(child);
|
|
const edge = {
|
|
ordinal: 0,
|
|
parent_artifact_id: rootNode.artifact_id,
|
|
relation: "contains" as const,
|
|
occurrence_id: child.occurrence_id,
|
|
producer: null,
|
|
};
|
|
inventory.edges.push({ ...edge, edge_id: artifactEdgeId(edge, child) });
|
|
const graph = artifactGraphDigest({
|
|
nodes: inventory.nodes,
|
|
occurrences: inventory.occurrences,
|
|
edges: inventory.edges,
|
|
contradictions: inventory.integrity_contradictions,
|
|
});
|
|
inventory.manifest = {
|
|
...inventory.manifest,
|
|
root_format: "zip",
|
|
node_count: 2,
|
|
occurrence_count: 2,
|
|
edge_count: 1,
|
|
graph_sha256: graph,
|
|
manifest_id: artifactManifestId(rootNode.artifact_id, graph),
|
|
};
|
|
return inventory;
|
|
};
|
|
const parent = (normalizedResult: unknown): AnalysisViewParent => ({
|
|
evidenceId: carrier.evidence_id,
|
|
operation: "inventory_artifact",
|
|
subject:
|
|
carrier.subject === null
|
|
? null
|
|
: { ...carrier.subject, format: "zip", architecture: null },
|
|
normalizedResult,
|
|
sealedResult: true,
|
|
limitations: [],
|
|
});
|
|
const page = (source: AnalysisViewParent, view: unknown) => {
|
|
const result = projectArtifactInventoryView(
|
|
source,
|
|
artifactInventoryViewRequestSchema.parse(view),
|
|
);
|
|
if (!result.ok) throw result.error;
|
|
if (result.value.kind !== "inventory")
|
|
throw new Error("Expected an inventory page");
|
|
return result.value;
|
|
};
|
|
afterEach(() => vi.restoreAllMocks());
|
|
|
|
it("batches exact occurrence IDs in source order while retaining linkage with no selected fields", () => {
|
|
const inventory = freshInventory();
|
|
const selected = inventory.occurrences.slice(0, 2);
|
|
expect(selected).toHaveLength(2);
|
|
const result = page(parent(inventory), {
|
|
kind: "inventory",
|
|
collection: "occurrences",
|
|
occurrence_ids: [...selected]
|
|
.reverse()
|
|
.flatMap((row) => [row.occurrence_id, row.occurrence_id]),
|
|
fields: [],
|
|
});
|
|
expect(result.items).toEqual(
|
|
selected.map((row) => ({
|
|
occurrence_id: row.occurrence_id,
|
|
artifact_id: row.artifact_id,
|
|
parent_occurrence_id: row.parent_occurrence_id,
|
|
})),
|
|
);
|
|
expect(result.coverage.total).toBe(2);
|
|
});
|
|
|
|
it("intersects exact IDs and paths, then pages the filtered order", () => {
|
|
const inventory = freshInventory();
|
|
const selected = inventory.occurrences.slice(0, 2);
|
|
const result = page(parent(inventory), {
|
|
kind: "inventory",
|
|
collection: "occurrences",
|
|
occurrence_ids: selected.map((row) => row.occurrence_id),
|
|
logical_paths: selected.map((row) => row.logical_path),
|
|
fields: ["logical_path"],
|
|
offset: 1,
|
|
limit: 1,
|
|
});
|
|
expect(result.items).toEqual([
|
|
expect.objectContaining({
|
|
occurrence_id: selected[1]?.occurrence_id,
|
|
logical_path: selected[1]?.logical_path,
|
|
}),
|
|
]);
|
|
expect(result.coverage).toMatchObject({
|
|
total: 2,
|
|
examined: 1,
|
|
next_offset: null,
|
|
});
|
|
expect(
|
|
page(parent(inventory), {
|
|
kind: "inventory",
|
|
collection: "occurrences",
|
|
occurrence_ids: [selected[0]!.occurrence_id],
|
|
logical_paths: [selected[1]!.logical_path],
|
|
}).items,
|
|
).toEqual([]);
|
|
});
|
|
|
|
it.each([{ occurrence_ids: [] }, { logical_paths: [] }])(
|
|
"keeps an explicitly empty occurrence selection empty",
|
|
(filter) => {
|
|
expect(
|
|
page(parent(freshInventory()), {
|
|
kind: "inventory",
|
|
collection: "occurrences",
|
|
...filter,
|
|
}).items,
|
|
).toEqual([]);
|
|
},
|
|
);
|
|
|
|
it("fetches only selected content identities and fields, in canonical node order", () => {
|
|
const inventory = freshInventory();
|
|
const selected = inventory.nodes.slice(0, 2);
|
|
const result = page(parent(inventory), {
|
|
kind: "inventory",
|
|
collection: "nodes",
|
|
artifact_ids: [...selected].reverse().map((row) => row.artifact_id),
|
|
fields: ["sha256", "size"],
|
|
});
|
|
expect(result.items).toEqual(
|
|
selected.map((row) => ({
|
|
artifact_id: row.artifact_id,
|
|
sha256: row.sha256,
|
|
size: row.size,
|
|
})),
|
|
);
|
|
expect(
|
|
page(parent(inventory), {
|
|
kind: "inventory",
|
|
collection: "nodes",
|
|
artifact_ids: [selected[0]!.artifact_id],
|
|
fields: [],
|
|
}).items,
|
|
).toEqual([{ artifact_id: selected[0]!.artifact_id }]);
|
|
expect(
|
|
page(parent(inventory), {
|
|
kind: "inventory",
|
|
collection: "nodes",
|
|
artifact_ids: [],
|
|
}).items,
|
|
).toEqual([]);
|
|
});
|
|
|
|
it("does not fabricate a selected field absent from the owning report", () => {
|
|
const inventory = freshInventory();
|
|
expect(
|
|
page(parent(inventory), {
|
|
kind: "inventory",
|
|
collection: "occurrences",
|
|
fields: ["format_metadata"],
|
|
limit: 1,
|
|
}).items,
|
|
).toEqual([
|
|
{
|
|
occurrence_id: inventory.occurrences[0]!.occurrence_id,
|
|
artifact_id: inventory.occurrences[0]!.artifact_id,
|
|
parent_occurrence_id: inventory.occurrences[0]!.parent_occurrence_id,
|
|
},
|
|
]);
|
|
expect(() =>
|
|
artifactInventoryViewRequestSchema.parse({
|
|
kind: "inventory",
|
|
collection: "nodes",
|
|
fields: ["logical_path"],
|
|
}),
|
|
).toThrow();
|
|
});
|
|
|
|
it("borrows authenticated immutable facts and validates once across retained queries", () => {
|
|
const inventory = freezeJsonSnapshot(freshInventory());
|
|
const source = parent(inventory);
|
|
const parse = vi.spyOn(artifactInventoryResultSchema, "parse");
|
|
const first = page(source, {
|
|
kind: "inventory",
|
|
collection: "occurrences",
|
|
limit: 1,
|
|
});
|
|
expect(first.items[0]).toBe(inventory.occurrences[0]);
|
|
expect(parse).toHaveBeenCalledOnce();
|
|
page(source, {
|
|
kind: "inventory",
|
|
collection: "nodes",
|
|
artifact_ids: [inventory.nodes[0]!.artifact_id],
|
|
});
|
|
expect(parse).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it("does not reuse validation for a mutable object carrying a forged sealing flag", () => {
|
|
const inventory = freshInventory();
|
|
const source = parent(inventory);
|
|
page(source, { kind: "inventory", collection: "nodes", fields: [] });
|
|
inventory.manifest.graph_sha256 = "0".repeat(64);
|
|
expect(() =>
|
|
page(source, { kind: "inventory", collection: "nodes", fields: [] }),
|
|
).toThrow();
|
|
});
|
|
|
|
it("keeps a missing match unknown when retained inventory pages are partial", () => {
|
|
const inventory = freshInventory();
|
|
inventory.occurrences = inventory.occurrences.slice(0, 1);
|
|
const result = page(parent(inventory), {
|
|
kind: "inventory",
|
|
collection: "occurrences",
|
|
logical_paths: ["not-recorded"],
|
|
});
|
|
expect(result.source_complete).toBe(false);
|
|
expect(result.items).toEqual([]);
|
|
expect(result.unknowns.join(" ")).toContain(
|
|
"Missing matches do not establish absence",
|
|
);
|
|
});
|
|
|
|
it("binds reused facts to the current Evidence ID and validates its subject on every projection", () => {
|
|
const inventory = freezeJsonSnapshot(freshInventory());
|
|
const first = parent(inventory);
|
|
page(first, { kind: "inventory", collection: "nodes", fields: [] });
|
|
const next = { ...first, evidenceId: `ev_${"f".repeat(64)}` };
|
|
expect(
|
|
page(next, { kind: "inventory", collection: "nodes", fields: [] })
|
|
.inventory_evidence_ids,
|
|
).toEqual([next.evidenceId]);
|
|
const subject = next.subject;
|
|
if (subject === null || subject === undefined)
|
|
throw new Error("Expected a subject");
|
|
expect(() =>
|
|
page(
|
|
{
|
|
...next,
|
|
subject: { ...subject, digest: { sha256: "f".repeat(64) } },
|
|
},
|
|
{ kind: "inventory", collection: "nodes" },
|
|
),
|
|
).toThrow();
|
|
expect(() =>
|
|
page(
|
|
{ ...next, operation: "inspect_artifact" },
|
|
{ kind: "inventory", collection: "nodes" },
|
|
),
|
|
).toThrow();
|
|
});
|