Skip to content

Commit 63a0cc4

Browse files
authored
Set Access Control for HTTP Functions (v1) (#921)
* add invoker option to RunWith * fixing lint issue * adding invoker checking logic * adding tests * find invoker in the trigger options during cli deployment * fix lint/format * add checks for public/private in invoker arrray
1 parent 3d70007 commit 63a0cc4

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

spec/v1/function-builder.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,4 +439,44 @@ describe('FunctionBuilder', () => {
439439
})
440440
).to.throw();
441441
});
442+
443+
it('should throw an error if invoker is an empty string', () => {
444+
expect(() =>
445+
functions.runWith({
446+
invoker: '',
447+
})
448+
).to.throw();
449+
});
450+
451+
it('should throw an error if invoker is an empty array', () => {
452+
expect(() =>
453+
functions.runWith({
454+
invoker: [''],
455+
})
456+
).to.throw();
457+
});
458+
459+
it('should throw an error if invoker has an empty string', () => {
460+
expect(() =>
461+
functions.runWith({
462+
invoker: ['service-account1', '', 'service-account2'],
463+
})
464+
).to.throw();
465+
});
466+
467+
it('should throw an error if public identifier is in the invoker array', () => {
468+
expect(() =>
469+
functions.runWith({
470+
invoker: ['service-account1', 'public', 'service-account2'],
471+
})
472+
).to.throw();
473+
});
474+
475+
it('', () => {
476+
expect(() =>
477+
functions.runWith({
478+
invoker: ['service-account1', 'private', 'service-account2'],
479+
})
480+
).to.throw();
481+
});
442482
});

src/v1/cloud-functions.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
DEFAULT_FAILURE_POLICY,
2828
DeploymentOptions,
2929
FailurePolicy,
30+
Invoker,
3031
Schedule,
3132
} from './function-configuration';
3233
export { Request, Response };
@@ -278,6 +279,7 @@ export interface TriggerAnnotated {
278279
vpcConnectorEgressSettings?: string;
279280
serviceAccountEmail?: string;
280281
ingressSettings?: string;
282+
invoker?: Invoker | Invoker[];
281283
};
282284
}
283285

@@ -497,7 +499,8 @@ export function optionsToTrigger(options: DeploymentOptions) {
497499
'ingressSettings',
498500
'vpcConnectorEgressSettings',
499501
'vpcConnector',
500-
'labels'
502+
'labels',
503+
'invoker'
501504
);
502505
convertIfPresent(
503506
trigger,

src/v1/function-builder.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,43 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean {
192192
);
193193
}
194194
}
195+
196+
if (
197+
typeof runtimeOptions.invoker === 'string' &&
198+
runtimeOptions.invoker.length === 0
199+
) {
200+
throw new Error(
201+
'Invalid service account for function invoker, must be a non-empty string'
202+
);
203+
}
204+
if (
205+
runtimeOptions.invoker !== undefined &&
206+
Array.isArray(runtimeOptions.invoker)
207+
) {
208+
if (runtimeOptions.invoker.length === 0) {
209+
throw new Error(
210+
'Invalid invoker array, must contain at least 1 service account entry'
211+
);
212+
}
213+
for (const serviceAccount of runtimeOptions.invoker) {
214+
if (serviceAccount.length === 0) {
215+
throw new Error(
216+
'Invalid invoker array, a service account must be a non-empty string'
217+
);
218+
}
219+
if (serviceAccount === 'public') {
220+
throw new Error(
221+
"Invalid invoker array, a service account cannot be set to the 'public' identifier"
222+
);
223+
}
224+
if (serviceAccount === 'private') {
225+
throw new Error(
226+
"Invalid invoker array, a service account cannot be set to the 'private' identifier"
227+
);
228+
}
229+
}
230+
}
231+
195232
return true;
196233
}
197234

src/v1/function-configuration.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ export const DEFAULT_FAILURE_POLICY: FailurePolicy = {
9898

9999
export const MAX_NUMBER_USER_LABELS = 58;
100100

101+
/**
102+
* Invoker access control type for https functions.
103+
*/
104+
export type Invoker = 'public' | 'private' | string;
105+
101106
export interface RuntimeOptions {
102107
/**
103108
* Which platform should host the backend. Valid options are "gcfv1"
@@ -156,6 +161,11 @@ export interface RuntimeOptions {
156161
* User labels to set on the function.
157162
*/
158163
labels?: Record<string, string>;
164+
165+
/**
166+
* Invoker to set access control on https functions.
167+
*/
168+
invoker?: Invoker | Invoker[];
159169
}
160170

161171
export interface DeploymentOptions extends RuntimeOptions {

0 commit comments

Comments
 (0)