1import { execFileSync } from "node:child_process";2import { existsSync, readFileSync } from "node:fs";3import { dirname, resolve } from "node:path";4import { fileURLToPath } from "node:url";56const browserRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");7const androidRoot = resolve(browserRoot, "../peach-android");8const localJavaHome = "/opt/homebrew/opt/openjdk@17";9const javaHome = process.env.JAVA_HOME ??10 (existsSync(localJavaHome) ? localJavaHome : undefined);11const browserCoordinator = readFileSync(12 resolve(browserRoot, "src/background/sync-coordinator.ts"),13 "utf8",14);15const androidCoordinator = readFileSync(16 resolve(androidRoot, "app/src/main/java/com/peachpasswords/sync/SyncCoordinator.kt"),17 "utf8",18);19const browserSyncTypes = readFileSync(resolve(browserRoot, "src/shared/sync-types.ts"), "utf8");20const androidManifest = readFileSync(21 resolve(androidRoot, "app/src/main/java/com/peachpasswords/sync/DeviceManifestSupport.kt"),22 "utf8",23);24const browserPairedDevices = readFileSync(25 resolve(browserRoot, "src/background/paired-devices.ts"),26 "utf8",27);28const androidPairedDevices = readFileSync(29 resolve(androidRoot, "app/src/main/java/com/peachpasswords/sync/PairedDeviceStore.kt"),30 "utf8",31);3233if (browserCoordinator.includes('helloIn.version === localVersion')) {34 throw new Error("Browser still contains the forbidden equal-version fast path");35}36if (!browserCoordinator.includes("helloIn.deviceManifestVersion === DEVICE_MANIFEST_VERSION")) {37 throw new Error("Browser does not negotiate device manifests from SYNC_HELLO");38}39if (!androidCoordinator.includes("val exchangeDeviceManifest = vault.negotiatesDeviceManifest(hello)")) {40 throw new Error("Android does not negotiate device manifests from SYNC_HELLO");41}42if (!androidCoordinator.includes("peerVersion == DEVICE_MANIFEST_VERSION")) {43 throw new Error("Android does not require an exact device-manifest version match");44}45if (!browserSyncTypes.includes("DEVICE_MANIFEST_VERSION = 0x04") ||46 !androidManifest.includes("DEVICE_MANIFEST_VERSION = 0x04")) {47 throw new Error("Browser and Android device-manifest versions differ");48}49if (!browserPairedDevices.includes("MAX_REVOCATIONS = 500") ||50 !androidPairedDevices.includes("MAX_REVOCATION_RECORDS = 500")) {51 throw new Error("Browser and Android revocation ledger caps differ");52}53if (!browserPairedDevices.includes("enqueueDeviceMutation") ||54 !androidPairedDevices.includes("RegistryMutationGate")) {55 throw new Error("A paired-device registry lacks whole-list mutation serialization");56}57if (!browserPairedDevices.includes("function capRevocations") ||58 !androidPairedDevices.includes("fun capRevocationRecords")) {59 throw new Error("A client lacks largest-issuer-first revocation retention");60}6162execFileSync(63 "npm",64 [65 "test", "--", "--run",66 "src/background/sync-coordinator.test.ts",67 "src/shared/sync-padding.test.ts",68 "src/shared/rendezvous.test.ts",69 "src/shared/device-manifest.test.ts",70 "src/crypto/peachPayload.test.ts",71 "src/shared/sync-entry-envelope.kat.test.ts",72 "src/shared/vault-adopt.test.ts",73 "src/background/paired-devices.test.ts",74 "src/background/relay-adoption-bg.test.ts",75 ],76 { cwd: browserRoot, stdio: "inherit" },77);78execFileSync(79 resolve(androidRoot, "gradlew"),80 [81 "--no-configuration-cache",82 "testDebugUnitTest",83 "--tests",84 "com.peachpasswords.sync.SyncCoordinatorTest",85 "--tests",86 "com.peachpasswords.sync.LockedSyncSpoolModelTest",87 "--tests",88 "com.peachpasswords.sync.SyncPaddingTest",89 "--tests",90 "com.peachpasswords.sync.DeviceManifestSupportTest",91 "--tests",92 "com.peachpasswords.CrossPlatformKATTest",93 "--tests",94 "com.peachpasswords.vault.PeachScriptTest",95 "--tests",96 "com.peachpasswords.sync.SyncEntryEnvelopeKatTest",97 "--tests",98 "com.peachpasswords.sync.VaultAdoptTest",99 "--tests",100 "com.peachpasswords.sync.PairedDeviceRevocationTest",101 ],102 {103 cwd: androidRoot,104 env: { ...process.env, ...(javaHome ? { JAVA_HOME: javaHome } : {}) },105 stdio: "inherit",106 },107);108109console.log("Cross-client sync protocol gate passed.");