diff --git a/packages/client-runtime/src/connection/onboarding.test.ts b/packages/client-runtime/src/connection/onboarding.test.ts index 2131507e547f7..df4b182ee95d5 100644 --- a/packages/client-runtime/src/connection/onboarding.test.ts +++ b/packages/client-runtime/src/connection/onboarding.test.ts @@ -442,9 +442,10 @@ describe("connection onboarding", () => { }), }, ] as const)( - "leaves a platform-managed $kind environment untouched when its id is paired", - ({ registration }) => - Effect.gen(function* () { + "refuses to pair a host reporting the platform-managed $kind environment's id, keeping the code", + ({ registration }) => { + const calls: Array<{ readonly url: string; readonly init: RequestInit }> = []; + return Effect.gen(function* () { const registry = yield* EnvironmentRegistry.EnvironmentRegistry; const onboarding = yield* Onboarding.ConnectionOnboarding; yield* registry.reconcilePlatform([registration]); @@ -455,11 +456,18 @@ describe("connection onboarding", () => { unsupportedReason: UNSUPPORTED_ERROR.message, }); - const environmentId = yield* onboarding.registerPairing(PAIRING_INPUT); + const error = yield* onboarding.registerPairing(PAIRING_INPUT).pipe(Effect.flip); - expect(environmentId).toBe(PAIRED_ENVIRONMENT_ID); + expect(error).toMatchObject({ + _tag: "ConnectionBlockedError", + reason: "configuration", + }); + expect(calls.map((call) => call.url)).toEqual([ + "https://remote.example.test/.well-known/t3/environment", + ]); expect(yield* SubscriptionRef.get(registry.entries)).toEqual(before); - }).pipe(Effect.provide(layerPairingOnboarding())), + }).pipe(Effect.provide(layerPairingOnboarding(undefined, calls))); + }, ); it.effect("leaves a switched-off environment unchanged when the pairing exchange fails", () => diff --git a/packages/client-runtime/src/connection/registry.ts b/packages/client-runtime/src/connection/registry.ts index 12f8aa5ec505f..6cb74a0e39e49 100644 --- a/packages/client-runtime/src/connection/registry.ts +++ b/packages/client-runtime/src/connection/registry.ts @@ -109,8 +109,9 @@ export class EnvironmentRegistry extends Context.Service< options?: { readonly knownAddressOnly?: boolean }, ) => Effect.Effect; /** - * Fails when the route would add a new address to a saved user environment. Pairing that does - * not target an environment checks this, because the server reports its own environment id. + * Fails when the route would add a new address to a saved user environment, or names a + * platform-managed one. Pairing that does not target an environment checks this, because the + * server reports its own environment id. */ readonly assertKnownAddress: ( route: ConnectionRoute, @@ -545,8 +546,13 @@ export const make = Effect.gen(function* () { route: ConnectionRoute, ) { const environmentId = route.target.environmentId; - if ((yield* Ref.get(platformEnvironmentIds)).has(environmentId)) return; const saved = (yield* SubscriptionRef.get(entries)).get(environmentId); + if ((yield* Ref.get(platformEnvironmentIds)).has(environmentId)) { + return yield* new ConnectionBlockedError({ + reason: "configuration", + detail: `That machine reports the same environment ID as ${saved?.target.label ?? "an environment this app already manages"}, so it can't be added. This happens when one machine's T3 data was copied to another.`, + }); + } if ( saved !== undefined && findRouteToSameAddress(connectionRoutes(saved), route) === undefined @@ -568,12 +574,12 @@ export const make = Effect.gen(function* () { return yield* withLeaseLock( environmentId, Effect.gen(function* () { - if ((yield* Ref.get(platformEnvironmentIds)).has(environmentId)) { - return false; - } if (options?.knownAddressOnly === true) { yield* assertKnownAddress(route); } + if ((yield* Ref.get(platformEnvironmentIds)).has(environmentId)) { + return false; + } const previous = (yield* SubscriptionRef.get(entries)).get(environmentId); let entry = registered; if (previous !== undefined) {