mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
96fd98cce0
* feat(apktool): decode Android resource tables through a caller-supplied launcher Add an Apktool family with two operations over the caller's apktool launcher (REA_APKTOOL_COMMAND, absolute, or apktool on PATH): - inspect_apktool_client: resolved launcher, selection source, and version; decodes nothing. - decode_android_resources: apktool d --no-src in a provider-owned workspace that is removed before the result returns. Projects the decoded AndroidManifest.xml (bounded at 512 KiB), apktool.yml version and SDK facts exactly as printed, string resources verbatim (default or one locale, bounded at 2000 entries, nested-markup entries counted as unparsed), available string locales, and the decoded file count with a hard cap. The target APK is digested with SHA-256 before decoding so Evidence binds the observation to the exact input. Smali production is skipped by design: Java-source recovery belongs to the JADX family. Workspace cleanup happens before results return; an unremovable workspace is named in the limitations instead of abandoned. Verified against apktool 2.7.0-dirty (Debian packaging) on Linux with OpenJDK 25 against a signed aapt2-built probe APK with two resource locales: launcher version, on-disk digest agreement, metadata projection, manifest package agreement, and both string tables (default and de). Parser goldens come from the same decode. READMEs carry the new 'Android resources' row in every supported language. * fix(apktool): own snapshots and bound decoded resource reads * docs(apktool): describe owned resources and bounded projection --------- Co-authored-by: REA Contributor <contributor@rea.tools> Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
174 lines
4.8 KiB
TypeScript
174 lines
4.8 KiB
TypeScript
import { realpathSync } from "node:fs";
|
|
import { availableParallelism, tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
import { defineConfig } from "vitest/config";
|
|
|
|
const CANONICAL_TEMPORARY_DIRECTORY = realpathSync(tmpdir());
|
|
const COVERAGE_ENABLED = process.argv.some((argument) =>
|
|
argument.startsWith("--coverage"),
|
|
);
|
|
const COVERAGE_SHARD = process.argv.some((argument) =>
|
|
argument.startsWith("--shard="),
|
|
);
|
|
// Keep local and CI concurrency bounded by the runner rather than command locks.
|
|
const MAX_TEST_WORKERS = Math.min(2, availableParallelism());
|
|
|
|
const TEST_PROJECTS = [
|
|
{
|
|
name: "domain",
|
|
include: ["src/{contracts,domain}/**/*.test.ts"],
|
|
pool: "threads" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
// Domain and contract modules are pure and own no process-global state, so
|
|
// per-file module isolation adds startup cost without protecting a seam.
|
|
isolate: false,
|
|
},
|
|
{
|
|
name: "services",
|
|
include: ["src/application/**/*.test.ts"],
|
|
pool: "threads" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
// Service tests use recording ports and own no process-global state. Share
|
|
// their module graph so file startup does not dominate the lane.
|
|
isolate: false,
|
|
},
|
|
{
|
|
name: "adapters",
|
|
include: [
|
|
"src/*.test.ts",
|
|
"src/{apktool,jeb,adb,artifacts,browser,dotnet,evm,firmware,ghidra,hopper,ida,inspector,javascript,native,process,reference,server,windows}/**/*.test.ts",
|
|
],
|
|
pool: "forks" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
},
|
|
{
|
|
name: "composition",
|
|
include: ["tests/composition/**/*.test.ts"],
|
|
pool: "threads" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
},
|
|
{
|
|
name: "boundary",
|
|
include: ["tests/boundary/**/*.test.ts"],
|
|
exclude: [
|
|
"tests/boundary/mcp/**/*.test.ts",
|
|
"tests/boundary/process/**/*.test.ts",
|
|
],
|
|
pool: "forks" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
},
|
|
{
|
|
// Process-tree observations share host sampling resources; keep this small
|
|
// lane serial while the independent projects run together.
|
|
name: "process-boundary",
|
|
include: ["tests/boundary/process/**/*.test.ts"],
|
|
pool: "forks" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
fileParallelism: false,
|
|
sequence: { groupOrder: 1 },
|
|
},
|
|
{
|
|
name: "mcp-boundary",
|
|
include: ["tests/boundary/mcp/**/*.test.ts"],
|
|
pool: "threads" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
// Each file creates and closes an explicit in-memory MCP session. Reuse the
|
|
// immutable server graph so module startup does not outweigh transport work.
|
|
isolate: false,
|
|
},
|
|
{
|
|
name: "acceptance",
|
|
include: ["tests/acceptance/**/*.test.ts"],
|
|
pool: "forks" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
},
|
|
{
|
|
name: "process-global",
|
|
include: ["tests/process-global/**/*.test.ts"],
|
|
pool: "forks" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
},
|
|
{
|
|
name: "conformance",
|
|
include: ["tests/conformance/**/*.test.ts"],
|
|
pool: "threads" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
},
|
|
{
|
|
name: "evaluation",
|
|
include: ["tests/evaluation/**/*.test.ts"],
|
|
pool: "threads" as const,
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
},
|
|
];
|
|
|
|
const ZERO_COVERAGE_THRESHOLDS = {
|
|
statements: 0,
|
|
branches: 0,
|
|
functions: 0,
|
|
lines: 0,
|
|
"src/domain/**": {
|
|
statements: 0,
|
|
branches: 0,
|
|
functions: 0,
|
|
lines: 0,
|
|
},
|
|
"src/contracts/**": {
|
|
statements: 0,
|
|
branches: 0,
|
|
functions: 0,
|
|
lines: 0,
|
|
},
|
|
};
|
|
|
|
const projects = TEST_PROJECTS.map((project) => ({
|
|
extends: true as const,
|
|
test: project,
|
|
}));
|
|
|
|
export default defineConfig({
|
|
test: {
|
|
env: { TMPDIR: CANONICAL_TEMPORARY_DIRECTORY },
|
|
maxWorkers: MAX_TEST_WORKERS,
|
|
projects,
|
|
retry: 0,
|
|
reporters: ["default"],
|
|
runner: "./tests/processOwnershipRunner.ts",
|
|
// Boundary projects may compete with TypeScript, docs, and package checks
|
|
// under Turbo. Keep the deadline bounded while avoiding false failures from
|
|
// host-level CPU and filesystem contention.
|
|
testTimeout: COVERAGE_ENABLED ? 60_000 : 30_000,
|
|
coverage: {
|
|
enabled: false,
|
|
provider: "v8",
|
|
reportsDirectory: join(
|
|
tmpdir(),
|
|
`rea-vitest-coverage-${String(process.pid)}`,
|
|
),
|
|
include: ["src/**"],
|
|
thresholds: COVERAGE_SHARD
|
|
? ZERO_COVERAGE_THRESHOLDS
|
|
: {
|
|
statements: 65,
|
|
branches: 60,
|
|
functions: 60,
|
|
lines: 68,
|
|
"src/domain/**": {
|
|
statements: 80,
|
|
branches: 75,
|
|
functions: 75,
|
|
lines: 80,
|
|
},
|
|
"src/contracts/**": {
|
|
statements: 85,
|
|
branches: 80,
|
|
functions: 80,
|
|
lines: 85,
|
|
},
|
|
},
|
|
reporter: ["text", "text-summary"],
|
|
},
|
|
},
|
|
});
|