/* * Copyright © 2020 Atomist, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as gcp from "@pulumi/gcp"; import * as pulumi from "@pulumi/pulumi"; /** * Remove "roles/" from IAM role identifier, replace "." with "-", and * lowercase the string, creating a string safe to use in a resource * name. */ export function simpleRoleName(role: string): string { return role .replace(/^roles\//, "") .replace(/\./g, "-") .toLowerCase(); } /** Arguments to [[serviceAccountMember]] */ export interface ServiceAccountMemberArgs { /** Roles to bind to [[serviceAccountEmail]]. */ roles: string[]; /** Service account email address to bind to [[roles]]. */ serviceAccountEmail: pulumi.Output; /** * User part of service account email address. Cannot use * [[serviceAccountEmail]] because it is used in the name of the * resource. */ serviceAccountName: string; /** Project ID to create binding in. */ projectId: string; /** If provided, import an existing binding with the provided member. */ import?: string; } /** * For each role, create an IAMMember resource. */ export function serviceAccountMember(args: ServiceAccountMemberArgs): void { for (const role of args.roles) { new gcp.projects.IAMMember( `${args.serviceAccountName}-${simpleRoleName(role)}-binding`, { member: pulumi.concat( "serviceAccount:", args.serviceAccountEmail, ), project: args.projectId, role, }, { import: args.import ? `${args.projectId} ${role} ${args.import}` : undefined, }, ); } } export interface UserAccount { accountId: string; email: string; member: string; } export function getAccounts( accounts: UserAccount[], userIds: string[], ): UserAccount[] { const selectedAccounts = accounts.filter(a => userIds.includes(a.accountId), ); if ( selectedAccounts .map(a => a.accountId) .sort() .join(",") != userIds.sort().join(",") ) { const cause = { cause: { requested: userIds, selected: selectedAccounts.map(a => a.accountId), }, }; throw new Error( `selected accounts did not match requested accounts.\n${JSON.stringify(cause)}`, ); } return selectedAccounts; }