import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import type { AppConfig } from "../src/config.js"; import { consumeHotspotConfigurationRequest, consumeNetworkCommand, hotspotConfigurationSchema, readNetworkStatus, requestHotspotConfiguration, requestNetworkAction } from "../src/network.js"; const directories: string[] = []; function config(directory: string, enabled = true): AppConfig { return { nodeEnv: "test", host: "127.0.0.1", port: 8787, databasePath: ":memory:", sessionTtlMs: 60_000, cookieSecure: false, allowedOrigins: new Set(), updateStatusPath: join(directory, "update.json"), versionFile: join(directory, "REVISION"), network: { enabled, statusPath: join(directory, "status.json"), commandPath: join(directory, "command.json"), configurationRequestPath: join(directory, "configuration.json") }, adb: { enabled: false, executable: "adb", serial: null, timeoutMs: 3_000 } }; } afterEach(async () => { await Promise.all(directories.splice(0).map((directory) => rm(directory, { recursive: true, force: true }))); }); describe("network control boundary", () => { it("writes and consumes only fixed action requests", async () => { const directory = await mkdtemp(join(tmpdir(), "pi-car-network-test-")); directories.push(directory); const testConfig = config(directory); const requested = await requestNetworkAction(testConfig, "retry-upstream", 7); expect(JSON.parse(await readFile(testConfig.network.commandPath, "utf8"))).toMatchObject({ id: requested.id, action: "retry-upstream", actorUserId: 7 }); await expect(consumeNetworkCommand(testConfig.network.commandPath)).resolves.toMatchObject({ action: "retry-upstream" }); await expect(consumeNetworkCommand(testConfig.network.commandPath)).resolves.toBeNull(); }); it("rejects malformed controller status", async () => { const directory = await mkdtemp(join(tmpdir(), "pi-car-network-test-")); directories.push(directory); const testConfig = config(directory); await writeFile(testConfig.network.statusPath, '{"mode":"shell"}'); await expect(readNetworkStatus(testConfig)).resolves.toMatchObject({ supported: false, mode: "starting" }); }); it("validates and transfers hotspot credentials only through the root request file", async () => { const directory = await mkdtemp(join(tmpdir(), "pi-car-network-test-")); directories.push(directory); const testConfig = config(directory, false); expect(hotspotConfigurationSchema.safeParse({ ssid: "MG4 Car", password: "Strong pass!2" }).success).toBe(true); expect(hotspotConfigurationSchema.safeParse({ ssid: "bad/name", password: "Strong pass!2" }).success).toBe(false); expect(hotspotConfigurationSchema.safeParse({ ssid: "MG4 Car", password: "short" }).success).toBe(false); await requestHotspotConfiguration(testConfig, { ssid: "MG4 Car", password: "Strong pass!2" }, 7, async () => undefined); await expect(consumeHotspotConfigurationRequest(testConfig.network.configurationRequestPath)).resolves.toMatchObject({ ssid: "MG4 Car", password: "Strong pass!2", actorUserId: 7 }); await expect(readFile(testConfig.network.configurationRequestPath, "utf8")).rejects.toThrow(); }); });