diff --git a/.changeset/fedramp-remote-config-diff.md b/.changeset/fedramp-remote-config-diff.md new file mode 100644 index 00000000000..9d606dc0112 --- /dev/null +++ b/.changeset/fedramp-remote-config-diff.md @@ -0,0 +1,8 @@ +--- +"@cloudflare/deploy-helpers": patch +"wrangler": patch +--- + +Fetch the remote config diff from the configured compliance region + +When a Worker was last deployed from the dashboard, `wrangler deploy` and `wrangler versions upload` download its remote configuration to compare with the local one. These requests ignored the `compliance_region` field in the Wrangler configuration file and only honoured the `CLOUDFLARE_COMPLIANCE_REGION` environment variable. A FedRAMP High Worker configured through the config file would send them to `api.cloudflare.com` instead of `api.fed.cloudflare.com`, and the deploy would fail with authentication errors. They now use the same compliance region as the rest of the deploy. diff --git a/packages/deploy-helpers/src/deploy/helpers/download-worker-config.ts b/packages/deploy-helpers/src/deploy/helpers/download-worker-config.ts index d98737385c7..ed6b40b6df2 100644 --- a/packages/deploy-helpers/src/deploy/helpers/download-worker-config.ts +++ b/packages/deploy-helpers/src/deploy/helpers/download-worker-config.ts @@ -1,9 +1,7 @@ -import { - COMPLIANCE_REGION_CONFIG_UNKNOWN, - constructWranglerConfig, -} from "@cloudflare/workers-utils"; +import { constructWranglerConfig } from "@cloudflare/workers-utils"; import { fetchResult } from "../../shared/context"; import type { + ComplianceConfig, RawConfig, ServiceMetadataRes, WorkerMetadata, @@ -44,6 +42,7 @@ type RoutesRes = { * Downloads all information required to construct a Wrangler config file for a Worker from the API */ export async function fetchWorkerConfig( + complianceConfig: ComplianceConfig, accountId: string, workerName: string, environment: string @@ -57,27 +56,27 @@ export async function fetchWorkerConfig( cronTriggers, ] = await Promise.all([ fetchResult( - COMPLIANCE_REGION_CONFIG_UNKNOWN, + complianceConfig, `/accounts/${accountId}/workers/services/${workerName}/environments/${environment}/bindings` ), fetchResult( - COMPLIANCE_REGION_CONFIG_UNKNOWN, + complianceConfig, `/accounts/${accountId}/workers/services/${workerName}/environments/${environment}/routes?show_zonename=true` ), fetchResult( - COMPLIANCE_REGION_CONFIG_UNKNOWN, + complianceConfig, `/accounts/${accountId}/workers/domains/records?page=0&per_page=5&service=${workerName}&environment=${environment}` ), fetchResult( - COMPLIANCE_REGION_CONFIG_UNKNOWN, + complianceConfig, `/accounts/${accountId}/workers/services/${workerName}/environments/${environment}/subdomain` ), fetchResult( - COMPLIANCE_REGION_CONFIG_UNKNOWN, + complianceConfig, `/accounts/${accountId}/workers/services/${workerName}/environments/${environment}` ), fetchResult( - COMPLIANCE_REGION_CONFIG_UNKNOWN, + complianceConfig, `/accounts/${accountId}/workers/scripts/${workerName}/schedules` ), ]).catch((e) => { @@ -101,6 +100,7 @@ export async function fetchWorkerConfig( * approximates what a wrangler config object for the worker was/would have been. */ export async function downloadWorkerConfig( + complianceConfig: ComplianceConfig, workerName: string, environment: string, entrypoint: string, @@ -113,7 +113,12 @@ export async function downloadWorkerConfig( subdomainStatus, serviceEnvMetadata, cronTriggers, - } = await fetchWorkerConfig(accountId, workerName, environment); + } = await fetchWorkerConfig( + complianceConfig, + accountId, + workerName, + environment + ); return constructWranglerConfig({ name: workerName, diff --git a/packages/deploy-helpers/src/deploy/helpers/validate-worker-props.ts b/packages/deploy-helpers/src/deploy/helpers/validate-worker-props.ts index b7b71bc869f..123211d6b2f 100644 --- a/packages/deploy-helpers/src/deploy/helpers/validate-worker-props.ts +++ b/packages/deploy-helpers/src/deploy/helpers/validate-worker-props.ts @@ -232,6 +232,7 @@ export async function preUploadApiChecks( if (script.last_deployed_from === "dash") { const remoteWorkerConfig = await downloadWorkerConfig( + config, name, serviceMetaData.default_environment.environment, props.entry.file, diff --git a/packages/wrangler/src/__tests__/deploy/config-remote.test.ts b/packages/wrangler/src/__tests__/deploy/config-remote.test.ts index 95f4a82db88..261827cbc88 100644 --- a/packages/wrangler/src/__tests__/deploy/config-remote.test.ts +++ b/packages/wrangler/src/__tests__/deploy/config-remote.test.ts @@ -706,5 +706,51 @@ describe("deploy", () => { // to set a non-zero exit code expect(process.exitCode).not.toBe(0); }); + + it.for([ + { source: "the config file", complianceRegionInConfig: true }, + { source: "an env var", complianceRegionInConfig: false }, + ])( + "should fetch the remote config from the FedRAMP High region when it is set in $source", + async ({ complianceRegionInConfig }, { expect }) => { + if (!complianceRegionInConfig) { + vi.stubEnv("CLOUDFLARE_COMPLIANCE_REGION", "fedramp_high"); + } + + writeWorkerSource(); + mockGetServiceByName("test-name", "production", "dash"); + writeWranglerConfig({ + compatibility_date: "2024-04-24", + main: "./index.js", + ...(complianceRegionInConfig && { + compliance_region: "fedramp_high", + }), + }); + mockSubDomainRequest(); + mockUploadWorkerRequest({ expectedBaseUrl: "api.fed.cloudflare.com" }); + mockGetServiceBindings("test-name", []); + mockGetServiceRoutes("test-name", []); + mockGetServiceCustomDomainRecords([]); + mockGetServiceSubDomainData("test-name", { + enabled: true, + previews_enabled: true, + }); + mockGetServiceSchedules("test-name", { schedules: [] }); + mockGetServiceMetadata("test-name", { + script: { compatibility_date: "2024-04-24" }, + } as unknown as ServiceMetadataRes["default_environment"]); + + const requestedHosts = new Set(); + msw.use( + http.all("*", ({ request }) => { + requestedHosts.add(new URL(request.url).host); + }) + ); + + await runWrangler("deploy"); + + expect([...requestedHosts]).toEqual(["api.fed.cloudflare.com"]); + } + ); }); }); diff --git a/packages/wrangler/src/init.ts b/packages/wrangler/src/init.ts index 111d97b4000..16b655fdaa7 100644 --- a/packages/wrangler/src/init.ts +++ b/packages/wrangler/src/init.ts @@ -195,6 +195,7 @@ export async function downloadWorker(accountId: string, workerName: string) { ); const config = await downloadWorkerConfig( + COMPLIANCE_REGION_CONFIG_UNKNOWN, workerName, defaultEnvironment, entrypoint, diff --git a/packages/wrangler/src/utils/download-worker-config.ts b/packages/wrangler/src/utils/download-worker-config.ts index cdfc29ae2d7..bdf514beb6f 100644 --- a/packages/wrangler/src/utils/download-worker-config.ts +++ b/packages/wrangler/src/utils/download-worker-config.ts @@ -2,23 +2,31 @@ import { downloadWorkerConfig as downloadWorkerConfigBase, fetchWorkerConfig as fetchWorkerConfigBase, } from "@cloudflare/deploy-helpers"; -import type { RawConfig } from "@cloudflare/workers-utils"; +import type { ComplianceConfig, RawConfig } from "@cloudflare/workers-utils"; export async function fetchWorkerConfig( + complianceConfig: ComplianceConfig, accountId: string, workerName: string, environment: string ) { - return fetchWorkerConfigBase(accountId, workerName, environment); + return fetchWorkerConfigBase( + complianceConfig, + accountId, + workerName, + environment + ); } export async function downloadWorkerConfig( + complianceConfig: ComplianceConfig, workerName: string, environment: string, entrypoint: string, accountId: string ): Promise { return downloadWorkerConfigBase( + complianceConfig, workerName, environment, entrypoint,