From 7539fb9fbf5c955284467079b07fe420dc656ea5 Mon Sep 17 00:00:00 2001 From: Bilal Godil Date: Fri, 19 Jun 2026 18:09:24 -0700 Subject: [PATCH] fix(tests): stub canonical HEXCLAVE_* env names so dual-read doesn't shadow/conflict The env-var rename added conflict-detecting dual-read (HEXCLAVE_* wins over STACK_*, throws when both differ) and set HEXCLAVE_* to non-empty values in the checked-in .env.development files. Tests that stubbed the legacy STACK_* twin either triggered the conflict throw or were silently shadowed by the canonical HEXCLAVE_* value loaded from .env. Point the test env stubs at the canonical HEXCLAVE_* names (production reads keep the legacy STACK_* argument and rely on dual-read): - plan-entitlements.test.ts: HEXCLAVE_DISABLE_PLAN_LIMITS - turnstile.tsx / users.tsx: HEXCLAVE_DISABLE_BOT_CHALLENGE, HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE - access-token-helpers.tsx: HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS - url-targets.test.ts: NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_* Also fix the turnstile dev-secret-key test to clear both twins so it actually exercises the dev-key fallback instead of passing on a string coincidence. --- .../access-token-helpers.tsx | 12 +++--- .../backend/src/lib/plan-entitlements.test.ts | 10 ++--- apps/backend/src/lib/turnstile.tsx | 37 +++++++++++++------ apps/backend/src/lib/users.tsx | 12 +++--- .../src/lib/hexclave-app/url-targets.test.ts | 14 +++---- 5 files changed, 49 insertions(+), 36 deletions(-) diff --git a/apps/backend/src/app/api/latest/connected-accounts/access-token-helpers.tsx b/apps/backend/src/app/api/latest/connected-accounts/access-token-helpers.tsx index 87b543c84..da6e290c4 100644 --- a/apps/backend/src/app/api/latest/connected-accounts/access-token-helpers.tsx +++ b/apps/backend/src/app/api/latest/connected-accounts/access-token-helpers.tsx @@ -45,7 +45,7 @@ export function isSharedAccessTokenBlocked(providerIsShared: boolean): boolean { import.meta.vitest?.describe("isSharedAccessTokenBlocked", () => { const { test, expect, beforeEach, afterEach, vi } = import.meta.vitest!; beforeEach(() => { - vi.stubEnv("STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", ""); + vi.stubEnv("HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", ""); }); afterEach(() => { vi.unstubAllEnvs(); @@ -53,7 +53,7 @@ import.meta.vitest?.describe("isSharedAccessTokenBlocked", () => { test("non-shared provider is never blocked, regardless of env var", () => { expect(isSharedAccessTokenBlocked(false)).toBe(false); - vi.stubEnv("STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", "true"); + vi.stubEnv("HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", "true"); expect(isSharedAccessTokenBlocked(false)).toBe(false); }); @@ -63,22 +63,22 @@ import.meta.vitest?.describe("isSharedAccessTokenBlocked", () => { test("shared provider is blocked for any value other than the literal 'true'", () => { for (const v of ["false", "1", "TRUE", "yes", " true "]) { - vi.stubEnv("STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", v); + vi.stubEnv("HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", v); expect(isSharedAccessTokenBlocked(true)).toBe(true); } }); test("shared provider is allowed only when env var === 'true'", () => { - vi.stubEnv("STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", "true"); + vi.stubEnv("HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", "true"); expect(isSharedAccessTokenBlocked(true)).toBe(false); }); test("result does not depend on NODE_ENV", () => { for (const nodeEnv of ["production", "development", "test", "preview", ""]) { vi.stubEnv("NODE_ENV", nodeEnv); - vi.stubEnv("STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", ""); + vi.stubEnv("HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", ""); expect(isSharedAccessTokenBlocked(true)).toBe(true); - vi.stubEnv("STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", "true"); + vi.stubEnv("HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS", "true"); expect(isSharedAccessTokenBlocked(true)).toBe(false); } }); diff --git a/apps/backend/src/lib/plan-entitlements.test.ts b/apps/backend/src/lib/plan-entitlements.test.ts index ef51ed90f..aec03993e 100644 --- a/apps/backend/src/lib/plan-entitlements.test.ts +++ b/apps/backend/src/lib/plan-entitlements.test.ts @@ -194,25 +194,25 @@ describe("arePlanLimitsEnforced", () => { }); it("returns true when env var is unset (default-on enforcement)", () => { - vi.stubEnv("STACK_DISABLE_PLAN_LIMITS", ""); + vi.stubEnv("HEXCLAVE_DISABLE_PLAN_LIMITS", ""); expect(arePlanLimitsEnforced()).toBe(true); }); it("returns false when env var is exactly 'true'", () => { - vi.stubEnv("STACK_DISABLE_PLAN_LIMITS", "true"); + vi.stubEnv("HEXCLAVE_DISABLE_PLAN_LIMITS", "true"); expect(arePlanLimitsEnforced()).toBe(false); }); it("returns true when env var is 'false'", () => { - vi.stubEnv("STACK_DISABLE_PLAN_LIMITS", "false"); + vi.stubEnv("HEXCLAVE_DISABLE_PLAN_LIMITS", "false"); expect(arePlanLimitsEnforced()).toBe(true); }); it("returns true for any non-'true' value (e.g. '1', 'yes', 'TRUE')", () => { // Explicit string match is intentional — we don't want to risk a typo - // like STACK_DISABLE_PLAN_LIMITS=trueee silently disabling enforcement. + // like HEXCLAVE_DISABLE_PLAN_LIMITS=trueee silently disabling enforcement. for (const value of ["1", "yes", "TRUE", "True", " true", "true ", "trueee"]) { - vi.stubEnv("STACK_DISABLE_PLAN_LIMITS", value); + vi.stubEnv("HEXCLAVE_DISABLE_PLAN_LIMITS", value); expect(arePlanLimitsEnforced()).toBe(true); } }); diff --git a/apps/backend/src/lib/turnstile.tsx b/apps/backend/src/lib/turnstile.tsx index d3ba9cc3f..8aee1ef2d 100644 --- a/apps/backend/src/lib/turnstile.tsx +++ b/apps/backend/src/lib/turnstile.tsx @@ -360,8 +360,12 @@ import.meta.vitest?.describe("verifyTurnstileToken(...)", () => { test("uses development secret key when none is configured", async ({ expect }) => { const processEnv = Reflect.get(process, "env"); const originalNodeEnv = Reflect.get(processEnv, "NODE_ENV"); - const originalKey = Reflect.get(processEnv, "STACK_TURNSTILE_SECRET_KEY"); + const originalHexclaveKey = Reflect.get(processEnv, "HEXCLAVE_TURNSTILE_SECRET_KEY"); + const originalStackKey = Reflect.get(processEnv, "STACK_TURNSTILE_SECRET_KEY"); Reflect.set(processEnv, "NODE_ENV", "development"); + // Clear both spellings so the value resolves to the dev-key default; the + // canonical HEXCLAVE_ name is set in .env.development and otherwise wins. + Reflect.set(processEnv, "HEXCLAVE_TURNSTILE_SECRET_KEY", ""); Reflect.set(processEnv, "STACK_TURNSTILE_SECRET_KEY", ""); let postedSecret = ""; @@ -380,7 +384,16 @@ import.meta.vitest?.describe("verifyTurnstileToken(...)", () => { .resolves.toEqual({ status: "ok" }); } finally { Reflect.set(processEnv, "NODE_ENV", originalNodeEnv); - Reflect.set(processEnv, "STACK_TURNSTILE_SECRET_KEY", originalKey); + for (const [key, original] of [ + ["HEXCLAVE_TURNSTILE_SECRET_KEY", originalHexclaveKey], + ["STACK_TURNSTILE_SECRET_KEY", originalStackKey], + ] as const) { + if (original === undefined) { + Reflect.deleteProperty(processEnv, key); + } else { + Reflect.set(processEnv, key, original); + } + } } expect(postedSecret).toBe(turnstileDevelopmentKeys.secretKey); @@ -390,25 +403,25 @@ import.meta.vitest?.describe("verifyTurnstileToken(...)", () => { import.meta.vitest?.describe("verifyTurnstileTokenWithOptionalVisibleChallenge(...)", () => { const { vi, test, afterEach, beforeEach } = import.meta.vitest!; const processEnv = Reflect.get(process, "env"); - const originalFlag = Reflect.get(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); - const originalDisableFlag = Reflect.get(processEnv, "STACK_DISABLE_BOT_CHALLENGE"); + const originalFlag = Reflect.get(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); + const originalDisableFlag = Reflect.get(processEnv, "HEXCLAVE_DISABLE_BOT_CHALLENGE"); beforeEach(() => { - Reflect.deleteProperty(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); - Reflect.deleteProperty(processEnv, "STACK_DISABLE_BOT_CHALLENGE"); + Reflect.deleteProperty(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); + Reflect.deleteProperty(processEnv, "HEXCLAVE_DISABLE_BOT_CHALLENGE"); }); afterEach(() => { vi.restoreAllMocks(); vi.unstubAllGlobals(); if (originalFlag === undefined) { - Reflect.deleteProperty(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); + Reflect.deleteProperty(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); } else { - Reflect.set(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", originalFlag); + Reflect.set(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", originalFlag); } if (originalDisableFlag === undefined) { - Reflect.deleteProperty(processEnv, "STACK_DISABLE_BOT_CHALLENGE"); + Reflect.deleteProperty(processEnv, "HEXCLAVE_DISABLE_BOT_CHALLENGE"); } else { - Reflect.set(processEnv, "STACK_DISABLE_BOT_CHALLENGE", originalDisableFlag); + Reflect.set(processEnv, "HEXCLAVE_DISABLE_BOT_CHALLENGE", originalDisableFlag); } }); @@ -448,7 +461,7 @@ import.meta.vitest?.describe("verifyTurnstileTokenWithOptionalVisibleChallenge(. }); test("skips all bot challenge verification when disabled", async ({ expect }) => { - Reflect.set(processEnv, "STACK_DISABLE_BOT_CHALLENGE", "true"); + Reflect.set(processEnv, "HEXCLAVE_DISABLE_BOT_CHALLENGE", "true"); const fetchSpy = vi.fn(); vi.stubGlobal("fetch", fetchSpy); @@ -463,7 +476,7 @@ import.meta.vitest?.describe("verifyTurnstileTokenWithOptionalVisibleChallenge(. }); test("can downgrade visible invalid responses into a scored assessment when bypass is enabled", async ({ expect }) => { - Reflect.set(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", "true"); + Reflect.set(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", "true"); vi.stubGlobal("fetch", async () => new Response(JSON.stringify({ success: false }), { status: 200, headers: { "Content-Type": "application/json" }, })); diff --git a/apps/backend/src/lib/users.tsx b/apps/backend/src/lib/users.tsx index d1561e41e..c37f9e886 100644 --- a/apps/backend/src/lib/users.tsx +++ b/apps/backend/src/lib/users.tsx @@ -115,17 +115,17 @@ import.meta.vitest?.test("getDerivedSignUpCountryCode", ({ expect }) => { import.meta.vitest?.describe("visible bot challenge sign-up policy", () => { const { expect, test, beforeEach, afterEach } = import.meta.vitest!; const processEnv = Reflect.get(process, "env"); - const originalFlag = Reflect.get(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); + const originalFlag = Reflect.get(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); beforeEach(() => { - Reflect.deleteProperty(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); + Reflect.deleteProperty(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); }); afterEach(() => { if (originalFlag === undefined) { - Reflect.deleteProperty(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); + Reflect.deleteProperty(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE"); } else { - Reflect.set(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", originalFlag); + Reflect.set(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", originalFlag); } }); @@ -137,7 +137,7 @@ import.meta.vitest?.describe("visible bot challenge sign-up policy", () => { }); test("allows sign-up when visible challenge failure override is enabled", () => { - Reflect.set(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", "true"); + Reflect.set(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", "true"); expect(() => assertVisibleBotChallengePassedForSignUp({ status: "error", @@ -146,7 +146,7 @@ import.meta.vitest?.describe("visible bot challenge sign-up policy", () => { }); test("treats invalid visible challenges as bypassable failures when the override is enabled", () => { - Reflect.set(processEnv, "STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", "true"); + Reflect.set(processEnv, "HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE", "true"); expect(() => assertVisibleBotChallengePassedForSignUp({ status: "invalid", diff --git a/packages/template/src/lib/hexclave-app/url-targets.test.ts b/packages/template/src/lib/hexclave-app/url-targets.test.ts index 71f48ee08..0a8983010 100644 --- a/packages/template/src/lib/hexclave-app/url-targets.test.ts +++ b/packages/template/src/lib/hexclave-app/url-targets.test.ts @@ -81,7 +81,7 @@ describe("handler URL targets", () => { }); it("uses hosted defaults for unspecified URLs", () => { - vi.stubEnv("NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test"); + vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test"); const urls = resolveHandlerUrls({ projectId: "project-id", @@ -97,7 +97,7 @@ describe("handler URL targets", () => { }); it("keeps redirect-only post-auth targets local even when the default target is hosted", () => { - vi.stubEnv("NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test"); + vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test"); const urls = resolveHandlerUrls({ projectId: "project-id", @@ -141,7 +141,7 @@ describe("handler URL targets", () => { }); it("inherits a hosted default target for the OAuth callback", () => { - vi.stubEnv("NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test"); + vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test"); const urls = resolveHandlerUrls({ projectId: "project-id", @@ -179,7 +179,7 @@ describe("handler URL targets", () => { }); it("uses default target for unknown /handler/* pages", () => { - vi.stubEnv("NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test"); + vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test"); const url = resolveUnknownHandlerPathFallbackUrl({ defaultTarget: { type: "hosted" }, @@ -191,7 +191,7 @@ describe("handler URL targets", () => { }); it("uses the full hosted handler URL template when configured", () => { - vi.stubEnv("NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE", "http://{projectId}.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09/{hostedPath}"); + vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE", "http://{projectId}.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09/{hostedPath}"); vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX", "93"); const urls = resolveHandlerUrls({ @@ -206,7 +206,7 @@ describe("handler URL targets", () => { }); it("validates the hosted handler URL template placeholders", () => { - vi.stubEnv("NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE", "http://localhost:9309/{projectId}/handler"); + vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE", "http://localhost:9309/{projectId}/handler"); expect(() => resolveHandlerUrls({ projectId: "project-id", @@ -217,7 +217,7 @@ describe("handler URL targets", () => { }); it("rejects hosted handler URL templates that put the project ID in the path", () => { - vi.stubEnv("NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE", "http://localhost:9309/{projectId}/{hostedPath}"); + vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE", "http://localhost:9309/{projectId}/{hostedPath}"); expect(() => resolveHandlerUrls({ projectId: "project-id",