mirror of
https://github.com/morluto/rea.git
synced 2026-11-01 04:16:28 +00:00
* fix: bind identity and coverage to the producing rule Logical paths, container families, examined bytes, path-segment conventions, destination collisions, file-id leases, Mach-O CPU selection, and firmware cleanup now follow the observation that owns each rule. * fix: fail unmatched Mach-O slices and keep firmware roots independent A fat target whose architecture lipo did not list now stops before slice tools run. Chained fixups still count unread LC_DYLD_INFO rebase bytes, and a firmware cleanup failure no longer blocks the next workspace. * test: cover path identity and runtime families at the projection boundary NFC joins and segment conventions are now asserted by the path resolver, the Apple projection, and a real APK inventory instead of helper unit tests. * test: expect unread dyld rebase bytes in the Apple dispatch fixture The legacy LC_DYLD_INFO fixture keeps a rebase range this reader does not decode, so the public CLI and MCP check now requires that partial coverage beside the bind opcodes. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
117 lines
3.7 KiB
TypeScript
117 lines
3.7 KiB
TypeScript
import { posix } from "node:path";
|
|
|
|
import { digestCanonicalValue } from "./canonicalDigest.js";
|
|
import type {
|
|
ArtifactEdge,
|
|
ArtifactNode,
|
|
ArtifactOccurrence,
|
|
IntegrityContradiction,
|
|
} from "./artifactGraph.js";
|
|
|
|
/** NFC spelling of a logical archive path. Inventory and path joins share it. */
|
|
export const logicalPathNfc = (value: string): string => value.normalize("NFC");
|
|
|
|
/**
|
|
* Lexical join against an inventoried logical path. The result is NFC.
|
|
* `"."` is the archive root. A path that escapes the root, or that contains
|
|
* NUL, is left in a form the caller can report; `logicalPathEscapesRoot`
|
|
* is then true.
|
|
*/
|
|
export const normalizeJoinedLogicalPath = (value: string): string => {
|
|
if (value.includes("\0")) return value;
|
|
return logicalPathNfc(
|
|
posix.normalize(value.replaceAll("\\", "/")).replace(/^\.\//u, ""),
|
|
);
|
|
};
|
|
|
|
/** Whether a joined logical path leaves the archive root. */
|
|
export const logicalPathEscapesRoot = (path: string): boolean =>
|
|
path.includes("\0") ||
|
|
path === ".." ||
|
|
path.startsWith("../") ||
|
|
path.startsWith("/");
|
|
|
|
/** Content-address an artifact independently of where it was observed. */
|
|
export const artifactIdForContent = (sha256: string): string =>
|
|
`art_${digestCanonicalValue({ sha256 }, "Artifact")}`;
|
|
|
|
/** Identify an occurrence by its root and exact logical location. */
|
|
export const occurrenceIdForLocation = (input: {
|
|
readonly rootArtifactId: string;
|
|
readonly logicalPath: string;
|
|
readonly entryKind: ArtifactOccurrence["entry_kind"];
|
|
}): string =>
|
|
input.logicalPath === "."
|
|
? `occ_${digestCanonicalValue({ root: input.rootArtifactId }, "Artifact")}`
|
|
: `occ_${digestCanonicalValue(
|
|
{
|
|
root_artifact_id: input.rootArtifactId,
|
|
logical_path: input.logicalPath,
|
|
entry_kind: input.entryKind,
|
|
},
|
|
"Artifact",
|
|
)}`;
|
|
|
|
/** Commit to graph members in the ordering established by the inventory owner. */
|
|
export const artifactGraphDigest = (input: {
|
|
readonly nodes: readonly ArtifactNode[];
|
|
readonly occurrences: readonly ArtifactOccurrence[];
|
|
readonly edges: readonly ArtifactEdge[];
|
|
readonly contradictions: readonly IntegrityContradiction[];
|
|
}): string =>
|
|
digestCanonicalValue(
|
|
{
|
|
nodes: input.nodes,
|
|
occurrences: input.occurrences,
|
|
edges: input.edges,
|
|
integrity_contradictions: input.contradictions,
|
|
},
|
|
"Artifact",
|
|
);
|
|
|
|
/** Bind a root artifact to its graph commitment. */
|
|
export const artifactManifestId = (
|
|
rootArtifactId: string,
|
|
graphSha256: string,
|
|
): string =>
|
|
`agm_${digestCanonicalValue(
|
|
{ root_artifact_id: rootArtifactId, graph_sha256: graphSha256 },
|
|
"Artifact",
|
|
)}`;
|
|
|
|
/** Identify one integrity disagreement at its observed logical path. */
|
|
export const artifactContradictionId = (input: {
|
|
readonly rootArtifactId: string;
|
|
readonly logicalPath: string;
|
|
readonly declaredSha256: string;
|
|
readonly observedSha256: string;
|
|
}): string =>
|
|
`ic_${digestCanonicalValue(
|
|
{
|
|
root_artifact_id: input.rootArtifactId,
|
|
logical_path: input.logicalPath,
|
|
declared_sha256: input.declaredSha256,
|
|
observed_sha256: input.observedSha256,
|
|
},
|
|
"Artifact",
|
|
)}`;
|
|
|
|
/**
|
|
* Identify an edge by its semantic relationship and exact occurrence. The
|
|
* child artifact and logical path come from that occurrence.
|
|
*/
|
|
export const artifactEdgeId = (
|
|
edge: Pick<ArtifactEdge, "parent_artifact_id" | "relation" | "occurrence_id">,
|
|
occurrence: Pick<ArtifactOccurrence, "artifact_id" | "logical_path">,
|
|
): string =>
|
|
`edge_${digestCanonicalValue(
|
|
{
|
|
parent_artifact_id: edge.parent_artifact_id,
|
|
child_artifact_id: occurrence.artifact_id,
|
|
relation: edge.relation,
|
|
occurrence_id: edge.occurrence_id,
|
|
logical_path: occurrence.logical_path,
|
|
},
|
|
"Artifact",
|
|
)}`;
|