diff --git a/tests/gateway-resolver.test.ts b/tests/gateway-resolver.test.ts index 0c0254b8..759f23f4 100644 --- a/tests/gateway-resolver.test.ts +++ b/tests/gateway-resolver.test.ts @@ -21,6 +21,17 @@ import { waitForHealthz, } from "../src/core/gateway-resolver.js"; import { ConfigurationError, GatewayError } from "../src/errors/index.js"; +import { nativeRuntimeAvailable } from "./helpers/native-runtime.js"; + +// The auto-start path resolves, allow-lists and spawns the native `aasm` +// binary, which only ships on platforms with a published runtime package. Those +// suites assume POSIX install dirs (`/usr/local/bin`, …) and a POSIX `$PATH` +// shape, so they cannot pass on a platform whose native runtime is absent +// (Windows today — `@agent-assembly/runtime-win32-x64` is not yet published, +// AAASM-3544 / AAASM-3809). Guard those cases on actual binary availability, +// not `process.platform`, so they re-enable automatically once it is published. +// On Linux/macOS the runtime is present and every case runs unchanged. +const NATIVE_RUNTIME_AVAILABLE = nativeRuntimeAvailable(); describe("probeHealthz", () => { let originalFetch: typeof globalThis.fetch; @@ -143,7 +154,7 @@ describe("loadConfigFile", () => { }); }); -describe("autoStartGateway", () => { +describe.skipIf(!NATIVE_RUNTIME_AVAILABLE)("autoStartGateway", () => { let originalFetch: typeof globalThis.fetch; let originalFind: (typeof __testing._seams)["findAasmOnPath"]; let originalSpawn: (typeof __testing._seams)["spawnAasm"]; @@ -294,9 +305,16 @@ describe("resolveGatewayUrl", () => { }); describe("assertAllowedAasmPath", () => { - it("accepts an absolute path inside an allow-listed install dir", () => { - expect(() => assertAllowedAasmPath("/usr/local/bin/aasm")).not.toThrow(); - }); + // The allow-list is built from POSIX install dirs, so a POSIX absolute path + // only resolves inside it on a POSIX platform. Guard on native-runtime + // availability (absent on Windows today) rather than asserting POSIX layout + // on every OS; the two rejection cases below stay platform-independent. + it.skipIf(!NATIVE_RUNTIME_AVAILABLE)( + "accepts an absolute path inside an allow-listed install dir", + () => { + expect(() => assertAllowedAasmPath("/usr/local/bin/aasm")).not.toThrow(); + } + ); it("rejects a relative / PATH-injected path", () => { expect(() => assertAllowedAasmPath("aasm")).toThrow(ConfigurationError); @@ -380,7 +398,7 @@ describe("resolveApiKey", () => { }); }); -describe("default PATH lookup and spawn seams", () => { +describe.skipIf(!NATIVE_RUNTIME_AVAILABLE)("default PATH lookup and spawn seams", () => { // Capture the production default implementations before any other suite can // reassign the mutable _seams entries. const defaultFindAasmOnPath = __testing._seams.findAasmOnPath; diff --git a/tests/helpers/native-runtime.ts b/tests/helpers/native-runtime.ts new file mode 100644 index 00000000..c2ddfac9 --- /dev/null +++ b/tests/helpers/native-runtime.ts @@ -0,0 +1,40 @@ +import { createRequire } from "node:module"; +import { arch, platform } from "node:os"; + +const requireFromHere = createRequire(import.meta.url); + +/** + * Name of the platform-specific bundled-runtime package that ships the native + * `aasm` binary for the given OS/arch, e.g. `@agent-assembly/runtime-linux-x64`. + * + * Mirrors the `runtime-${platform}-${arch}` naming used by `src/runtime.ts` and + * the `optionalDependencies` in package.json. On Windows this resolves to + * `@agent-assembly/runtime-win32-x64`, which is not yet built/published + * (AAASM-3544 / AAASM-3809). + */ +export function runtimePackageName( + osPlatform: string = platform(), + osArch: string = arch() +): string { + return `@agent-assembly/runtime-${osPlatform}-${osArch}`; +} + +/** + * True when the bundled native runtime package for the current platform is + * resolvable (installed). + * + * Returns `false` on platforms with no published runtime package — Windows + * today, since `@agent-assembly/runtime-win32-x64` (the napi-rs Windows native + * binding / bundled `aasm` runtime) is not yet built or published. Keyed on the + * actual package availability rather than `process.platform`, so any suite that + * guards on this re-enables itself automatically once the Windows runtime + * package is published. + */ +export function nativeRuntimeAvailable(): boolean { + try { + requireFromHere.resolve(`${runtimePackageName()}/package.json`); + return true; + } catch { + return false; + } +}