mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
* feat(adb): acquire installed APK sets from connected Android devices Add a read-only ADB device-acquisition family over the caller's adb binary: inspect_adb_client, list_adb_devices, inspect_adb_device, list_adb_packages, and pull_adb_package, exposed through the CLI and MCP with shared admission, Evidence provenance (binary, version, serial, transport), and fixed argv vectors that never reach a shell. pull_adb_package acquires the complete split set reported by pm path into a package-named directory that must not exist, digesting every file with SHA-256 and keeping per-file failure reasons and partial coverage. Device kind is reported as an inference with its basis; getprop whitelisting keeps build identity bounded. REA installs nothing and never manages devices or emulators; the first device query may start the caller's local adb server, recorded when observed. Verified against adb 34.0.5 on Linux with an Android 14 (API 34) x86_64 emulator: full 224-package inventory, a real two-APK split set pulled with byte-exact digests, and a 73.9 MB system-package pull. npm run verify:adb records the lane; parser goldens come from the same device. READMEs carry the new row in every supported language. * feat(adb): complete the adb surface with observation, transfer, and lifecycle tools Extend the ADB family from five to twenty-four operations, all through fixed adb argument vectors with no shell exposure: Observation: read_adb_logcat (bounded dump, count/buffer/pid), inspect_adb_package (dumpsys package projection), list_adb_processes (ps -A), list_adb_directory (ls -la with kinds and symlink targets), list_adb_features (hex GL versions), list_adb_services (AIDL slash-suffixed names), inspect_adb_display (wm size and density), inspect_adb_window (focus declarations), read_adb_setting (device-side nulls reported as such), capture_adb_screen (exec-out screencap with PNG dimensions), collect_adb_bugreport (digested device archive). Transfer and search: pull_adb_file and push_adb_file (device-side sha256sum verification, explicit overwrite authority), resolve_adb_packages (substring package search with exact-match flag — the find step of an easy get). Lifecycle for dynamic analysis, each declaring mutatesTarget: install_adb_package and uninstall_adb_package preserving the device's Success/Failure verdict, start_adb_app (resolve-activity then am start -W), start_adb_activity (typed extras as --es/--ez/--ei/--el/--ef), and stop_adb_app (am force-stop). Verified end-to-end against adb 34.0.5 on Linux with an Android 14 (API 34) x86_64 emulator: 287 services, 92 features, split-set pulls with byte-exact digests, verified push/pull roundtrip, sized screen capture, and the full install → resolve → start → observe-in-ps → force-stop → uninstall lifecycle. Fixed a v-mode regex incompatibility in the settings key pattern and added argument descriptions required by the CLI catalog audit. * fix(adb): quote remote shell operands and protect captured output * test(adb): cover bugreport destinations containing spaces --------- Co-authored-by: REA Contributor <[email protected]> Co-authored-by: morluto <[email protected]>
174 lines
4.7 KiB
TypeScript
174 lines
4.7 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/{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"],
|
|
},
|
|
},
|
|
});
|