fix(functions): fail-fast with actionable error when declarative security APIs are disabled - #11063
Conversation
…rity APIs are disabled When deploying functions with declarative security (requiresRole), check that iam.googleapis.com and cloudresourcemanager.googleapis.com are enabled on the project before attempting discovery or SA provisioning. If either API is disabled, fail fast with an actionable error message providing both the exact gcloud services enable command and Google Cloud Console enablement URLs. Also handle downstream cached/race 403 SERVICE_DISABLED errors with cache eviction and friendly rethrowing.
There was a problem hiding this comment.
Code Review
This pull request introduces a fail-fast mechanism that checks if the required Google Cloud APIs (IAM and Cloud Resource Manager) are enabled before deploying functions with declarative security, throwing actionable errors if they are not. The review feedback is highly constructive and identifies critical improvements: handling potential permission errors during API checks to avoid blocking users with restricted permissions, mapping service hostnames to friendly names to correctly match legacy GCP error messages, and adding a unit test to verify this mapping.
…I friendly names - Catch errors in checkDeclarativeSecurityApisEnabled to fail open when caller lacks Service Usage permissions - Add SERVICE_FRIENDLY_NAMES map in isServiceDisabledError for legacy GCP error messages - Add unit tests verifying both cases
…ing cache Remove downstream 403 catch and isServiceDisabledError helper, trusting local cache consistency like the rest of the CLI.
ajperel
left a comment
There was a problem hiding this comment.
A bunch of minor stuff but overall pretty good. Thanks for simplifying.
… API check - Move checkDeclarativeSecurityApisEnabled to src/deploy/functions/ensure.ts - Scope fail-open error handling specifically to HTTP 403 and PERMISSION_DENIED - Improve debug log message phrasing and preserve Winston error stack trace - Use Sinon .withArgs(...) in prepare.spec.ts and shorten expectation assertions - Add unit test verifying non-permission errors are re-thrown
ajperel
left a comment
There was a problem hiding this comment.
Looks great. Thanks for the fast iteration on this.
Description
When deploying functions configured with Declarative Security (
requiresRole/ Function Kits), deployment requires:iam.googleapis.com: To generate, inspect, and provision managed service accounts (firebase-fn-...).cloudresourcemanager.googleapis.com: To inspect and update project IAM policies.If
iam.googleapis.comis disabled on the target Google Cloud project, deployments previously passed thepreparephase, uploaded source code to Cloud Storage, and failed asynchronously 2–3 minutes later inside Cloud Build with an obscure error (generic::permission_denied: Identity and Access Management (IAM) API is disabled).Rather than adding these APIs to
STANDARD_APIS(which would auto-prompt enablement for all function deployments regardless of whether declarative security is used), this PR implements a lean fail-fast pre-flight check:Pre-Flight Validation (
checkDeclarativeSecurityApisEnabled):discoverSecurityDetails(), checks that bothiam.googleapis.comandcloudresourcemanager.googleapis.comare enabled on the project usingensureApiEnabled.check().{ exit: 1 }) before creating service accounts or packaging code.gcloud services enable <apis> --project <projectId>ensureApiEnabled.enableApiURI(projectId, api)) for users withoutgcloudor who need to forward the link to their project owner.Least-Privilege & CI/CD Safety (Fail-Open):
serviceusage.services.get) and fails open withlogger.debug. This ensures deployment-only credentials that lack Service Usage read access are not falsely blocked when the APIs are actually enabled.Guards & Unenrollment Safety:
requiresRole) bypass this check entirely.!requiredRoles && existingManagedSA) also bypass the check, ensuring users removing declarative security are never blocked.Scenarios Tested
src/deploy/functions/prepare.spec.ts):iam.googleapis.comandcloudresourcemanager.googleapis.comdisabled: asserts unified error message, combinedgcloudcommand, and console URLs.iam.googleapis.comdisabled: asserts single-API isolation.cloudresourcemanager.googleapis.comdisabled: asserts single-API isolation.serviceusage.services.getfails open and does not block deployment.(All 89 tests passing)
Sample Commands & Error Output
When required APIs are disabled: