From 42d31a2b09bc8c1bba86f79c070ca9387831e8f2 Mon Sep 17 00:00:00 2001 From: kdelay Date: Mon, 3 Aug 2026 11:19:47 +0900 Subject: [PATCH] [wrangler] Let CLOUDFLARE_ACCOUNT_ID override the cached account id in pages project commands pages project list, create and delete passed the internal Pages cache (pages.json) straight to requireAuth. Account selection treats config.account_id as user-authored configuration and ranks it above CLOUDFLARE_ACCOUNT_ID, so a stale cached account silently won and the command targeted the wrong account. Overlay the environment account id on top of the cache before resolving auth, matching what pages deploy, pages deployment list, pages deployment delete, pages download config and pages secret already do. The three existing "should override cached accountId" tests used vi.mock("getConfigCache", ...), which mocks a module specifier that does not exist, so the cache was empty and the assertions passed against the bug. They now seed the real cache with saveToConfigCache and fail without the fix. --- .../pages-project-commands-env-account-id.md | 9 +++++++++ .../__tests__/pages/project-create.test.ts | 11 ++++++----- .../__tests__/pages/project-delete.test.ts | 11 ++++++----- .../src/__tests__/pages/project-list.test.ts | 12 ++++++------ packages/wrangler/src/pages/projects.ts | 19 ++++++++++++++++--- 5 files changed, 43 insertions(+), 19 deletions(-) create mode 100644 .changeset/pages-project-commands-env-account-id.md diff --git a/.changeset/pages-project-commands-env-account-id.md b/.changeset/pages-project-commands-env-account-id.md new file mode 100644 index 00000000000..4053cb14d21 --- /dev/null +++ b/.changeset/pages-project-commands-env-account-id.md @@ -0,0 +1,9 @@ +--- +"wrangler": patch +--- + +Let `CLOUDFLARE_ACCOUNT_ID` override the cached account id in `wrangler pages project` commands + +`pages project list`, `pages project create` and `pages project delete` passed the internal Pages cache (`pages.json`) straight to account selection, which treats `account_id` as user-authored configuration and therefore ranks it above `CLOUDFLARE_ACCOUNT_ID`. In a multi-account setup a stale cached account won silently, so the command targeted the wrong account and failed with `Authentication error [code: 10000]`. + +These three commands now overlay the environment account id on top of the cache before resolving auth, which is what `pages deploy`, `pages deployment list`, `pages deployment delete`, `pages download config` and `pages secret` already do. The cache is still used as a fallback when the environment variable is unset. diff --git a/packages/wrangler/src/__tests__/pages/project-create.test.ts b/packages/wrangler/src/__tests__/pages/project-create.test.ts index ace31374cac..f1810dbff4d 100644 --- a/packages/wrangler/src/__tests__/pages/project-create.test.ts +++ b/packages/wrangler/src/__tests__/pages/project-create.test.ts @@ -1,11 +1,14 @@ import { runInTempDir } from "@cloudflare/workers-utils/test-helpers"; import { http, HttpResponse } from "msw"; import { afterEach, describe, it, vi } from "vitest"; +import { saveToConfigCache } from "../../config-cache"; +import { PAGES_CONFIG_CACHE_FILENAME } from "../../pages/constants"; import { endEventLoop } from "../helpers/end-event-loop"; import { mockAccountId, mockApiToken } from "./../helpers/mock-account-id"; import { mockConsoleMethods } from "./../helpers/mock-console"; import { msw } from "./../helpers/msw"; import { runWrangler } from "./../helpers/run-wrangler"; +import type { PagesConfigCache } from "../../pages/types"; describe("pages project create", () => { const std = mockConsoleMethods(); @@ -186,11 +189,9 @@ describe("pages project create", () => { { once: true } ) ); - vi.mock("getConfigCache", () => { - return { - account_id: "original-account-id", - project_name: "an-existing-project", - }; + saveToConfigCache(PAGES_CONFIG_CACHE_FILENAME, { + account_id: "original-account-id", + project_name: "an-existing-project", }); vi.stubEnv("CLOUDFLARE_ACCOUNT_ID", "new-account-id"); await runWrangler( diff --git a/packages/wrangler/src/__tests__/pages/project-delete.test.ts b/packages/wrangler/src/__tests__/pages/project-delete.test.ts index 48b64476f9f..3ece4c40137 100644 --- a/packages/wrangler/src/__tests__/pages/project-delete.test.ts +++ b/packages/wrangler/src/__tests__/pages/project-delete.test.ts @@ -1,6 +1,8 @@ import { runInTempDir } from "@cloudflare/workers-utils/test-helpers"; import { http, HttpResponse } from "msw"; import { afterEach, beforeEach, describe, it, vi } from "vitest"; +import { saveToConfigCache } from "../../config-cache"; +import { PAGES_CONFIG_CACHE_FILENAME } from "../../pages/constants"; import { endEventLoop } from "../helpers/end-event-loop"; import { mockAccountId, mockApiToken } from "../helpers/mock-account-id"; import { mockConsoleMethods } from "../helpers/mock-console"; @@ -8,6 +10,7 @@ import { clearDialogs, mockConfirm } from "../helpers/mock-dialogs"; import { useMockIsTTY } from "../helpers/mock-istty"; import { msw } from "../helpers/msw"; import { runWrangler } from "../helpers/run-wrangler"; +import type { PagesConfigCache } from "../../pages/types"; describe("pages project delete", () => { const std = mockConsoleMethods(); @@ -151,11 +154,9 @@ describe("pages project delete", () => { text: `Are you sure you want to delete "an-existing-project"? This action cannot be undone.`, result: true, }); - vi.mock("getConfigCache", () => { - return { - account_id: "original-account-id", - project_name: "an-existing-project", - }; + saveToConfigCache(PAGES_CONFIG_CACHE_FILENAME, { + account_id: "original-account-id", + project_name: "an-existing-project", }); vi.stubEnv("CLOUDFLARE_ACCOUNT_ID", "new-account-id"); await runWrangler("pages project delete an-existing-project"); diff --git a/packages/wrangler/src/__tests__/pages/project-list.test.ts b/packages/wrangler/src/__tests__/pages/project-list.test.ts index 2667eb11fb3..da22c071296 100644 --- a/packages/wrangler/src/__tests__/pages/project-list.test.ts +++ b/packages/wrangler/src/__tests__/pages/project-list.test.ts @@ -1,12 +1,14 @@ import { runInTempDir } from "@cloudflare/workers-utils/test-helpers"; import { http, HttpResponse } from "msw"; import { afterEach, describe, it, vi } from "vitest"; +import { saveToConfigCache } from "../../config-cache"; +import { PAGES_CONFIG_CACHE_FILENAME } from "../../pages/constants"; import { endEventLoop } from "../helpers/end-event-loop"; import { mockConsoleMethods } from "../helpers/mock-console"; import { mockAccountId, mockApiToken } from "./../helpers/mock-account-id"; import { msw } from "./../helpers/msw"; import { runWrangler } from "./../helpers/run-wrangler"; -import type { Project } from "./../../pages/types"; +import type { PagesConfigCache, Project } from "./../../pages/types"; import type { ExpectStatic } from "vitest"; describe("pages project list", () => { @@ -83,11 +85,9 @@ describe("pages project list", () => { it("should override cached accountId with CLOUDFLARE_ACCOUNT_ID environmental variable if provided", async ({ expect, }) => { - vi.mock("getConfigCache", () => { - return { - account_id: "original-account-id", - project_name: "an-existing-project", - }; + saveToConfigCache(PAGES_CONFIG_CACHE_FILENAME, { + account_id: "original-account-id", + project_name: "an-existing-project", }); vi.stubEnv("CLOUDFLARE_ACCOUNT_ID", "new-account-id"); const requests = mockProjectListRequest(expect, [], "new-account-id"); diff --git a/packages/wrangler/src/pages/projects.ts b/packages/wrangler/src/pages/projects.ts index 415fd2cda42..e1f9b06036a 100644 --- a/packages/wrangler/src/pages/projects.ts +++ b/packages/wrangler/src/pages/projects.ts @@ -1,4 +1,5 @@ import { execSync } from "node:child_process"; +import { getCloudflareAccountIdFromEnv } from "@cloudflare/workers-auth"; import { COMPLIANCE_REGION_CONFIG_PUBLIC, UserError, @@ -42,7 +43,11 @@ export const pagesProjectListCommand = createCommand({ PAGES_CONFIG_CACHE_FILENAME ); - const accountId = await requireAuth(config); + const envAccountId = getCloudflareAccountIdFromEnv(); + const accountId = await requireAuth({ + ...config, + ...(envAccountId ? { account_id: envAccountId } : {}), + }); const projects: Array = await listProjects({ accountId }); @@ -148,7 +153,11 @@ export const pagesProjectCreateCommand = createCommand({ const config = getConfigCache( PAGES_CONFIG_CACHE_FILENAME ); - const accountId = await requireAuth(config); + const envAccountId = getCloudflareAccountIdFromEnv(); + const accountId = await requireAuth({ + ...config, + ...(envAccountId ? { account_id: envAccountId } : {}), + }); // When run by an AI agent, delegate new static Pages projects to a Workers // static-assets deploy of the current directory. Accounts that already @@ -303,7 +312,11 @@ export const pagesProjectDeleteCommand = createCommand({ const config = getConfigCache( PAGES_CONFIG_CACHE_FILENAME ); - const accountId = await requireAuth(config); + const envAccountId = getCloudflareAccountIdFromEnv(); + const accountId = await requireAuth({ + ...config, + ...(envAccountId ? { account_id: envAccountId } : {}), + }); const confirmed = args.yes ||