Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load secrets when emulating functions with --inspect-function flag #5308

Merged
merged 2 commits into from Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions 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)
2 changes: 1 addition & 1 deletion src/emulator/extensionsEmulator.ts
Expand Up @@ -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,
Expand Down
84 changes: 48 additions & 36 deletions src/emulator/functionsEmulator.ts
Expand Up @@ -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<string, backend.SecretEnvVar>, curr: EmulatedTriggerDefinition) => {
for (const secret of curr.secretEnvironmentVariables || []) {
acc[secret.key] = secret;
}
return acc;
},
{}
Comment on lines +662 to +669
Copy link
Contributor

Choose a reason for hiding this comment

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

(no action required) ohhh reduce is so hard for me. I think I always just end up writing a for loop.

)
);
await this.startRuntime(emulatableBackend);
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/test/emulators/extensionsEmulator.spec.ts
Expand Up @@ -119,7 +119,7 @@ describe("Extensions Emulator", () => {
],
extension: TEST_EXTENSION,
extensionVersion: TEST_EXTENSION_VERSION,
codebase: "",
codebase: "ext-test",
},
},
];
Expand Down