diff --git a/src/deploy/functions/services/index.ts b/src/deploy/functions/services/index.ts index c79971daa34..afbaeffb973 100644 --- a/src/deploy/functions/services/index.ts +++ b/src/deploy/functions/services/index.ts @@ -207,6 +207,8 @@ const EVENT_SERVICE_MAPPING: Record = { "google.firebase.dataconnect.connector.v1.mutationExecuted": dataconnectService, "google.firebase.ailogic.v1.beforeGenerate": aiLogicService, "google.firebase.ailogic.v1.afterGenerate": aiLogicService, + "google.firebase.auth.user.v2.created": noOpService, + "google.firebase.auth.user.v2.deleted": noOpService, }; export function serviceForEndpoint(endpoint: backend.Endpoint | build.Endpoint): Service { diff --git a/src/deploy/functions/validate.spec.ts b/src/deploy/functions/validate.spec.ts index 34a527a0b73..22ee7ed6ed5 100644 --- a/src/deploy/functions/validate.spec.ts +++ b/src/deploy/functions/validate.spec.ts @@ -9,6 +9,7 @@ import * as secretManager from "../../gcp/secretManager"; import * as backend from "./backend"; import { BEFORE_CREATE_EVENT, BEFORE_SIGN_IN_EVENT } from "../../functions/events/v1"; import { resolveCpuAndConcurrency } from "./prepare"; +import * as experiments from "../../experiments"; describe("validate", () => { describe("functionsDirectoryExists", () => { @@ -494,6 +495,46 @@ describe("validate", () => { "The following functions have timeouts that exceed the maximum allowed for their trigger typ", ); }); + + it("disallows v2 Auth Eventarc triggers if autheventarc experiment is not enabled", () => { + experiments.setEnabled("autheventarc", false); + const ep: backend.Endpoint = { + ...ENDPOINT_BASE, + platform: "gcfv2", + eventTrigger: { + eventType: "google.firebase.auth.user.v2.created", + eventFilters: {}, + retry: false, + }, + }; + + try { + expect(() => validate.endpointsAreValid(backend.of(ep))).to.throw( + /Cannot deploy Auth Eventarc triggers because the experiment.*autheventarc.*is not enabled/, + ); + } finally { + experiments.setEnabled("autheventarc", null); + } + }); + + it("allows v2 Auth Eventarc triggers if autheventarc experiment is enabled", () => { + experiments.setEnabled("autheventarc", true); + const ep: backend.Endpoint = { + ...ENDPOINT_BASE, + platform: "gcfv2", + eventTrigger: { + eventType: "google.firebase.auth.user.v2.created", + eventFilters: {}, + retry: false, + }, + }; + + try { + expect(() => validate.endpointsAreValid(backend.of(ep))).to.not.throw(); + } finally { + experiments.setEnabled("autheventarc", null); + } + }); }); describe("endpointsAreUnqiue", () => { diff --git a/src/deploy/functions/validate.ts b/src/deploy/functions/validate.ts index fe12d75ff8b..aa5d66a9f7c 100644 --- a/src/deploy/functions/validate.ts +++ b/src/deploy/functions/validate.ts @@ -10,6 +10,10 @@ import * as fsutils from "../../fsutils"; import * as backend from "./backend"; import * as utils from "../../utils"; import * as secrets from "../../functions/secrets"; +import * as experiments from "../../experiments"; +import { AUTH_EVENTS } from "../../functions/events/v2"; + +const AUTH_EVENTS_SET = new Set(AUTH_EVENTS); /** * GCF Gen 1 has a max timeout of 540s. @@ -89,6 +93,11 @@ export function endpointsAreValid(wantBackend: backend.Backend): void { validateTimeoutConfig(endpoints); for (const ep of endpoints) { validateScheduledTimeout(ep); + if (backend.isEventTriggered(ep)) { + if (AUTH_EVENTS_SET.has(ep.eventTrigger.eventType)) { + experiments.assertEnabled("autheventarc", "deploy Auth Eventarc triggers"); + } + } const service = serviceForEndpoint(ep); if (backend.isBlockingTriggered(ep)) { if (service.name === "noop") { diff --git a/src/experiments.ts b/src/experiments.ts index 5daa8e826b3..b05c02e61f3 100644 --- a/src/experiments.ts +++ b/src/experiments.ts @@ -215,6 +215,13 @@ export const ALL_EXPERIMENTS = experiments({ default: false, public: true, }, + autheventarc: { + shortDescription: "Enable experimental Eventarc-based Auth triggers", + fullDescription: + "Enable support for v2 Eventarc-based Auth triggers (onUserCreated and onUserDeleted)", + default: false, + public: true, + }, }); export type ExperimentName = keyof typeof ALL_EXPERIMENTS; diff --git a/src/functions/events/v2.ts b/src/functions/events/v2.ts index 8dd1fe9d691..177e9a0d251 100644 --- a/src/functions/events/v2.ts +++ b/src/functions/events/v2.ts @@ -41,6 +41,11 @@ export const FIREALERTS_EVENT = "google.firebase.firebasealerts.alerts.v1.publis export const DATACONNECT_EVENT = "google.firebase.dataconnect.connector.v1.mutationExecuted"; +export const AUTH_EVENTS = [ + "google.firebase.auth.user.v2.created", + "google.firebase.auth.user.v2.deleted", +] as const; + export type Event = | typeof PUBSUB_PUBLISH_EVENT | (typeof STORAGE_EVENTS)[number] @@ -51,7 +56,8 @@ export type Event = | (typeof FIRESTORE_EVENTS)[number] | typeof FIREALERTS_EVENT | typeof DATACONNECT_EVENT - | (typeof AI_LOGIC_EVENTS)[number]; + | (typeof AI_LOGIC_EVENTS)[number] + | (typeof AUTH_EVENTS)[number]; // Why can't auth context be removed? This is map was added to correct a bug where a regex // allowed any non-auth type to be converted to any auth type, but we should follow up for why