From d29a8e73990df5390c61a06facac73c43a08a642 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 19 Apr 2026 19:50:53 -0400 Subject: [PATCH 1/2] fix(firestore-bigquery-change-tracker): resolve project ID from GOOGLE_CLOUD_PROJECT for Gen2 functions PROJECT_ID is only set in Gen1 Cloud Functions. Gen2 functions running on Cloud Run expose GOOGLE_CLOUD_PROJECT instead, causing project ID to resolve to undefined and producing broken SQL (undefined.dataset.table). Adds a small gcpProject utility that mirrors the GOOGLE_CLOUD_PROJECT || PROJECT_ID fallback pattern already used in other extensions (delete-user-data). Fixes https://github.com/firebase/extensions/issues/2778 Co-Authored-By: Claude Sonnet 4.6 --- .../src/__tests__/bigquery/gcpProject.test.ts | 50 +++++++++++++++++++ .../src/bigquery/gcpProject.ts | 26 ++++++++++ .../src/bigquery/index.ts | 3 +- .../src/bigquery/snapshot.ts | 3 +- 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 firestore-bigquery-export/firestore-bigquery-change-tracker/src/__tests__/bigquery/gcpProject.test.ts create mode 100644 firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/gcpProject.ts diff --git a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/__tests__/bigquery/gcpProject.test.ts b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/__tests__/bigquery/gcpProject.test.ts new file mode 100644 index 000000000..01c153378 --- /dev/null +++ b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/__tests__/bigquery/gcpProject.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { resolveGcpProjectIdForBigQuery } from "../../bigquery/gcpProject"; + +const ENV_VARS = ["PROJECT_ID", "GOOGLE_CLOUD_PROJECT"]; + +function clearEnv() { + for (const v of ENV_VARS) delete process.env[v]; +} + +beforeEach(clearEnv); +afterEach(clearEnv); + +describe("resolveGcpProjectIdForBigQuery", () => { + it("returns the explicit preferred value first", () => { + process.env.GOOGLE_CLOUD_PROJECT = "env-project"; + expect(resolveGcpProjectIdForBigQuery("explicit-project")).toBe( + "explicit-project" + ); + }); + + it("prefers GOOGLE_CLOUD_PROJECT over PROJECT_ID (Gen2 / Cloud Run)", () => { + process.env.GOOGLE_CLOUD_PROJECT = "gen2-project"; + process.env.PROJECT_ID = "gen1-project"; + expect(resolveGcpProjectIdForBigQuery(undefined)).toBe("gen2-project"); + }); + + it("falls back to PROJECT_ID when GOOGLE_CLOUD_PROJECT is absent", () => { + process.env.PROJECT_ID = "gen1-project"; + expect(resolveGcpProjectIdForBigQuery(undefined)).toBe("gen1-project"); + }); + + it("returns undefined when no source is available", () => { + expect(resolveGcpProjectIdForBigQuery(undefined)).toBeUndefined(); + }); +}); diff --git a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/gcpProject.ts b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/gcpProject.ts new file mode 100644 index 000000000..9dbe194f2 --- /dev/null +++ b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/gcpProject.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function resolveGcpProjectIdForBigQuery( + preferred?: string +): string | undefined { + return ( + preferred || + process.env.GOOGLE_CLOUD_PROJECT || + process.env.PROJECT_ID || + undefined + ); +} diff --git a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/index.ts b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/index.ts index 7b6f8a15e..ef9627f54 100644 --- a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/index.ts +++ b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/index.ts @@ -42,6 +42,7 @@ import { tableRequiresUpdate } from "./checkUpdates"; import { parseErrorMessage, waitForInitialization } from "./utils"; import { initializeLatestView } from "./initializeLatestView"; import { logger, LogLevel } from "../logger"; +import { resolveGcpProjectIdForBigQuery } from "./gcpProject"; export { RawChangelogSchema, RawChangelogViewSchema } from "./schema"; import type { ChangeTrackerConfig } from "./types"; @@ -68,7 +69,7 @@ export class FirestoreBigQueryEventHistoryTracker constructor(public config: ChangeTrackerConfig) { this.bq = new bigquery.BigQuery(); - this.bq.projectId = config.bqProjectId || process.env.PROJECT_ID; + this.bq.projectId = resolveGcpProjectIdForBigQuery(config.bqProjectId); this.partitioningConfig = new PartitioningConfig(this.config.partitioning); diff --git a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/snapshot.ts b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/snapshot.ts index 01d2bee62..37c434b85 100644 --- a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/snapshot.ts +++ b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/snapshot.ts @@ -16,6 +16,7 @@ import * as sqlFormatter from "sql-formatter"; import { timestampField } from "./schema"; +import { resolveGcpProjectIdForBigQuery } from "./gcpProject"; const excludeFields: string[] = ["document_name", "document_id"]; const nonGroupFields = ["event_id", "data", "old_data"]; @@ -65,7 +66,7 @@ export function buildLatestSnapshotViewQuery({ }: BuildLatestSnapshotViewQueryOptions): string { validateInputs({ datasetId, tableName, timestampColumnName, groupByColumns }); - const projectId = bqProjectId || process.env.PROJECT_ID; + const projectId = resolveGcpProjectIdForBigQuery(bqProjectId); return useLegacyQuery ? buildLegacyQuery( From 87ad4b8c1261c0582a45cfb9c3caf95c92fdaf19 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 20 Apr 2026 07:14:10 -0400 Subject: [PATCH 2/2] fix(firestore-bigquery-change-tracker): address Gemini code review feedback - Remove redundant `|| undefined` in resolveGcpProjectIdForBigQuery - Throw a descriptive error in buildLatestSnapshotViewQuery when project ID cannot be resolved, preventing silent generation of invalid SQL Co-Authored-By: Claude Sonnet 4.6 --- .../src/bigquery/gcpProject.ts | 3 +-- .../src/bigquery/snapshot.ts | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/gcpProject.ts b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/gcpProject.ts index 9dbe194f2..7c23866ef 100644 --- a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/gcpProject.ts +++ b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/gcpProject.ts @@ -20,7 +20,6 @@ export function resolveGcpProjectIdForBigQuery( return ( preferred || process.env.GOOGLE_CLOUD_PROJECT || - process.env.PROJECT_ID || - undefined + process.env.PROJECT_ID ); } diff --git a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/snapshot.ts b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/snapshot.ts index 37c434b85..7e5fd69e0 100644 --- a/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/snapshot.ts +++ b/firestore-bigquery-export/firestore-bigquery-change-tracker/src/bigquery/snapshot.ts @@ -67,6 +67,11 @@ export function buildLatestSnapshotViewQuery({ validateInputs({ datasetId, tableName, timestampColumnName, groupByColumns }); const projectId = resolveGcpProjectIdForBigQuery(bqProjectId); + if (!projectId) { + throw new Error( + "Could not determine BigQuery project ID. Provide it via the bqProjectId config option or set the GOOGLE_CLOUD_PROJECT / PROJECT_ID environment variable." + ); + } return useLegacyQuery ? buildLegacyQuery(