From dfac1cae5039ee15cdc95b2ea52cc75ed82c8675 Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Tue, 20 Oct 2026 16:09:14 +0100 Subject: [PATCH 01/11] docs(delete-user-data): recommend .env. and document uninstall functions:kits:uninstall only deletes deployed resources for a project with a .env. file, so with a plain .env the kit kept running after uninstall. Recommend .env. and add an Uninstall section covering the topics and IAM bindings it leaves behind. --- kits/delete-user-data/CHANGELOG.md | 2 ++ kits/delete-user-data/README.md | 45 +++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/kits/delete-user-data/CHANGELOG.md b/kits/delete-user-data/CHANGELOG.md index 0e40c6a6f..ad933cd6f 100644 --- a/kits/delete-user-data/CHANGELOG.md +++ b/kits/delete-user-data/CHANGELOG.md @@ -1,3 +1,5 @@ +- fix: the README now recommends `.env.` for instance config and has an Uninstall section. `firebase functions:kits:uninstall` only deletes deployed resources for a project with a `.env.` file, so with the plain `.env` the README suggested before, it removed the instance from `firebase.json` and exited without an error but left the functions running and deleting user data. The new section also covers the Pub/Sub topics and IAM role bindings that uninstall leaves behind. + - fix: an Eventarc publish failure no longer fails the function. A channel that was deleted or is unreachable answers `PERMISSION_DENIED`, and the publish was awaited after the work, so the deletion completed but the invocation still failed. The publish failure is now logged as a warning and the invocation continues. Deploys also declare `eventarcpublishing.googleapis.com`, so the API is enabled on your project whether or not you use events. The failed invocation used to be redelivered, re-running a deletion that had already succeeded; it no longer is. - fix: `ENABLE_AUTO_DISCOVERY` accepts the extension's `yes` / `no` values again. The kit had declared it as a boolean param, which only counts the literal `true` as enabled, so a `.env` copied from an installed extension instance carried `yes` and silently left auto-discovery switched off. The param is now the extension's labeled `Yes` / `No` select and is read the same way the extension read it. diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index 465d7a7cd..0c86beb3f 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -53,7 +53,8 @@ export { } from "@firebase-function-kits/delete-user-data"; ``` -and configure with a `.env` (or `.env.`). +and configure it in a `.env.` file (see [Uninstall](#uninstall) for +why not a plain `.env`). Importing the package without exporting its functions deploys nothing — the CLI only deploys what your entry file exports. @@ -79,7 +80,7 @@ later, behind the `kits` experiment — earlier CLIs do not provide the ``` `instances` maps each instance id to the directory (relative to -`firebase.json`) holding that instance's `.env`. The CLI prefixes every +`firebase.json`) holding that instance's `.env.`. The CLI prefixes every function and task queue name with `kit--`, so the functions above deploy as `kit-default-clearData`, `kit-default-handleSearch`, and `kit-default-handleDeletion`. @@ -93,8 +94,10 @@ Deploy a single instance with `firebase deploy --only functions:`. ## Configuration -Set these values in a `.env` (or `.env.`) file. The Firebase CLI -loads them at deploy time and prompts for any required values that are missing. +Set these values in a `.env.` file, such as `.env.my-project`. The +Firebase CLI loads them at deploy time and prompts for any required values that +are missing. A plain `.env` deploys the same way, but +`functions:kits:uninstall` ignores it (see [Uninstall](#uninstall)). The instance id is not a setting: the CLI provides it to each instance as `FIREBASE_KIT_INSTANCE_ID`, set to that instance's key in the `instances` map. @@ -121,7 +124,7 @@ overridden there. ## Multiple instances To run several deletion pipelines, add one entry per instance to the `instances` -map, each pointing at its own config directory with its own `.env`: +map, each pointing at its own config directory with its own `.env.`: ```json { @@ -148,7 +151,7 @@ in sync by hand. The functions can publish deletion events for each backend under `firebase.extensions.delete-user-data.v1.*` (`firestore`, `database`, and -`storage`). Set both of these in `.env` to turn them on: +`storage`). Set both of these in `.env.` to turn them on: | Env var | Description | |---|---| @@ -162,6 +165,34 @@ no event types selected. The channel must already exist. Deploying the kit does not create it, and publishing to a missing channel logs a warning without failing the function. +## Uninstall + +```sh +firebase functions:kits:uninstall --instance +``` + +This deletes the instance's functions, their triggers and Pub/Sub subscriptions, +and the service account the CLI created for them. It then removes the instance +from `firebase.json` and deletes its `.env.` file. + +It only deletes what is deployed to a project with a `.env.` file in +the instance's config directory. With only a plain `.env`, it still removes the +instance from `firebase.json` and exits without an error, but the functions keep +running and keep deleting user data. Rename `.env` to `.env.` before +you uninstall. If you already uninstalled with a plain `.env`, put the instance +back in `firebase.json`, rename the file, and run the command again. + +Uninstalling the extension removed the same resources and kept its two Pub/Sub +topics. The kit also keeps two things: + +- The topics `kit--discovery` and `kit--deletion` (or + the names in `DISCOVERY_TOPIC_NAME` and `DELETION_TOPIC_NAME`). Delete them + with `gcloud pubsub topics delete `. +- The deleted service account's project roles, which the extension removed. + They show in your project's IAM policy as `deleted:serviceAccount:firebase-fn-…` + members, no longer grant access, and can be removed with + `gcloud projects remove-iam-policy-binding --member= --role=`. + ## Differences from the Delete User Data extension This kit is the extension repackaged as an npm package, but a few things behave @@ -252,7 +283,7 @@ using the bug template, with `delete-user-data kit` in the title. Include: - The kit version (run `npm ls @firebase-function-kits/delete-user-data` in the directory where you installed it), your `firebase-tools` version (`firebase --version`) and Node.js version. -- Your configuration from your `.env` (or `.env.`) file, with +- Your configuration from your `.env.` (or `.env`) file, with secrets and project details redacted. - Steps to reproduce, the result you expected, and the result you got. - Logs from the kit's functions in Cloud Logging (with their From 864b7d70b03d186575d2b55efb1e2b2a86246071 Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 2 Nov 2026 18:55:58 +0000 Subject: [PATCH 02/11] docs(delete-user-data): say uninstall needs --force without a TTY --- kits/delete-user-data/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index 0c86beb3f..9892868d0 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -175,6 +175,10 @@ This deletes the instance's functions, their triggers and Pub/Sub subscriptions, and the service account the CLI created for them. It then removes the instance from `firebase.json` and deletes its `.env.` file. +The command asks you to confirm, twice if this is the kit's only instance. In a +non-interactive shell (CI, a script, or any shell without a TTY), add +`--force`: without it the command exits 0 and deletes nothing. + It only deletes what is deployed to a project with a `.env.` file in the instance's config directory. With only a plain `.env`, it still removes the instance from `firebase.json` and exits without an error, but the functions keep From 078b9ae9a7a6e3b35155e13a9dc1455091356b57 Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 2 Nov 2026 18:56:08 +0000 Subject: [PATCH 03/11] docs(delete-user-data): say uninstalling the only instance removes the kit entry --- kits/delete-user-data/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index 9892868d0..c1c71c817 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -173,7 +173,10 @@ firebase functions:kits:uninstall --instance This deletes the instance's functions, their triggers and Pub/Sub subscriptions, and the service account the CLI created for them. It then removes the instance -from `firebase.json` and deletes its `.env.` file. +from `firebase.json` and deletes its `.env.` file. If it is the kit's +only instance, it removes the whole kit entry, leaving `"functions": []`. +Despite what the prompt says, it doesn't delete your functions source when the +kit is exported from your own codebase, as in [Usage](#usage). The command asks you to confirm, twice if this is the kit's only instance. In a non-interactive shell (CI, a script, or any shell without a TTY), add @@ -184,7 +187,8 @@ the instance's config directory. With only a plain `.env`, it still removes the instance from `firebase.json` and exits without an error, but the functions keep running and keep deleting user data. Rename `.env` to `.env.` before you uninstall. If you already uninstalled with a plain `.env`, put the instance -back in `firebase.json`, rename the file, and run the command again. +(or, if it was the only one, the whole kit entry) back in `firebase.json`, +rename the file, and run the command again. Uninstalling the extension removed the same resources and kept its two Pub/Sub topics. The kit also keeps two things: From 6e9eef49dd7517f46fb4ae2a2b6417df466231e5 Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 2 Nov 2026 18:56:19 +0000 Subject: [PATCH 04/11] docs(delete-user-data): note that .env.local breaks uninstall --- kits/delete-user-data/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index c1c71c817..7201f861e 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -190,6 +190,9 @@ you uninstall. If you already uninstalled with a plain `.env`, put the instance (or, if it was the only one, the whole kit entry) back in `firebase.json`, rename the file, and run the command again. +A `.env.local` file (the emulator override) next to a plain `.env` makes the +command fail with "contains no .env file for current project". + Uninstalling the extension removed the same resources and kept its two Pub/Sub topics. The kit also keeps two things: From c62613209469148ff9156dc4d29e4eb8e8b1596b Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 2 Nov 2026 18:56:25 +0000 Subject: [PATCH 05/11] docs(delete-user-data): explain uninstalling an instance deployed to several projects --- kits/delete-user-data/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index 7201f861e..51b077ab6 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -190,6 +190,11 @@ you uninstall. If you already uninstalled with a plain `.env`, put the instance (or, if it was the only one, the whole kit entry) back in `firebase.json`, rename the file, and run the command again. +If the instance is deployed to more than one project, give each project its own +`.env.` (copy a shared `.env`, don't rename it) and run the command +once per project with `--project `. The instance stays in +`firebase.json` until the last project's file is gone. + A `.env.local` file (the emulator override) next to a plain `.env` makes the command fail with "contains no .env file for current project". From 6a35a790b762f4842bf304d92181593b03cb2a1c Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 2 Nov 2026 18:56:33 +0000 Subject: [PATCH 06/11] docs(delete-user-data): show how to find and remove leftover IAM bindings --- kits/delete-user-data/README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index 51b077ab6..8091988c4 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -204,9 +204,17 @@ topics. The kit also keeps two things: - The topics `kit--discovery` and `kit--deletion` (or the names in `DISCOVERY_TOPIC_NAME` and `DELETION_TOPIC_NAME`). Delete them with `gcloud pubsub topics delete `. -- The deleted service account's project roles, which the extension removed. - They show in your project's IAM policy as `deleted:serviceAccount:firebase-fn-…` - members, no longer grant access, and can be removed with +- The deleted service account's seven project roles, which the extension + removed. They no longer grant access, and show in your project's IAM policy + as members like + `deleted:serviceAccount:firebase-fn-@.iam.gserviceaccount.com?uid=`. + List them with: + + ```sh + gcloud projects get-iam-policy --flatten="bindings[].members" --filter="bindings.members:deleted:serviceAccount:firebase-fn-" --format="value(bindings.role,bindings.members)" + ``` + + and remove each one, one command per role, with `gcloud projects remove-iam-policy-binding --member= --role=`. ## Differences from the Delete User Data extension From e8a92c6206502fedccfaa260a5b20c71e65c003c Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 2 Nov 2026 18:56:52 +0000 Subject: [PATCH 07/11] docs(kits): recommend .env. over a plain .env --- kits/README.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/kits/README.md b/kits/README.md index ae645d0df..a2d36016c 100644 --- a/kits/README.md +++ b/kits/README.md @@ -7,10 +7,10 @@ Firebase Functions codebase and deploy into your own project. While an extension is installed as a managed instance configured through the Firebase console or CLI, a kit is code you own: you install the package, export the functions you want from your functions entry file, configure it with a -`.env`, and deploy with `firebase deploy`. There is no hosted version, so the -functions run in your project, under your service account, on your deployment -schedule. That also means you can read the source, fork it, or import the -package's `./lib` entry point and register the triggers yourself. +`.env.` file, and deploy with `firebase deploy`. There is no hosted +version, so the functions run in your project, under your service account, on +your deployment schedule. That also means you can read the source, fork it, or +import the package's `./lib` entry point and register the triggers yourself. Each directory here contains the source code for a kit and a README explaining how it works, including the roles it needs, the settings it reads, and the @@ -63,10 +63,16 @@ instances to deploy: } ``` -Each instance ID maps to the directory holding that instance's `.env`, and the -CLI prefixes every function name with `kit--`, so one kit can run -several independently configured instances side by side. See each kit's README -for its exports, its settings, and the roles the CLI grants on deploy. +Each instance ID maps to the directory holding that instance's +`.env.` file, and the CLI prefixes every function name with +`kit--`, so one kit can run several independently configured +instances side by side. See each kit's README for its exports, its settings, and +the roles the CLI grants on deploy. + +Use a `.env.` file rather than a plain `.env`. +`firebase functions:kits:uninstall` only deletes what is deployed to a project +with a `.env.` file; with a plain `.env` it removes the instance from +`firebase.json` but leaves its functions running. ## Migrating from an extension From 316d0cf0711d5ac2e522a357e7a37cac92e4af40 Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 9 Nov 2026 15:51:10 +0000 Subject: [PATCH 08/11] docs(delete-user-data): say uninstall without --force only exits 0 for the kit's only instance --- kits/delete-user-data/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index 22183c1af..20c05bea3 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -198,8 +198,10 @@ Despite what the prompt says, it doesn't delete your functions source when the kit is exported from your own codebase, as in [Usage](#usage). The command asks you to confirm, twice if this is the kit's only instance. In a -non-interactive shell (CI, a script, or any shell without a TTY), add -`--force`: without it the command exits 0 and deletes nothing. +non-interactive shell (CI, a script, any shell without a TTY, or when the CLI +detects an AI agent), add `--force`. Without it nothing is deleted: the command +exits 0 for the kit's only instance, and fails with `Command aborted.` +otherwise. It only deletes what is deployed to a project with a `.env.` file in the instance's config directory. With only a plain `.env`, it still removes the From 2ce09f87cd352bd5894ea6dddc0dad52e31ef775 Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 9 Nov 2026 15:51:10 +0000 Subject: [PATCH 09/11] docs(delete-user-data): cover .env.local next to .env. when uninstalling --- kits/delete-user-data/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index 20c05bea3..b77cf4688 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -216,8 +216,11 @@ If the instance is deployed to more than one project, give each project its own once per project with `--project `. The instance stays in `firebase.json` until the last project's file is gone. -A `.env.local` file (the emulator override) next to a plain `.env` makes the -command fail with "contains no .env file for current project". +Move any `.env.local` file (the emulator override) out of the instance's config +directory before you uninstall. Next to a plain `.env`, it makes the command +fail with "contains no .env file for current project". Next to +`.env.`, the command deletes the functions but leaves the instance in +`firebase.json`, and running it again fails with that error. Uninstalling the extension removed the same resources and kept its two Pub/Sub topics. The kit also keeps two things: From 8b6a9f3cac80a21bc2ed54f9c260fd423854a091 Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 9 Nov 2026 15:51:10 +0000 Subject: [PATCH 10/11] docs(delete-user-data): list only the uninstalled instance's leftover IAM bindings --- kits/delete-user-data/README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index b77cf4688..ca6d242f0 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -232,14 +232,19 @@ topics. The kit also keeps two things: removed. They no longer grant access, and show in your project's IAM policy as members like `deleted:serviceAccount:firebase-fn-@.iam.gserviceaccount.com?uid=`. - List them with: + The account's name doesn't include the instance id, and other kits' deleted + accounts look the same, so note the `firebase-fn-` account the uninstall + command prints ("The following managed service accounts will also be + deleted" or "Deleting managed service account"). List its roles with: ```sh - gcloud projects get-iam-policy --flatten="bindings[].members" --filter="bindings.members:deleted:serviceAccount:firebase-fn-" --format="value(bindings.role,bindings.members)" + gcloud projects get-iam-policy --flatten="bindings[].members" --filter="bindings.members:deleted:serviceAccount:firebase-fn-@" --format="value(bindings.role,bindings.members)" ``` and remove each one, one command per role, with - `gcloud projects remove-iam-policy-binding --member= --role=`. + `gcloud projects remove-iam-policy-binding --member='' --role= --condition=None`. + Keep the quotes: the `?` in the member makes some shells, such as zsh, fail + with "no matches found". ## Differences from the Delete User Data extension From a1e6917c6783ff3d3acc7d0d6f4c53dd0da2b3e9 Mon Sep 17 00:00:00 2001 From: Corie Watson Date: Mon, 9 Nov 2026 15:51:10 +0000 Subject: [PATCH 11/11] docs(delete-user-data): recommend .env. in the remaining README sections --- kits/delete-user-data/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index ca6d242f0..bee02b42e 100644 --- a/kits/delete-user-data/README.md +++ b/kits/delete-user-data/README.md @@ -99,7 +99,7 @@ Firebase CLI loads them at deploy time and prompts for any required values that are missing. A plain `.env` deploys the same way, but `functions:kits:uninstall` ignores it (see [Uninstall](#uninstall)). -The CLI does not check values that are already in `.env`, so the kit checks +The CLI does not check values that are already in the file, so the kit checks them itself when the deploy loads it, as the extension did at install time. The deploy fails with an error naming the setting if `FIRESTORE_DELETE_MODE`, `ENABLE_AUTO_DISCOVERY` or `SELECTED_DATABASE_LOCATION` is not one of the @@ -275,12 +275,12 @@ since one function publishes to a topic the other is triggered by. The extension deployed to the location you picked at install time (`us-central1` by default). The kit reads the region from -`FUNCTION_DEFAULT_REGION` in each instance's `.env`, also defaulting to +`FUNCTION_DEFAULT_REGION` in each instance's `.env.`, also defaulting to `us-central1`, so instances can deploy to different regions. `firebase ext:migrate` writes it with the region the extension ran in. ```sh -# .env (or .env.) +# .env. FUNCTION_DEFAULT_REGION=us-central1 ```