Skip to content

fix: preserve existing cloud run invokers for scheduled v2 functions#10411

Closed
IzaakGough wants to merge 1 commit intomainfrom
@invertase/fix-preserve-external-changes
Closed

fix: preserve existing cloud run invokers for scheduled v2 functions#10411
IzaakGough wants to merge 1 commit intomainfrom
@invertase/fix-preserve-external-changes

Conversation

@IzaakGough
Copy link
Copy Markdown

@IzaakGough IzaakGough commented Apr 23, 2026

Summary

Fixes #6549

Scheduled GCFv2 functions currently overwrite the roles/run.invoker binding on Cloud Run during deploy. This causes externally added invoker members to be removed on create/update, even if the scheduler-required service account is still present.

This change ensures that scheduled GCFv2 deploys preserve existing Cloud Run invoker members by merging them with the required scheduler invoker, instead of replacing the binding outright.


What Changed

  • Added an optional merge mode to:

    src/gcp/run.ts -> setInvokerUpdate(...)
  • Updated scheduled GCFv2 create flow in src/deploy/functions/release/fabricator.ts
    to use:

    setInvokerUpdate(..., { mergeExistingMembers: true })
  • Updated scheduled GCFv2 update flow in the same file to pass the same merge option.

  • Added helper-level test coverage in src/gcp/run.spec.ts

  • Added deploy-layer test coverage in src/deploy/functions/release/fabricator.spec.ts for scheduled create/update call paths.


Why

Before this change, scheduled GCFv2 deploys computed a single desired invoker:

  • The function’s configured serviceAccount, or
  • The default compute service account

This value was then written back as the full roles/run.invoker binding, which removed any additional invoker members added outside of Firebase.

Reproduction

  1. Deploy a scheduled GCFv2 function
  2. Add an additional custom invoker member on the backing Cloud Run service
  3. Re-deploy the function (or make a trivial update)
  4. Observe that the custom invoker is removed

Further details of this reproduction can be seen here


Tests

Added coverage for:

  • run.setInvokerUpdate(..., { mergeExistingMembers: true })

    preserving existing invoker members

  • Scheduled createV2Function using merge mode with:

    • default service account
    • explicit service account
  • Scheduled updateV2Function using merge mode


Important Behavior Note

This change is currently unconditional for scheduled GCFv2 functions. It does not consult or derive from the preserveExternalChanges / preserve_external_changes option.

Instead, scheduled-function invoker updates now always merge existing roles/run.invoker members by default. This is intentional for this fix, but worth calling out explicitly.


Potential Follow-up

A future improvement could thread a real preserveExternalChanges signal into this path, making the behavior conditional rather than always-on for scheduled GCFv2 functions.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@IzaakGough IzaakGough marked this pull request as ready for review April 23, 2026 09:51
@IzaakGough
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the Cloud Run invoker logic to support merging existing IAM members instead of overwriting them, specifically for scheduled functions. It replaces setInvokerCreate with setInvokerUpdate in the fabricator's creation flow and introduces an InvokerUpdateOptions interface to toggle member merging. Corresponding unit tests have been updated and expanded to cover these changes. I have no feedback to provide.

@cabljac cabljac self-requested a review April 23, 2026 14:15
@cabljac
Copy link
Copy Markdown

cabljac commented Apr 23, 2026

Ah so the main problem is, as the PR description says - you're making it unconditional, whereas the proper fix would make preserve_external_changes=True work?

@cabljac
Copy link
Copy Markdown

cabljac commented Apr 23, 2026

Closing for now, have a new branch with a full fix on incoming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

firebase deploy overrides members of invoker role on CloudRun service, even if preserve_external_changes is set to True

2 participants