diff --git a/src/hopper/BridgeLauncher.ts b/src/hopper/BridgeLauncher.ts index 1cef1cf7d2..8e48b5e2a2 100644 --- a/src/hopper/BridgeLauncher.ts +++ b/src/hopper/BridgeLauncher.ts @@ -250,8 +250,6 @@ export class HopperApplicationLauncher implements BridgeLauncher { let launched = false; try { if (signal?.aborted === true) return err(new HopperCancelledError()); - const display = await this.#privateDisplay(signal); - if (!display.ok) return err(display.error); let expectedLinuxSha256: string | undefined; if (usesLinuxDemo(this.options)) { const inspected = await ( @@ -272,6 +270,8 @@ export class HopperApplicationLauncher implements BridgeLauncher { ); expectedLinuxSha256 = inspected.value.sha256; } + const display = await this.#privateDisplay(signal); + if (!display.ok) return err(display.error); const nativeHelperVerified = (this.dependencies.platform ?? process.platform) === "darwin" && this.options.launchMode === "native" && diff --git a/tests/acceptance/applications/hopperPublisherRejectionCli.test.ts b/tests/acceptance/applications/hopperPublisherRejectionCli.test.ts index 092ee9f6ab..9e22759839 100644 --- a/tests/acceptance/applications/hopperPublisherRejectionCli.test.ts +++ b/tests/acceptance/applications/hopperPublisherRejectionCli.test.ts @@ -5,9 +5,11 @@ import { cliTest } from "../../support/cli/cliFixture.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { analysisCliErrorEnvelopeSchema } from "../../../src/contracts/errorSchemas.js"; -cliTest.skipIf(process.platform !== "linux")( - "refuses an unauthenticated Hopper launcher through the public CLI before executing it", - async ({ cli }) => { +cliTest + .skipIf(process.platform !== "linux") + .for(["default-python-home", "missing-python-home"] as const)( + "refuses an unauthenticated Hopper launcher through the public CLI before executing it (%s)", + async (pythonHome, { cli }) => { const home = await createTestTempDirectory("rea-hopper-publisher-cli-"); const launcher = join(home, "foreign-hopper"); const target = join(home, "sample"); @@ -38,6 +40,10 @@ cliTest.skipIf(process.platform !== "linux")( HOPPER_LAUNCHER_PATH: launcher, REA_HOPPER_TEST_MARKER: marker, REA_LOG_LEVEL: "silent", + // Publisher rejection must not depend on the display probe's Python. + ...(pythonHome === "missing-python-home" + ? { PYTHONHOME: join(home, "missing-python-home") } + : {}), // Reject deterministically without pretending to authenticate a build. NODE_OPTIONS: `--import=${new URL("../../fixtures/hopperRejectionFeed.mjs", import.meta.url).href}`, }, diff --git a/tests/boundary/providers/hopper/bridgeLauncher.test.ts b/tests/boundary/providers/hopper/bridgeLauncher.test.ts index 155a6414f0..85a561bfd9 100644 --- a/tests/boundary/providers/hopper/bridgeLauncher.test.ts +++ b/tests/boundary/providers/hopper/bridgeLauncher.test.ts @@ -327,6 +327,7 @@ it.skipIf(process.platform !== "linux")( "gives the demo helper a live owner stream through Node's actual stdio transport", async () => { const directory = await createTestTempDirectory("rea-hopper-owner-stdio-"); + const selectPrivateDisplay = vi.fn(readyDirectDisplay); const launcher = new HopperApplicationLauncher( { ...options(process.execPath), @@ -344,7 +345,7 @@ it.skipIf(process.platform !== "linux")( signingFingerprint: "1".repeat(40), source: "signed_package_cache", }), - selectPrivateDisplay: readyDirectDisplay, + selectPrivateDisplay, }, ); const launched = await launcher.launch({ @@ -354,6 +355,7 @@ it.skipIf(process.platform !== "linux")( runId: randomUUID(), }); if (!launched.ok) throw launched.error; + expect(selectPrivateDisplay).toHaveBeenCalledOnce(); const supervisor = new ProviderProcessSupervisor(launched.value); try { expect(await supervisor.waitForOutputClose(5_000)).toBe(true); @@ -378,10 +380,11 @@ it.skipIf(process.platform !== "linux")( "unsupported_hopper_build", "Fixture launcher is outside verified releases", ); + const selectPrivateDisplay = vi.fn(readyDirectDisplay); const launcher = new HopperApplicationLauncher( { ...options("/unused/Hopper"), targetPath }, { - selectPrivateDisplay: readyDirectDisplay, + selectPrivateDisplay, verifyLinuxLauncher: async () => err(rejected), }, ); @@ -405,5 +408,6 @@ it.skipIf(process.platform !== "linux")( }); expect(projected.details).not.toHaveProperty("exit_code"); expect(projected.details).not.toHaveProperty("launcher"); + expect(selectPrivateDisplay).not.toHaveBeenCalled(); }, );