mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 05:56:19 -10:00
refactor(snapshot): centralize resource cache eligibility
This commit is contained in:
1 parent
5d25aa4f52
commit
5b8e415483
4 files changed
+81
-15
No files matched your search
@@ -716,6 +716,26 @@ describe("analysis snapshot cache policy", () => {
|
||||
effects: { changesPermissions: true },
|
||||
cacheable: false,
|
||||
},
|
||||
{
|
||||
policy: "snapshot",
|
||||
operation: "decode_interface_builder",
|
||||
cacheable: false,
|
||||
},
|
||||
{
|
||||
policy: "snapshot",
|
||||
operation: "inspect_asset_catalog",
|
||||
cacheable: false,
|
||||
},
|
||||
{
|
||||
policy: "snapshot",
|
||||
operation: "inspect_keyed_archive",
|
||||
cacheable: false,
|
||||
},
|
||||
{
|
||||
policy: "snapshot",
|
||||
operation: "trace_dylib_resolution",
|
||||
cacheable: false,
|
||||
},
|
||||
{ policy: "snapshot", operation: "list_documents", cacheable: false },
|
||||
{ policy: "snapshot", operation: "list_strings", cacheable: false },
|
||||
{
|
||||
|
||||
@@ -51,6 +51,15 @@ const RELATIONSHIP_OPERATIONS: ReadonlySet<AnalysisOperation> = new Set([
|
||||
"procedure_callees",
|
||||
]);
|
||||
|
||||
// These reports depend on selected bundle resources or loader context beyond
|
||||
// the immutable executable identity carried by a binary analysis snapshot.
|
||||
const RESOURCE_SCOPED_OPERATIONS: ReadonlySet<AnalysisOperation> = new Set([
|
||||
"decode_interface_builder",
|
||||
"inspect_asset_catalog",
|
||||
"inspect_keyed_archive",
|
||||
"trace_dylib_resolution",
|
||||
]);
|
||||
|
||||
const STATEFUL_OPERATIONS: ReadonlySet<AnalysisOperation> = new Set([
|
||||
"health",
|
||||
"current_address",
|
||||
@@ -85,6 +94,7 @@ export const isSnapshotCacheable = (
|
||||
parameters: Readonly<Record<string, JsonValue>>,
|
||||
): descriptor is CapabilityDescriptor =>
|
||||
!STATEFUL_OPERATIONS.has(operation) &&
|
||||
!RESOURCE_SCOPED_OPERATIONS.has(operation) &&
|
||||
(!DOCUMENT_SCOPED_OPERATIONS.has(operation) ||
|
||||
typeof parameters.document === "string") &&
|
||||
(!CURSOR_DEFAULT_OPERATIONS.has(operation) ||
|
||||
|
||||
@@ -1224,12 +1224,7 @@ export class BinarySession
|
||||
unboundOperationError: (operation, route) =>
|
||||
this.#providerRouter.unboundOperationError(operation, route),
|
||||
lookupSnapshot: (target, profile, operation, parameters) =>
|
||||
operation === "decode_interface_builder" ||
|
||||
operation === "inspect_asset_catalog" ||
|
||||
operation === "inspect_keyed_archive" ||
|
||||
operation === "trace_dylib_resolution"
|
||||
? undefined
|
||||
: this.lookupSnapshot(target, profile, operation, parameters),
|
||||
this.lookupSnapshot(target, profile, operation, parameters),
|
||||
});
|
||||
if (!prepared.ok) return prepared;
|
||||
const { active, capability, profile, cacheable, cached } = prepared.value;
|
||||
@@ -1275,15 +1270,7 @@ export class BinarySession
|
||||
);
|
||||
if (!sourcesRecorded.ok) return sourcesRecorded;
|
||||
}
|
||||
if (
|
||||
execution.ok &&
|
||||
cacheable &&
|
||||
profile !== undefined &&
|
||||
name !== "decode_interface_builder" &&
|
||||
name !== "inspect_asset_catalog" &&
|
||||
name !== "inspect_keyed_archive" &&
|
||||
name !== "trace_dylib_resolution"
|
||||
) {
|
||||
if (execution.ok && cacheable && profile !== undefined) {
|
||||
const evidence = createAnalysisExecutionEvidence(
|
||||
name,
|
||||
arguments_,
|
||||
|
||||
@@ -968,6 +968,55 @@ describe("snapshot switch rollback", () => {
|
||||
});
|
||||
|
||||
describe("snapshot cache eligibility", () => {
|
||||
it.each([
|
||||
"decode_interface_builder",
|
||||
"inspect_asset_catalog",
|
||||
"inspect_keyed_archive",
|
||||
"trace_dylib_resolution",
|
||||
] as const)(
|
||||
"reobserves resource-scoped %s without executable snapshot Evidence",
|
||||
async (operation) => {
|
||||
const [target] = await createBinarySessionTargets();
|
||||
const provider = createCacheProvider([]);
|
||||
const [baseCapability] = provider.capabilities();
|
||||
if (baseCapability === undefined)
|
||||
throw new Error("Expected fixture capability");
|
||||
provider.capabilities = () => [
|
||||
{ ...baseCapability, operation, cachePolicy: "snapshot" },
|
||||
];
|
||||
let observations = 0;
|
||||
provider.createClient = () => ({
|
||||
execute: async (name) =>
|
||||
resultOk(
|
||||
createAnalysisExecution(
|
||||
name === "health" ? null : ++observations,
|
||||
provider.identity(),
|
||||
),
|
||||
),
|
||||
close: async () => resultOk(null),
|
||||
});
|
||||
const session = createTestBinarySession(provider);
|
||||
try {
|
||||
expect((await session.open(target)).ok).toBe(true);
|
||||
for (const observation of [1, 2]) {
|
||||
const result = await session.execute(operation, {});
|
||||
expect(result).toMatchObject({
|
||||
ok: true,
|
||||
value: { result: observation },
|
||||
});
|
||||
if (result.ok) expect(result.value.evidenceId).toBeUndefined();
|
||||
}
|
||||
expect(session.exportEvidenceBundle().records).toEqual([]);
|
||||
expect(session.exportAnalysisSnapshot()).toMatchObject({
|
||||
ok: true,
|
||||
value: { entries: [] },
|
||||
});
|
||||
} finally {
|
||||
await session.close();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it.each([false, true])(
|
||||
"retains source Evidence independently of snapshot eligibility (live=%s)",
|
||||
async (live) => {
|
||||
|
||||
Reference in new issue
Block a user