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 diff --git a/kits/delete-user-data/CHANGELOG.md b/kits/delete-user-data/CHANGELOG.md index 66cf755b7..e76901c0a 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: `EXT_SELECTED_EVENTS` is validated at deploy, as the extension's install did. firebase-admin splits the list on commas without trimming, so `a, b, c` published only `a` and silently dropped the rest, and a type with different case or a typo was dropped without a warning. The deploy now fails if an entry has spaces or different case, isn't one of the three event types, or is listed twice. It also fails if event types are listed without `EVENTARC_CHANNEL`, or the channel isn't a full `projects//locations//channels/` name in this project and a location the extension supported (`us-central1`, `us-west1`, `europe-west4` or `asia-northeast1`); before, events were silently turned off. Empty entries are still skipped, and an unset or empty value still publishes nothing. - fix: `clearData`, `handleSearch` and `handleDeletion` can scale to 3000 instances each again, as the extension's 1st gen functions could. The kit set no `maxInstances`, so each function took the 2nd gen default of 100, and with one event per instance it handled at most 100 deletions or searches at once. `setGlobalOptions({ maxInstances })` still overrides it. Existing kit deployments switch on their next deploy. diff --git a/kits/delete-user-data/README.md b/kits/delete-user-data/README.md index 723c06523..e53195ac1 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,10 +94,12 @@ 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 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 @@ -140,7 +143,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 { @@ -167,7 +170,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 | |---|---| @@ -188,6 +191,68 @@ 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. 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, 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 +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 +(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. + +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: + +- 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 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=`. + 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)" + ``` + + and remove each one, one command per role, with + `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 This kit is the extension repackaged as an npm package, but a few things behave @@ -217,12 +282,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 ``` @@ -308,7 +373,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