Skip to content

Commit 94414f4

Browse files
authored
Set Access Control for HTTP Functions (v2) (#935)
* adding invoker to v2 http functions * fix format * change invoker to always turn into an array, add error handling * fix trigger annotated in v2 and change v1 to only put invoker array in trigger annotated * changing invoker type for better type completion
1 parent e9f5e43 commit 94414f4

File tree

7 files changed

+71
-10
lines changed

7 files changed

+71
-10
lines changed

spec/common/encoding.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { expect } from 'chai';
2+
import { convertInvoker } from '../../src/common/encoding';
3+
4+
describe('convertInvoker', () => {
5+
it('should raise an error on mixing public and service accounts', () => {
6+
expect(() => convertInvoker(['public', 'service-account@'])).to.throw;
7+
});
8+
9+
it('should raise an error on mixing private and service accounts', () => {
10+
expect(() => convertInvoker(['private', 'service-account@'])).to.throw;
11+
});
12+
13+
it('should return the correct public invoker', () => {
14+
const invoker = convertInvoker('public');
15+
16+
expect(invoker).to.deep.equal(['public']);
17+
});
18+
19+
it('should return the correct private invoker', () => {
20+
const invoker = convertInvoker('private');
21+
22+
expect(invoker).to.deep.equal(['private']);
23+
});
24+
25+
it('should return the correct scalar invoker', () => {
26+
const invoker = convertInvoker('service-account@');
27+
28+
expect(invoker).to.deep.equal(['service-account@']);
29+
});
30+
31+
it('should return the correct array invoker', () => {
32+
const invoker = convertInvoker(['service-account1@', 'service-account2@']);
33+
34+
expect(invoker).to.deep.equal(['service-account1@', 'service-account2@']);
35+
});
36+
});

spec/v2/providers/https.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ describe('onRequest', () => {
9090
{
9191
...FULL_OPTIONS,
9292
region: ['us-west1', 'us-central1'],
93+
invoker: ['service-account1@', 'service-account2@'],
9394
},
9495
(req, res) => {
9596
res.send(200);
@@ -101,6 +102,7 @@ describe('onRequest', () => {
101102
allowInsecure: false,
102103
},
103104
regions: ['us-west1', 'us-central1'],
105+
invoker: ['service-account1@', 'service-account2@'],
104106
});
105107
});
106108

@@ -109,12 +111,14 @@ describe('onRequest', () => {
109111
concurrency: 20,
110112
region: 'europe-west1',
111113
minInstances: 1,
114+
invoker: 'public',
112115
});
113116

114117
const result = https.onRequest(
115118
{
116119
region: ['us-west1', 'us-central1'],
117120
minInstances: 3,
121+
invoker: 'private',
118122
},
119123
(req, res) => {
120124
res.send(200);
@@ -131,6 +135,7 @@ describe('onRequest', () => {
131135
minInstances: 3,
132136
regions: ['us-west1', 'us-central1'],
133137
labels: {},
138+
invoker: ['private'],
134139
});
135140
});
136141

src/common/encoding.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,20 @@ export function serviceAccountFromShorthand(
6464
);
6565
}
6666
}
67+
68+
export function convertInvoker(invoker: string | string[]): string[] {
69+
if (typeof invoker === 'string') {
70+
invoker = [invoker];
71+
}
72+
73+
if (
74+
invoker.length > 1 &&
75+
invoker.find((inv) => inv === 'public' || inv === 'private')
76+
) {
77+
throw new Error(
78+
"Invalid option for invoker. Cannot have 'public' or 'private' in an array of service accounts"
79+
);
80+
}
81+
82+
return invoker;
83+
}

src/v1/cloud-functions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
DEFAULT_FAILURE_POLICY,
2828
DeploymentOptions,
2929
FailurePolicy,
30-
Invoker,
3130
Schedule,
3231
} from './function-configuration';
3332
export { Request, Response };
@@ -37,6 +36,7 @@ import {
3736
Duration,
3837
durationFromSeconds,
3938
serviceAccountFromShorthand,
39+
convertInvoker,
4040
} from '../common/encoding';
4141

4242
/** @hidden */
@@ -279,7 +279,7 @@ export interface TriggerAnnotated {
279279
vpcConnectorEgressSettings?: string;
280280
serviceAccountEmail?: string;
281281
ingressSettings?: string;
282-
invoker?: Invoker | Invoker[];
282+
invoker?: string[];
283283
};
284284
}
285285

@@ -499,8 +499,7 @@ export function optionsToTrigger(options: DeploymentOptions) {
499499
'ingressSettings',
500500
'vpcConnectorEgressSettings',
501501
'vpcConnector',
502-
'labels',
503-
'invoker'
502+
'labels'
504503
);
505504
convertIfPresent(
506505
trigger,
@@ -543,6 +542,7 @@ export function optionsToTrigger(options: DeploymentOptions) {
543542
'serviceAccount',
544543
serviceAccountFromShorthand
545544
);
545+
convertIfPresent(trigger, options, 'invoker', 'invoker', convertInvoker);
546546

547547
return trigger;
548548
}

src/v1/function-configuration.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,6 @@ 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-
106101
export interface RuntimeOptions {
107102
/**
108103
* Which platform should host the backend. Valid options are "gcfv1"
@@ -165,7 +160,7 @@ export interface RuntimeOptions {
165160
/**
166161
* Invoker to set access control on https functions.
167162
*/
168-
invoker?: Invoker | Invoker[];
163+
invoker?: 'public' | 'private' | string | string[];
169164
}
170165

171166
export interface DeploymentOptions extends RuntimeOptions {

src/v2/core.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export interface TriggerAnnotation {
4040
vpcConnectorEgressSettings?: string;
4141
serviceAccountEmail?: string;
4242
ingressSettings?: string;
43+
invoker?: string[];
4344

4445
// TODO: schedule
4546
}

src/v2/options.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import {
2424
durationFromSeconds,
2525
serviceAccountFromShorthand,
26+
convertInvoker,
2627
} from '../common/encoding';
2728
import { convertIfPresent, copyIfPresent } from '../common/encoding';
2829
import * as logger from '../logger';
@@ -182,6 +183,11 @@ export interface GlobalOptions {
182183
* User labels to set on the function.
183184
*/
184185
labels?: Record<string, string>;
186+
187+
/**
188+
* Invoker to set access control on https functions.
189+
*/
190+
invoker?: 'public' | 'private' | string | string[];
185191
}
186192

187193
let globalOptions: GlobalOptions | undefined;
@@ -270,6 +276,7 @@ export function optionsToTriggerAnnotations(
270276
return retry ? { retry: true } : null;
271277
}
272278
);
279+
convertIfPresent(annotation, opts, 'invoker', 'invoker', convertInvoker);
273280

274281
return annotation;
275282
}

0 commit comments

Comments
 (0)