From 443a9b9538804d4f564cfdafa040a125c6276251 Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:02:42 +0200 Subject: [PATCH 01/36] Create CLEANUP.md instructions to clean up FAST deployment --- fast/CLEANUP.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 fast/CLEANUP.md diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md new file mode 100644 index 000000000..952339bf8 --- /dev/null +++ b/fast/CLEANUP.md @@ -0,0 +1,38 @@ +# FAST deployment clean up +In case you require destroying FAST deployment in your organization, follow these steps. + +Destruction goes in reverse order, from stage 3 to stage 0: + +## Stage 3 (Project Factory) + +```bash +cd $FAST_PWD/03-project-factory/prod/ +terraform destroy +``` + +## Stage 3 (GKE) + +```bash +cd $FAST_PWD/03-project-factory/prod/ + +for x in $(terraform state list | grep google_bigquery_dataset); do + terraform state rm "$x"; +done + +terraform destroy +``` + + +# Stage 2 (Security) +```bash +cd $FAST_PWD/02-security/ +terraform destroy +``` + +# Networking +```bash +cd $FAST_PWD/02-networking-XXX/ +terraform destroy +```bash + +There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the gcloud beta compute shared-vpc associated-projects remove command when terraform destroy fails, and then relaunch the command. From 8d4ea4ec67cb3ab353ec80ac22368dc0e95e3ac8 Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:06:46 +0200 Subject: [PATCH 02/36] Update CLEANUP.md --- fast/CLEANUP.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index 952339bf8..26adeaf98 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -29,10 +29,28 @@ cd $FAST_PWD/02-security/ terraform destroy ``` -# Networking +# Stage 2 (Networking) ```bash cd $FAST_PWD/02-networking-XXX/ terraform destroy -```bash +``` There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the gcloud beta compute shared-vpc associated-projects remove command when terraform destroy fails, and then relaunch the command. + +# Stage 1 (Resource Management) +Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder + + +```bash +cd $FAST_PWD/01-resman/ + +# remove buckets from state since terraform refuses to delete them +for x in $(terraform state list | grep google_storage_bucket.bucket); do + terraform state rm "$x" +done + +terraform destroy + +``` + + From d7fd11b5fd090e0e785ea61db0631d2be4df261a Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:15:18 +0200 Subject: [PATCH 03/36] Update CLEANUP.md --- fast/CLEANUP.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index 26adeaf98..edc93f04b 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -50,7 +50,55 @@ for x in $(terraform state list | grep google_storage_bucket.bucket); do done terraform destroy - ``` +# Stage 0 (Bootstrap) +You should follow these steps carefully because we can end up destroying our own permissions. We also have to remove several resources (GCS buckets and BQ datasets) manually. +```bash +cd $FAST_PWD/00-bootstrap/ + +# remove provider config to execute without SA impersonation +rm 00-bootstrap-providers.tf + +# migrate to local state +terraform init -migrate-state + +# remove buckets and BQ dataset manually +for x in $(terraform state list | grep google_storage_bucket.bucket); do + terraform state rm "$x"; +done + +for x in $(terraform state list | grep google_bigquery_dataset); do + terraform state rm "$x"; +done + +terraform destroy + +# when this fails continue with the steps below +# make your user (the one you are using to execute this step) org admin again, as we will remove organization-admins group roles + +# Add the Organization Admin role to $BU_USER in the GCP Console + +# grant yourself this permission so you can finish the destruction +export FAST_DESTROY_ROLES="roles/billing.admin roles/logging.admin \ + roles/iam.organizationRoleAdmin roles/resourcemanager.projectDeleter \ + roles/resourcemanager.folderAdmin roles/owner" + +export FAST_BU=$(gcloud config list --format 'value(core.account)') + +# find your org id +gcloud organizations list --filter display_name:[part of your domain] + +# set your org id +export FAST_ORG_ID=XXXX + +for role in $FAST_DESTROY_ROLES; do + gcloud organizations add-iam-policy-binding $FAST_ORG_ID \ + --member user:$FAST_BU --role $role +done + +terraform destroy +rm -i terraform.tfstate* + +``` From 5701348d3df0b86625002bb564e648f06c7874b9 Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:21:30 +0200 Subject: [PATCH 04/36] Update CLEANUP.md --- fast/CLEANUP.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index edc93f04b..3f9b230a7 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -23,13 +23,13 @@ terraform destroy ``` -# Stage 2 (Security) +## Stage 2 (Security) ```bash cd $FAST_PWD/02-security/ terraform destroy ``` -# Stage 2 (Networking) +## Stage 2 (Networking) ```bash cd $FAST_PWD/02-networking-XXX/ terraform destroy @@ -37,7 +37,7 @@ terraform destroy There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the gcloud beta compute shared-vpc associated-projects remove command when terraform destroy fails, and then relaunch the command. -# Stage 1 (Resource Management) +## Stage 1 (Resource Management) Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder @@ -52,8 +52,10 @@ done terraform destroy ``` -# Stage 0 (Bootstrap) -You should follow these steps carefully because we can end up destroying our own permissions. We also have to remove several resources (GCS buckets and BQ datasets) manually. +## Stage 0 (Bootstrap) +***You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs, you will be required to grant organization admin role again *** + +We also have to remove several resources (GCS buckets and BQ datasets) manually. ```bash cd $FAST_PWD/00-bootstrap/ From 2ace596ca88fa3cb711f52ac2170cbb127e973c3 Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:22:49 +0200 Subject: [PATCH 05/36] Update CLEANUP.md --- fast/CLEANUP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index 3f9b230a7..2ea26275b 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -53,7 +53,7 @@ terraform destroy ``` ## Stage 0 (Bootstrap) -***You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs, you will be required to grant organization admin role again *** +**You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs, you will be required to grant organization admin role again** We also have to remove several resources (GCS buckets and BQ datasets) manually. From 02f8986a1e751db858d69aa6ba92dc9f3556db15 Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:38:05 +0200 Subject: [PATCH 06/36] Update CLEANUP.md --- fast/CLEANUP.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index 2ea26275b..1994067bc 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -11,10 +11,12 @@ terraform destroy ``` ## Stage 3 (GKE) +Terraform refuses to delete empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state ```bash cd $FAST_PWD/03-project-factory/prod/ +# remove BQ dataset manually for x in $(terraform state list | grep google_bigquery_dataset); do terraform state rm "$x"; done @@ -66,7 +68,7 @@ rm 00-bootstrap-providers.tf # migrate to local state terraform init -migrate-state -# remove buckets and BQ dataset manually +# remove GCS buckets and BQ dataset manually for x in $(terraform state list | grep google_storage_bucket.bucket); do terraform state rm "$x"; done From 21cfb69797c80f68b45c12c2e9c0cbbc4b03cf21 Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 10 Jun 2022 16:03:10 +0200 Subject: [PATCH 07/36] Update CLEANUP.md delete spaces in headers --- fast/CLEANUP.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index 1994067bc..e0aa6e4e8 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -1,16 +1,16 @@ -# FAST deployment clean up +#FAST deployment clean up In case you require destroying FAST deployment in your organization, follow these steps. Destruction goes in reverse order, from stage 3 to stage 0: -## Stage 3 (Project Factory) +##Stage 3 (Project Factory) ```bash cd $FAST_PWD/03-project-factory/prod/ terraform destroy ``` -## Stage 3 (GKE) +##Stage 3 (GKE) Terraform refuses to delete empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state ```bash @@ -25,13 +25,13 @@ terraform destroy ``` -## Stage 2 (Security) +##Stage 2 (Security) ```bash cd $FAST_PWD/02-security/ terraform destroy ``` -## Stage 2 (Networking) +##Stage 2 (Networking) ```bash cd $FAST_PWD/02-networking-XXX/ terraform destroy @@ -39,7 +39,7 @@ terraform destroy There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the gcloud beta compute shared-vpc associated-projects remove command when terraform destroy fails, and then relaunch the command. -## Stage 1 (Resource Management) +##Stage 1 (Resource Management) Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder @@ -54,7 +54,7 @@ done terraform destroy ``` -## Stage 0 (Bootstrap) +##Stage 0 (Bootstrap) **You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs, you will be required to grant organization admin role again** We also have to remove several resources (GCS buckets and BQ datasets) manually. From a262ed39414e7d358b1d4e81ce22042e2d33a3d3 Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 10 Jun 2022 16:20:29 +0200 Subject: [PATCH 08/36] Update CLEANUP.md --- fast/CLEANUP.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index e0aa6e4e8..1994067bc 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -1,16 +1,16 @@ -#FAST deployment clean up +# FAST deployment clean up In case you require destroying FAST deployment in your organization, follow these steps. Destruction goes in reverse order, from stage 3 to stage 0: -##Stage 3 (Project Factory) +## Stage 3 (Project Factory) ```bash cd $FAST_PWD/03-project-factory/prod/ terraform destroy ``` -##Stage 3 (GKE) +## Stage 3 (GKE) Terraform refuses to delete empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state ```bash @@ -25,13 +25,13 @@ terraform destroy ``` -##Stage 2 (Security) +## Stage 2 (Security) ```bash cd $FAST_PWD/02-security/ terraform destroy ``` -##Stage 2 (Networking) +## Stage 2 (Networking) ```bash cd $FAST_PWD/02-networking-XXX/ terraform destroy @@ -39,7 +39,7 @@ terraform destroy There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the gcloud beta compute shared-vpc associated-projects remove command when terraform destroy fails, and then relaunch the command. -##Stage 1 (Resource Management) +## Stage 1 (Resource Management) Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder @@ -54,7 +54,7 @@ done terraform destroy ``` -##Stage 0 (Bootstrap) +## Stage 0 (Bootstrap) **You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs, you will be required to grant organization admin role again** We also have to remove several resources (GCS buckets and BQ datasets) manually. From 77f3048a8c2b4ab75ad7e92243c1e8ec75c71e1f Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 10 Jun 2022 16:34:46 +0200 Subject: [PATCH 09/36] Update CLEANUP.md include comments in PR --- fast/CLEANUP.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index 1994067bc..2cc35a267 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -1,4 +1,4 @@ -# FAST deployment clean up +# a FAST deployment clean up In case you require destroying FAST deployment in your organization, follow these steps. Destruction goes in reverse order, from stage 3 to stage 0: @@ -11,7 +11,7 @@ terraform destroy ``` ## Stage 3 (GKE) -Terraform refuses to delete empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state +Terraform refuses to delete non empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state ```bash cd $FAST_PWD/03-project-factory/prod/ @@ -37,7 +37,7 @@ cd $FAST_PWD/02-networking-XXX/ terraform destroy ``` -There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the gcloud beta compute shared-vpc associated-projects remove command when terraform destroy fails, and then relaunch the command. +There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the ```gcloud beta compute shared-vpc associated-projects remove``` command when terraform destroy fails, and then relaunch the command. ## Stage 1 (Resource Management) Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder From a1a5011cd147a317f0d55d741a83586c61be07c8 Mon Sep 17 00:00:00 2001 From: Antonio Lopez <94461129+ajlopezn@users.noreply.github.com> Date: Fri, 10 Jun 2022 16:41:10 +0200 Subject: [PATCH 10/36] Update CLEANUP.md link to gcloud beta compute shared-vpc associated-projects remove doc --- fast/CLEANUP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md index 2cc35a267..88469dad1 100644 --- a/fast/CLEANUP.md +++ b/fast/CLEANUP.md @@ -37,7 +37,7 @@ cd $FAST_PWD/02-networking-XXX/ terraform destroy ``` -There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the ```gcloud beta compute shared-vpc associated-projects remove``` command when terraform destroy fails, and then relaunch the command. +There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the ```gcloud beta compute shared-vpc associated-projects remove``` [command](https://cloud.google.com/sdk/gcloud/reference/beta/compute/shared-vpc/associated-projects/remove) when terraform destroy fails, and then relaunch the command. ## Stage 1 (Resource Management) Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder From 1dbd13fc4b934a4bfc96c1203cde7ba33ce11b76 Mon Sep 17 00:00:00 2001 From: ajlopezn Date: Fri, 10 Jun 2022 16:47:24 +0200 Subject: [PATCH 11/36] fichero movido a fast/stages --- fast/CLEANUP.md | 108 ------------------------------------------------ 1 file changed, 108 deletions(-) delete mode 100644 fast/CLEANUP.md diff --git a/fast/CLEANUP.md b/fast/CLEANUP.md deleted file mode 100644 index 88469dad1..000000000 --- a/fast/CLEANUP.md +++ /dev/null @@ -1,108 +0,0 @@ -# a FAST deployment clean up -In case you require destroying FAST deployment in your organization, follow these steps. - -Destruction goes in reverse order, from stage 3 to stage 0: - -## Stage 3 (Project Factory) - -```bash -cd $FAST_PWD/03-project-factory/prod/ -terraform destroy -``` - -## Stage 3 (GKE) -Terraform refuses to delete non empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state - -```bash -cd $FAST_PWD/03-project-factory/prod/ - -# remove BQ dataset manually -for x in $(terraform state list | grep google_bigquery_dataset); do - terraform state rm "$x"; -done - -terraform destroy -``` - - -## Stage 2 (Security) -```bash -cd $FAST_PWD/02-security/ -terraform destroy -``` - -## Stage 2 (Networking) -```bash -cd $FAST_PWD/02-networking-XXX/ -terraform destroy -``` - -There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the ```gcloud beta compute shared-vpc associated-projects remove``` [command](https://cloud.google.com/sdk/gcloud/reference/beta/compute/shared-vpc/associated-projects/remove) when terraform destroy fails, and then relaunch the command. - -## Stage 1 (Resource Management) -Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder - - -```bash -cd $FAST_PWD/01-resman/ - -# remove buckets from state since terraform refuses to delete them -for x in $(terraform state list | grep google_storage_bucket.bucket); do - terraform state rm "$x" -done - -terraform destroy -``` - -## Stage 0 (Bootstrap) -**You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs, you will be required to grant organization admin role again** - -We also have to remove several resources (GCS buckets and BQ datasets) manually. - -```bash -cd $FAST_PWD/00-bootstrap/ - -# remove provider config to execute without SA impersonation -rm 00-bootstrap-providers.tf - -# migrate to local state -terraform init -migrate-state - -# remove GCS buckets and BQ dataset manually -for x in $(terraform state list | grep google_storage_bucket.bucket); do - terraform state rm "$x"; -done - -for x in $(terraform state list | grep google_bigquery_dataset); do - terraform state rm "$x"; -done - -terraform destroy - -# when this fails continue with the steps below -# make your user (the one you are using to execute this step) org admin again, as we will remove organization-admins group roles - -# Add the Organization Admin role to $BU_USER in the GCP Console - -# grant yourself this permission so you can finish the destruction -export FAST_DESTROY_ROLES="roles/billing.admin roles/logging.admin \ - roles/iam.organizationRoleAdmin roles/resourcemanager.projectDeleter \ - roles/resourcemanager.folderAdmin roles/owner" - -export FAST_BU=$(gcloud config list --format 'value(core.account)') - -# find your org id -gcloud organizations list --filter display_name:[part of your domain] - -# set your org id -export FAST_ORG_ID=XXXX - -for role in $FAST_DESTROY_ROLES; do - gcloud organizations add-iam-policy-binding $FAST_ORG_ID \ - --member user:$FAST_BU --role $role -done - -terraform destroy -rm -i terraform.tfstate* - -``` From a37af012038e68cb63771f693428586ae8d891f4 Mon Sep 17 00:00:00 2001 From: ajlopezn Date: Fri, 10 Jun 2022 16:57:40 +0200 Subject: [PATCH 12/36] fichero movido a fast/stages --- fast/stages/CLEANUP.md | 108 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 fast/stages/CLEANUP.md diff --git a/fast/stages/CLEANUP.md b/fast/stages/CLEANUP.md new file mode 100644 index 000000000..88469dad1 --- /dev/null +++ b/fast/stages/CLEANUP.md @@ -0,0 +1,108 @@ +# a FAST deployment clean up +In case you require destroying FAST deployment in your organization, follow these steps. + +Destruction goes in reverse order, from stage 3 to stage 0: + +## Stage 3 (Project Factory) + +```bash +cd $FAST_PWD/03-project-factory/prod/ +terraform destroy +``` + +## Stage 3 (GKE) +Terraform refuses to delete non empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state + +```bash +cd $FAST_PWD/03-project-factory/prod/ + +# remove BQ dataset manually +for x in $(terraform state list | grep google_bigquery_dataset); do + terraform state rm "$x"; +done + +terraform destroy +``` + + +## Stage 2 (Security) +```bash +cd $FAST_PWD/02-security/ +terraform destroy +``` + +## Stage 2 (Networking) +```bash +cd $FAST_PWD/02-networking-XXX/ +terraform destroy +``` + +There's a minor glitch that can surface running terraform destroy, where the service project attachments to the Shared VPC will not get destroyed even with the relevant API call succeeding. We are investigating the issue, in the meantime just manually remove the attachment in the Cloud console or via the ```gcloud beta compute shared-vpc associated-projects remove``` [command](https://cloud.google.com/sdk/gcloud/reference/beta/compute/shared-vpc/associated-projects/remove) when terraform destroy fails, and then relaunch the command. + +## Stage 1 (Resource Management) +Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder + + +```bash +cd $FAST_PWD/01-resman/ + +# remove buckets from state since terraform refuses to delete them +for x in $(terraform state list | grep google_storage_bucket.bucket); do + terraform state rm "$x" +done + +terraform destroy +``` + +## Stage 0 (Bootstrap) +**You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs, you will be required to grant organization admin role again** + +We also have to remove several resources (GCS buckets and BQ datasets) manually. + +```bash +cd $FAST_PWD/00-bootstrap/ + +# remove provider config to execute without SA impersonation +rm 00-bootstrap-providers.tf + +# migrate to local state +terraform init -migrate-state + +# remove GCS buckets and BQ dataset manually +for x in $(terraform state list | grep google_storage_bucket.bucket); do + terraform state rm "$x"; +done + +for x in $(terraform state list | grep google_bigquery_dataset); do + terraform state rm "$x"; +done + +terraform destroy + +# when this fails continue with the steps below +# make your user (the one you are using to execute this step) org admin again, as we will remove organization-admins group roles + +# Add the Organization Admin role to $BU_USER in the GCP Console + +# grant yourself this permission so you can finish the destruction +export FAST_DESTROY_ROLES="roles/billing.admin roles/logging.admin \ + roles/iam.organizationRoleAdmin roles/resourcemanager.projectDeleter \ + roles/resourcemanager.folderAdmin roles/owner" + +export FAST_BU=$(gcloud config list --format 'value(core.account)') + +# find your org id +gcloud organizations list --filter display_name:[part of your domain] + +# set your org id +export FAST_ORG_ID=XXXX + +for role in $FAST_DESTROY_ROLES; do + gcloud organizations add-iam-policy-binding $FAST_ORG_ID \ + --member user:$FAST_BU --role $role +done + +terraform destroy +rm -i terraform.tfstate* + +``` From 8da7fbd351a7f47b9b7f93d92aa0e3528b337ae6 Mon Sep 17 00:00:00 2001 From: ajlopezn Date: Fri, 10 Jun 2022 17:16:11 +0200 Subject: [PATCH 13/36] cleanup reference in readme --- fast/stages/CLEANUP.md | 4 ++-- fast/stages/README.md | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fast/stages/CLEANUP.md b/fast/stages/CLEANUP.md index 88469dad1..aeeed567d 100644 --- a/fast/stages/CLEANUP.md +++ b/fast/stages/CLEANUP.md @@ -1,5 +1,5 @@ -# a FAST deployment clean up -In case you require destroying FAST deployment in your organization, follow these steps. +# FAST deployment clean up +In case you require destroying a FAST deployment in your organization, follow these steps. Destruction goes in reverse order, from stage 3 to stage 0: diff --git a/fast/stages/README.md b/fast/stages/README.md index 8b0814280..d7951ba79 100644 --- a/fast/stages/README.md +++ b/fast/stages/README.md @@ -17,6 +17,8 @@ To achieve this, we rely on specific GCP functionality like [delegated role gran Refer to each stage's documentation for a detailed description of its purpose, the architectural choices made in its design, and how it can be configured and wired together to terraform a whole GCP organization. The following is a brief overview of each stage. +To destroy a previous FAST deployment follow the instructions detailed in [cleanup](CLEANUP.md). + ## Organizational level (00-01) - [Bootstrap](00-bootstrap/README.md) From 4658e5faa78991bc00e2ddb5b0731b1581a0f1a4 Mon Sep 17 00:00:00 2001 From: ajlopezn Date: Fri, 10 Jun 2022 17:29:04 +0200 Subject: [PATCH 14/36] added variables required to be modified before applying again --- fast/stages/CLEANUP.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fast/stages/CLEANUP.md b/fast/stages/CLEANUP.md index aeeed567d..ff27945cc 100644 --- a/fast/stages/CLEANUP.md +++ b/fast/stages/CLEANUP.md @@ -104,5 +104,8 @@ done terraform destroy rm -i terraform.tfstate* - ``` + +In case you are willing to deploy again FAST stages, the following changes shall be done before: +* Modify [prefix](/00-bootstrap/variables.tf#L167) variable to allow deployment of resources that need unique names (eg, projects) +* Modify [custom_roles](00-bootstrap/variables.tf#L77) variable to allow recently deleted custom roles to be created again \ No newline at end of file From 822e4b987abcf411889d174170f96a036da72e7c Mon Sep 17 00:00:00 2001 From: ajlopezn Date: Fri, 10 Jun 2022 18:21:44 +0200 Subject: [PATCH 15/36] solved links issue --- fast/stages/CLEANUP.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/fast/stages/CLEANUP.md b/fast/stages/CLEANUP.md index ff27945cc..e138a6d0c 100644 --- a/fast/stages/CLEANUP.md +++ b/fast/stages/CLEANUP.md @@ -1,7 +1,7 @@ # FAST deployment clean up -In case you require destroying a FAST deployment in your organization, follow these steps. +In case you require destroying a previous FAST deployment in your organization, follow these steps. -Destruction goes in reverse order, from stage 3 to stage 0: +Destruction must be done in reverse order, from stage 3 to stage 0: ## Stage 3 (Project Factory) @@ -11,7 +11,7 @@ terraform destroy ``` ## Stage 3 (GKE) -Terraform refuses to delete non empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state +Terraform refuses to delete non-empty GCS buckets and/or BigQuery datasets, so they need to be removed manually from tf state ```bash cd $FAST_PWD/03-project-factory/prod/ @@ -42,7 +42,6 @@ There's a minor glitch that can surface running terraform destroy, where the ser ## Stage 1 (Resource Management) Stage 1 is a little more complicated because of the GCS Buckets. By default terraform refuses to delete non-empty buckets, which is a good thing for your terraform state. However, it makes destruction a bit harder - ```bash cd $FAST_PWD/01-resman/ @@ -55,7 +54,7 @@ terraform destroy ``` ## Stage 0 (Bootstrap) -**You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs, you will be required to grant organization admin role again** +**You should follow these steps carefully because we can end up destroying our own permissions. As we will be removing gcp-admins group roles, where your user belongs to, you will be required to grant organization admin role again** We also have to remove several resources (GCS buckets and BQ datasets) manually. @@ -106,6 +105,6 @@ terraform destroy rm -i terraform.tfstate* ``` -In case you are willing to deploy again FAST stages, the following changes shall be done before: -* Modify [prefix](/00-bootstrap/variables.tf#L167) variable to allow deployment of resources that need unique names (eg, projects) -* Modify [custom_roles](00-bootstrap/variables.tf#L77) variable to allow recently deleted custom roles to be created again \ No newline at end of file +In case you are willing to deploy FAST stages again, the following changes shall be done before: +* Modify the [prefix](/00-bootstrap/variables.tf) variable to allow the deployment of resources that need unique names (eg, projects). +* Modify the [custom_roles](00-bootstrap/variables.tf) variable to allow recently deleted custom roles to be created again. \ No newline at end of file From c91ec944f98af068fe7addef786636314dad052b Mon Sep 17 00:00:00 2001 From: ajlopezn Date: Fri, 10 Jun 2022 18:34:00 +0200 Subject: [PATCH 16/36] solved another link issue --- fast/stages/CLEANUP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast/stages/CLEANUP.md b/fast/stages/CLEANUP.md index e138a6d0c..a0a1688fe 100644 --- a/fast/stages/CLEANUP.md +++ b/fast/stages/CLEANUP.md @@ -106,5 +106,5 @@ rm -i terraform.tfstate* ``` In case you are willing to deploy FAST stages again, the following changes shall be done before: -* Modify the [prefix](/00-bootstrap/variables.tf) variable to allow the deployment of resources that need unique names (eg, projects). +* Modify the [prefix](00-bootstrap/variables.tf) variable to allow the deployment of resources that need unique names (eg, projects). * Modify the [custom_roles](00-bootstrap/variables.tf) variable to allow recently deleted custom roles to be created again. \ No newline at end of file From 2eb996d33d806b34bc4c0d52f140f68401d9224e Mon Sep 17 00:00:00 2001 From: "agusramirez@google.com" Date: Wed, 15 Jun 2022 19:12:11 -0500 Subject: [PATCH 17/36] sourcerepo and cloudbuild at 01-resman --- fast/stages/00-bootstrap/automation.tf | 3 ++- fast/stages/01-resman/cicd-networking.tf | 2 +- fast/stages/01-resman/cicd-security.tf | 2 +- fast/stages/01-resman/cicd-teams.tf | 4 ++-- fast/stages/01-resman/outputs.tf | 8 +++++--- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/fast/stages/00-bootstrap/automation.tf b/fast/stages/00-bootstrap/automation.tf index 0874fc4ff..11a8b34d8 100644 --- a/fast/stages/00-bootstrap/automation.tf +++ b/fast/stages/00-bootstrap/automation.tf @@ -36,7 +36,8 @@ module "automation-project" { # machine (service accounts) IAM bindings iam = { "roles/owner" = [ - module.automation-tf-bootstrap-sa.iam_email + module.automation-tf-bootstrap-sa.iam_email, + module.automation-tf-resman-sa.iam_email ] "roles/iam.serviceAccountAdmin" = [ module.automation-tf-resman-sa.iam_email diff --git a/fast/stages/01-resman/cicd-networking.tf b/fast/stages/01-resman/cicd-networking.tf index 541d8bda0..9bb96f796 100644 --- a/fast/stages/01-resman/cicd-networking.tf +++ b/fast/stages/01-resman/cicd-networking.tf @@ -35,7 +35,7 @@ module "branch-network-cicd-repo" { fast-02-networking = { filename = ".cloudbuild/workflow.yaml" included_files = ["**/*tf", ".cloudbuild/workflow.yaml"] - service_account = module.branch-network-sa.id + service_account = module.branch-network-sa-cicd.0.id substitutions = {} template = { project_id = null diff --git a/fast/stages/01-resman/cicd-security.tf b/fast/stages/01-resman/cicd-security.tf index d6b0b8691..ff456166a 100644 --- a/fast/stages/01-resman/cicd-security.tf +++ b/fast/stages/01-resman/cicd-security.tf @@ -35,7 +35,7 @@ module "branch-security-cicd-repo" { fast-02-security = { filename = ".cloudbuild/workflow.yaml" included_files = ["**/*tf", ".cloudbuild/workflow.yaml"] - service_account = module.branch-security-sa.id + service_account = module.branch-security-sa-cicd.0.id substitutions = {} template = { project_id = null diff --git a/fast/stages/01-resman/cicd-teams.tf b/fast/stages/01-resman/cicd-teams.tf index 2766e301e..931b0a7ca 100644 --- a/fast/stages/01-resman/cicd-teams.tf +++ b/fast/stages/01-resman/cicd-teams.tf @@ -37,7 +37,7 @@ module "branch-teams-dev-pf-cicd-repo" { included_files = [ "**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml" ] - service_account = module.branch-teams-dev-pf-sa.iam_email + service_account = module.branch-teams-dev-pf-sa-cicd.0.id substitutions = {} template = { project_id = null @@ -68,7 +68,7 @@ module "branch-teams-prod-pf-cicd-repo" { included_files = [ "**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml" ] - service_account = module.branch-teams-prod-pf-sa.iam_email + service_account = module.branch-teams-prod-pf-sa-cicd.0.id substitutions = {} template = { project_id = null diff --git a/fast/stages/01-resman/outputs.tf b/fast/stages/01-resman/outputs.tf index f91a843d8..b7de52409 100644 --- a/fast/stages/01-resman/outputs.tf +++ b/fast/stages/01-resman/outputs.tf @@ -144,9 +144,11 @@ output "cicd_repositories" { description = "WIF configuration for CI/CD repositories." value = { for k, v in local.cicd_repositories : k => { - branch = v.branch - name = v.name - provider = local.identity_providers[v.identity_provider].name + branch = v.branch + name = v.name + provider = try( + local.identity_providers[v.identity_provider].name, null + ) service_account = local.cicd_workflow_attrs[k].service_account } if v != null } From 35e5ffaf854edd1ec8509427b7c94a1711ec0e07 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Thu, 16 Jun 2022 10:39:05 +1000 Subject: [PATCH 18/36] fix: Raise ValueError when check_names detects overlong names ValueError may not be the correct type? Closes #679 --- tools/check_names.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/check_names.py b/tools/check_names.py index 7e45fd877..e3fcf88f1 100755 --- a/tools/check_names.py +++ b/tools/check_names.py @@ -84,13 +84,21 @@ def main(dirs, prefix_length=None): source_just = max(len(k) for k in MOD_LIMITS) name_just = max(len(n.name) for n in names) value_just = max(len(n.value) for n in names) + errors = [] for name in names: name_length = name.length + prefix_length - flag = '✗' if name_length >= MOD_LIMITS[name.source] else '✓' - print(f'[{flag}] {name.source.ljust(source_just)} ' - f'{name.name.ljust(name_just)} ' - f'{name.value.ljust(value_just)} ' - f'({name_length})') + if name_length >= MOD_LIMITS[name.source]: + flag = "✗" + errors += [f"{name.source}:{name.name}:{name_length}"] + else: + flag = "✓" + + print(f"[{flag}] {name.source.ljust(source_just)} " + f"{name.name.ljust(name_just)} " + f"{name.value.ljust(value_just)} " + f"({name_length})") + if errors: + raise ValueError(errors) if __name__ == '__main__': From e3d91e84e4463162cac6ca9d96645bc2787a17ec Mon Sep 17 00:00:00 2001 From: "agusramirez@google.com" Date: Wed, 15 Jun 2022 21:34:26 -0500 Subject: [PATCH 19/36] sourcerepo and cloudbuild at 01-resman --- fast/stages/01-resman/cicd-data-platform.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fast/stages/01-resman/cicd-data-platform.tf b/fast/stages/01-resman/cicd-data-platform.tf index e62a02208..66247d269 100644 --- a/fast/stages/01-resman/cicd-data-platform.tf +++ b/fast/stages/01-resman/cicd-data-platform.tf @@ -37,7 +37,7 @@ module "branch-dp-dev-cicd-repo" { included_files = [ "**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml" ] - service_account = module.branch-dp-dev-sa.iam_email + service_account = module.branch-dp-dev-sa-cicd.0.id substitutions = {} template = { project_id = null @@ -68,7 +68,7 @@ module "branch-dp-prod-cicd-repo" { included_files = [ "**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml" ] - service_account = module.branch-dp-prod-sa.iam_email + service_account = module.branch-dp-prod-sa-cicd.0.id substitutions = {} template = { project_id = null From 073196c56eab22e63220fa8fc4b56fc24757e97c Mon Sep 17 00:00:00 2001 From: Miren Esnaola Date: Mon, 13 Jun 2022 02:55:57 +0200 Subject: [PATCH 20/36] Binary authorization module and example --- .gitignore | 4 +- examples/cloud-operations/binauthz/README.md | 127 + examples/cloud-operations/binauthz/app | 1 + .../cloud-operations/binauthz/diagram.png | Bin 0 -> 52258 bytes .../binauthz/image/.dockerignore | 1 + .../binauthz/image/.gitignore | 1 + .../binauthz/image/Dockerfile | 25 + .../cloud-operations/binauthz/image/README.md | 27 + .../binauthz/image/cloudbuild.yaml | 40 + .../cloud-operations/binauthz/image/index.js | 81 + .../binauthz/image/package-lock.json | 2277 +++++++++++++++++ .../binauthz/image/package.json | 15 + examples/cloud-operations/binauthz/main.tf | 274 ++ examples/cloud-operations/binauthz/outputs.tf | 25 + .../binauthz/templates/app.yaml.tpl | 45 + .../binauthz/templates/tenant-setup.yaml.tpl | 54 + .../cloud-operations/binauthz/variables.tf | 71 + modules/binauthz/README.md | 79 + modules/binauthz/main.tf | 91 + modules/binauthz/outputs.tf | 33 + modules/binauthz/variables.tf | 71 + modules/binauthz/versions.tf | 29 + .../cloud_operations/binauthz/__init__.py | 13 + .../cloud_operations/binauthz/fixture/main.tf | 21 + .../binauthz/fixture/variables.tf | 26 + .../cloud_operations/binauthz/test_plan.py | 19 + tests/modules/binauthz/__init__.py | 13 + tests/modules/binauthz/fixture/main.tf | 23 + tests/modules/binauthz/fixture/variables.tf | 103 + tests/modules/binauthz/test_plan.py | 24 + 30 files changed, 3612 insertions(+), 1 deletion(-) create mode 100644 examples/cloud-operations/binauthz/README.md create mode 160000 examples/cloud-operations/binauthz/app create mode 100644 examples/cloud-operations/binauthz/diagram.png create mode 100644 examples/cloud-operations/binauthz/image/.dockerignore create mode 100644 examples/cloud-operations/binauthz/image/.gitignore create mode 100644 examples/cloud-operations/binauthz/image/Dockerfile create mode 100644 examples/cloud-operations/binauthz/image/README.md create mode 100644 examples/cloud-operations/binauthz/image/cloudbuild.yaml create mode 100644 examples/cloud-operations/binauthz/image/index.js create mode 100644 examples/cloud-operations/binauthz/image/package-lock.json create mode 100644 examples/cloud-operations/binauthz/image/package.json create mode 100644 examples/cloud-operations/binauthz/main.tf create mode 100644 examples/cloud-operations/binauthz/outputs.tf create mode 100644 examples/cloud-operations/binauthz/templates/app.yaml.tpl create mode 100644 examples/cloud-operations/binauthz/templates/tenant-setup.yaml.tpl create mode 100644 examples/cloud-operations/binauthz/variables.tf create mode 100644 modules/binauthz/README.md create mode 100644 modules/binauthz/main.tf create mode 100644 modules/binauthz/outputs.tf create mode 100644 modules/binauthz/variables.tf create mode 100644 modules/binauthz/versions.tf create mode 100644 tests/examples/cloud_operations/binauthz/__init__.py create mode 100644 tests/examples/cloud_operations/binauthz/fixture/main.tf create mode 100644 tests/examples/cloud_operations/binauthz/fixture/variables.tf create mode 100644 tests/examples/cloud_operations/binauthz/test_plan.py create mode 100644 tests/modules/binauthz/__init__.py create mode 100644 tests/modules/binauthz/fixture/main.tf create mode 100644 tests/modules/binauthz/fixture/variables.tf create mode 100644 tests/modules/binauthz/test_plan.py diff --git a/.gitignore b/.gitignore index 4fb446019..2067242c9 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,6 @@ fast/stages/**/terraform-*.auto.tfvars.json fast/stages/**/0*.auto.tfvars* **/node_modules fast/stages/**/globals.auto.tfvars.json -cloud_sql_proxy \ No newline at end of file +cloud_sql_proxy +examples/cloud-operations/binauthz/tenant-setup.yaml +examples/cloud-operations/binauthz/app/app.yaml \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/README.md b/examples/cloud-operations/binauthz/README.md new file mode 100644 index 000000000..18d7ab51b --- /dev/null +++ b/examples/cloud-operations/binauthz/README.md @@ -0,0 +1,127 @@ +# Binary Authorization + +The following example shows to how to create a CI and a CD pipeline in Cloud Build for the deployment of an application to a private GKE cluster with unrestricted access to a public endpoint. The example enables a Binary Authorization policy in the project so only images that have been attested can be deployed to the cluster. The attestations are created using a cryptographic key pair that has been provisioned in KMS. + +The diagram below depicts the architecture used in the example. + +![Architecture](diagram.png) + +The CI and CD pipelines are implemented as Cloud Build triggers that run with a user-specified service account. + +The CI pipeline does the following: + +* Builds and pushes the image to Artifact registry +* Creates an attestation for the image. + +The CD pipeline deploys the application to the cluster. + +## Running the example + +Clone this repository or [open it in cloud shell](https://ssh.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fterraform-google-modules%2Fcloud-foundation-fabric&cloudshell_print=cloud-shell-readme.txt&cloudshell_working_dir=examples%2Fcloud-operations%2Fbinauthz), then go through the following steps to create resources: + +* `terraform init` +* `terraform apply -var project_id=my-project-id` + +WARNING: The example requires the activation of the Binary Authorization API. That API does not support authentication with user credentials. A service account will need to be used to run the example + +## Testing the example + +Once the resources have been created, do the following to verify that everything works as expected. + +1. Fetch the cluster credentials + + gcloud container clusters get-credentials cluster --project + +2. Apply the manifest tenant-setup.yaml available in your work directory. + + kubectl apply -f tenant-setup.yaml + + By applying that manifest thw following is created: + + * A namespace called "apis". This is the namespace where the application will be deployed. + * A Role and a RoleBinding in previously created namespace so the service account that has been configured for the CD pipeline trigger in Cloud Build is able to deploy the kubernetes application to that namespace. + +3. Change to the image subdirectory in your work directory + + cd /image + +4. Run the following commands: + + git init + git remote add origin ssh://:2022/p//r/image + git push -u origin main + +4. In the Cloud Build > History section in the Google Cloud console you should see a job running. That job is build the image, pushing to Artifact Registry and creating an attestation. + + Once the job finishes copy the digest of the image that is displayed in the Cloud Build job output. + +5. Change to the app subdirectory in your working directory. + + cd /app + +6. Edit the app.yaml file and replace the string DIGEST with the value you copied before. + +7. Run the following commands: + + git init + git remote add origin ssh://:2022/p//r/app + git push -u origin main + +8. In the Cloud Build > History section in the Google Cloud console you should see a job running. The job will deploy the application to the cluster. + +9. Go to the Kubernetes Engine > Workloads section to check that the deployment was successful and that the Binary Authorization admissions controller webhook did not block the deployment. + +10. Change to the working directory and try to deploy an image that has not been attested. + + cat < Workloads section to check that that the Binary Authorization admissions controller webhook did not block the deployment. + +The application deployed to the cluster is an RESTful API that enables managing Google Cloud storage buckets in the project. Workload identity is used so the app can interact with the Google Cloud Storage API. + +Once done testing, you can clean up resources by running `terraform destroy`. + + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [project_id](variables.tf#L26) | Project ID. | string | ✓ | | +| [master_cidr_block](variables.tf#L49) | Master CIDR block. | string | | "10.0.0.0/28" | +| [pods_cidr_block](variables.tf#L37) | Pods CIDR block. | string | | "172.16.0.0/20" | +| [prefix](variables.tf#L31) | Prefix for resources created. | string | | null | +| [project_create](variables.tf#L17) | Parameters for the creation of the new project. | object({…}) | | null | +| [region](variables.tf#L61) | Region. | string | | "europe-west1" | +| [services_cidr_block](variables.tf#L43) | Services CIDR block. | string | | "192.168.0.0/24" | +| [subnet_cidr_block](variables.tf#L55) | Subnet CIDR block. | string | | "10.0.1.0/24" | +| [zone](variables.tf#L67) | Zone. | string | | "europe-west1-c" | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| [app_repo_url](outputs.tf#L22) | App source repository url. | | +| [image_repo_url](outputs.tf#L17) | Image source repository url. | | + + diff --git a/examples/cloud-operations/binauthz/app b/examples/cloud-operations/binauthz/app new file mode 160000 index 000000000..0f46c645d --- /dev/null +++ b/examples/cloud-operations/binauthz/app @@ -0,0 +1 @@ +Subproject commit 0f46c645da4a1e409433c927807204a4fb6005a8 diff --git a/examples/cloud-operations/binauthz/diagram.png b/examples/cloud-operations/binauthz/diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..0ee786f0326abdf06ac3ef8d3c9ec130b2b5221b GIT binary patch literal 52258 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 $ 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 literal 0 HcmV?d00001 diff --git a/examples/cloud-operations/binauthz/image/.dockerignore b/examples/cloud-operations/binauthz/image/.dockerignore new file mode 100644 index 000000000..b512c09d4 --- /dev/null +++ b/examples/cloud-operations/binauthz/image/.dockerignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/image/.gitignore b/examples/cloud-operations/binauthz/image/.gitignore new file mode 100644 index 000000000..a8603104a --- /dev/null +++ b/examples/cloud-operations/binauthz/image/.gitignore @@ -0,0 +1 @@ +node_modules/** diff --git a/examples/cloud-operations/binauthz/image/Dockerfile b/examples/cloud-operations/binauthz/image/Dockerfile new file mode 100644 index 000000000..03c3e436c --- /dev/null +++ b/examples/cloud-operations/binauthz/image/Dockerfile @@ -0,0 +1,25 @@ +# Copyright 2019 Google LLC +# +# 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. + +FROM node:18-alpine + +WORKDIR /app + +COPY ["package.json", "package-lock.json*", "./"] + +RUN npm install + +COPY . . + +CMD [ "node", "index.js" ] \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/image/README.md b/examples/cloud-operations/binauthz/image/README.md new file mode 100644 index 000000000..88481cc82 --- /dev/null +++ b/examples/cloud-operations/binauthz/image/README.md @@ -0,0 +1,27 @@ +# Storage API + +This application it is a RESTful API that let's you manage the Google Cloud Storage buckets available is a project. In order to do so the application needs to authenticate with a service account that has been granted the Storage Admin (`roles/storage.admin`) role. + +Find below the operations that can be performed using it: + +* Get buckets in project + + curl -v http://localhost:3000/buckets + +* Get files in bucket + + curl -v http://localhost:3000/buckets/BUCKET_NAME + +* Create a bucket + + curl -v http://localhost:3000/buckets \ + -H'Content-Type: application/json' \ + -d @- < { + try { + const [buckets] = await storage.getBuckets(); + res.json(buckets.map(bucket => bucket.name)); + } catch (error) { + res.status(500).json({ + message: `An error occurred trying to fetch the buckets in project: ${error}` + }); + } +}); + +app.get('/buckets/:name', async (req, res) => { + const name = req.params.name; + try { + const [files] = await storage.bucket(name).getFiles(); + res.json(files.map(file => file.name)); + } catch (error) { + res.status(500).json({ + message: `An error occurred fetch the files in ${name} bucket: ${error}` + }); + } +}); + +app.post('/buckets', async (req, res) => { + const name = req.body.name; + try { + const [bucket] = await storage.createBucket(name); + res.status(201).json({ + "name": bucket.name + }); + } catch (error) { + res.status(500).json({ + message: `An error occurred trying to create ${name} bucket: ${error}` + }); + } +}); + +app.delete('/buckets/:name', async (req, res) => { + const name = req.params.name; + try { + await storage.bucket(name).delete(); + res.send() + } catch (error) { + res.status(500).json({ + message: `An error occurred trying to delete ${name} bucket: ${error}` + }); + } +}); + +app.listen(PORT, () => { + console.log(`App listening on port ${PORT}`) +}) \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/image/package-lock.json b/examples/cloud-operations/binauthz/image/package-lock.json new file mode 100644 index 000000000..c7eed8518 --- /dev/null +++ b/examples/cloud-operations/binauthz/image/package-lock.json @@ -0,0 +1,2277 @@ +{ + "name": "app", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "app", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@google-cloud/storage": "^5.18.3", + "express": "^4.17.3" + } + }, + "node_modules/@google-cloud/common": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.10.0.tgz", + "integrity": "sha512-XMbJYMh/ZSaZnbnrrOFfR/oQrb0SxG4qh6hDisWCoEbFcBHV0qHQo4uXfeMCzolx2Mfkh6VDaOGg+hyJsmxrlw==", + "dependencies": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^7.14.0", + "retry-request": "^4.2.2", + "teeny-request": "^7.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/paginator": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", + "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "dependencies": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.1.1.tgz", + "integrity": "sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.4.tgz", + "integrity": "sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/storage": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.18.3.tgz", + "integrity": "sha512-573qJ0ECoy3nkY5YaMWcVf4/46n/zdvfNgAyjaLQywl/eL38uxDhs7YVJd3pcgslaMUwKKsd/eD3St+Pq2iPew==", + "dependencies": { + "@google-cloud/common": "^3.8.1", + "@google-cloud/paginator": "^3.0.7", + "@google-cloud/promisify": "^2.0.0", + "abort-controller": "^3.0.0", + "arrify": "^2.0.0", + "async-retry": "^1.3.3", + "compressible": "^2.0.12", + "configstore": "^5.0.0", + "date-and-time": "^2.0.0", + "duplexify": "^4.0.0", + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "get-stream": "^6.0.0", + "google-auth-library": "^7.0.0", + "hash-stream-validation": "^0.2.2", + "mime": "^3.0.0", + "mime-types": "^2.0.8", + "p-limit": "^3.0.1", + "pumpify": "^2.0.0", + "snakeize": "^0.1.0", + "stream-events": "^1.0.4", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "engines": { + "node": ">=8" + } + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bignumber.js": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", + "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", + "engines": { + "node": "*" + } + }, + "node_modules/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/date-and-time": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.3.0.tgz", + "integrity": "sha512-DY53oj742mykXjZzDxT7NxH5cxwBRb7FsVG5+8pcV96qU9JQd0UhA21pQB18fwwsXOXeSM0RJV4OzgVxu8eatg==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/gaxios": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", + "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "dependencies": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-auth-library": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.1.tgz", + "integrity": "sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA==", + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-p12-pem": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.3.tgz", + "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==", + "dependencies": { + "node-forge": "^1.0.0" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "node_modules/gtoken": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", + "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "dependencies": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hash-stream-validation": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", + "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" + }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "dependencies": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, + "node_modules/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/retry-request": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.2.2.tgz", + "integrity": "sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg==", + "dependencies": { + "debug": "^4.1.1", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" + }, + "node_modules/teeny-request": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.2.0.tgz", + "integrity": "sha512-SyY0pek1zWsi0LRVAALem+avzMLc33MKW/JLLakdP4s9+D7+jHcy5x6P+h94g2QNZsAqQNfX5lsbd3WSeJXrrw==", + "dependencies": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@google-cloud/common": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.10.0.tgz", + "integrity": "sha512-XMbJYMh/ZSaZnbnrrOFfR/oQrb0SxG4qh6hDisWCoEbFcBHV0qHQo4uXfeMCzolx2Mfkh6VDaOGg+hyJsmxrlw==", + "requires": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^7.14.0", + "retry-request": "^4.2.2", + "teeny-request": "^7.0.0" + } + }, + "@google-cloud/paginator": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", + "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "requires": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + } + }, + "@google-cloud/projectify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.1.1.tgz", + "integrity": "sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ==" + }, + "@google-cloud/promisify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.4.tgz", + "integrity": "sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA==" + }, + "@google-cloud/storage": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.18.3.tgz", + "integrity": "sha512-573qJ0ECoy3nkY5YaMWcVf4/46n/zdvfNgAyjaLQywl/eL38uxDhs7YVJd3pcgslaMUwKKsd/eD3St+Pq2iPew==", + "requires": { + "@google-cloud/common": "^3.8.1", + "@google-cloud/paginator": "^3.0.7", + "@google-cloud/promisify": "^2.0.0", + "abort-controller": "^3.0.0", + "arrify": "^2.0.0", + "async-retry": "^1.3.3", + "compressible": "^2.0.12", + "configstore": "^5.0.0", + "date-and-time": "^2.0.0", + "duplexify": "^4.0.0", + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "get-stream": "^6.0.0", + "google-auth-library": "^7.0.0", + "hash-stream-validation": "^0.2.2", + "mime": "^3.0.0", + "mime-types": "^2.0.8", + "p-limit": "^3.0.1", + "pumpify": "^2.0.0", + "snakeize": "^0.1.0", + "stream-events": "^1.0.4", + "xdg-basedir": "^4.0.0" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "requires": { + "retry": "0.13.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bignumber.js": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", + "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" + }, + "body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "date-and-time": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.3.0.tgz", + "integrity": "sha512-DY53oj742mykXjZzDxT7NxH5cxwBRb7FsVG5+8pcV96qU9JQd0UhA21pQB18fwwsXOXeSM0RJV4OzgVxu8eatg==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "gaxios": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", + "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.1" + } + }, + "gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "google-auth-library": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.1.tgz", + "integrity": "sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.3.tgz", + "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==", + "requires": { + "node-forge": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "gtoken": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", + "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.1.3", + "jws": "^4.0.0" + } + }, + "hash-stream-validation": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", + "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "requires": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, + "qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "requires": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, + "retry-request": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.2.2.tgz", + "integrity": "sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg==", + "requires": { + "debug": "^4.1.1", + "extend": "^3.0.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "requires": { + "stubs": "^3.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" + }, + "teeny-request": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.2.0.tgz", + "integrity": "sha512-SyY0pek1zWsi0LRVAALem+avzMLc33MKW/JLLakdP4s9+D7+jHcy5x6P+h94g2QNZsAqQNfX5lsbd3WSeJXrrw==", + "requires": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} diff --git a/examples/cloud-operations/binauthz/image/package.json b/examples/cloud-operations/binauthz/image/package.json new file mode 100644 index 000000000..26cd3ebbc --- /dev/null +++ b/examples/cloud-operations/binauthz/image/package.json @@ -0,0 +1,15 @@ +{ + "name": "app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@google-cloud/storage": "^5.18.3", + "express": "^4.17.3" + } +} diff --git a/examples/cloud-operations/binauthz/main.tf b/examples/cloud-operations/binauthz/main.tf new file mode 100644 index 000000000..af34cb926 --- /dev/null +++ b/examples/cloud-operations/binauthz/main.tf @@ -0,0 +1,274 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +locals { + prefix = (var.prefix == null || var.prefix == "") ? "" : "${var.prefix}-" + k8s_ns = "apis" + k8s_sa = "storage-api-sa" + image = ( + "${var.region}-docker.pkg.dev/${module.project.project_id}/${module.docker_artifact_registry.name}/storage-api" + ) +} + +module "project" { + source = "../../../modules/project" + billing_account = (var.project_create != null + ? var.project_create.billing_account_id + : null + ) + parent = (var.project_create != null + ? var.project_create.parent + : null + ) + prefix = var.project_create == null ? null : var.prefix + name = var.project_id + services = [ + "artifactregistry.googleapis.com", + "binaryauthorization.googleapis.com", + "cloudbuild.googleapis.com", + "cloudkms.googleapis.com", + "cloudresourcemanager.googleapis.com", + "container.googleapis.com", + "containeranalysis.googleapis.com", + "sourcerepo.googleapis.com" + ] + iam = { + "roles/storage.admin" = [module.sa.iam_email] + "roles/logging.logWriter" = [ + module.image_cb_sa.iam_email, + module.app_cb_sa.iam_email + ] + "roles/container.viewer" = [module.app_cb_sa.iam_email] + "roles/containeranalysis.occurrences.editor" = [module.image_cb_sa.iam_email] + "roles/containeranalysis.notes.attacher" = [module.image_cb_sa.iam_email] + } +} + +module "vpc" { + source = "../../../modules/net-vpc" + project_id = module.project.project_id + name = "${local.prefix}vpc" + subnets = [ + { + ip_cidr_range = var.subnet_cidr_block + name = "subnet" + region = var.region + secondary_ip_range = { + pods = var.pods_cidr_block + services = var.services_cidr_block + } + } + ] +} + +module "nat" { + source = "../../../modules/net-cloudnat" + project_id = module.project.project_id + region = var.region + name = "${local.prefix}nat" + router_network = module.vpc.name +} + +module "cluster" { + source = "../../../modules/gke-cluster" + project_id = module.project.project_id + name = "${local.prefix}cluster" + location = var.zone + network = module.vpc.self_link + subnetwork = module.vpc.subnet_self_links["${var.region}/subnet"] + secondary_range_pods = "pods" + secondary_range_services = "services" + private_cluster_config = { + enable_private_nodes = true + enable_private_endpoint = false + master_ipv4_cidr_block = var.master_cidr_block + master_global_access = false + } + enable_binary_authorization = true + workload_identity = true +} + +module "cluster_nodepool" { + source = "../../../modules/gke-nodepool" + project_id = module.project.project_id + cluster_name = module.cluster.name + location = var.zone + name = "nodepool" + node_service_account_create = true + initial_node_count = 3 +} + +module "kms" { + source = "../../../modules/kms" + project_id = module.project.project_id + keyring = { location = var.region, name = "test-keyring" } + keyring_create = true + keys = { test-key = null } + key_purpose = { + test-key = { + purpose = "ASYMMETRIC_SIGN" + version_template = { + algorithm = "RSA_SIGN_PKCS1_4096_SHA512" + protection_level = null + } + } + } + key_iam = { + test-key = { + "roles/cloudkms.publicKeyViewer" = [module.image_cb_sa.iam_email] + "roles/cloudkms.signer" = [module.image_cb_sa.iam_email] + } + } +} + +data "google_kms_crypto_key_version" "version" { + crypto_key = module.kms.key_ids["test-key"] +} + +module "binauthz" { + source = "../../../modules/binauthz" + project_id = module.project.project_id + default_admission_rule = { + evaluation_mode = "ALWAYS_DENY" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + attestors = null + } + cluster_admission_rules = { + "${var.zone}.${module.cluster.name}" = { + evaluation_mode = "REQUIRE_ATTESTATION" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + attestors = ["test-attestor"] + } + } + attestors_config = { + "test-attestor" : { + note_reference = null + pgp_public_keys = null + pkix_public_keys = [{ + id = data.google_kms_crypto_key_version.version.id + public_key_pem = data.google_kms_crypto_key_version.version.public_key[0].pem + signature_algorithm = data.google_kms_crypto_key_version.version.public_key[0].algorithm + }] + iam = { + "roles/binaryauthorization.attestorsViewer" = [module.image_cb_sa.iam_email] + } + } + } +} + +module "docker_artifact_registry" { + source = "../../../modules/artifact-registry" + project_id = module.project.project_id + location = var.region + format = "DOCKER" + id = "${local.prefix}registry" + iam = { + "roles/artifactregistry.writer" = [module.image_cb_sa.iam_email] + "roles/artifactregistry.reader" = [module.cluster_nodepool.service_account_iam_email] + } +} + +module "image_cb_sa" { + source = "../../../modules/iam-service-account" + project_id = module.project.project_id + name = "sa-cb-image" +} + +module "image_repo" { + source = "../../../modules/source-repository" + project_id = module.project.project_id + name = "${local.prefix}image" + triggers = { + image-trigger = { + filename = "cloudbuild.yaml" + included_files = null + service_account = module.image_cb_sa.id + template = { + branch_name = "main" + project_id = module.project.project_id + tag_name = null + } + substitutions = { + _IMAGE = local.image + _ATTESTOR = module.binauthz.attestors["test-attestor"].id + _KEY_VERSION = data.google_kms_crypto_key_version.version.name + } + } + } + iam = { + "roles/source.reader" = [module.image_cb_sa.iam_email] + } +} + +module "app_cb_sa" { + source = "../../../modules/iam-service-account" + project_id = module.project.project_id + name = "sa-cb-app" +} + +module "app_repo" { + source = "../../../modules/source-repository" + project_id = module.project.project_id + name = "${local.prefix}app" + triggers = { + app-trigger = { + filename = "cloudbuild.yaml" + included_files = null + service_account = module.app_cb_sa.id + template = { + branch_name = "main" + project_id = module.project.project_id + tag_name = null + } + substitutions = { + _ZONE = var.zone + _CLUSTER = module.cluster.name + } + } + } + iam = { + "roles/source.reader" = [module.app_cb_sa.iam_email] + } +} + +module "sa" { + source = "../../../modules/iam-service-account" + project_id = module.project.project_id + name = "sa-storage-api" + iam = { + "roles/iam.workloadIdentityUser" : ["serviceAccount:${module.cluster.cluster.project}.svc.id.goog[${local.k8s_ns}/${local.k8s_sa}]"] + } +} + +resource "local_file" "app_file" { + content = templatefile("${path.module}/templates/app.yaml.tpl", { + k8s_ns = local.k8s_ns + k8s_sa = local.k8s_sa + google_sa = module.sa.email + image = local.image + }) + filename = "${path.module}/app/app.yaml" + file_permission = "0666" +} + +resource "local_file" "rbac_file" { + content = templatefile("${path.module}/templates/tenant-setup.yaml.tpl", { + k8s_ns = local.k8s_ns + google_sa = module.app_cb_sa.email + }) + filename = "${path.module}/tenant-setup.yaml" + file_permission = "0666" +} diff --git a/examples/cloud-operations/binauthz/outputs.tf b/examples/cloud-operations/binauthz/outputs.tf new file mode 100644 index 000000000..dc0829d58 --- /dev/null +++ b/examples/cloud-operations/binauthz/outputs.tf @@ -0,0 +1,25 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +output "image_repo_url" { + description = "Image source repository url." + value = "ssh://@source.developers.google.com:2022/p/${module.project.project_id}/r/${module.image_repo.name}" +} + +output "app_repo_url" { + description = "App source repository url." + value = "ssh://@source.developers.google.com:2022/p/${module.project.project_id}/r/${module.app_repo.name}" +} diff --git a/examples/cloud-operations/binauthz/templates/app.yaml.tpl b/examples/cloud-operations/binauthz/templates/app.yaml.tpl new file mode 100644 index 000000000..43991c8d3 --- /dev/null +++ b/examples/cloud-operations/binauthz/templates/app.yaml.tpl @@ -0,0 +1,45 @@ +# Copyright 2022 Google LLC +# +# 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 +# +# https://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. + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: storage-api-sa + namespace: ${k8s_ns} + annotations: + iam.gke.io/gcp-service-account: ${google_sa} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: storage-api-deployment + namespace: ${k8s_ns} +spec: + selector: + matchLabels: + app: storage-api + replicas: 2 + template: + metadata: + labels: + app: storage-api + spec: + serviceAccountName: ${k8s_sa} + containers: + - name: storage-api + image: ${image}:DIGEST + ports: + - containerPort: 3000 + nodeSelector: + iam.gke.io/gke-metadata-server-enabled: "true" \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/templates/tenant-setup.yaml.tpl b/examples/cloud-operations/binauthz/templates/tenant-setup.yaml.tpl new file mode 100644 index 000000000..f5609dc23 --- /dev/null +++ b/examples/cloud-operations/binauthz/templates/tenant-setup.yaml.tpl @@ -0,0 +1,54 @@ +# Copyright 2022 Google LLC +# +# 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 +# +# https://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. + +apiVersion: v1 +kind: Namespace +metadata: + name: ${k8s_ns} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: app-deployment-manager + namespace: ${k8s_ns} +rules: +- apiGroups: + - '' + - 'extensions' + - 'apps' + resources: + - 'namespaces' + - 'serviceaccounts' + - 'deployments' + verbs: + - 'get' + - 'list' + - 'watch' + - 'create' + - 'update' + - 'patch' + - 'delete' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: app-deployment-manager + namespace: ${k8s_ns} +subjects: +- kind: User + name: ${google_sa} +roleRef: + kind: Role + name: app-deployment-manager + apiGroup: rbac.authorization.k8s.io diff --git a/examples/cloud-operations/binauthz/variables.tf b/examples/cloud-operations/binauthz/variables.tf new file mode 100644 index 000000000..c010a12ac --- /dev/null +++ b/examples/cloud-operations/binauthz/variables.tf @@ -0,0 +1,71 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +variable "project_create" { + description = "Parameters for the creation of the new project." + type = object({ + billing_account_id = string + parent = string + }) + default = null +} + +variable "project_id" { + description = "Project ID." + type = string +} + +variable "prefix" { + description = "Prefix for resources created." + type = string + default = null +} + +variable "pods_cidr_block" { + description = "Pods CIDR block." + type = string + default = "172.16.0.0/20" +} + +variable "services_cidr_block" { + description = "Services CIDR block." + type = string + default = "192.168.0.0/24" +} + +variable "master_cidr_block" { + description = "Master CIDR block." + type = string + default = "10.0.0.0/28" +} + +variable "subnet_cidr_block" { + description = "Subnet CIDR block." + type = string + default = "10.0.1.0/24" +} + +variable "region" { + description = "Region." + type = string + default = "europe-west1" +} + +variable "zone" { + description = "Zone." + type = string + default = "europe-west1-c" +} diff --git a/modules/binauthz/README.md b/modules/binauthz/README.md new file mode 100644 index 000000000..b773ceb6d --- /dev/null +++ b/modules/binauthz/README.md @@ -0,0 +1,79 @@ +# Google Cloud Artifact Registry Module + +This module simplifies the creation of a Binary Authorization policy, attestors and attestor IAM bindings. + +## Example + +### Binary Athorization + +```hcl +module "binauthz" { + source = "./modules/binauthz" + project_id = "my_project" + global_policy_evaluation_mode = "DISABLE" + default_admission_rule = { + evaluation_mode = "ALWAYS_DENY" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + attestors = null + } + cluster_admission_rules = { + "europe-west1-c.cluster" = { + evaluation_mode = "REQUIRE_ATTESTATION" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + attestors = [ "test" ] + } + } + attestors_config = { + "test": { + note_reference = null + pgp_public_keys = [ + < + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [project_id](variables.tf#L17) | Project ID. | string | ✓ | | +| [admission_whitelist_patterns](variables.tf#L28) | An image name pattern to allowlist | list(string) | | null | +| [attestors_config](variables.tf#L58) | Attestors configuration | map(object({…})) | | null | +| [cluster_admission_rules](variables.tf#L48) | Admission rules | map(object({…})) | | null | +| [default_admission_rule](variables.tf#L34) | Default admission rule | object({…}) | | {…} | +| [global_policy_evaluation_mode](variables.tf#L22) | Global policy evaluation mode. | string | | null | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| [attestors](outputs.tf#L22) | Attestors. | | +| [id](outputs.tf#L17) | Binary Authorization policy ID | | +| [notes](outputs.tf#L30) | Notes. | | + + diff --git a/modules/binauthz/main.tf b/modules/binauthz/main.tf new file mode 100644 index 000000000..2c1af463a --- /dev/null +++ b/modules/binauthz/main.tf @@ -0,0 +1,91 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +resource "google_binary_authorization_policy" "policy" { + project = var.project_id + dynamic "admission_whitelist_patterns" { + for_each = toset(coalesce(var.admission_whitelist_patterns, [])) + content { + name_pattern = admission_whitelist_patterns.value + } + } + default_admission_rule { + evaluation_mode = var.default_admission_rule.evaluation_mode + enforcement_mode = var.default_admission_rule.enforcement_mode + require_attestations_by = [for attestor in coalesce(var.default_admission_rule.attestors, []) : google_binary_authorization_attestor.attestors[attestor].name] + } + dynamic "cluster_admission_rules" { + for_each = coalesce(var.cluster_admission_rules, {}) + content { + cluster = cluster_admission_rules.key + evaluation_mode = cluster_admission_rules.value.evaluation_mode + enforcement_mode = cluster_admission_rules.value.enforcement_mode + require_attestations_by = [for attestor in cluster_admission_rules.value.attestors : google_binary_authorization_attestor.attestors[attestor].name] + } + } +} + +resource "google_binary_authorization_attestor" "attestors" { + for_each = coalesce(var.attestors_config, {}) + name = each.key + project = var.project_id + attestation_authority_note { + note_reference = each.value.note_reference == null ? google_container_analysis_note.notes[each.key].name : each.value.note_reference + dynamic "public_keys" { + for_each = coalesce(each.value.pgp_public_keys, []) + content { + ascii_armored_pgp_public_key = public_keys.value + } + } + dynamic "public_keys" { + for_each = { + for pkix_public_key in coalesce(each.value.pkix_public_keys, []) : + "${pkix_public_key.public_key_pem}-${pkix_public_key.signature_algorithm}" => pkix_public_key + } + content { + id = public_keys.value.id + pkix_public_key { + public_key_pem = public_keys.value.public_key_pem + signature_algorithm = public_keys.value.signature_algorithm + } + } + } + } +} + +resource "google_binary_authorization_attestor_iam_binding" "bindings" { + for_each = merge(flatten([ + for name, attestor_config in var.attestors_config : { for role, members in coalesce(attestor_config.iam, {}) : "${name}-${role}" => { + name = name + role = role + members = members + } }])...) + project = google_binary_authorization_attestor.attestors[each.value.name].project + attestor = google_binary_authorization_attestor.attestors[each.value.name].name + role = each.value.role + members = each.value.members +} + +resource "google_container_analysis_note" "notes" { + for_each = toset([for name, attestor_config in var.attestors_config : name if attestor_config.note_reference == null]) + name = "${each.value}-note" + project = var.project_id + attestation_authority { + hint { + human_readable_name = "Attestor ${each.value} note" + } + } +} diff --git a/modules/binauthz/outputs.tf b/modules/binauthz/outputs.tf new file mode 100644 index 000000000..19fac8368 --- /dev/null +++ b/modules/binauthz/outputs.tf @@ -0,0 +1,33 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +output "id" { + description = "Binary Authorization policy ID" + value = google_binary_authorization_policy.policy.id +} + +output "attestors" { + description = "Attestors." + value = google_binary_authorization_attestor.attestors + depends_on = [ + google_binary_authorization_attestor_iam_binding.bindings + ] +} + +output "notes" { + description = "Notes." + value = google_container_analysis_note.notes +} diff --git a/modules/binauthz/variables.tf b/modules/binauthz/variables.tf new file mode 100644 index 000000000..f9502a69b --- /dev/null +++ b/modules/binauthz/variables.tf @@ -0,0 +1,71 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +variable "project_id" { + description = "Project ID." + type = string +} + +variable "global_policy_evaluation_mode" { + description = "Global policy evaluation mode." + type = string + default = null +} + +variable "admission_whitelist_patterns" { + description = "An image name pattern to allowlist" + type = list(string) + default = null +} + +variable "default_admission_rule" { + description = "Default admission rule" + type = object({ + evaluation_mode = string + enforcement_mode = string + attestors = list(string) + }) + default = { + evaluation_mode = "ALWAYS_ALLOW" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + attestors = null + } +} + +variable "cluster_admission_rules" { + description = "Admission rules" + type = map(object({ + evaluation_mode = string + enforcement_mode = string + attestors = list(string) + })) + default = null +} + +variable "attestors_config" { + description = "Attestors configuration" + type = map(object({ + note_reference = string + iam = map(list(string)) + pgp_public_keys = list(string) + pkix_public_keys = list(object({ + id = string + public_key_pem = string + signature_algorithm = string + })) + })) + default = null +} diff --git a/modules/binauthz/versions.tf b/modules/binauthz/versions.tf new file mode 100644 index 000000000..b2efbeadf --- /dev/null +++ b/modules/binauthz/versions.tf @@ -0,0 +1,29 @@ +# Copyright 2022 Google LLC +# +# 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 +# +# https://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. + +terraform { + required_version = ">= 1.1.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 4.17.0" + } + google-beta = { + source = "hashicorp/google-beta" + version = ">= 4.17.0" + } + } +} + + diff --git a/tests/examples/cloud_operations/binauthz/__init__.py b/tests/examples/cloud_operations/binauthz/__init__.py new file mode 100644 index 000000000..6d6d1266c --- /dev/null +++ b/tests/examples/cloud_operations/binauthz/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022 Google LLC +# +# 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. diff --git a/tests/examples/cloud_operations/binauthz/fixture/main.tf b/tests/examples/cloud_operations/binauthz/fixture/main.tf new file mode 100644 index 000000000..5871ca851 --- /dev/null +++ b/tests/examples/cloud_operations/binauthz/fixture/main.tf @@ -0,0 +1,21 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +module "test" { + source = "../../../../../examples/cloud-operations/binauthz" + project_create = var.project_create + project_id = var.project_id +} diff --git a/tests/examples/cloud_operations/binauthz/fixture/variables.tf b/tests/examples/cloud_operations/binauthz/fixture/variables.tf new file mode 100644 index 000000000..439d6b0b4 --- /dev/null +++ b/tests/examples/cloud_operations/binauthz/fixture/variables.tf @@ -0,0 +1,26 @@ +# Copyright 2022 Google LLC +# +# 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 +# +# https://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. + +variable "project_create" { + type = object({ + billing_account_id = string + parent = string + }) + default = null +} + +variable "project_id" { + type = string + default = "my-project" +} diff --git a/tests/examples/cloud_operations/binauthz/test_plan.py b/tests/examples/cloud_operations/binauthz/test_plan.py new file mode 100644 index 000000000..6e176b1c0 --- /dev/null +++ b/tests/examples/cloud_operations/binauthz/test_plan.py @@ -0,0 +1,19 @@ +# Copyright 2022 Google LLC +# +# 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. + +def test_resources(e2e_plan_runner): + "Test that plan works and the numbers of resources is as expected." + modules, resources = e2e_plan_runner() + assert len(modules) == 13 + assert len(resources) == 42 diff --git a/tests/modules/binauthz/__init__.py b/tests/modules/binauthz/__init__.py new file mode 100644 index 000000000..6d6d1266c --- /dev/null +++ b/tests/modules/binauthz/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022 Google LLC +# +# 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. diff --git a/tests/modules/binauthz/fixture/main.tf b/tests/modules/binauthz/fixture/main.tf new file mode 100644 index 000000000..95f76d634 --- /dev/null +++ b/tests/modules/binauthz/fixture/main.tf @@ -0,0 +1,23 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +module "test" { + source = "../../../../modules/binauthz" + project_id = var.project_id + global_policy_evaluation_mode = var.global_policy_evaluation_mode + default_admission_rule = var.default_admission_rule + attestors_config = var.attestors_config +} diff --git a/tests/modules/binauthz/fixture/variables.tf b/tests/modules/binauthz/fixture/variables.tf new file mode 100644 index 000000000..327ced252 --- /dev/null +++ b/tests/modules/binauthz/fixture/variables.tf @@ -0,0 +1,103 @@ +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +variable "project_id" { + type = string + default = "my_project" +} + +variable "global_policy_evaluation_mode" { + type = string + default = null +} + +variable "admission_whitelist_patterns" { + type = list(string) + default = [ + "gcr.io/google_containers/*" + ] +} + +variable "default_admission_rule" { + type = object({ + evaluation_mode = string + enforcement_mode = string + attestors = list(string) + }) + default = { + evaluation_mode = "ALWAYS_ALLOW" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + attestors = null + } +} + +variable "cluster_admission_rules" { + type = map(object({ + evaluation_mode = string + enforcement_mode = string + attestors = list(string) + })) + default = { + "europe-west1-c.cluster" = { + evaluation_mode = "REQUIRE_ATTESTATION" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + attestors = ["test"] + } + } +} + +variable "attestors_config" { + description = "Attestors configuration" + type = map(object({ + note_reference = string + iam = map(list(string)) + pgp_public_keys = list(string) + pkix_public_keys = list(object({ + id = string + public_key_pem = string + signature_algorithm = string + })) + })) + default = { + "test" : { + note_reference = null + pgp_public_keys = [ + < Date: Thu, 16 Jun 2022 16:34:46 +0200 Subject: [PATCH 21/36] add support for secrets (#684) --- modules/cloud-function/README.md | 11 ++++++----- modules/cloud-function/main.tf | 29 +++++++++++++++++++++++++++++ modules/cloud-function/variables.tf | 12 ++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/modules/cloud-function/README.md b/modules/cloud-function/README.md index 6eac68bf1..73a1d3f2a 100644 --- a/modules/cloud-function/README.md +++ b/modules/cloud-function/README.md @@ -173,11 +173,12 @@ module "cf-http" { | [labels](variables.tf#L82) | Resource labels. | map(string) | | {} | | [prefix](variables.tf#L93) | Optional prefix used for resource names. | string | | null | | [region](variables.tf#L104) | Region used for all resources. | string | | "europe-west1" | -| [service_account](variables.tf#L110) | Service account email. Unused if service account is auto-created. | string | | null | -| [service_account_create](variables.tf#L116) | Auto-create service account. | bool | | false | -| [trigger_config](variables.tf#L122) | Function trigger configuration. Leave null for HTTP trigger. | object({…}) | | null | -| [vpc_connector](variables.tf#L132) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | object({…}) | | null | -| [vpc_connector_config](variables.tf#L142) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null | +| [secrets](variables.tf#L110) | Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format. | map(object({…})) | | {} | +| [service_account](variables.tf#L122) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L128) | Auto-create service account. | bool | | false | +| [trigger_config](variables.tf#L134) | Function trigger configuration. Leave null for HTTP trigger. | object({…}) | | null | +| [vpc_connector](variables.tf#L144) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | object({…}) | | null | +| [vpc_connector_config](variables.tf#L154) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null | ## Outputs diff --git a/modules/cloud-function/main.tf b/modules/cloud-function/main.tf index 949cb69b1..0a26c1205 100644 --- a/modules/cloud-function/main.tf +++ b/modules/cloud-function/main.tf @@ -91,6 +91,35 @@ resource "google_cloudfunctions_function" "function" { } } + dynamic "secret_environment_variables" { + for_each = { for k, v in var.secrets : k => v if !v.is_volume } + iterator = secret + content { + key = secret.key + project_id = secret.value.project_id + secret = secret.value.secret + version = try(secret.value.versions.0, "latest") + } + } + + dynamic "secret_volumes" { + for_each = { for k, v in var.secrets : k => v if v.is_volume } + iterator = secret + content { + mount_path = secret.key + project_id = secret.value.project_id + secret = secret.value.secret + dynamic "versions" { + for_each = secret.value.versions + iterator = version + content { + path = split(":", version)[1] + version = split(":", version)[0] + } + } + } + } + } resource "google_cloudfunctions_function_iam_binding" "default" { diff --git a/modules/cloud-function/variables.tf b/modules/cloud-function/variables.tf index a613b2f68..ce8633c8f 100644 --- a/modules/cloud-function/variables.tf +++ b/modules/cloud-function/variables.tf @@ -107,6 +107,18 @@ variable "region" { default = "europe-west1" } +variable "secrets" { + description = "Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format." + type = map(object({ + is_volume = bool + project_id = number + secret = string + versions = list(string) + })) + nullable = false + default = {} +} + variable "service_account" { description = "Service account email. Unused if service account is auto-created." type = string From 58e553c2df730dc3d18e93963ff4b114638bc8dc Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 19:06:35 +0200 Subject: [PATCH 22/36] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b8bdd3ab..c2bfa1509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. - add support for IAM and Cloud Build triggers to source repository module - add `id` output to service account module +- add support for secrets to cloud function module **FAST** From f163bad220972d58d36de4864a36c4f459276f2f Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 21:56:18 +0200 Subject: [PATCH 23/36] add automation project number to stage 0 outputs --- fast/stages/00-bootstrap/automation.tf | 7 ++++++- fast/stages/00-bootstrap/outputs.tf | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fast/stages/00-bootstrap/automation.tf b/fast/stages/00-bootstrap/automation.tf index 11a8b34d8..bba34d06f 100644 --- a/fast/stages/00-bootstrap/automation.tf +++ b/fast/stages/00-bootstrap/automation.tf @@ -36,7 +36,9 @@ module "automation-project" { # machine (service accounts) IAM bindings iam = { "roles/owner" = [ - module.automation-tf-bootstrap-sa.iam_email, + module.automation-tf-bootstrap-sa.iam_email + ] + "roles/cloudbuild.builds.editor" = [ module.automation-tf-resman-sa.iam_email ] "roles/iam.serviceAccountAdmin" = [ @@ -45,6 +47,9 @@ module "automation-project" { "roles/iam.workloadIdentityPoolAdmin" = [ module.automation-tf-resman-sa.iam_email ] + "roles/source.admin" = [ + module.automation-tf-resman-sa.iam_email + ] "roles/storage.admin" = [ module.automation-tf-resman-sa.iam_email ] diff --git a/fast/stages/00-bootstrap/outputs.tf b/fast/stages/00-bootstrap/outputs.tf index cfb2460b8..910458651 100644 --- a/fast/stages/00-bootstrap/outputs.tf +++ b/fast/stages/00-bootstrap/outputs.tf @@ -57,6 +57,7 @@ locals { federated_identity_providers = local.wif_providers outputs_bucket = module.automation-tf-output-gcs.name project_id = module.automation-project.project_id + project_number = module.automation-project.number } custom_roles = local.custom_roles } From c87c645bf088e37521ea54b956a316a4bc3e980f Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 21:56:48 +0200 Subject: [PATCH 24/36] add missing try to stage 1 outputs --- fast/stages/01-resman/outputs.tf | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fast/stages/01-resman/outputs.tf b/fast/stages/01-resman/outputs.tf index b7de52409..73ed2eedd 100644 --- a/fast/stages/01-resman/outputs.tf +++ b/fast/stages/01-resman/outputs.tf @@ -52,9 +52,11 @@ locals { for k, v in local.cicd_repositories : k => templatefile( "${path.module}/templates/workflow-${v.type}.yaml", merge(local.cicd_workflow_attrs[k], { - identity_provider = local.identity_providers[v.identity_provider].name - outputs_bucket = var.automation.outputs_bucket - stage_name = k + identity_provider = try( + local.identity_providers[v.identity_provider].name, null + ) + outputs_bucket = var.automation.outputs_bucket + stage_name = k }) ) } From 2b61efb722187ba548dd79aff08a9f41ad20212d Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 21:57:09 +0200 Subject: [PATCH 25/36] add project number to sgae 1 values --- fast/stages/01-resman/variables.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/fast/stages/01-resman/variables.tf b/fast/stages/01-resman/variables.tf index c31e67790..c1d534bca 100644 --- a/fast/stages/01-resman/variables.tf +++ b/fast/stages/01-resman/variables.tf @@ -23,6 +23,7 @@ variable "automation" { type = object({ outputs_bucket = string project_id = string + project_number = string federated_identity_pool = string federated_identity_providers = map(object({ issuer = string From da17d5786346eace988e6ed8a95c7cad6b848b33 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 21:59:44 +0200 Subject: [PATCH 26/36] fix tfdoc --- fast/stages/00-bootstrap/README.md | 20 +++++++-------- fast/stages/01-resman/README.md | 40 +++++++++++++++--------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/fast/stages/00-bootstrap/README.md b/fast/stages/00-bootstrap/README.md index c217a50f7..3fcfb66c1 100644 --- a/fast/stages/00-bootstrap/README.md +++ b/fast/stages/00-bootstrap/README.md @@ -457,15 +457,15 @@ The remaining configuration is manual, as it regards the repositories themselves | name | description | sensitive | consumers | |---|---|:---:|---| -| [automation](outputs.tf#L81) | Automation resources. | | | -| [billing_dataset](outputs.tf#L86) | BigQuery dataset prepared for billing export. | | | -| [cicd_repositories](outputs.tf#L91) | CI/CD repository configurations. | | | -| [custom_roles](outputs.tf#L103) | Organization-level custom roles. | | | -| [federated_identity](outputs.tf#L108) | Workload Identity Federation pool and providers. | | | -| [outputs_bucket](outputs.tf#L118) | GCS bucket where generated output files are stored. | | | -| [project_ids](outputs.tf#L123) | Projects created by this stage. | | | -| [providers](outputs.tf#L142) | Terraform provider files for this stage and dependent stages. | ✓ | stage-01 | -| [service_accounts](outputs.tf#L132) | Automation service accounts created by this stage. | | | -| [tfvars](outputs.tf#L151) | Terraform variable files for the following stages. | ✓ | | +| [automation](outputs.tf#L82) | Automation resources. | | | +| [billing_dataset](outputs.tf#L87) | BigQuery dataset prepared for billing export. | | | +| [cicd_repositories](outputs.tf#L92) | CI/CD repository configurations. | | | +| [custom_roles](outputs.tf#L104) | Organization-level custom roles. | | | +| [federated_identity](outputs.tf#L109) | Workload Identity Federation pool and providers. | | | +| [outputs_bucket](outputs.tf#L119) | GCS bucket where generated output files are stored. | | | +| [project_ids](outputs.tf#L124) | Projects created by this stage. | | | +| [providers](outputs.tf#L143) | Terraform provider files for this stage and dependent stages. | ✓ | stage-01 | +| [service_accounts](outputs.tf#L133) | Automation service accounts created by this stage. | | | +| [tfvars](outputs.tf#L152) | Terraform variable files for the following stages. | ✓ | | diff --git a/fast/stages/01-resman/README.md b/fast/stages/01-resman/README.md index 8ec133ce0..a054106f6 100644 --- a/fast/stages/01-resman/README.md +++ b/fast/stages/01-resman/README.md @@ -178,30 +178,30 @@ Due to its simplicity, this stage lends itself easily to customizations: adding | name | description | type | required | default | producer | |---|---|:---:|:---:|:---:|:---:| -| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 00-bootstrap | -| [billing_account](variables.tf#L37) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | 00-bootstrap | -| [organization](variables.tf#L140) | Organization details. | object({…}) | ✓ | | 00-bootstrap | -| [prefix](variables.tf#L164) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | -| [cicd_repositories](variables.tf#L46) | CI/CD repository configuration. Identity providers reference keys in the `automation.federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | | -| [custom_roles](variables.tf#L116) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 00-bootstrap | -| [groups](variables.tf#L125) | Group names to grant organization-level permissions. | map(string) | | {…} | 00-bootstrap | -| [organization_policy_configs](variables.tf#L150) | Organization policies customization. | object({…}) | | null | | -| [outputs_location](variables.tf#L158) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable | string | | null | | -| [tag_names](variables.tf#L175) | Customized names for resource management tags. | object({…}) | | {…} | | -| [team_folders](variables.tf#L192) | Team folders to be created. Format is described in a code comment. | map(object({…})) | | null | | +| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 00-bootstrap | +| [billing_account](variables.tf#L38) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | 00-bootstrap | +| [organization](variables.tf#L141) | Organization details. | object({…}) | ✓ | | 00-bootstrap | +| [prefix](variables.tf#L165) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | +| [cicd_repositories](variables.tf#L47) | CI/CD repository configuration. Identity providers reference keys in the `automation.federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | | +| [custom_roles](variables.tf#L117) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 00-bootstrap | +| [groups](variables.tf#L126) | Group names to grant organization-level permissions. | map(string) | | {…} | 00-bootstrap | +| [organization_policy_configs](variables.tf#L151) | Organization policies customization. | object({…}) | | null | | +| [outputs_location](variables.tf#L159) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable | string | | null | | +| [tag_names](variables.tf#L176) | Customized names for resource management tags. | object({…}) | | {…} | | +| [team_folders](variables.tf#L193) | Team folders to be created. Format is described in a code comment. | map(object({…})) | | null | | ## Outputs | name | description | sensitive | consumers | |---|---|:---:|---| -| [cicd_repositories](outputs.tf#L143) | WIF configuration for CI/CD repositories. | | | -| [dataplatform](outputs.tf#L155) | Data for the Data Platform stage. | | | -| [networking](outputs.tf#L171) | Data for the networking stage. | | | -| [project_factories](outputs.tf#L180) | Data for the project factories stage. | | | -| [providers](outputs.tf#L196) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform · xx-sandbox · xx-teams | -| [sandbox](outputs.tf#L203) | Data for the sandbox stage. | | xx-sandbox | -| [security](outputs.tf#L213) | Data for the networking stage. | | 02-security | -| [teams](outputs.tf#L223) | Data for the teams stage. | | | -| [tfvars](outputs.tf#L236) | Terraform variable files for the following stages. | ✓ | | +| [cicd_repositories](outputs.tf#L145) | WIF configuration for CI/CD repositories. | | | +| [dataplatform](outputs.tf#L159) | Data for the Data Platform stage. | | | +| [networking](outputs.tf#L175) | Data for the networking stage. | | | +| [project_factories](outputs.tf#L184) | Data for the project factories stage. | | | +| [providers](outputs.tf#L200) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform · xx-sandbox · xx-teams | +| [sandbox](outputs.tf#L207) | Data for the sandbox stage. | | xx-sandbox | +| [security](outputs.tf#L217) | Data for the networking stage. | | 02-security | +| [teams](outputs.tf#L227) | Data for the teams stage. | | | +| [tfvars](outputs.tf#L240) | Terraform variable files for the following stages. | ✓ | | From 528219bbf34ad6a2f2caf280e7edb9dad4c8fd46 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 22:03:08 +0200 Subject: [PATCH 27/36] fix stage1 tests --- tests/fast/stages/s01_resman/fixture/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/fast/stages/s01_resman/fixture/main.tf b/tests/fast/stages/s01_resman/fixture/main.tf index ddb9aafef..57d35b163 100644 --- a/tests/fast/stages/s01_resman/fixture/main.tf +++ b/tests/fast/stages/s01_resman/fixture/main.tf @@ -20,6 +20,7 @@ module "stage" { federated_identity_pool = null federated_identity_providers = null project_id = "fast-prod-automation" + project_number = 123456 outputs_bucket = "test" } billing_account = { From 6d8f3f7e22f071b9a8e6ef77db3deb4339df6b5b Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 22:16:20 +0200 Subject: [PATCH 28/36] depend service account outputs on iam roles --- modules/iam-service-account/README.md | 12 ++++++------ modules/iam-service-account/outputs.tf | 13 +++++++++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/modules/iam-service-account/README.md b/modules/iam-service-account/README.md index ab6b1882c..fe07ddbff 100644 --- a/modules/iam-service-account/README.md +++ b/modules/iam-service-account/README.md @@ -62,11 +62,11 @@ module "myproject-default-service-accounts" { | name | description | sensitive | |---|---|:---:| | [email](outputs.tf#L17) | Service account email. | | -| [iam_email](outputs.tf#L25) | IAM-format service account email. | | -| [id](outputs.tf#L33) | Service account id. | | -| [key](outputs.tf#L38) | Service account key. | ✓ | -| [name](outputs.tf#L44) | Service account name. | | -| [service_account](outputs.tf#L49) | Service account resource. | | -| [service_account_credentials](outputs.tf#L54) | Service account json credential templates for uploaded public keys data. | | +| [iam_email](outputs.tf#L27) | IAM-format service account email. | | +| [id](outputs.tf#L37) | Service account id. | | +| [key](outputs.tf#L47) | Service account key. | ✓ | +| [name](outputs.tf#L53) | Service account name. | | +| [service_account](outputs.tf#L58) | Service account resource. | | +| [service_account_credentials](outputs.tf#L63) | Service account json credential templates for uploaded public keys data. | | diff --git a/modules/iam-service-account/outputs.tf b/modules/iam-service-account/outputs.tf index 4f0e0aa52..2823910bd 100644 --- a/modules/iam-service-account/outputs.tf +++ b/modules/iam-service-account/outputs.tf @@ -18,7 +18,9 @@ output "email" { description = "Service account email." value = local.resource_email_static depends_on = [ - local.service_account + local.service_account, + google_service_account_iam_binding.roles, + google_service_account_iam_member.additive ] } @@ -26,13 +28,20 @@ output "iam_email" { description = "IAM-format service account email." value = local.resource_iam_email_static depends_on = [ - local.service_account + local.service_account, + google_service_account_iam_binding.roles, + google_service_account_iam_member.additive ] } output "id" { description = "Service account id." value = local.service_account.id + depends_on = [ + local.service_account, + google_service_account_iam_binding.roles, + google_service_account_iam_member.additive + ] } output "key" { From a35ed1ca0f2665f1e88c1b967b0287445a4d1ef7 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 22:16:43 +0200 Subject: [PATCH 29/36] allow using cicd service accounts in build triggers --- fast/stages/01-resman/cicd-data-platform.tf | 8 ++++++-- fast/stages/01-resman/cicd-networking.tf | 4 +++- fast/stages/01-resman/cicd-security.tf | 4 +++- fast/stages/01-resman/cicd-teams.tf | 8 ++++++-- fast/stages/01-resman/main.tf | 6 ++++++ 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/fast/stages/01-resman/cicd-data-platform.tf b/fast/stages/01-resman/cicd-data-platform.tf index 66247d269..c5c08d7f3 100644 --- a/fast/stages/01-resman/cicd-data-platform.tf +++ b/fast/stages/01-resman/cicd-data-platform.tf @@ -96,7 +96,9 @@ module "branch-dp-dev-sa-cicd" { iam = ( each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos - ? {} + ? { + "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + } # impersonated via workload identity federation for external repos : { "roles/iam.workloadIdentityUser" = [ @@ -135,7 +137,9 @@ module "branch-dp-prod-sa-cicd" { iam = ( each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos - ? {} + ? { + "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + } # impersonated via workload identity federation for external repos : { "roles/iam.workloadIdentityUser" = [ diff --git a/fast/stages/01-resman/cicd-networking.tf b/fast/stages/01-resman/cicd-networking.tf index 9bb96f796..2853db885 100644 --- a/fast/stages/01-resman/cicd-networking.tf +++ b/fast/stages/01-resman/cicd-networking.tf @@ -63,7 +63,9 @@ module "branch-network-sa-cicd" { iam = ( each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos - ? {} + ? { + "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + } # impersonated via workload identity federation for external repos : { "roles/iam.workloadIdentityUser" = [ diff --git a/fast/stages/01-resman/cicd-security.tf b/fast/stages/01-resman/cicd-security.tf index ff456166a..601b7cc56 100644 --- a/fast/stages/01-resman/cicd-security.tf +++ b/fast/stages/01-resman/cicd-security.tf @@ -63,7 +63,9 @@ module "branch-security-sa-cicd" { iam = ( each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos - ? {} + ? { + "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + } # impersonated via workload identity federation for external repos : { "roles/iam.workloadIdentityUser" = [ diff --git a/fast/stages/01-resman/cicd-teams.tf b/fast/stages/01-resman/cicd-teams.tf index 931b0a7ca..67b333f67 100644 --- a/fast/stages/01-resman/cicd-teams.tf +++ b/fast/stages/01-resman/cicd-teams.tf @@ -96,7 +96,9 @@ module "branch-teams-dev-pf-sa-cicd" { iam = ( each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos - ? {} + ? { + "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + } # impersonated via workload identity federation for external repos : { "roles/iam.workloadIdentityUser" = [ @@ -135,7 +137,9 @@ module "branch-teams-prod-pf-sa-cicd" { iam = ( each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos - ? {} + ? { + "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + } # impersonated via workload identity federation for external repos : { "roles/iam.workloadIdentityUser" = [ diff --git a/fast/stages/01-resman/main.tf b/fast/stages/01-resman/main.tf index 6cefbd25d..5520c03aa 100644 --- a/fast/stages/01-resman/main.tf +++ b/fast/stages/01-resman/main.tf @@ -16,6 +16,10 @@ locals { # convenience flags that express where billing account resides + automation_resman_sa = format( + "serviceAccount:%s", + data.google_client_openid_userinfo.provider_identity.email + ) billing_ext = var.billing_account.organization_id == null billing_org = var.billing_account.organization_id == var.organization.id billing_org_ext = !local.billing_ext && !local.billing_org @@ -64,3 +68,5 @@ locals { try(var.automation.federated_identity_providers, null), {} ) } + +data "google_client_openid_userinfo" "provider_identity" {} From ee23694fed4cc3373578ee9fb1bf874da209adb7 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 23:09:35 +0200 Subject: [PATCH 30/36] revert service account modules changes to outputs --- modules/iam-service-account/README.md | 14 ++++++++------ modules/iam-service-account/outputs.tf | 12 +++--------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/modules/iam-service-account/README.md b/modules/iam-service-account/README.md index fe07ddbff..ad39c389e 100644 --- a/modules/iam-service-account/README.md +++ b/modules/iam-service-account/README.md @@ -2,6 +2,8 @@ This module allows simplified creation and management of one a service account and its IAM bindings. A key can optionally be generated and will be stored in Terraform state. To use it create a sensitive output in your root modules referencing the `key` output, then extract the private key from the JSON formatted outputs. Alternatively, the `key` can be generated with `openssl` library and only public part uploaded to the Service Account, for more refer to the [Onprem SA Key Management](../../examples/cloud-operations/onprem-sa-key-management/) example. +Note that this module does not fully comply with our design principles, as outputs have no dependencies on IAM bindings to prevent resource cycles. + ## Example ```hcl @@ -62,11 +64,11 @@ module "myproject-default-service-accounts" { | name | description | sensitive | |---|---|:---:| | [email](outputs.tf#L17) | Service account email. | | -| [iam_email](outputs.tf#L27) | IAM-format service account email. | | -| [id](outputs.tf#L37) | Service account id. | | -| [key](outputs.tf#L47) | Service account key. | ✓ | -| [name](outputs.tf#L53) | Service account name. | | -| [service_account](outputs.tf#L58) | Service account resource. | | -| [service_account_credentials](outputs.tf#L63) | Service account json credential templates for uploaded public keys data. | | +| [iam_email](outputs.tf#L25) | IAM-format service account email. | | +| [id](outputs.tf#L33) | Service account id. | | +| [key](outputs.tf#L41) | Service account key. | ✓ | +| [name](outputs.tf#L47) | Service account name. | | +| [service_account](outputs.tf#L52) | Service account resource. | | +| [service_account_credentials](outputs.tf#L57) | Service account json credential templates for uploaded public keys data. | | diff --git a/modules/iam-service-account/outputs.tf b/modules/iam-service-account/outputs.tf index 2823910bd..42196534c 100644 --- a/modules/iam-service-account/outputs.tf +++ b/modules/iam-service-account/outputs.tf @@ -18,9 +18,7 @@ output "email" { description = "Service account email." value = local.resource_email_static depends_on = [ - local.service_account, - google_service_account_iam_binding.roles, - google_service_account_iam_member.additive + local.service_account ] } @@ -28,9 +26,7 @@ output "iam_email" { description = "IAM-format service account email." value = local.resource_iam_email_static depends_on = [ - local.service_account, - google_service_account_iam_binding.roles, - google_service_account_iam_member.additive + local.service_account ] } @@ -38,9 +34,7 @@ output "id" { description = "Service account id." value = local.service_account.id depends_on = [ - local.service_account, - google_service_account_iam_binding.roles, - google_service_account_iam_member.additive + local.service_account ] } From a09eb39a962f075ab8330fabd10aa7da3afa584b Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 16 Jun 2022 23:11:08 +0200 Subject: [PATCH 31/36] disable provider data source when not needed, explicitly depend on CI/CD SAs --- fast/stages/01-resman/cicd-data-platform.tf | 6 ++++-- fast/stages/01-resman/cicd-networking.tf | 3 ++- fast/stages/01-resman/cicd-security.tf | 3 ++- fast/stages/01-resman/cicd-teams.tf | 6 ++++-- fast/stages/01-resman/main.tf | 13 +++++++++---- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/fast/stages/01-resman/cicd-data-platform.tf b/fast/stages/01-resman/cicd-data-platform.tf index c5c08d7f3..4a5c6d3f5 100644 --- a/fast/stages/01-resman/cicd-data-platform.tf +++ b/fast/stages/01-resman/cicd-data-platform.tf @@ -47,6 +47,7 @@ module "branch-dp-dev-cicd-repo" { } } } + depends_on = [module.branch-dp-dev-sa-cicd] } module "branch-dp-prod-cicd-repo" { @@ -78,6 +79,7 @@ module "branch-dp-prod-cicd-repo" { } } } + depends_on = [module.branch-dp-prod-sa-cicd] } # SAs used by CI/CD workflows to impersonate automation SAs @@ -97,7 +99,7 @@ module "branch-dp-dev-sa-cicd" { each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos ? { - "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + "roles/iam.serviceAccountUser" = local.automation_resman_sa } # impersonated via workload identity federation for external repos : { @@ -138,7 +140,7 @@ module "branch-dp-prod-sa-cicd" { each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos ? { - "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + "roles/iam.serviceAccountUser" = local.automation_resman_sa } # impersonated via workload identity federation for external repos : { diff --git a/fast/stages/01-resman/cicd-networking.tf b/fast/stages/01-resman/cicd-networking.tf index 2853db885..951770475 100644 --- a/fast/stages/01-resman/cicd-networking.tf +++ b/fast/stages/01-resman/cicd-networking.tf @@ -45,6 +45,7 @@ module "branch-network-cicd-repo" { } } } + depends_on = [module.branch-network-sa-cicd] } # SA used by CI/CD workflows to impersonate automation SAs @@ -64,7 +65,7 @@ module "branch-network-sa-cicd" { each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos ? { - "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + "roles/iam.serviceAccountUser" = local.automation_resman_sa } # impersonated via workload identity federation for external repos : { diff --git a/fast/stages/01-resman/cicd-security.tf b/fast/stages/01-resman/cicd-security.tf index 601b7cc56..86fd84fdb 100644 --- a/fast/stages/01-resman/cicd-security.tf +++ b/fast/stages/01-resman/cicd-security.tf @@ -45,6 +45,7 @@ module "branch-security-cicd-repo" { } } } + depends_on = [module.branch-security-sa-cicd] } # SA used by CI/CD workflows to impersonate automation SAs @@ -64,7 +65,7 @@ module "branch-security-sa-cicd" { each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos ? { - "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + "roles/iam.serviceAccountUser" = local.automation_resman_sa } # impersonated via workload identity federation for external repos : { diff --git a/fast/stages/01-resman/cicd-teams.tf b/fast/stages/01-resman/cicd-teams.tf index 67b333f67..f5e81fd3f 100644 --- a/fast/stages/01-resman/cicd-teams.tf +++ b/fast/stages/01-resman/cicd-teams.tf @@ -47,6 +47,7 @@ module "branch-teams-dev-pf-cicd-repo" { } } } + depends_on = [module.branch-teams-dev-pf-sa-cicd] } module "branch-teams-prod-pf-cicd-repo" { @@ -78,6 +79,7 @@ module "branch-teams-prod-pf-cicd-repo" { } } } + depends_on = [module.branch-teams-prod-pf-sa-cicd] } # SAs used by CI/CD workflows to impersonate automation SAs @@ -97,7 +99,7 @@ module "branch-teams-dev-pf-sa-cicd" { each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos ? { - "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + "roles/iam.serviceAccountUser" = local.automation_resman_sa } # impersonated via workload identity federation for external repos : { @@ -138,7 +140,7 @@ module "branch-teams-prod-pf-sa-cicd" { each.value.type == "sourcerepo" # used directly from the cloud build trigger for source repos ? { - "roles/iam.serviceAccountUser" = [local.automation_resman_sa] + "roles/iam.serviceAccountUser" = local.automation_resman_sa } # impersonated via workload identity federation for external repos : { diff --git a/fast/stages/01-resman/main.tf b/fast/stages/01-resman/main.tf index 5520c03aa..c40957964 100644 --- a/fast/stages/01-resman/main.tf +++ b/fast/stages/01-resman/main.tf @@ -16,9 +16,12 @@ locals { # convenience flags that express where billing account resides - automation_resman_sa = format( - "serviceAccount:%s", - data.google_client_openid_userinfo.provider_identity.email + automation_resman_sa = try( + [format( + "serviceAccount:%s", + data.google_client_openid_userinfo.provider_identity.0.email + )], + [] ) billing_ext = var.billing_account.organization_id == null billing_org = var.billing_account.organization_id == var.organization.id @@ -69,4 +72,6 @@ locals { ) } -data "google_client_openid_userinfo" "provider_identity" {} +data "google_client_openid_userinfo" "provider_identity" { + count = length(local.cicd_repositories) > 0 ? 1 : 0 +} From 6c80aedc681f849958d765d5bcf0cb3683c6526e Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Fri, 17 Jun 2022 07:36:12 +0200 Subject: [PATCH 32/36] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2bfa1509..decff9ae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ All notable changes to this project will be documented in this file. - add support for Cloud Source Repositories in stage 0 and 1 CI/CD - fix Gitlab workflow indentation - remove unsupported attributes and add supported ones to the Gitlab mapping used for Workload Identity Federation pools +- add roles for CI/CD source repositories to stage 1 service account on automation project +- fixes to CI/CD source repositories in stage 1 ## [16.0.0] - 2022-06-06 From 1db795ab89ba13f290f5f98aebec99371d96dcdb Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Fri, 17 Jun 2022 11:38:19 +0200 Subject: [PATCH 33/36] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index decff9ae9..4ae3a0091 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. - add support for IAM and Cloud Build triggers to source repository module - add `id` output to service account module - add support for secrets to cloud function module +- new binary authorization module **FAST** From 943d6d431ed7a5f822f7d9120463a54530c5a10b Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Fri, 17 Jun 2022 12:32:42 +0200 Subject: [PATCH 34/36] Revert "Binary authorization module and example" (#686) --- .gitignore | 4 +- examples/cloud-operations/binauthz/README.md | 127 - examples/cloud-operations/binauthz/app | 1 - .../cloud-operations/binauthz/diagram.png | Bin 52258 -> 0 bytes .../binauthz/image/.dockerignore | 1 - .../binauthz/image/.gitignore | 1 - .../binauthz/image/Dockerfile | 25 - .../cloud-operations/binauthz/image/README.md | 27 - .../binauthz/image/cloudbuild.yaml | 40 - .../cloud-operations/binauthz/image/index.js | 81 - .../binauthz/image/package-lock.json | 2277 ----------------- .../binauthz/image/package.json | 15 - examples/cloud-operations/binauthz/main.tf | 274 -- examples/cloud-operations/binauthz/outputs.tf | 25 - .../binauthz/templates/app.yaml.tpl | 45 - .../binauthz/templates/tenant-setup.yaml.tpl | 54 - .../cloud-operations/binauthz/variables.tf | 71 - modules/binauthz/README.md | 79 - modules/binauthz/main.tf | 91 - modules/binauthz/outputs.tf | 33 - modules/binauthz/variables.tf | 71 - modules/binauthz/versions.tf | 29 - .../cloud_operations/binauthz/__init__.py | 13 - .../cloud_operations/binauthz/fixture/main.tf | 21 - .../binauthz/fixture/variables.tf | 26 - .../cloud_operations/binauthz/test_plan.py | 19 - tests/modules/binauthz/__init__.py | 13 - tests/modules/binauthz/fixture/main.tf | 23 - tests/modules/binauthz/fixture/variables.tf | 103 - tests/modules/binauthz/test_plan.py | 24 - 30 files changed, 1 insertion(+), 3612 deletions(-) delete mode 100644 examples/cloud-operations/binauthz/README.md delete mode 160000 examples/cloud-operations/binauthz/app delete mode 100644 examples/cloud-operations/binauthz/diagram.png delete mode 100644 examples/cloud-operations/binauthz/image/.dockerignore delete mode 100644 examples/cloud-operations/binauthz/image/.gitignore delete mode 100644 examples/cloud-operations/binauthz/image/Dockerfile delete mode 100644 examples/cloud-operations/binauthz/image/README.md delete mode 100644 examples/cloud-operations/binauthz/image/cloudbuild.yaml delete mode 100644 examples/cloud-operations/binauthz/image/index.js delete mode 100644 examples/cloud-operations/binauthz/image/package-lock.json delete mode 100644 examples/cloud-operations/binauthz/image/package.json delete mode 100644 examples/cloud-operations/binauthz/main.tf delete mode 100644 examples/cloud-operations/binauthz/outputs.tf delete mode 100644 examples/cloud-operations/binauthz/templates/app.yaml.tpl delete mode 100644 examples/cloud-operations/binauthz/templates/tenant-setup.yaml.tpl delete mode 100644 examples/cloud-operations/binauthz/variables.tf delete mode 100644 modules/binauthz/README.md delete mode 100644 modules/binauthz/main.tf delete mode 100644 modules/binauthz/outputs.tf delete mode 100644 modules/binauthz/variables.tf delete mode 100644 modules/binauthz/versions.tf delete mode 100644 tests/examples/cloud_operations/binauthz/__init__.py delete mode 100644 tests/examples/cloud_operations/binauthz/fixture/main.tf delete mode 100644 tests/examples/cloud_operations/binauthz/fixture/variables.tf delete mode 100644 tests/examples/cloud_operations/binauthz/test_plan.py delete mode 100644 tests/modules/binauthz/__init__.py delete mode 100644 tests/modules/binauthz/fixture/main.tf delete mode 100644 tests/modules/binauthz/fixture/variables.tf delete mode 100644 tests/modules/binauthz/test_plan.py diff --git a/.gitignore b/.gitignore index 2067242c9..4fb446019 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,4 @@ fast/stages/**/terraform-*.auto.tfvars.json fast/stages/**/0*.auto.tfvars* **/node_modules fast/stages/**/globals.auto.tfvars.json -cloud_sql_proxy -examples/cloud-operations/binauthz/tenant-setup.yaml -examples/cloud-operations/binauthz/app/app.yaml \ No newline at end of file +cloud_sql_proxy \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/README.md b/examples/cloud-operations/binauthz/README.md deleted file mode 100644 index 18d7ab51b..000000000 --- a/examples/cloud-operations/binauthz/README.md +++ /dev/null @@ -1,127 +0,0 @@ -# Binary Authorization - -The following example shows to how to create a CI and a CD pipeline in Cloud Build for the deployment of an application to a private GKE cluster with unrestricted access to a public endpoint. The example enables a Binary Authorization policy in the project so only images that have been attested can be deployed to the cluster. The attestations are created using a cryptographic key pair that has been provisioned in KMS. - -The diagram below depicts the architecture used in the example. - -![Architecture](diagram.png) - -The CI and CD pipelines are implemented as Cloud Build triggers that run with a user-specified service account. - -The CI pipeline does the following: - -* Builds and pushes the image to Artifact registry -* Creates an attestation for the image. - -The CD pipeline deploys the application to the cluster. - -## Running the example - -Clone this repository or [open it in cloud shell](https://ssh.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fterraform-google-modules%2Fcloud-foundation-fabric&cloudshell_print=cloud-shell-readme.txt&cloudshell_working_dir=examples%2Fcloud-operations%2Fbinauthz), then go through the following steps to create resources: - -* `terraform init` -* `terraform apply -var project_id=my-project-id` - -WARNING: The example requires the activation of the Binary Authorization API. That API does not support authentication with user credentials. A service account will need to be used to run the example - -## Testing the example - -Once the resources have been created, do the following to verify that everything works as expected. - -1. Fetch the cluster credentials - - gcloud container clusters get-credentials cluster --project - -2. Apply the manifest tenant-setup.yaml available in your work directory. - - kubectl apply -f tenant-setup.yaml - - By applying that manifest thw following is created: - - * A namespace called "apis". This is the namespace where the application will be deployed. - * A Role and a RoleBinding in previously created namespace so the service account that has been configured for the CD pipeline trigger in Cloud Build is able to deploy the kubernetes application to that namespace. - -3. Change to the image subdirectory in your work directory - - cd /image - -4. Run the following commands: - - git init - git remote add origin ssh://:2022/p//r/image - git push -u origin main - -4. In the Cloud Build > History section in the Google Cloud console you should see a job running. That job is build the image, pushing to Artifact Registry and creating an attestation. - - Once the job finishes copy the digest of the image that is displayed in the Cloud Build job output. - -5. Change to the app subdirectory in your working directory. - - cd /app - -6. Edit the app.yaml file and replace the string DIGEST with the value you copied before. - -7. Run the following commands: - - git init - git remote add origin ssh://:2022/p//r/app - git push -u origin main - -8. In the Cloud Build > History section in the Google Cloud console you should see a job running. The job will deploy the application to the cluster. - -9. Go to the Kubernetes Engine > Workloads section to check that the deployment was successful and that the Binary Authorization admissions controller webhook did not block the deployment. - -10. Change to the working directory and try to deploy an image that has not been attested. - - cat < Workloads section to check that that the Binary Authorization admissions controller webhook did not block the deployment. - -The application deployed to the cluster is an RESTful API that enables managing Google Cloud storage buckets in the project. Workload identity is used so the app can interact with the Google Cloud Storage API. - -Once done testing, you can clean up resources by running `terraform destroy`. - - -## Variables - -| name | description | type | required | default | -|---|---|:---:|:---:|:---:| -| [project_id](variables.tf#L26) | Project ID. | string | ✓ | | -| [master_cidr_block](variables.tf#L49) | Master CIDR block. | string | | "10.0.0.0/28" | -| [pods_cidr_block](variables.tf#L37) | Pods CIDR block. | string | | "172.16.0.0/20" | -| [prefix](variables.tf#L31) | Prefix for resources created. | string | | null | -| [project_create](variables.tf#L17) | Parameters for the creation of the new project. | object({…}) | | null | -| [region](variables.tf#L61) | Region. | string | | "europe-west1" | -| [services_cidr_block](variables.tf#L43) | Services CIDR block. | string | | "192.168.0.0/24" | -| [subnet_cidr_block](variables.tf#L55) | Subnet CIDR block. | string | | "10.0.1.0/24" | -| [zone](variables.tf#L67) | Zone. | string | | "europe-west1-c" | - -## Outputs - -| name | description | sensitive | -|---|---|:---:| -| [app_repo_url](outputs.tf#L22) | App source repository url. | | -| [image_repo_url](outputs.tf#L17) | Image source repository url. | | - - diff --git a/examples/cloud-operations/binauthz/app b/examples/cloud-operations/binauthz/app deleted file mode 160000 index 0f46c645d..000000000 --- a/examples/cloud-operations/binauthz/app +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0f46c645da4a1e409433c927807204a4fb6005a8 diff --git a/examples/cloud-operations/binauthz/diagram.png b/examples/cloud-operations/binauthz/diagram.png deleted file mode 100644 index 0ee786f0326abdf06ac3ef8d3c9ec130b2b5221b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52258 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 $ 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 diff --git a/examples/cloud-operations/binauthz/image/.dockerignore b/examples/cloud-operations/binauthz/image/.dockerignore deleted file mode 100644 index b512c09d4..000000000 --- a/examples/cloud-operations/binauthz/image/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -node_modules \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/image/.gitignore b/examples/cloud-operations/binauthz/image/.gitignore deleted file mode 100644 index a8603104a..000000000 --- a/examples/cloud-operations/binauthz/image/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/** diff --git a/examples/cloud-operations/binauthz/image/Dockerfile b/examples/cloud-operations/binauthz/image/Dockerfile deleted file mode 100644 index 03c3e436c..000000000 --- a/examples/cloud-operations/binauthz/image/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2019 Google LLC -# -# 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. - -FROM node:18-alpine - -WORKDIR /app - -COPY ["package.json", "package-lock.json*", "./"] - -RUN npm install - -COPY . . - -CMD [ "node", "index.js" ] \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/image/README.md b/examples/cloud-operations/binauthz/image/README.md deleted file mode 100644 index 88481cc82..000000000 --- a/examples/cloud-operations/binauthz/image/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Storage API - -This application it is a RESTful API that let's you manage the Google Cloud Storage buckets available is a project. In order to do so the application needs to authenticate with a service account that has been granted the Storage Admin (`roles/storage.admin`) role. - -Find below the operations that can be performed using it: - -* Get buckets in project - - curl -v http://localhost:3000/buckets - -* Get files in bucket - - curl -v http://localhost:3000/buckets/BUCKET_NAME - -* Create a bucket - - curl -v http://localhost:3000/buckets \ - -H'Content-Type: application/json' \ - -d @- < { - try { - const [buckets] = await storage.getBuckets(); - res.json(buckets.map(bucket => bucket.name)); - } catch (error) { - res.status(500).json({ - message: `An error occurred trying to fetch the buckets in project: ${error}` - }); - } -}); - -app.get('/buckets/:name', async (req, res) => { - const name = req.params.name; - try { - const [files] = await storage.bucket(name).getFiles(); - res.json(files.map(file => file.name)); - } catch (error) { - res.status(500).json({ - message: `An error occurred fetch the files in ${name} bucket: ${error}` - }); - } -}); - -app.post('/buckets', async (req, res) => { - const name = req.body.name; - try { - const [bucket] = await storage.createBucket(name); - res.status(201).json({ - "name": bucket.name - }); - } catch (error) { - res.status(500).json({ - message: `An error occurred trying to create ${name} bucket: ${error}` - }); - } -}); - -app.delete('/buckets/:name', async (req, res) => { - const name = req.params.name; - try { - await storage.bucket(name).delete(); - res.send() - } catch (error) { - res.status(500).json({ - message: `An error occurred trying to delete ${name} bucket: ${error}` - }); - } -}); - -app.listen(PORT, () => { - console.log(`App listening on port ${PORT}`) -}) \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/image/package-lock.json b/examples/cloud-operations/binauthz/image/package-lock.json deleted file mode 100644 index c7eed8518..000000000 --- a/examples/cloud-operations/binauthz/image/package-lock.json +++ /dev/null @@ -1,2277 +0,0 @@ -{ - "name": "app", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "app", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@google-cloud/storage": "^5.18.3", - "express": "^4.17.3" - } - }, - "node_modules/@google-cloud/common": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.10.0.tgz", - "integrity": "sha512-XMbJYMh/ZSaZnbnrrOFfR/oQrb0SxG4qh6hDisWCoEbFcBHV0qHQo4uXfeMCzolx2Mfkh6VDaOGg+hyJsmxrlw==", - "dependencies": { - "@google-cloud/projectify": "^2.0.0", - "@google-cloud/promisify": "^2.0.0", - "arrify": "^2.0.1", - "duplexify": "^4.1.1", - "ent": "^2.2.0", - "extend": "^3.0.2", - "google-auth-library": "^7.14.0", - "retry-request": "^4.2.2", - "teeny-request": "^7.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@google-cloud/paginator": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", - "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", - "dependencies": { - "arrify": "^2.0.0", - "extend": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@google-cloud/projectify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.1.1.tgz", - "integrity": "sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@google-cloud/promisify": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.4.tgz", - "integrity": "sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@google-cloud/storage": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.18.3.tgz", - "integrity": "sha512-573qJ0ECoy3nkY5YaMWcVf4/46n/zdvfNgAyjaLQywl/eL38uxDhs7YVJd3pcgslaMUwKKsd/eD3St+Pq2iPew==", - "dependencies": { - "@google-cloud/common": "^3.8.1", - "@google-cloud/paginator": "^3.0.7", - "@google-cloud/promisify": "^2.0.0", - "abort-controller": "^3.0.0", - "arrify": "^2.0.0", - "async-retry": "^1.3.3", - "compressible": "^2.0.12", - "configstore": "^5.0.0", - "date-and-time": "^2.0.0", - "duplexify": "^4.0.0", - "extend": "^3.0.2", - "gaxios": "^4.0.0", - "get-stream": "^6.0.0", - "google-auth-library": "^7.0.0", - "hash-stream-validation": "^0.2.2", - "mime": "^3.0.0", - "mime-types": "^2.0.8", - "p-limit": "^3.0.1", - "pumpify": "^2.0.0", - "snakeize": "^0.1.0", - "stream-events": "^1.0.4", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "engines": { - "node": ">=8" - } - }, - "node_modules/async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "dependencies": { - "retry": "0.13.1" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", - "engines": { - "node": "*" - } - }, - "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/date-and-time": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.3.0.tgz", - "integrity": "sha512-DY53oj742mykXjZzDxT7NxH5cxwBRb7FsVG5+8pcV96qU9JQd0UhA21pQB18fwwsXOXeSM0RJV4OzgVxu8eatg==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.19.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.2", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.7", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/fast-text-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/gaxios": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", - "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", - "dependencies": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/gcp-metadata": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", - "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", - "dependencies": { - "gaxios": "^4.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-auth-library": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.1.tgz", - "integrity": "sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA==", - "dependencies": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^4.0.0", - "gcp-metadata": "^4.2.0", - "gtoken": "^5.0.4", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/google-p12-pem": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.3.tgz", - "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==", - "dependencies": { - "node-forge": "^1.0.0" - }, - "bin": { - "gp12-pem": "build/src/bin/gp12-pem.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "node_modules/gtoken": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", - "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", - "dependencies": { - "gaxios": "^4.0.0", - "google-p12-pem": "^3.1.3", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hash-stream-validation": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", - "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" - }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "node_modules/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, - "node_modules/jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "dependencies": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", - "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", - "dependencies": { - "duplexify": "^4.1.1", - "inherits": "^2.0.3", - "pump": "^3.0.0" - } - }, - "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/retry-request": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.2.2.tgz", - "integrity": "sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg==", - "dependencies": { - "debug": "^4.1.1", - "extend": "^3.0.2" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/send/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/snakeize": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", - "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=" - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stream-events": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", - "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", - "dependencies": { - "stubs": "^3.0.0" - } - }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/stubs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" - }, - "node_modules/teeny-request": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.2.0.tgz", - "integrity": "sha512-SyY0pek1zWsi0LRVAALem+avzMLc33MKW/JLLakdP4s9+D7+jHcy5x6P+h94g2QNZsAqQNfX5lsbd3WSeJXrrw==", - "dependencies": { - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", - "stream-events": "^1.0.5", - "uuid": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@google-cloud/common": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.10.0.tgz", - "integrity": "sha512-XMbJYMh/ZSaZnbnrrOFfR/oQrb0SxG4qh6hDisWCoEbFcBHV0qHQo4uXfeMCzolx2Mfkh6VDaOGg+hyJsmxrlw==", - "requires": { - "@google-cloud/projectify": "^2.0.0", - "@google-cloud/promisify": "^2.0.0", - "arrify": "^2.0.1", - "duplexify": "^4.1.1", - "ent": "^2.2.0", - "extend": "^3.0.2", - "google-auth-library": "^7.14.0", - "retry-request": "^4.2.2", - "teeny-request": "^7.0.0" - } - }, - "@google-cloud/paginator": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", - "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", - "requires": { - "arrify": "^2.0.0", - "extend": "^3.0.2" - } - }, - "@google-cloud/projectify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.1.1.tgz", - "integrity": "sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ==" - }, - "@google-cloud/promisify": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.4.tgz", - "integrity": "sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA==" - }, - "@google-cloud/storage": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.18.3.tgz", - "integrity": "sha512-573qJ0ECoy3nkY5YaMWcVf4/46n/zdvfNgAyjaLQywl/eL38uxDhs7YVJd3pcgslaMUwKKsd/eD3St+Pq2iPew==", - "requires": { - "@google-cloud/common": "^3.8.1", - "@google-cloud/paginator": "^3.0.7", - "@google-cloud/promisify": "^2.0.0", - "abort-controller": "^3.0.0", - "arrify": "^2.0.0", - "async-retry": "^1.3.3", - "compressible": "^2.0.12", - "configstore": "^5.0.0", - "date-and-time": "^2.0.0", - "duplexify": "^4.0.0", - "extend": "^3.0.2", - "gaxios": "^4.0.0", - "get-stream": "^6.0.0", - "google-auth-library": "^7.0.0", - "hash-stream-validation": "^0.2.2", - "mime": "^3.0.0", - "mime-types": "^2.0.8", - "p-limit": "^3.0.1", - "pumpify": "^2.0.0", - "snakeize": "^0.1.0", - "stream-events": "^1.0.4", - "xdg-basedir": "^4.0.0" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - }, - "async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "requires": { - "retry": "0.13.1" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" - }, - "body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" - }, - "date-and-time": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.3.0.tgz", - "integrity": "sha512-DY53oj742mykXjZzDxT7NxH5cxwBRb7FsVG5+8pcV96qU9JQd0UhA21pQB18fwwsXOXeSM0RJV4OzgVxu8eatg==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.19.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.2", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.7", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "fast-text-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "gaxios": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", - "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.1" - } - }, - "gcp-metadata": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", - "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", - "requires": { - "gaxios": "^4.0.0", - "json-bigint": "^1.0.0" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - }, - "google-auth-library": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.1.tgz", - "integrity": "sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA==", - "requires": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^4.0.0", - "gcp-metadata": "^4.2.0", - "gtoken": "^5.0.4", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - } - }, - "google-p12-pem": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.3.tgz", - "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==", - "requires": { - "node-forge": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "gtoken": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", - "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", - "requires": { - "gaxios": "^4.0.0", - "google-p12-pem": "^3.1.3", - "jws": "^4.0.0" - } - }, - "hash-stream-validation": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", - "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" - }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - } - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "requires": { - "bignumber.js": "^9.0.0" - } - }, - "jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "requires": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", - "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", - "requires": { - "duplexify": "^4.1.1", - "inherits": "^2.0.3", - "pump": "^3.0.0" - } - }, - "qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", - "requires": { - "bytes": "3.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" - }, - "retry-request": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.2.2.tgz", - "integrity": "sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg==", - "requires": { - "debug": "^4.1.1", - "extend": "^3.0.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "snakeize": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", - "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stream-events": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", - "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", - "requires": { - "stubs": "^3.0.0" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "stubs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" - }, - "teeny-request": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.2.0.tgz", - "integrity": "sha512-SyY0pek1zWsi0LRVAALem+avzMLc33MKW/JLLakdP4s9+D7+jHcy5x6P+h94g2QNZsAqQNfX5lsbd3WSeJXrrw==", - "requires": { - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", - "stream-events": "^1.0.5", - "uuid": "^8.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - } - } -} diff --git a/examples/cloud-operations/binauthz/image/package.json b/examples/cloud-operations/binauthz/image/package.json deleted file mode 100644 index 26cd3ebbc..000000000 --- a/examples/cloud-operations/binauthz/image/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "app", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@google-cloud/storage": "^5.18.3", - "express": "^4.17.3" - } -} diff --git a/examples/cloud-operations/binauthz/main.tf b/examples/cloud-operations/binauthz/main.tf deleted file mode 100644 index af34cb926..000000000 --- a/examples/cloud-operations/binauthz/main.tf +++ /dev/null @@ -1,274 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -locals { - prefix = (var.prefix == null || var.prefix == "") ? "" : "${var.prefix}-" - k8s_ns = "apis" - k8s_sa = "storage-api-sa" - image = ( - "${var.region}-docker.pkg.dev/${module.project.project_id}/${module.docker_artifact_registry.name}/storage-api" - ) -} - -module "project" { - source = "../../../modules/project" - billing_account = (var.project_create != null - ? var.project_create.billing_account_id - : null - ) - parent = (var.project_create != null - ? var.project_create.parent - : null - ) - prefix = var.project_create == null ? null : var.prefix - name = var.project_id - services = [ - "artifactregistry.googleapis.com", - "binaryauthorization.googleapis.com", - "cloudbuild.googleapis.com", - "cloudkms.googleapis.com", - "cloudresourcemanager.googleapis.com", - "container.googleapis.com", - "containeranalysis.googleapis.com", - "sourcerepo.googleapis.com" - ] - iam = { - "roles/storage.admin" = [module.sa.iam_email] - "roles/logging.logWriter" = [ - module.image_cb_sa.iam_email, - module.app_cb_sa.iam_email - ] - "roles/container.viewer" = [module.app_cb_sa.iam_email] - "roles/containeranalysis.occurrences.editor" = [module.image_cb_sa.iam_email] - "roles/containeranalysis.notes.attacher" = [module.image_cb_sa.iam_email] - } -} - -module "vpc" { - source = "../../../modules/net-vpc" - project_id = module.project.project_id - name = "${local.prefix}vpc" - subnets = [ - { - ip_cidr_range = var.subnet_cidr_block - name = "subnet" - region = var.region - secondary_ip_range = { - pods = var.pods_cidr_block - services = var.services_cidr_block - } - } - ] -} - -module "nat" { - source = "../../../modules/net-cloudnat" - project_id = module.project.project_id - region = var.region - name = "${local.prefix}nat" - router_network = module.vpc.name -} - -module "cluster" { - source = "../../../modules/gke-cluster" - project_id = module.project.project_id - name = "${local.prefix}cluster" - location = var.zone - network = module.vpc.self_link - subnetwork = module.vpc.subnet_self_links["${var.region}/subnet"] - secondary_range_pods = "pods" - secondary_range_services = "services" - private_cluster_config = { - enable_private_nodes = true - enable_private_endpoint = false - master_ipv4_cidr_block = var.master_cidr_block - master_global_access = false - } - enable_binary_authorization = true - workload_identity = true -} - -module "cluster_nodepool" { - source = "../../../modules/gke-nodepool" - project_id = module.project.project_id - cluster_name = module.cluster.name - location = var.zone - name = "nodepool" - node_service_account_create = true - initial_node_count = 3 -} - -module "kms" { - source = "../../../modules/kms" - project_id = module.project.project_id - keyring = { location = var.region, name = "test-keyring" } - keyring_create = true - keys = { test-key = null } - key_purpose = { - test-key = { - purpose = "ASYMMETRIC_SIGN" - version_template = { - algorithm = "RSA_SIGN_PKCS1_4096_SHA512" - protection_level = null - } - } - } - key_iam = { - test-key = { - "roles/cloudkms.publicKeyViewer" = [module.image_cb_sa.iam_email] - "roles/cloudkms.signer" = [module.image_cb_sa.iam_email] - } - } -} - -data "google_kms_crypto_key_version" "version" { - crypto_key = module.kms.key_ids["test-key"] -} - -module "binauthz" { - source = "../../../modules/binauthz" - project_id = module.project.project_id - default_admission_rule = { - evaluation_mode = "ALWAYS_DENY" - enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" - attestors = null - } - cluster_admission_rules = { - "${var.zone}.${module.cluster.name}" = { - evaluation_mode = "REQUIRE_ATTESTATION" - enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" - attestors = ["test-attestor"] - } - } - attestors_config = { - "test-attestor" : { - note_reference = null - pgp_public_keys = null - pkix_public_keys = [{ - id = data.google_kms_crypto_key_version.version.id - public_key_pem = data.google_kms_crypto_key_version.version.public_key[0].pem - signature_algorithm = data.google_kms_crypto_key_version.version.public_key[0].algorithm - }] - iam = { - "roles/binaryauthorization.attestorsViewer" = [module.image_cb_sa.iam_email] - } - } - } -} - -module "docker_artifact_registry" { - source = "../../../modules/artifact-registry" - project_id = module.project.project_id - location = var.region - format = "DOCKER" - id = "${local.prefix}registry" - iam = { - "roles/artifactregistry.writer" = [module.image_cb_sa.iam_email] - "roles/artifactregistry.reader" = [module.cluster_nodepool.service_account_iam_email] - } -} - -module "image_cb_sa" { - source = "../../../modules/iam-service-account" - project_id = module.project.project_id - name = "sa-cb-image" -} - -module "image_repo" { - source = "../../../modules/source-repository" - project_id = module.project.project_id - name = "${local.prefix}image" - triggers = { - image-trigger = { - filename = "cloudbuild.yaml" - included_files = null - service_account = module.image_cb_sa.id - template = { - branch_name = "main" - project_id = module.project.project_id - tag_name = null - } - substitutions = { - _IMAGE = local.image - _ATTESTOR = module.binauthz.attestors["test-attestor"].id - _KEY_VERSION = data.google_kms_crypto_key_version.version.name - } - } - } - iam = { - "roles/source.reader" = [module.image_cb_sa.iam_email] - } -} - -module "app_cb_sa" { - source = "../../../modules/iam-service-account" - project_id = module.project.project_id - name = "sa-cb-app" -} - -module "app_repo" { - source = "../../../modules/source-repository" - project_id = module.project.project_id - name = "${local.prefix}app" - triggers = { - app-trigger = { - filename = "cloudbuild.yaml" - included_files = null - service_account = module.app_cb_sa.id - template = { - branch_name = "main" - project_id = module.project.project_id - tag_name = null - } - substitutions = { - _ZONE = var.zone - _CLUSTER = module.cluster.name - } - } - } - iam = { - "roles/source.reader" = [module.app_cb_sa.iam_email] - } -} - -module "sa" { - source = "../../../modules/iam-service-account" - project_id = module.project.project_id - name = "sa-storage-api" - iam = { - "roles/iam.workloadIdentityUser" : ["serviceAccount:${module.cluster.cluster.project}.svc.id.goog[${local.k8s_ns}/${local.k8s_sa}]"] - } -} - -resource "local_file" "app_file" { - content = templatefile("${path.module}/templates/app.yaml.tpl", { - k8s_ns = local.k8s_ns - k8s_sa = local.k8s_sa - google_sa = module.sa.email - image = local.image - }) - filename = "${path.module}/app/app.yaml" - file_permission = "0666" -} - -resource "local_file" "rbac_file" { - content = templatefile("${path.module}/templates/tenant-setup.yaml.tpl", { - k8s_ns = local.k8s_ns - google_sa = module.app_cb_sa.email - }) - filename = "${path.module}/tenant-setup.yaml" - file_permission = "0666" -} diff --git a/examples/cloud-operations/binauthz/outputs.tf b/examples/cloud-operations/binauthz/outputs.tf deleted file mode 100644 index dc0829d58..000000000 --- a/examples/cloud-operations/binauthz/outputs.tf +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -output "image_repo_url" { - description = "Image source repository url." - value = "ssh://@source.developers.google.com:2022/p/${module.project.project_id}/r/${module.image_repo.name}" -} - -output "app_repo_url" { - description = "App source repository url." - value = "ssh://@source.developers.google.com:2022/p/${module.project.project_id}/r/${module.app_repo.name}" -} diff --git a/examples/cloud-operations/binauthz/templates/app.yaml.tpl b/examples/cloud-operations/binauthz/templates/app.yaml.tpl deleted file mode 100644 index 43991c8d3..000000000 --- a/examples/cloud-operations/binauthz/templates/app.yaml.tpl +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. - -apiVersion: v1 -kind: ServiceAccount -metadata: - name: storage-api-sa - namespace: ${k8s_ns} - annotations: - iam.gke.io/gcp-service-account: ${google_sa} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: storage-api-deployment - namespace: ${k8s_ns} -spec: - selector: - matchLabels: - app: storage-api - replicas: 2 - template: - metadata: - labels: - app: storage-api - spec: - serviceAccountName: ${k8s_sa} - containers: - - name: storage-api - image: ${image}:DIGEST - ports: - - containerPort: 3000 - nodeSelector: - iam.gke.io/gke-metadata-server-enabled: "true" \ No newline at end of file diff --git a/examples/cloud-operations/binauthz/templates/tenant-setup.yaml.tpl b/examples/cloud-operations/binauthz/templates/tenant-setup.yaml.tpl deleted file mode 100644 index f5609dc23..000000000 --- a/examples/cloud-operations/binauthz/templates/tenant-setup.yaml.tpl +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. - -apiVersion: v1 -kind: Namespace -metadata: - name: ${k8s_ns} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: app-deployment-manager - namespace: ${k8s_ns} -rules: -- apiGroups: - - '' - - 'extensions' - - 'apps' - resources: - - 'namespaces' - - 'serviceaccounts' - - 'deployments' - verbs: - - 'get' - - 'list' - - 'watch' - - 'create' - - 'update' - - 'patch' - - 'delete' ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: app-deployment-manager - namespace: ${k8s_ns} -subjects: -- kind: User - name: ${google_sa} -roleRef: - kind: Role - name: app-deployment-manager - apiGroup: rbac.authorization.k8s.io diff --git a/examples/cloud-operations/binauthz/variables.tf b/examples/cloud-operations/binauthz/variables.tf deleted file mode 100644 index c010a12ac..000000000 --- a/examples/cloud-operations/binauthz/variables.tf +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -variable "project_create" { - description = "Parameters for the creation of the new project." - type = object({ - billing_account_id = string - parent = string - }) - default = null -} - -variable "project_id" { - description = "Project ID." - type = string -} - -variable "prefix" { - description = "Prefix for resources created." - type = string - default = null -} - -variable "pods_cidr_block" { - description = "Pods CIDR block." - type = string - default = "172.16.0.0/20" -} - -variable "services_cidr_block" { - description = "Services CIDR block." - type = string - default = "192.168.0.0/24" -} - -variable "master_cidr_block" { - description = "Master CIDR block." - type = string - default = "10.0.0.0/28" -} - -variable "subnet_cidr_block" { - description = "Subnet CIDR block." - type = string - default = "10.0.1.0/24" -} - -variable "region" { - description = "Region." - type = string - default = "europe-west1" -} - -variable "zone" { - description = "Zone." - type = string - default = "europe-west1-c" -} diff --git a/modules/binauthz/README.md b/modules/binauthz/README.md deleted file mode 100644 index b773ceb6d..000000000 --- a/modules/binauthz/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# Google Cloud Artifact Registry Module - -This module simplifies the creation of a Binary Authorization policy, attestors and attestor IAM bindings. - -## Example - -### Binary Athorization - -```hcl -module "binauthz" { - source = "./modules/binauthz" - project_id = "my_project" - global_policy_evaluation_mode = "DISABLE" - default_admission_rule = { - evaluation_mode = "ALWAYS_DENY" - enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" - attestors = null - } - cluster_admission_rules = { - "europe-west1-c.cluster" = { - evaluation_mode = "REQUIRE_ATTESTATION" - enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" - attestors = [ "test" ] - } - } - attestors_config = { - "test": { - note_reference = null - pgp_public_keys = [ - < - -## Variables - -| name | description | type | required | default | -|---|---|:---:|:---:|:---:| -| [project_id](variables.tf#L17) | Project ID. | string | ✓ | | -| [admission_whitelist_patterns](variables.tf#L28) | An image name pattern to allowlist | list(string) | | null | -| [attestors_config](variables.tf#L58) | Attestors configuration | map(object({…})) | | null | -| [cluster_admission_rules](variables.tf#L48) | Admission rules | map(object({…})) | | null | -| [default_admission_rule](variables.tf#L34) | Default admission rule | object({…}) | | {…} | -| [global_policy_evaluation_mode](variables.tf#L22) | Global policy evaluation mode. | string | | null | - -## Outputs - -| name | description | sensitive | -|---|---|:---:| -| [attestors](outputs.tf#L22) | Attestors. | | -| [id](outputs.tf#L17) | Binary Authorization policy ID | | -| [notes](outputs.tf#L30) | Notes. | | - - diff --git a/modules/binauthz/main.tf b/modules/binauthz/main.tf deleted file mode 100644 index 2c1af463a..000000000 --- a/modules/binauthz/main.tf +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -resource "google_binary_authorization_policy" "policy" { - project = var.project_id - dynamic "admission_whitelist_patterns" { - for_each = toset(coalesce(var.admission_whitelist_patterns, [])) - content { - name_pattern = admission_whitelist_patterns.value - } - } - default_admission_rule { - evaluation_mode = var.default_admission_rule.evaluation_mode - enforcement_mode = var.default_admission_rule.enforcement_mode - require_attestations_by = [for attestor in coalesce(var.default_admission_rule.attestors, []) : google_binary_authorization_attestor.attestors[attestor].name] - } - dynamic "cluster_admission_rules" { - for_each = coalesce(var.cluster_admission_rules, {}) - content { - cluster = cluster_admission_rules.key - evaluation_mode = cluster_admission_rules.value.evaluation_mode - enforcement_mode = cluster_admission_rules.value.enforcement_mode - require_attestations_by = [for attestor in cluster_admission_rules.value.attestors : google_binary_authorization_attestor.attestors[attestor].name] - } - } -} - -resource "google_binary_authorization_attestor" "attestors" { - for_each = coalesce(var.attestors_config, {}) - name = each.key - project = var.project_id - attestation_authority_note { - note_reference = each.value.note_reference == null ? google_container_analysis_note.notes[each.key].name : each.value.note_reference - dynamic "public_keys" { - for_each = coalesce(each.value.pgp_public_keys, []) - content { - ascii_armored_pgp_public_key = public_keys.value - } - } - dynamic "public_keys" { - for_each = { - for pkix_public_key in coalesce(each.value.pkix_public_keys, []) : - "${pkix_public_key.public_key_pem}-${pkix_public_key.signature_algorithm}" => pkix_public_key - } - content { - id = public_keys.value.id - pkix_public_key { - public_key_pem = public_keys.value.public_key_pem - signature_algorithm = public_keys.value.signature_algorithm - } - } - } - } -} - -resource "google_binary_authorization_attestor_iam_binding" "bindings" { - for_each = merge(flatten([ - for name, attestor_config in var.attestors_config : { for role, members in coalesce(attestor_config.iam, {}) : "${name}-${role}" => { - name = name - role = role - members = members - } }])...) - project = google_binary_authorization_attestor.attestors[each.value.name].project - attestor = google_binary_authorization_attestor.attestors[each.value.name].name - role = each.value.role - members = each.value.members -} - -resource "google_container_analysis_note" "notes" { - for_each = toset([for name, attestor_config in var.attestors_config : name if attestor_config.note_reference == null]) - name = "${each.value}-note" - project = var.project_id - attestation_authority { - hint { - human_readable_name = "Attestor ${each.value} note" - } - } -} diff --git a/modules/binauthz/outputs.tf b/modules/binauthz/outputs.tf deleted file mode 100644 index 19fac8368..000000000 --- a/modules/binauthz/outputs.tf +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -output "id" { - description = "Binary Authorization policy ID" - value = google_binary_authorization_policy.policy.id -} - -output "attestors" { - description = "Attestors." - value = google_binary_authorization_attestor.attestors - depends_on = [ - google_binary_authorization_attestor_iam_binding.bindings - ] -} - -output "notes" { - description = "Notes." - value = google_container_analysis_note.notes -} diff --git a/modules/binauthz/variables.tf b/modules/binauthz/variables.tf deleted file mode 100644 index f9502a69b..000000000 --- a/modules/binauthz/variables.tf +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -variable "project_id" { - description = "Project ID." - type = string -} - -variable "global_policy_evaluation_mode" { - description = "Global policy evaluation mode." - type = string - default = null -} - -variable "admission_whitelist_patterns" { - description = "An image name pattern to allowlist" - type = list(string) - default = null -} - -variable "default_admission_rule" { - description = "Default admission rule" - type = object({ - evaluation_mode = string - enforcement_mode = string - attestors = list(string) - }) - default = { - evaluation_mode = "ALWAYS_ALLOW" - enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" - attestors = null - } -} - -variable "cluster_admission_rules" { - description = "Admission rules" - type = map(object({ - evaluation_mode = string - enforcement_mode = string - attestors = list(string) - })) - default = null -} - -variable "attestors_config" { - description = "Attestors configuration" - type = map(object({ - note_reference = string - iam = map(list(string)) - pgp_public_keys = list(string) - pkix_public_keys = list(object({ - id = string - public_key_pem = string - signature_algorithm = string - })) - })) - default = null -} diff --git a/modules/binauthz/versions.tf b/modules/binauthz/versions.tf deleted file mode 100644 index b2efbeadf..000000000 --- a/modules/binauthz/versions.tf +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. - -terraform { - required_version = ">= 1.1.0" - required_providers { - google = { - source = "hashicorp/google" - version = ">= 4.17.0" - } - google-beta = { - source = "hashicorp/google-beta" - version = ">= 4.17.0" - } - } -} - - diff --git a/tests/examples/cloud_operations/binauthz/__init__.py b/tests/examples/cloud_operations/binauthz/__init__.py deleted file mode 100644 index 6d6d1266c..000000000 --- a/tests/examples/cloud_operations/binauthz/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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. diff --git a/tests/examples/cloud_operations/binauthz/fixture/main.tf b/tests/examples/cloud_operations/binauthz/fixture/main.tf deleted file mode 100644 index 5871ca851..000000000 --- a/tests/examples/cloud_operations/binauthz/fixture/main.tf +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -module "test" { - source = "../../../../../examples/cloud-operations/binauthz" - project_create = var.project_create - project_id = var.project_id -} diff --git a/tests/examples/cloud_operations/binauthz/fixture/variables.tf b/tests/examples/cloud_operations/binauthz/fixture/variables.tf deleted file mode 100644 index 439d6b0b4..000000000 --- a/tests/examples/cloud_operations/binauthz/fixture/variables.tf +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. - -variable "project_create" { - type = object({ - billing_account_id = string - parent = string - }) - default = null -} - -variable "project_id" { - type = string - default = "my-project" -} diff --git a/tests/examples/cloud_operations/binauthz/test_plan.py b/tests/examples/cloud_operations/binauthz/test_plan.py deleted file mode 100644 index 6e176b1c0..000000000 --- a/tests/examples/cloud_operations/binauthz/test_plan.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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. - -def test_resources(e2e_plan_runner): - "Test that plan works and the numbers of resources is as expected." - modules, resources = e2e_plan_runner() - assert len(modules) == 13 - assert len(resources) == 42 diff --git a/tests/modules/binauthz/__init__.py b/tests/modules/binauthz/__init__.py deleted file mode 100644 index 6d6d1266c..000000000 --- a/tests/modules/binauthz/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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. diff --git a/tests/modules/binauthz/fixture/main.tf b/tests/modules/binauthz/fixture/main.tf deleted file mode 100644 index 95f76d634..000000000 --- a/tests/modules/binauthz/fixture/main.tf +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -module "test" { - source = "../../../../modules/binauthz" - project_id = var.project_id - global_policy_evaluation_mode = var.global_policy_evaluation_mode - default_admission_rule = var.default_admission_rule - attestors_config = var.attestors_config -} diff --git a/tests/modules/binauthz/fixture/variables.tf b/tests/modules/binauthz/fixture/variables.tf deleted file mode 100644 index 327ced252..000000000 --- a/tests/modules/binauthz/fixture/variables.tf +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -variable "project_id" { - type = string - default = "my_project" -} - -variable "global_policy_evaluation_mode" { - type = string - default = null -} - -variable "admission_whitelist_patterns" { - type = list(string) - default = [ - "gcr.io/google_containers/*" - ] -} - -variable "default_admission_rule" { - type = object({ - evaluation_mode = string - enforcement_mode = string - attestors = list(string) - }) - default = { - evaluation_mode = "ALWAYS_ALLOW" - enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" - attestors = null - } -} - -variable "cluster_admission_rules" { - type = map(object({ - evaluation_mode = string - enforcement_mode = string - attestors = list(string) - })) - default = { - "europe-west1-c.cluster" = { - evaluation_mode = "REQUIRE_ATTESTATION" - enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" - attestors = ["test"] - } - } -} - -variable "attestors_config" { - description = "Attestors configuration" - type = map(object({ - note_reference = string - iam = map(list(string)) - pgp_public_keys = list(string) - pkix_public_keys = list(object({ - id = string - public_key_pem = string - signature_algorithm = string - })) - })) - default = { - "test" : { - note_reference = null - pgp_public_keys = [ - < Date: Fri, 17 Jun 2022 10:35:15 +0000 Subject: [PATCH 35/36] fixed iam dependency issue --- examples/factories/project-factory/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/factories/project-factory/main.tf b/examples/factories/project-factory/main.tf index 774fc1d64..b9f64361c 100644 --- a/examples/factories/project-factory/main.tf +++ b/examples/factories/project-factory/main.tf @@ -28,7 +28,7 @@ locals { _service_accounts_iam = { for r in local._service_accounts_iam_bindings : r => [ for k, v in var.service_accounts : - "serviceAccount:${k}@${local._project_id}.iam.gserviceaccount.com" + module.service-accounts[k].iam_email if try(index(v, r), null) != null ] } From 4492b0cff7dfdaba1afb302fcc87b0988c1cc179 Mon Sep 17 00:00:00 2001 From: temiloluwa ademuwagun Date: Fri, 17 Jun 2022 10:36:19 +0000 Subject: [PATCH 36/36] corrected the wrong name reference --- fast/stages/03-project-factory/dev/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast/stages/03-project-factory/dev/main.tf b/fast/stages/03-project-factory/dev/main.tf index 802bff9db..120b83590 100644 --- a/fast/stages/03-project-factory/dev/main.tf +++ b/fast/stages/03-project-factory/dev/main.tf @@ -50,7 +50,7 @@ module "projects" { prefix = var.prefix service_accounts = try(each.value.service_accounts, {}) services = try(each.value.services, []) - service_identities_iam = try(each.value.services_iam, {}) + service_identities_iam = try(each.value.service_identities_iam, {}) vpc = try(each.value.vpc, null) }