mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 01:13:39 +00:00
132 lines
5.1 KiB
TypeScript
132 lines
5.1 KiB
TypeScript
import { projectCliAnalysisResult } from "../../../src/cli/projectCliAnalysisResult.js";
|
|
import { readFile, symlink, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { TextReader, Uint8ArrayWriter, ZipWriter } from "@zip.js/zip.js";
|
|
import { expect, it, vi } from "vitest";
|
|
import { parseBinaryTarget } from "../../../src/application/BinaryTargetResolver.js";
|
|
import { createDirectAnalysis } from "../../../src/composition/directAnalysis.js";
|
|
import {
|
|
artifactExtractionResultSchema,
|
|
artifactInventoryResultSchema,
|
|
} from "../../../src/domain/artifactGraph.js";
|
|
import { parseEvidence } from "../../../src/domain/evidence.js";
|
|
import { elf } from "../../../src/domain/binaryTarget.fixture.js";
|
|
import { ArtifactProvider } from "../../../src/artifacts/ArtifactProvider.js";
|
|
import { createTestBinarySession } from "../../fixtures/binarySession.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
|
|
const fixture = async (storedName = "content-addressed-archive") => {
|
|
const root = await createTestTempDirectory("rea-artifact-selected-name-");
|
|
const canonical = join(root, storedName);
|
|
const writer = new ZipWriter(new Uint8ArrayWriter());
|
|
await writer.add(
|
|
"AndroidManifest.xml",
|
|
new TextReader(
|
|
'<manifest package="example.fixture"><application /></manifest>',
|
|
),
|
|
);
|
|
await writer.add("payload.txt", new TextReader("same packed bytes"));
|
|
await writeFile(canonical, await writer.close());
|
|
return { root, canonical };
|
|
};
|
|
|
|
it.skipIf(process.platform === "win32").each([
|
|
["selected.apk", "content", "apk"],
|
|
["selected.ipa", "content", "ipa"],
|
|
["selected.apk", "canonical.ipa", "apk"],
|
|
["selected.ipa", "canonical.apk", "ipa"],
|
|
["selected.unknown", "canonical.apk", "apk"],
|
|
["selected.asar", "content", "zip"],
|
|
] as const)(
|
|
"keeps selected %s and stored %s consistent across admission, inventory and extraction",
|
|
async (name, stored, format) => {
|
|
const { root, canonical } = await fixture(stored);
|
|
const selected = join(root, name);
|
|
await symlink(canonical, selected);
|
|
const admitted = await parseBinaryTarget(selected);
|
|
if (!admitted.ok) throw admitted.error;
|
|
expect(admitted.value.path).toBe(canonical);
|
|
expect(admitted.value.format).toBe(format);
|
|
const { runProviderAnalysis } = createDirectAnalysis({});
|
|
const observed = parseEvidence(
|
|
await runProviderAnalysis(selected, "inventory_artifact", {}).then(
|
|
projectCliAnalysisResult,
|
|
),
|
|
);
|
|
expect(observed.subject?.local_path).toBe(selected);
|
|
expect(
|
|
artifactInventoryResultSchema.parse(observed.normalized_result).manifest
|
|
.root_format,
|
|
).toBe(format);
|
|
const provider = new ArtifactProvider({});
|
|
const client = provider.createClient(admitted.value);
|
|
try {
|
|
const execution = await client.execute("extract_artifact", {
|
|
output_root: join(root, "output"),
|
|
integrity_policy: "fail",
|
|
});
|
|
if (!execution.ok) throw execution.error;
|
|
expect(execution.value.subject?.path).toBe(selected);
|
|
const result = artifactExtractionResultSchema.parse(
|
|
execution.value.result,
|
|
);
|
|
expect(result.manifest.root_format).toBe(format);
|
|
expect(
|
|
await readFile(join(result.output_root, "payload.txt"), "utf8"),
|
|
).toBe("same packed bytes");
|
|
} finally {
|
|
await client.close();
|
|
}
|
|
},
|
|
);
|
|
|
|
it.skipIf(process.platform === "win32")(
|
|
"reopens the same packed file under distinct package selections and reuses unchanged selection",
|
|
async () => {
|
|
const { root, canonical } = await fixture();
|
|
const apk = join(root, "selected.apk");
|
|
const ipa = join(root, "selected.ipa");
|
|
await symlink(canonical, apk);
|
|
await symlink(canonical, ipa);
|
|
const provider = new ArtifactProvider({});
|
|
const created = vi.spyOn(provider, "createClient");
|
|
const session = createTestBinarySession(provider);
|
|
try {
|
|
for (const [path, format, calls] of [
|
|
[apk, "apk", 1],
|
|
[apk, "apk", 1],
|
|
[ipa, "ipa", 2],
|
|
] as const) {
|
|
const opened = await session.open(path);
|
|
if (!opened.ok) throw opened.error;
|
|
expect(created).toHaveBeenCalledTimes(calls);
|
|
const execution = await session.execute("inventory_artifact", {});
|
|
if (!execution.ok) throw execution.error;
|
|
expect(execution.value.subject?.path).toBe(path);
|
|
expect(
|
|
artifactInventoryResultSchema.parse(execution.value.result).manifest
|
|
.root_format,
|
|
).toBe(format);
|
|
}
|
|
} finally {
|
|
await session.close();
|
|
created.mockRestore();
|
|
}
|
|
},
|
|
);
|
|
|
|
it.skipIf(process.platform === "win32")(
|
|
"does not reinterpret real executable bytes from an artifact alias suffix",
|
|
async () => {
|
|
const root = await createTestTempDirectory("rea-artifact-executable-name-");
|
|
const canonical = join(root, "program");
|
|
const selected = join(root, "selected.asar");
|
|
await writeFile(canonical, elf(2, 1, 62));
|
|
await symlink(canonical, selected);
|
|
const admitted = await parseBinaryTarget(selected);
|
|
if (!admitted.ok) throw admitted.error;
|
|
expect(admitted.value.format).toBe("elf");
|
|
expect(admitted.value.kind).toBe("executable");
|
|
},
|
|
);
|