firebase-tools icon indicating copy to clipboard operation
firebase-tools copied to clipboard

Functions emulator should not requires authenticated secret manager calls if .secret.local is defined

Open glorat opened this issue 7 months ago • 2 comments

[REQUIRED] Environment info

firebase-tools: 13.12.0

Platform: macOS

[REQUIRED] Test case

A firebase function that depends on a secret. E.g.

export const processUploadedFile = functions
  .region(FUNCTION_REGION)
  .runWith({ secrets: FUNCTION_SECRETS })
  .storage.object()
  .onFinalize(processUploadedFileHandler)

Also have a .secret.local file that defines all required secrets

[REQUIRED] Steps to reproduce

With no firebase or application default credentials in place (or being offline) firebase --project demo-my-project-id emulators:start

[REQUIRED] Expected behavior

Since .secret.local is defined, we should not worry if secrets manager is inaccessible (due to lack of credentials or being offline) since we assume user has populated .secret.local properly. I expect any issues to be handled at runtime with ⬢ functions: Unable to access secret environment variables from Google Cloud Secret Manager. Make sure the credential used for the Functions Emulator have access or provide override values in /.../functions/.secret.local: as correctly handled by resolveSecretEnvs

[REQUIRED] Actual behavior

⬢ functions: Failed to load function definition from source: FirebaseError: HTTP Error: 401, Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.

Through debugging with local firebase-tools, this is happening in the functions deploy phase, where the issue is at resolveParams which has the following code

const [needSecret, needPrompt] = partition(outstanding, (param) => param.type === "secret");
  for (const param of needSecret) {
    await handleSecret(param as SecretParam, firebaseConfig.projectId);
  }

which requires caller to have access to the secret manager APIs to succeed.

Commenting out the call to handleSecret gives me the expected behaviour - if I have no credentials or even if I'm offline, the emulator starts with functions and my full stack operates as expected.

Background

The background is that I'm trying to get the emulator to work while fully offline as I'll be travelling without internet for a while and have been following advice from #3916 and elsewhere. This is the only issue that needs to be resolved for me to work offline.

Workaround

I have built a local copy of firebase-tools and commented out the await handleSecret line and am okay now.

Proposed fix

The best fix is for handleSecret in params.ts to check for the existence of the secret in .secret.local before making the call out to secret manager. Centralise the code in resolveSecretEnvs in functionsEmulator for reuse.

Or if it were me doing the PR, after line 385 in params.ts, I'd load .secret.local there, then for any matched secret, ignore the call to handleSecret.

I am open to making a PR for this patch if requested (since I'm using a local copy of firebase-tools anyway and can test easily).

glorat avatar Jun 30 '24 03:06 glorat