From 97ce5505af95ea9e3cffcdf8b2d460c68786cde7 Mon Sep 17 00:00:00 2001 From: joehan Date: Wed, 7 Dec 2022 10:22:37 -0800 Subject: [PATCH] Load secrets when emulating functions with --inspect-function flag (#5308) * Load secrets when emulating functions with --inspect-function flag * add changeloag --- CHANGELOG.md | 1 + src/emulator/extensionsEmulator.ts | 2 +- src/emulator/functionsEmulator.ts | 84 +++++++++++-------- src/test/emulators/extensionsEmulator.spec.ts | 2 +- 4 files changed, 51 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 237eed9fca2..94af501af7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ - Add support for Firestore TTL (#5267) +- Fix bug where secrets were not loaded when emulating functions with `--inpsect-functions`. (#4605) diff --git a/src/emulator/extensionsEmulator.ts b/src/emulator/extensionsEmulator.ts index 04233bfe57d..c1fd847d7dc 100644 --- a/src/emulator/extensionsEmulator.ts +++ b/src/emulator/extensionsEmulator.ts @@ -234,7 +234,7 @@ export class ExtensionsEmulator implements EmulatorInstance { const emulatableBackend: EmulatableBackend = { functionsDir, env: nonSecretEnv, - codebase: "", + codebase: instance.instanceId, // Give each extension its own codebase name so that they don't share workerPools. secretEnv: secretEnvVariables, predefinedTriggers: extensionTriggers, nodeMajorVersion: nodeMajorVersion, diff --git a/src/emulator/functionsEmulator.ts b/src/emulator/functionsEmulator.ts index 296e0015d08..44ff3151ee3 100644 --- a/src/emulator/functionsEmulator.ts +++ b/src/emulator/functionsEmulator.ts @@ -653,10 +653,22 @@ export class FunctionsEmulator implements EmulatorInstance { this.logger.logLabeled("SUCCESS", `functions[${definition.id}]`, msg); } } - - // In debug mode, we eagerly start a runtime process to allow debuggers to attach + // In debug mode, we eagerly start the runtime processes to allow debuggers to attach // before invoking a function. if (this.args.debugPort) { + // Since we're about to start a runtime to be shared by all the functions in this codebase, + // we need to make sure it has all the secrets used by any function in the codebase. + emulatableBackend.secretEnv = Object.values( + toSetup.reduce( + (acc: Record, curr: EmulatedTriggerDefinition) => { + for (const secret of curr.secretEnvironmentVariables || []) { + acc[secret.key] = secret; + } + return acc; + }, + {} + ) + ); await this.startRuntime(emulatableBackend); } } @@ -1206,42 +1218,42 @@ export class FunctionsEmulator implements EmulatorInstance { ); } } + // Note - if trigger is undefined, we are loading in 'sequential' mode. + // In that case, we need to load all secrets for that codebase. + const secrets: backend.SecretEnvVar[] = + trigger?.secretEnvironmentVariables || backend.secretEnv; + const accesses = secrets + .filter((s) => !secretEnvs[s.key]) + .map(async (s) => { + this.logger.logLabeled("INFO", "functions", `Trying to access secret ${s.secret}@latest`); + const value = await accessSecretVersion( + this.getProjectId(), + s.secret, + s.version ?? "latest" + ); + return [s.key, value]; + }); + const accessResults = await allSettled(accesses); - if (trigger) { - const secrets: backend.SecretEnvVar[] = trigger.secretEnvironmentVariables || []; - const accesses = secrets - .filter((s) => !secretEnvs[s.key]) - .map(async (s) => { - this.logger.logLabeled("INFO", "functions", `Trying to access secret ${s.secret}@latest`); - const value = await accessSecretVersion( - this.getProjectId(), - s.secret, - s.version ?? "latest" - ); - return [s.key, value]; - }); - const accessResults = await allSettled(accesses); - - const errs: string[] = []; - for (const result of accessResults) { - if (result.status === "rejected") { - errs.push(result.reason as string); - } else { - const [k, v] = result.value; - secretEnvs[k] = v; - } + const errs: string[] = []; + for (const result of accessResults) { + if (result.status === "rejected") { + errs.push(result.reason as string); + } else { + const [k, v] = result.value; + secretEnvs[k] = v; } + } - if (errs.length > 0) { - this.logger.logLabeled( - "ERROR", - "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 ${secretPath}:\n\t` + - errs.join("\n\t") - ); - } + if (errs.length > 0) { + this.logger.logLabeled( + "ERROR", + "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 ${secretPath}:\n\t` + + errs.join("\n\t") + ); } return secretEnvs; @@ -1280,7 +1292,6 @@ export class FunctionsEmulator implements EmulatorInstance { "See https://yarnpkg.com/getting-started/migration#step-by-step for more information." ); } - const runtimeEnv = this.getRuntimeEnvs(backend, trigger); const secretEnvs = await this.resolveSecretEnvs(backend, trigger); const socketPath = getTemporarySocketPath(); @@ -1307,6 +1318,7 @@ export class FunctionsEmulator implements EmulatorInstance { instanceId: backend.extensionInstanceId, ref: backend.extensionVersion?.ref, }; + const pool = this.workerPools[backend.codebase]; const worker = pool.addWorker(trigger?.id, runtime, extensionLogInfo); await worker.waitForSocketReady(); diff --git a/src/test/emulators/extensionsEmulator.spec.ts b/src/test/emulators/extensionsEmulator.spec.ts index 2a4ff08dfaa..59231fd3636 100644 --- a/src/test/emulators/extensionsEmulator.spec.ts +++ b/src/test/emulators/extensionsEmulator.spec.ts @@ -119,7 +119,7 @@ describe("Extensions Emulator", () => { ], extension: TEST_EXTENSION, extensionVersion: TEST_EXTENSION_VERSION, - codebase: "", + codebase: "ext-test", }, }, ];