diff --git a/.changeset/skip-api-project-config.md b/.changeset/skip-api-project-config.md new file mode 100644 index 000000000..f1e2059a1 --- /dev/null +++ b/.changeset/skip-api-project-config.md @@ -0,0 +1,7 @@ +--- +"cf": patch +--- + +Skip reading the compliance region from the config file when it is set in the environment + +Resolve `CLOUDFLARE_COMPLIANCE_REGION` before project settings, matching the existing account ID priority. Commands with both `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_COMPLIANCE_REGION` no longer evaluate a `cloudflare.config.ts` file solely to establish API context. diff --git a/packages/cli/src/__tests__/commands/api-config-loading.test.ts b/packages/cli/src/__tests__/commands/api-config-loading.test.ts new file mode 100644 index 000000000..832a5b40f --- /dev/null +++ b/packages/cli/src/__tests__/commands/api-config-loading.test.ts @@ -0,0 +1,44 @@ +import { writeFile } from "node:fs/promises"; +import { runInTempDir } from "@cloudflare/workers-utils/test-helpers"; +import { http, HttpResponse } from "msw/http"; +import { afterEach, describe, expect, it, vi } from "vite-plus/test"; +import { server, setupMsw, TEST_BASE_URL } from "../helpers/msw.js"; +import { runCf } from "../helpers/run-cf.js"; + +describe("API command project config loading", () => { + runInTempDir(); + setupMsw(); + + afterEach(() => vi.restoreAllMocks()); + + it("does not load project config when account ID and compliance region are in the environment", async () => { + await writeFile( + "cloudflare.config.ts", + `import "a-package-that-does-not-exist"; export default {};` + ); + vi.spyOn(console, "log").mockImplementation(() => undefined); + let requested = false; + server.use( + http.get( + `${TEST_BASE_URL}/accounts/account-1/workers/scripts-search`, + () => { + requested = true; + return HttpResponse.json({ success: true, result: [] }); + } + ) + ); + + const result = await runCf( + ["workers", "scripts", "search", "--name", "x"], + { + CLOUDFLARE_API_BASE_URL: TEST_BASE_URL, + CLOUDFLARE_API_TOKEN: "test-token", + CLOUDFLARE_ACCOUNT_ID: "account-1", + CLOUDFLARE_COMPLIANCE_REGION: "public", + } + ); + + expect(result.exitCode).toBe(0); + expect(requested).toBe(true); + }); +}); diff --git a/packages/cli/src/__tests__/lib/context.test.ts b/packages/cli/src/__tests__/lib/context.test.ts index f4ef120f3..c51b4bd9b 100644 --- a/packages/cli/src/__tests__/lib/context.test.ts +++ b/packages/cli/src/__tests__/lib/context.test.ts @@ -156,27 +156,15 @@ describe("context", () => { await expect(getComplianceRegion()).resolves.toBe("fedramp_high"); }); - it("prioritises the legacy env representation", async () => { + it("reads the environment before loading project settings", async () => { + writeFileSync( + join(process.cwd(), "cloudflare.config.ts"), + `throw new Error("project config should not be loaded");` + ); vi.stubEnv("CLOUDFLARE_COMPLIANCE_REGION", "fedramp_high"); await expect(getComplianceRegion()).resolves.toBe("fedramp_high"); }); - it("warns when the environment overrides project settings", async () => { - const warn = vi - .spyOn(console, "warn") - .mockImplementation(() => undefined); - vi.stubEnv("CLOUDFLARE_COMPLIANCE_REGION", "public"); - writeProjectSettings({ complianceRegion: "fedramp-high" }); - - await expect(getComplianceRegion()).resolves.toBe("public"); - await expect(getComplianceRegion()).resolves.toBe("public"); - - expect(warn).toHaveBeenCalledOnce(); - expect(warn).toHaveBeenCalledWith( - 'The compliance region was resolved to "public" from the `CLOUDFLARE_COMPLIANCE_REGION` environment variable, which takes precedence over the configured value "fedramp-high" in `cloudflare.config.ts`.' - ); - }); - it("throws on an invalid value", async () => { vi.stubEnv("CLOUDFLARE_COMPLIANCE_REGION", "invalid"); await expect(getComplianceRegion()).rejects.toThrow( diff --git a/packages/cli/src/lib/context.ts b/packages/cli/src/lib/context.ts index 487bcd0c4..d37821fc7 100644 --- a/packages/cli/src/lib/context.ts +++ b/packages/cli/src/lib/context.ts @@ -203,8 +203,6 @@ const VALID_COMPLIANCE_REGIONS = ["public", "fedramp_high"] as const; export type ComplianceRegion = (typeof VALID_COMPLIANCE_REGIONS)[number]; -let complianceRegionConflictsReported = false; - /** * Resolve the compliance region in the representation consumed by * workers-auth/workers-utils. cloudflare.config.ts uses `fedramp-high`, which @@ -213,38 +211,23 @@ let complianceRegionConflictsReported = false; async function resolveComplianceRegion( options: { isPreview?: boolean } = {} ): Promise { + const envRegion = normalizeComplianceRegion( + process.env.CLOUDFLARE_COMPLIANCE_REGION, + "CLOUDFLARE_COMPLIANCE_REGION" + ); + if (envRegion) { + return envRegion; + } + const preloadedProjectSettings = getLoadedProjectSettings(undefined, options); const projectSettings = preloadedProjectSettings === undefined ? await loadProjectSettings(undefined, options) : preloadedProjectSettings; - const configuredValue = projectSettings?.settings?.complianceRegion; - const configureRegion = normalizeComplianceRegion( - configuredValue, + return normalizeComplianceRegion( + projectSettings?.settings?.complianceRegion, "cloudflare.config.ts" ); - const envValue = process.env.CLOUDFLARE_COMPLIANCE_REGION; - const envRegion = normalizeComplianceRegion( - envValue, - "CLOUDFLARE_COMPLIANCE_REGION" - ); - - if (!envRegion) { - return configureRegion; - } - - if ( - configureRegion && - configureRegion !== envRegion && - !complianceRegionConflictsReported - ) { - complianceRegionConflictsReported = true; - console.warn( - `The compliance region was resolved to "${envValue}" from the \`CLOUDFLARE_COMPLIANCE_REGION\` environment variable, which takes precedence over the configured value "${configuredValue}" in \`cloudflare.config.ts\`.` - ); - } - - return envRegion; } /** Get the compliance region, defaulting to public. */