From 2e9fdea1a48a935b52e4704f0847297b1cd6b0c3 Mon Sep 17 00:00:00 2001 From: Miren Esnaola Date: Fri, 17 Jun 2022 15:58:54 +0200 Subject: [PATCH] Binary authorization module and example --- .gitignore | 4 +- examples/cloud-operations/binauthz/README.md | 127 + .../binauthz/app/clobuild.yaml | 26 + .../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, 3637 insertions(+), 1 deletion(-) create mode 100644 examples/cloud-operations/binauthz/README.md create mode 100644 examples/cloud-operations/binauthz/app/clobuild.yaml 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 4fb44601..f2ac5f40 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 diff --git a/examples/cloud-operations/binauthz/README.md b/examples/cloud-operations/binauthz/README.md new file mode 100644 index 00000000..18d7ab51 --- /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/clobuild.yaml b/examples/cloud-operations/binauthz/app/clobuild.yaml new file mode 100644 index 00000000..6477ecd7 --- /dev/null +++ b/examples/cloud-operations/binauthz/app/clobuild.yaml @@ -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. + +steps: + - id: 'Deploy app' + name: 'gcr.io/cloud-builders/kubectl' + args: + - 'apply' + - '-f' + - 'app.yaml' + env: + - 'CLOUDSDK_COMPUTE_ZONE=${_ZONE}' + - 'CLOUDSDK_CONTAINER_CLUSTER=${_CLUSTER}' +options: + logging: CLOUD_LOGGING_ONLY 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 00000000..b512c09d --- /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 00000000..a8603104 --- /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 00000000..03c3e436 --- /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 00000000..88481cc8 --- /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 00000000..c7eed851 --- /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 00000000..26cd3ebb --- /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 00000000..af34cb92 --- /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 00000000..dc0829d5 --- /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 00000000..43991c8d --- /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 00000000..f5609dc2 --- /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 00000000..c010a12a --- /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 00000000..b773ceb6 --- /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 00000000..2c1af463 --- /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 00000000..19fac836 --- /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 00000000..f9502a69 --- /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 00000000..b2efbead --- /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 00000000..6d6d1266 --- /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 00000000..5871ca85 --- /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 00000000..439d6b0b --- /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 00000000..6e176b1c --- /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 00000000..6d6d1266 --- /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 00000000..95f76d63 --- /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 00000000..327ced25 --- /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 = [ + <