Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Allow `JsonSecretParam` in function `secrets` option arrays. (#1788)
26 changes: 26 additions & 0 deletions spec/v1/cloud-functions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
RESET_VALUE,
} from "../../src/v1";
import { MINIMAL_V1_ENDPOINT } from "../fixtures";
import { defineJsonSecret, defineSecret } from "../../src/params";

describe("makeCloudFunction", () => {
const cloudFunctionArgs: MakeCloudFunctionArgs<any> = {
Expand Down Expand Up @@ -161,6 +162,31 @@ describe("makeCloudFunction", () => {
});
});

it("should accept all valid secret types in secrets array (type test)", () => {
// This is a compile-time type test. If any of these types are not assignable
// to the secrets array, TypeScript will fail to compile this test file.
const jsonSecret = defineJsonSecret<{ key: string }>("JSON_SECRET");
const stringSecret = defineSecret("STRING_SECRET");
const plainSecret = "PLAIN_SECRET";

const cf = makeCloudFunction({
provider: "mock.provider",
eventType: "mock.event",
service: "service",
triggerResource: () => "resource",
handler: () => null,
options: {
secrets: [plainSecret, stringSecret, jsonSecret],
},
});

expect(cf.__endpoint.secretEnvironmentVariables).to.deep.equal([
{ key: "PLAIN_SECRET" },
{ key: "STRING_SECRET" },
{ key: "JSON_SECRET" },
]);
});

it("should set retry given failure policy in __endpoint", () => {
const cf = makeCloudFunction({
provider: "mock.provider",
Expand Down
41 changes: 41 additions & 0 deletions spec/v2/options.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// The MIT License (MIT)
//
// Copyright (c) 2025 Firebase
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { expect } from "chai";
import { defineJsonSecret, defineSecret } from "../../src/params";
import { GlobalOptions } from "../../src/v2/options";

describe("GlobalOptions", () => {
it("should accept all valid secret types in secrets array (type test)", () => {
// This is a compile-time type test. If any of these types are not assignable
// to the secrets array, TypeScript will fail to compile this test file.
const jsonSecret = defineJsonSecret<{ key: string }>("JSON_SECRET");
const stringSecret = defineSecret("STRING_SECRET");
const plainSecret = "PLAIN_SECRET";

const opts: GlobalOptions = {
secrets: [plainSecret, stringSecret, jsonSecret],
};

expect(opts.secrets).to.have.length(3);
});
});
6 changes: 6 additions & 0 deletions src/params/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,12 @@ export class JsonSecretParam<T = any> {
}
}

/**
* A union type representing all valid secret parameter types that can be used
* in a function's `secrets` configuration array.
*/
export type SupportedSecretParam = string | SecretParam | JsonSecretParam<unknown>;

/**
* A parametrized value of String type that will be read from .env files
* if present, or prompted for by the CLI if missing.
Expand Down
8 changes: 5 additions & 3 deletions src/v1/cloud-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
ManifestRequiredAPI,
} from "../runtime/manifest";
import { ResetValue } from "../common/options";
import { SecretParam } from "../params/types";
import { SupportedSecretParam } from "../params/types";
import { withInit } from "../common/onInit";

export { Change } from "../common/change";
Expand Down Expand Up @@ -638,8 +638,10 @@ export function optionsToEndpoint(options: DeploymentOptions): ManifestEndpoint
options,
"secretEnvironmentVariables",
"secrets",
(secrets: (string | SecretParam)[]) =>
secrets.map((secret) => ({ key: secret instanceof SecretParam ? secret.name : secret }))
(secrets: SupportedSecretParam[]) =>
secrets.map((secret) => ({
key: typeof secret === "string" ? secret : secret.name,
}))
);
if (options?.vpcConnector !== undefined) {
if (options.vpcConnector === null || options.vpcConnector instanceof ResetValue) {
Expand Down
4 changes: 2 additions & 2 deletions src/v1/function-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import * as express from "express";

import { ResetValue } from "../common/options";
import { Expression, SecretParam } from "../params/types";
import { Expression } from "../params/types";
import { EventContext } from "./cloud-functions";
import {
DeploymentOptions,
Expand Down Expand Up @@ -200,7 +200,7 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean {

if (runtimeOptions.secrets !== undefined) {
const invalidSecrets = runtimeOptions.secrets.filter(
(s) => !/^[A-Za-z\d\-_]+$/.test(s instanceof SecretParam ? s.name : s)
(s) => !/^[A-Za-z\d\-_]+$/.test(typeof s === "string" ? s : s.name)
);
if (invalidSecrets.length > 0) {
throw new Error(
Expand Down
4 changes: 2 additions & 2 deletions src/v1/function-configuration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Expression } from "../params";
import { ResetValue } from "../common/options";
import { SecretParam } from "../params/types";
import { SupportedSecretParam } from "../params/types";

export { RESET_VALUE } from "../common/options";

Expand Down Expand Up @@ -235,7 +235,7 @@ export interface RuntimeOptions {
/*
* Secrets to bind to a function instance.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/**
* Determines whether Firebase AppCheck is enforced.
Expand Down
10 changes: 6 additions & 4 deletions src/v2/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { RESET_VALUE, ResetValue } from "../common/options";
import { ManifestEndpoint } from "../runtime/manifest";
import { TriggerAnnotation } from "./core";
import { declaredParams, Expression } from "../params";
import { ParamSpec, SecretParam } from "../params/types";
import { ParamSpec, SupportedSecretParam } from "../params/types";
import { HttpsOptions } from "./providers/https";
import * as logger from "../logger";

Expand Down Expand Up @@ -210,7 +210,7 @@ export interface GlobalOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/**
* Determines whether Firebase App Check is enforced. Defaults to false.
Expand Down Expand Up @@ -396,8 +396,10 @@ export function optionsToEndpoint(
opts,
"secretEnvironmentVariables",
"secrets",
(secrets: (string | SecretParam)[]) =>
secrets.map((secret) => ({ key: secret instanceof SecretParam ? secret.name : secret }))
(secrets: SupportedSecretParam[]) =>
secrets.map((secret) => ({
key: typeof secret === "string" ? secret : secret.name,
}))
);

return endpoint;
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/alerts/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +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";
import { SupportedSecretParam } from "../../../params/types";
import { withInit } from "../../../common/onInit";

/**
Expand Down Expand Up @@ -180,7 +180,7 @@ export interface FirebaseAlertOptions extends options.EventHandlerOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/** Whether failed executions should be delivered again. */
retry?: boolean | Expression<boolean> | ResetValue;
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/alerts/appDistribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +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";
import { SupportedSecretParam } from "../../../params/types";
import { withInit } from "../../../common/onInit";

/**
Expand Down Expand Up @@ -191,7 +191,7 @@ export interface AppDistributionOptions extends options.EventHandlerOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/** Whether failed executions should be delivered again. */
retry?: boolean | Expression<boolean> | ResetValue;
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/alerts/crashlytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +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";
import { SupportedSecretParam } from "../../../params/types";
import { withInit } from "../../../common/onInit";

/** Generic Crashlytics issue interface */
Expand Down Expand Up @@ -271,7 +271,7 @@ export interface CrashlyticsOptions extends options.EventHandlerOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/** Whether failed executions should be delivered again. */
retry?: boolean | Expression<boolean> | ResetValue;
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +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";
import { SupportedSecretParam } from "../../params/types";
import { withInit } from "../../common/onInit";

export { DataSnapshot };
Expand Down Expand Up @@ -192,7 +192,7 @@ export interface ReferenceOptions<Ref extends string = string> extends options.E
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/** Whether failed executions should be delivered again. */
retry?: boolean | Expression<boolean> | ResetValue;
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/eventarc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +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";
import { SupportedSecretParam } from "../../params/types";
import { withInit } from "../../common/onInit";

/** Options that can be set on an Eventarc trigger. */
Expand Down Expand Up @@ -156,7 +156,7 @@ export interface EventarcTriggerOptions extends options.EventHandlerOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/** Whether failed executions should be delivered again. */
retry?: boolean | Expression<boolean> | ResetValue;
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/https.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
import { initV2Endpoint, ManifestEndpoint } from "../../runtime/manifest";
import { GlobalOptions, SupportedRegion } from "../options";
import { Expression } from "../../params";
import { SecretParam } from "../../params/types";
import { SupportedSecretParam } from "../../params/types";
import * as options from "../options";
import { withInit } from "../../common/onInit";
import * as logger from "../../logger";
Expand Down Expand Up @@ -165,7 +165,7 @@ export interface HttpsOptions extends Omit<GlobalOptions, "region" | "enforceApp
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/**
* Invoker to set access control on https functions.
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { wrapTraceContext } from "../trace";
import { Expression } from "../../params";
import { initV2Endpoint } from "../../runtime/manifest";
import * as options from "../options";
import { SecretParam } from "../../params/types";
import { SupportedSecretParam } from "../../params/types";
import { withInit } from "../../common/onInit";

export { HttpsError };
Expand Down Expand Up @@ -163,7 +163,7 @@ export interface BlockingOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/pubsub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +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";
import { SupportedSecretParam } from "../../params/types";
import { withInit } from "../../common/onInit";

/**
Expand Down Expand Up @@ -249,7 +249,7 @@ export interface PubSubOptions extends options.EventHandlerOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/** Whether failed executions should be delivered again. */
retry?: boolean | Expression<boolean> | ResetValue;
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +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";
import { SupportedSecretParam } from "../../params/types";
import { withInit } from "../../common/onInit";

/**
Expand Down Expand Up @@ -297,7 +297,7 @@ export interface StorageOptions extends options.EventHandlerOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/** Whether failed executions should be delivered again. */
retry?: boolean | Expression<boolean> | ResetValue;
Expand Down
4 changes: 2 additions & 2 deletions src/v2/providers/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +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 { SupportedSecretParam } from "../../params/types";
import { initV2Endpoint, initTaskQueueTrigger } from "../../runtime/manifest";
import { withInit } from "../../common/onInit";

Expand Down Expand Up @@ -154,7 +154,7 @@ export interface TaskQueueOptions extends options.EventHandlerOptions {
/*
* Secrets to bind to a function.
*/
secrets?: (string | SecretParam)[];
secrets?: SupportedSecretParam[];

/** Whether failed executions should be delivered again. */
retry?: boolean;
Expand Down
Loading