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

Add support for secrets in v2 #1079

Merged
merged 9 commits into from Apr 29, 2022
9 changes: 7 additions & 2 deletions spec/v2/providers/fixtures.ts
@@ -1,3 +1,5 @@
import { ManifestEndpoint } from '../../../src/runtime/manifest';
import { TriggerAnnotation } from '../../../src/v2/core';
import * as options from '../../../src/v2/options';

export const FULL_OPTIONS: options.GlobalOptions = {
Expand All @@ -15,9 +17,10 @@ export const FULL_OPTIONS: options.GlobalOptions = {
labels: {
hello: 'world',
},
secrets: ['MY_SECRET'],
};

export const FULL_TRIGGER = {
export const FULL_TRIGGER: TriggerAnnotation = {
platform: 'gcfv2',
regions: ['us-west1'],
availableMemoryMb: 512,
Expand All @@ -32,9 +35,10 @@ export const FULL_TRIGGER = {
labels: {
hello: 'world',
},
secrets: ['MY_SECRET'],
};

export const FULL_ENDPOINT = {
export const FULL_ENDPOINT: ManifestEndpoint = {
platform: 'gcfv2',
region: ['us-west1'],
availableMemoryMb: 512,
Expand All @@ -52,4 +56,5 @@ export const FULL_ENDPOINT = {
labels: {
hello: 'world',
},
secretEnvironmentVariables: [{ key: 'MY_SECRET', secret: 'MY_SECRET' }],
};
2 changes: 2 additions & 0 deletions src/v2/core.ts
Expand Up @@ -24,6 +24,7 @@ import { ManifestEndpoint } from '../runtime/manifest';

/** @internal */
export interface TriggerAnnotation {
platform?: string;
concurrency?: number;
minInstances?: number;
maxInstances?: number;
Expand All @@ -44,6 +45,7 @@ export interface TriggerAnnotation {
vpcConnectorEgressSettings?: string;
serviceAccountEmail?: string;
ingressSettings?: string;
secrets?: string[];

// TODO: schedule
}
Expand Down
28 changes: 25 additions & 3 deletions src/v2/options.ts
Expand Up @@ -215,6 +215,11 @@ export interface GlobalOptions {
* Invoker to set access control on https functions.
*/
invoker?: 'public' | 'private' | string | string[];

/*
* Secrets to bind to a functions.
*/
secrets?: string[];
jhuleatt marked this conversation as resolved.
Show resolved Hide resolved
}

let globalOptions: GlobalOptions | undefined;
Expand All @@ -239,6 +244,15 @@ export function getGlobalOptions(): GlobalOptions {
return globalOptions || {};
}

/**
* Options that can be set on an individual HTTPS Cloud Function.
*/
export interface HttpsOptions extends Omit<GlobalOptions, 'region'> {
taeold marked this conversation as resolved.
Show resolved Hide resolved
/* HTTP functions can override and specify more than one regions. */
region?: SupportedRegion | string | Array<SupportedRegion | string>;
cors?: string | boolean | RegExp | Array<string | RegExp>;
}

/**
* Options that can be set on an individual event-handling Cloud Function.
*/
Expand All @@ -251,7 +265,7 @@ export interface EventHandlerOptions extends GlobalOptions {
* @internal
*/
export function optionsToTriggerAnnotations(
opts: GlobalOptions | EventHandlerOptions
opts: GlobalOptions | EventHandlerOptions | HttpsOptions
): TriggerAnnotation {
const annotation: TriggerAnnotation = {};
copyIfPresent(
Expand All @@ -263,7 +277,8 @@ export function optionsToTriggerAnnotations(
'ingressSettings',
'labels',
'vpcConnector',
'vpcConnectorEgressSettings'
'vpcConnectorEgressSettings',
'secrets'
);
convertIfPresent(
annotation,
Expand Down Expand Up @@ -312,7 +327,7 @@ export function optionsToTriggerAnnotations(
* @internal
*/
export function optionsToEndpoint(
opts: GlobalOptions | EventHandlerOptions
opts: GlobalOptions | EventHandlerOptions | HttpsOptions
): ManifestEndpoint {
const endpoint: ManifestEndpoint = {};
copyIfPresent(
Expand Down Expand Up @@ -350,6 +365,13 @@ export function optionsToEndpoint(
}
return region;
});
convertIfPresent(
endpoint,
opts,
'secretEnvironmentVariables',
'secrets',
(secrets) => secrets.map((secret) => ({ secret, key: secret }))
Copy link
Member

Choose a reason for hiding this comment

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

I'm confused. Isn't this specifying both the env var and the secret name? DIdn't we not want to do that in the SDK but in the CLI since (in the future) the build process needs to not set the secret name so that extensions can?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah excellent catch.

);

return endpoint;
}
Expand Down
34 changes: 12 additions & 22 deletions src/v2/providers/https.ts
Expand Up @@ -36,14 +36,6 @@ import * as options from '../options';

export { Request, CallableRequest, FunctionsErrorCode, HttpsError };

export interface HttpsOptions extends Omit<options.GlobalOptions, 'region'> {
taeold marked this conversation as resolved.
Show resolved Hide resolved
region?:
| options.SupportedRegion
| string
| Array<options.SupportedRegion | string>;
cors?: string | boolean | RegExp | Array<string | RegExp>;
}

export type HttpsFunction = ((
req: Request,
res: express.Response
Expand All @@ -56,7 +48,7 @@ export interface CallableFunction<T, Return> extends HttpsFunction {
}

export function onRequest(
opts: HttpsOptions,
opts: options.HttpsOptions,
handler: (
request: Request,
response: express.Response
Expand All @@ -70,22 +62,22 @@ export function onRequest(
): HttpsFunction;
export function onRequest(
optsOrHandler:
| HttpsOptions
| options.HttpsOptions
| ((request: Request, response: express.Response) => void | Promise<void>),
handler?: (
request: Request,
response: express.Response
) => void | Promise<void>
): HttpsFunction {
let opts: HttpsOptions;
let opts: options.HttpsOptions;
if (arguments.length === 1) {
opts = {};
handler = optsOrHandler as (
request: Request,
response: express.Response
) => void | Promise<void>;
} else {
opts = optsOrHandler as HttpsOptions;
opts = optsOrHandler as options.HttpsOptions;
}

if ('cors' in opts) {
Expand Down Expand Up @@ -160,22 +152,24 @@ export function onRequest(
}

export function onCall<T = any, Return = any | Promise<any>>(
opts: HttpsOptions,
opts: options.HttpsOptions,
handler: (request: CallableRequest<T>) => Return
): CallableFunction<T, Return>;
export function onCall<T = any, Return = any | Promise<any>>(
handler: (request: CallableRequest<T>) => Return
): CallableFunction<T, Return>;
export function onCall<T = any, Return = any | Promise<any>>(
optsOrHandler: HttpsOptions | ((request: CallableRequest<T>) => Return),
optsOrHandler:
| options.HttpsOptions
| ((request: CallableRequest<T>) => Return),
handler?: (request: CallableRequest<T>) => Return
): CallableFunction<T, Return> {
let opts: HttpsOptions;
let opts: options.HttpsOptions;
if (arguments.length == 1) {
opts = {};
handler = optsOrHandler as (request: CallableRequest<T>) => Return;
} else {
opts = optsOrHandler as HttpsOptions;
opts = optsOrHandler as options.HttpsOptions;
}

const origin = 'cors' in opts ? opts.cors : true;
Expand All @@ -195,9 +189,7 @@ export function onCall<T = any, Return = any | Promise<any>>(
);
// global options calls region a scalar and https allows it to be an array,
// but optionsToTriggerAnnotations handles both cases.
const specificOpts = options.optionsToTriggerAnnotations(
opts as options.GlobalOptions
);
const specificOpts = options.optionsToTriggerAnnotations(opts);
return {
platform: 'gcfv2',
...baseOpts,
Expand All @@ -215,9 +207,7 @@ export function onCall<T = any, Return = any | Promise<any>>(
});

const baseOpts = options.optionsToEndpoint(options.getGlobalOptions());
// global options calls region a scalar and https allows it to be an array,
// but optionsToManifestEndpoint handles both cases.
const specificOpts = options.optionsToEndpoint(opts as options.GlobalOptions);
const specificOpts = options.optionsToEndpoint(opts);
func.__endpoint = {
platform: 'gcfv2',
...baseOpts,
Expand Down