From f6e5a11d5f97aa275ba6286b91b374b0c60a45b8 Mon Sep 17 00:00:00 2001 From: Izaak Gough Date: Wed, 19 Aug 2026 16:05:38 +0100 Subject: [PATCH] fix(bigquery-firestore-export): remove unused service account plumbing `serviceAccountName` belongs on the create request, not inside the transfer config, so the value passed here never reached the API. Nothing populated it either, since there is no param for it. The query runs as the function's own account, which is what it would have used regardless. Removing it rather than correcting the placement, because naming an account explicitly needs `actAs` on it, even its own, which would mean requesting project-wide `roles/iam.serviceAccountUser`. --- kits/bigquery-firestore-export/src/dts.ts | 17 ++++++++++------- .../src/export-config.ts | 4 ---- .../bigquery-firestore-export/tests/dts.test.ts | 6 +----- .../tests/export-config.test.ts | 4 ---- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/kits/bigquery-firestore-export/src/dts.ts b/kits/bigquery-firestore-export/src/dts.ts index 5f509b360..1129e48bf 100644 --- a/kits/bigquery-firestore-export/src/dts.ts +++ b/kits/bigquery-firestore-export/src/dts.ts @@ -65,10 +65,16 @@ function stringField(value: string | undefined): { stringValue: string } { return { stringValue: value ?? "" }; } -/** Creates the protobuf-shaped request used for a scheduled query. */ +/** + * Creates the protobuf-shaped request used for a scheduled query. + * + * The query runs as whichever identity creates it, which is this function. To + * name a different account, `serviceAccountName` goes on the request rather + * than on the transfer config, and the caller needs `actAs` on the account it + * names, including its own. + */ export function createTransferConfigRequest( - config: ResolvedBigqueryFirestoreExportConfig, - serviceAccountEmail?: string + config: ResolvedBigqueryFirestoreExportConfig ): bigqueryDataTransfer.protos.google.cloud.bigquery.datatransfer.v1.ICreateTransferConfigRequest { return { parent: `projects/${config.projectId}`, @@ -88,9 +94,6 @@ export function createTransferConfigRequest( }, schedule: config.schedule, notificationPubsubTopic: `projects/${config.projectId}/topics/${config.pubSubTopic}`, - ...(serviceAccountEmail - ? { serviceAccountName: serviceAccountEmail } - : {}), }, }; } @@ -120,7 +123,7 @@ export async function createTransferConfig( ): Promise { logs.createTransferConfig(); const [created] = await client.createTransferConfig( - createTransferConfigRequest(config, config.serviceAccount) + createTransferConfigRequest(config) ); if (!created.name) { throw new Error("BigQuery API returned a transfer config without a name"); diff --git a/kits/bigquery-firestore-export/src/export-config.ts b/kits/bigquery-firestore-export/src/export-config.ts index c39f434d3..6718bb67e 100644 --- a/kits/bigquery-firestore-export/src/export-config.ts +++ b/kits/bigquery-firestore-export/src/export-config.ts @@ -45,8 +45,6 @@ export interface BigqueryFirestoreExportConfig { pubSubTopic?: string; /** Root Firestore collection for configs and run output. */ firestoreCollection?: string; - /** Runtime identity used when creating a DTS config. */ - serviceAccount?: string; /** Log verbosity. Defaults to `info`. */ logLevel?: LogLevel; } @@ -65,7 +63,6 @@ export interface ResolvedBigqueryFirestoreExportConfig { schedule: string; pubSubTopic: string; firestoreCollection: string; - serviceAccount?: string; logLevel: LogLevel; } @@ -117,7 +114,6 @@ export function resolveConfig( optional(config.pubSubTopic) ?? `kit-${instanceId}-processMessages`, firestoreCollection: optional(config.firestoreCollection) ?? "transferConfigs", - serviceAccount: optional(config.serviceAccount), logLevel, }; } diff --git a/kits/bigquery-firestore-export/tests/dts.test.ts b/kits/bigquery-firestore-export/tests/dts.test.ts index 060ff3ae3..0e54b1bb0 100644 --- a/kits/bigquery-firestore-export/tests/dts.test.ts +++ b/kits/bigquery-firestore-export/tests/dts.test.ts @@ -43,10 +43,7 @@ function clientWithTransferConfig(transferConfig: object): DataTransferClient { describe("createTransferConfigRequest", () => { test("creates the scheduled-query request", () => { - const request = createTransferConfigRequest( - config, - "runtime@test-project.iam.gserviceaccount.com" - ); + const request = createTransferConfigRequest(config); expect(request).toMatchObject({ parent: "projects/test-project", @@ -57,7 +54,6 @@ describe("createTransferConfigRequest", () => { schedule: "every 24 hours", notificationPubsubTopic: "projects/test-project/topics/kit-users-export-processMessages", - serviceAccountName: "runtime@test-project.iam.gserviceaccount.com", }, }); expect( diff --git a/kits/bigquery-firestore-export/tests/export-config.test.ts b/kits/bigquery-firestore-export/tests/export-config.test.ts index 728ae2883..d28ebb9f6 100644 --- a/kits/bigquery-firestore-export/tests/export-config.test.ts +++ b/kits/bigquery-firestore-export/tests/export-config.test.ts @@ -46,16 +46,12 @@ describe("resolveConfig", () => { ...minimal, transferConfigName: " projects/p/locations/us/transferConfigs/c ", partitioningField: " created_at ", - serviceAccount: " runtime@test-project.iam.gserviceaccount.com ", }); expect(resolved.transferConfigName).toBe( "projects/p/locations/us/transferConfigs/c" ); expect(resolved.partitioningField).toBe("created_at"); - expect(resolved.serviceAccount).toBe( - "runtime@test-project.iam.gserviceaccount.com" - ); }); test.each(["instanceId", "datasetId", "tableName", "queryString"] as const)(