diff --git a/spec/v1/function-builder.spec.ts b/spec/v1/function-builder.spec.ts index f1e3e1189..da041e8f5 100644 --- a/spec/v1/function-builder.spec.ts +++ b/spec/v1/function-builder.spec.ts @@ -21,6 +21,7 @@ // SOFTWARE. import { expect } from "chai"; +import { clearParams, defineSecret } from "../../src/params"; import * as functions from "../../src/v1"; import { ResetValue } from "../../src/common/options"; @@ -94,6 +95,24 @@ describe("FunctionBuilder", () => { expect(fn.__endpoint.eventTrigger.retry).to.deep.equal(true); }); + it("should allow SecretParams in the secrets array and convert them", () => { + const sp = defineSecret("API_KEY"); + const fn = functions + .runWith({ + secrets: [sp], + }) + .auth.user() + .onCreate((user) => user); + + expect(fn.__endpoint.secretEnvironmentVariables).to.deep.equal([ + { + key: "API_KEY", + }, + ]); + + clearParams(); + }); + it("should apply a default failure policy if it's aliased with `true`", () => { const fn = functions .runWith({ @@ -493,26 +512,53 @@ describe("FunctionBuilder", () => { }); it("should throw error given secrets expressed with full resource name", () => { + const sp = defineSecret("projects/my-project/secrets/API_KEY"); + expect(() => functions.runWith({ secrets: ["projects/my-project/secrets/API_KEY"], }) ).to.throw(); + + expect(() => + functions.runWith({ + secrets: [sp], + }) + ).to.throw(); + clearParams(); }); it("should throw error given invalid secret config", () => { + const sp = defineSecret("ABC/efg"); + expect(() => functions.runWith({ secrets: ["ABC/efg"], }) ).to.throw(); + + expect(() => + functions.runWith({ + secrets: [sp], + }) + ).to.throw(); + clearParams(); }); it("should throw error given invalid secret with versions", () => { + const sp = defineSecret("ABC@3"); + expect(() => functions.runWith({ secrets: ["ABC@3"], }) ).to.throw(); + + expect(() => + functions.runWith({ + secrets: [sp], + }) + ).to.throw(); + clearParams(); }); }); diff --git a/src/runtime/manifest.ts b/src/runtime/manifest.ts index 7bdc0abf6..377e9f071 100644 --- a/src/runtime/manifest.ts +++ b/src/runtime/manifest.ts @@ -78,7 +78,6 @@ export interface ManifestEndpoint { maxDispatchesPerSecond?: number | Expression | ResetValue; }; }; - scheduleTrigger?: { schedule: string | Expression; timeZone?: string | Expression | ResetValue; diff --git a/src/v1/cloud-functions.ts b/src/v1/cloud-functions.ts index 588a257b7..a1793b3d1 100644 --- a/src/v1/cloud-functions.ts +++ b/src/v1/cloud-functions.ts @@ -32,6 +32,7 @@ import { ManifestRequiredAPI, } from "../runtime/manifest"; import { ResetValue } from "../common/options"; +import { SecretParam } from "../params/types"; export { Change } from "../common/change"; @@ -485,8 +486,13 @@ export function optionsToEndpoint(options: DeploymentOptions): ManifestEndpoint ); convertIfPresent(endpoint, options, "region", "regions"); convertIfPresent(endpoint, options, "serviceAccountEmail", "serviceAccount", (sa) => sa); - convertIfPresent(endpoint, options, "secretEnvironmentVariables", "secrets", (secrets) => - secrets.map((secret) => ({ key: secret })) + convertIfPresent( + endpoint, + options, + "secretEnvironmentVariables", + "secrets", + (secrets: (string | SecretParam)[]) => + secrets.map((secret) => ({ key: secret instanceof SecretParam ? secret.name : secret })) ); if (options?.vpcConnector !== undefined) { if (options.vpcConnector === null || options.vpcConnector instanceof ResetValue) { diff --git a/src/v1/function-builder.ts b/src/v1/function-builder.ts index 38f151a7d..0f813ec96 100644 --- a/src/v1/function-builder.ts +++ b/src/v1/function-builder.ts @@ -23,6 +23,7 @@ import * as express from "express"; import { ResetValue } from "../common/options"; +import { SecretParam } from "../params/types"; import { EventContext } from "./cloud-functions"; import { DeploymentOptions, @@ -192,7 +193,9 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean { } if (runtimeOptions.secrets !== undefined) { - const invalidSecrets = runtimeOptions.secrets.filter((s) => !/^[A-Za-z\d\-_]+$/.test(s)); + const invalidSecrets = runtimeOptions.secrets.filter( + (s) => !/^[A-Za-z\d\-_]+$/.test(s instanceof SecretParam ? s.name : s) + ); if (invalidSecrets.length > 0) { throw new Error( `Invalid secrets: ${invalidSecrets.join(",")}. ` + diff --git a/src/v1/function-configuration.ts b/src/v1/function-configuration.ts index 1da208b6e..cbaef9803 100644 --- a/src/v1/function-configuration.ts +++ b/src/v1/function-configuration.ts @@ -1,5 +1,6 @@ import { Expression } from "../params"; import { ResetValue } from "../common/options"; +import { SecretParam } from "../params/types"; export { RESET_VALUE } from "../common/options"; @@ -230,7 +231,7 @@ export interface RuntimeOptions { /* * Secrets to bind to a function instance. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** * Determines whether Firebase AppCheck is enforced. diff --git a/src/v2/options.ts b/src/v2/options.ts index 2072a6d0c..fc85bf148 100644 --- a/src/v2/options.ts +++ b/src/v2/options.ts @@ -29,7 +29,7 @@ import { convertIfPresent, copyIfPresent } from "../common/encoding"; import { RESET_VALUE, ResetValue } from "../common/options"; import { ManifestEndpoint } from "../runtime/manifest"; import { declaredParams, Expression } from "../params"; -import { ParamSpec } from "../params/types"; +import { ParamSpec, SecretParam } from "../params/types"; import { HttpsOptions } from "./providers/https"; import * as logger from "../logger"; @@ -181,7 +181,7 @@ export interface GlobalOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** * Determines whether Firebase AppCheck is enforced. Defaults to false. @@ -296,8 +296,13 @@ export function optionsToEndpoint( } return region; }); - convertIfPresent(endpoint, opts, "secretEnvironmentVariables", "secrets", (secrets) => - secrets.map((secret) => ({ key: secret })) + convertIfPresent( + endpoint, + opts, + "secretEnvironmentVariables", + "secrets", + (secrets: (string | SecretParam)[]) => + secrets.map((secret) => ({ key: secret instanceof SecretParam ? secret.name : secret })) ); return endpoint; diff --git a/src/v2/providers/alerts/alerts.ts b/src/v2/providers/alerts/alerts.ts index 404e71f13..3b544ecd1 100644 --- a/src/v2/providers/alerts/alerts.ts +++ b/src/v2/providers/alerts/alerts.ts @@ -26,6 +26,7 @@ import { CloudEvent, CloudFunction } from "../../core"; import { Expression } from "../../../params"; import { wrapTraceContext } from "../../trace"; import * as options from "../../options"; +import { SecretParam } from "../../../params/types"; /** * The CloudEvent data emitted by Firebase Alerts. @@ -173,7 +174,7 @@ export interface FirebaseAlertOptions extends options.EventHandlerOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** Whether failed executions should be delivered again. */ retry?: boolean | Expression | ResetValue; diff --git a/src/v2/providers/alerts/appDistribution.ts b/src/v2/providers/alerts/appDistribution.ts index f8c3a4a9c..cd3b3704a 100644 --- a/src/v2/providers/alerts/appDistribution.ts +++ b/src/v2/providers/alerts/appDistribution.ts @@ -31,6 +31,7 @@ import { CloudEvent, CloudFunction } from "../../core"; import { wrapTraceContext } from "../../trace"; import { convertAlertAndApp, FirebaseAlertData, getEndpointAnnotation } from "./alerts"; import * as options from "../../options"; +import { SecretParam } from "../../../params/types"; /** * The internal payload object for adding a new tester device to app distribution. @@ -186,7 +187,7 @@ export interface AppDistributionOptions extends options.EventHandlerOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** Whether failed executions should be delivered again. */ retry?: boolean | Expression | ResetValue; diff --git a/src/v2/providers/alerts/crashlytics.ts b/src/v2/providers/alerts/crashlytics.ts index 2a572f83b..e142406b6 100644 --- a/src/v2/providers/alerts/crashlytics.ts +++ b/src/v2/providers/alerts/crashlytics.ts @@ -31,6 +31,7 @@ import { CloudEvent, CloudFunction } from "../../core"; import { wrapTraceContext } from "../../trace"; import { convertAlertAndApp, FirebaseAlertData, getEndpointAnnotation } from "./alerts"; import * as options from "../../options"; +import { SecretParam } from "../../../params/types"; /** Generic Crashlytics issue interface */ export interface Issue { @@ -264,7 +265,7 @@ export interface CrashlyticsOptions extends options.EventHandlerOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** Whether failed executions should be delivered again. */ retry?: boolean | Expression | ResetValue; diff --git a/src/v2/providers/database.ts b/src/v2/providers/database.ts index e81993c5e..af9ced565 100644 --- a/src/v2/providers/database.ts +++ b/src/v2/providers/database.ts @@ -33,6 +33,7 @@ import { CloudEvent, CloudFunction } from "../core"; import { Expression } from "../../params"; import { wrapTraceContext } from "../trace"; import * as options from "../options"; +import { SecretParam } from "../../params/types"; export { DataSnapshot }; @@ -185,7 +186,7 @@ export interface ReferenceOptions extends options.E /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** Whether failed executions should be delivered again. */ retry?: boolean | Expression | ResetValue; diff --git a/src/v2/providers/eventarc.ts b/src/v2/providers/eventarc.ts index 2b6fe4627..4f425faef 100644 --- a/src/v2/providers/eventarc.ts +++ b/src/v2/providers/eventarc.ts @@ -32,6 +32,7 @@ import { CloudEvent, CloudFunction } from "../core"; import { wrapTraceContext } from "../trace"; import { Expression } from "../../params"; import * as options from "../options"; +import { SecretParam } from "../../params/types"; /** Options that can be set on an Eventarc trigger. */ export interface EventarcTriggerOptions extends options.EventHandlerOptions { @@ -149,7 +150,7 @@ export interface EventarcTriggerOptions extends options.EventHandlerOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** Whether failed executions should be delivered again. */ retry?: boolean | Expression | ResetValue; diff --git a/src/v2/providers/https.ts b/src/v2/providers/https.ts index cd7c140c5..0bbc43d18 100644 --- a/src/v2/providers/https.ts +++ b/src/v2/providers/https.ts @@ -41,6 +41,7 @@ import { import { initV2Endpoint, ManifestEndpoint } from "../../runtime/manifest"; import { GlobalOptions, SupportedRegion } from "../options"; import { Expression } from "../../params"; +import { SecretParam } from "../../params/types"; import * as options from "../options"; export { Request, CallableRequest, FunctionsErrorCode, HttpsError }; @@ -142,7 +143,7 @@ export interface HttpsOptions extends Omit { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** * Invoker to set access control on https functions. diff --git a/src/v2/providers/identity.ts b/src/v2/providers/identity.ts index 19cd39b5e..a1a29a252 100644 --- a/src/v2/providers/identity.ts +++ b/src/v2/providers/identity.ts @@ -39,6 +39,7 @@ import { wrapTraceContext } from "../trace"; import { Expression } from "../../params"; import { initV2Endpoint } from "../../runtime/manifest"; import * as options from "../options"; +import { SecretParam } from "../../params/types"; export { AuthUserRecord, AuthBlockingEvent, HttpsError }; @@ -151,7 +152,7 @@ export interface BlockingOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; } /** diff --git a/src/v2/providers/pubsub.ts b/src/v2/providers/pubsub.ts index 9808c15b4..0be727adc 100644 --- a/src/v2/providers/pubsub.ts +++ b/src/v2/providers/pubsub.ts @@ -32,6 +32,7 @@ import { CloudEvent, CloudFunction } from "../core"; import { wrapTraceContext } from "../trace"; import { Expression } from "../../params"; import * as options from "../options"; +import { SecretParam } from "../../params/types"; /** * Google Cloud Pub/Sub is a globally distributed message bus that automatically scales as you need it. @@ -242,7 +243,7 @@ export interface PubSubOptions extends options.EventHandlerOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** Whether failed executions should be delivered again. */ retry?: boolean | Expression | ResetValue; diff --git a/src/v2/providers/storage.ts b/src/v2/providers/storage.ts index 58cccacc7..3428576bf 100644 --- a/src/v2/providers/storage.ts +++ b/src/v2/providers/storage.ts @@ -33,6 +33,7 @@ import { CloudEvent, CloudFunction } from "../core"; import { wrapTraceContext } from "../trace"; import { Expression } from "../../params"; import * as options from "../options"; +import { SecretParam } from "../../params/types"; /** * An object within Google Cloud Storage. @@ -290,7 +291,7 @@ export interface StorageOptions extends options.EventHandlerOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** Whether failed executions should be delivered again. */ retry?: boolean | Expression | ResetValue; diff --git a/src/v2/providers/tasks.ts b/src/v2/providers/tasks.ts index 314210d78..f6e63b210 100644 --- a/src/v2/providers/tasks.ts +++ b/src/v2/providers/tasks.ts @@ -38,6 +38,7 @@ import * as options from "../options"; import { wrapTraceContext } from "../trace"; import { HttpsFunction } from "./https"; import { Expression } from "../../params"; +import { SecretParam } from "../../params/types"; import { initV2Endpoint, initTaskQueueTrigger } from "../../runtime/manifest"; export { AuthData, Request }; @@ -147,7 +148,7 @@ export interface TaskQueueOptions extends options.EventHandlerOptions { /* * Secrets to bind to a function. */ - secrets?: string[]; + secrets?: (string | SecretParam)[]; /** Whether failed executions should be delivered again. */ retry?: boolean;