Skip to content
48 changes: 48 additions & 0 deletions spec/function-builder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,52 @@ describe('FunctionBuilder', () => {
)}`
);
});

it('should allow a serviceAccount to be set as-is', () => {
const serviceAccount = 'test-service-account@test.iam.gserviceaccount.com';
const fn = functions
.runWith({
serviceAccount,
})
.auth.user()
.onCreate((user) => user);

expect(fn.__trigger.serviceAccountEmail).to.equal(serviceAccount);
});

it('should allow a serviceAccount to be set with generated service account email', () => {
const serviceAccount = 'test-service-account@';
const projectId = process.env.GCLOUD_PROJECT;
const fn = functions
.runWith({
serviceAccount,
})
.auth.user()
.onCreate((user) => user);

expect(fn.__trigger.serviceAccountEmail).to.equal(
`test-service-account@${projectId}.iam.gserviceaccount.com`
);
});

it('should not set a serviceAccountEmail if service account is set to `default`', () => {
const serviceAccount = 'default';
const fn = functions
.runWith({
serviceAccount,
})
.auth.user()
.onCreate((user) => user);

expect(fn.__trigger.serviceAccountEmail).to.be.undefined;
});

it('should throw an error if serviceAccount is set to an invalid value', () => {
const serviceAccount = 'test-service-account';
expect(() => {
functions.runWith({
serviceAccount,
});
}).to.throw();
});
});
20 changes: 20 additions & 0 deletions src/cloud-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ export interface TriggerAnnotated {
timeout?: string;
vpcConnector?: string;
vpcConnectorEgressSettings?: string;
serviceAccountEmail?: string;
};
}

Expand Down Expand Up @@ -525,5 +526,24 @@ export function optionsToTrigger(options: DeploymentOptions) {
trigger.vpcConnectorEgressSettings = options.vpcConnectorEgressSettings;
}

if (options.serviceAccount) {
if (options.serviceAccount === 'default') {
// Do nothing, since this is equivalent to not setting serviceAccount.
} else if (options.serviceAccount.endsWith('@')) {
if (!process.env.GCLOUD_PROJECT) {
throw new Error(
`Unable to determine email for service account '${options.serviceAccount}' because process.env.GCLOUD_PROJECT is not set.`
);
}
trigger.serviceAccountEmail = `${options.serviceAccount}${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`;
} else if (options.serviceAccount.includes('@')) {
trigger.serviceAccountEmail = options.serviceAccount;
} else {
throw new Error(
`Invalid option for serviceAccount: '${options.serviceAccount}'. Valid options are 'default', a service account email, or '{serviceAccountName}@'`
);
}
}

return trigger;
}
19 changes: 16 additions & 3 deletions src/function-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean {
}
}
}

if (
runtimeOptions.serviceAccount &&
runtimeOptions.serviceAccount !== 'default' &&
!_.includes(runtimeOptions.serviceAccount, '@')
) {
throw new Error(
`serviceAccount must be set to 'default', a service account email, or '{serviceAccountName}@'`
);
}
return true;
}

Expand Down Expand Up @@ -139,9 +149,12 @@ export function region(
* 0 to 540.
* 3. `failurePolicy`: failure policy of the function, with boolean `true` being
* equivalent to providing an empty retry object.
* 4. `vpcConnector`: id of a VPC connector in the same project and region
* 5. `vpcConnectorEgressSettings`: when a `vpcConnector` is set, control which
* egress traffic is sent through the `vpcConnector`.
* 4. `vpcConnector`: id of a VPC connector in same project and region.
* 5. `vpcConnectorEgressSettings`: when a vpcConnector is set, control which
* egress traffic is sent through the vpcConnector.
* 6. `serviceAccount`: Specific service account for the function.
* 7. `ingressSettings`: ingress settings for the function, which control where a HTTPS
* function can be called from.
*
* Value must not be null.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/function-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ export interface RuntimeOptions {
*/
vpcConnectorEgressSettings?: typeof VPC_EGRESS_SETTINGS_OPTIONS[number];

/**
* Specific service account for the function to run as
*/
serviceAccount?: 'default' | string;

/**
* Ingress settings
*/
Expand Down