From f9769f7239aef1375949fdad426aa8f4e6786111 Mon Sep 17 00:00:00 2001 From: ekovalets Date: Wed, 5 Nov 2025 10:54:10 -0800 Subject: [PATCH] SERVER-112109: Evergreen Task and scripts to run Server SBOM upload Google Drive at release - 8.0 backport (#43226) GitOrigin-RevId: d8135f9d92d8ef43783376d6737c3bbd72e0f639 --- .../tasks/release_tasks.yml | 78 ++++++++ .../variants/misc/misc.yml | 1 + .../variants/release/release.yml | 1 + .../security_reporting_scripts/BUILD.bazel | 17 ++ .../security_reporting_scripts/OWNERS.yml | 5 + .../augment_sbom.sh | 55 ++++++ .../upload_to_google_drive.py | 119 +++++++++++ .../write_aws_creds_to_silkbomb_env_file.sh | 21 ++ poetry.lock | 185 +++++++++++++++++- pyproject.toml | 2 + 10 files changed, 481 insertions(+), 3 deletions(-) create mode 100644 evergreen/functions/security_reporting_scripts/BUILD.bazel create mode 100644 evergreen/functions/security_reporting_scripts/OWNERS.yml create mode 100644 evergreen/functions/security_reporting_scripts/augment_sbom.sh create mode 100644 evergreen/functions/security_reporting_scripts/upload_to_google_drive.py create mode 100644 evergreen/functions/security_reporting_scripts/write_aws_creds_to_silkbomb_env_file.sh diff --git a/etc/evergreen_yml_components/tasks/release_tasks.yml b/etc/evergreen_yml_components/tasks/release_tasks.yml index 8af9427e924..78ffee3a347 100644 --- a/etc/evergreen_yml_components/tasks/release_tasks.yml +++ b/etc/evergreen_yml_components/tasks/release_tasks.yml @@ -55,3 +55,81 @@ tasks: remote_file: ${project}/${build_variant}/${revision}/artifacts/${build_id}/${task_name}/ permissions: private visibility: signed + + - name: publish-augmented-sbom + tags: ["auxiliary", "assigned_to_jira_team_platsec_server"] + depends_on: + - name: version_expansions_gen + variant: generate-tasks-for-version + exec_timeout_secs: 600 # 10 minute timeout + commands: + - command: manifest.load + - func: "git get project and add git tag" + - func: "get version expansions" + - func: "apply version expansions" + - func: "f_expansions_write" + - func: "kill processes" + - func: "cleanup environment" + - func: "set up venv" + - func: "upload pip requirements" + - command: ec2.assume_role + display_name: Assume Silkbomb IAM role + params: + role_arn: arn:aws:iam::119629040606:role/silkbomb + - func: "f_expansions_write" + - command: subprocess.exec + display_name: Write temporary AWS credentials to Silkbomb environment file + params: + binary: bash + args: + - "src/evergreen/functions/security_reporting_scripts/write_aws_creds_to_silkbomb_env_file.sh" + include_expansions_in_env: + [AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN] + - command: ec2.assume_role + display_name: Assume DevProd Platforms ECR readonly IAM role + params: + role_arn: arn:aws:iam::901841024863:role/ecr-role-evergreen-ro + - func: "f_expansions_write" + - command: subprocess.exec + display_name: Run Silkbomb to augment SBOM with VEX data + params: + binary: bash + args: + - "src/evergreen/functions/security_reporting_scripts/augment_sbom.sh" + include_expansions_in_env: + [AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN] + env: + REQUESTER: ${requester} + BRANCH_NAME: ${branch_name} + GITHUB_ORG: ${github_org} + GITHUB_REPO: ${github_repo} + CONTAINER_COMMAND: docker # podman or docker + CONTAINER_OPTIONS: --pull=always --platform=linux/amd64 -i --rm + CONTAINER_ENV_FILES: ${workdir}/silkbomb.env + CONTAINER_VOLUMES: -v ${workdir}:/workdir + CONTAINER_IMAGE: 901841024863.dkr.ecr.us-east-1.amazonaws.com/release-infrastructure/silkbomb:2.0 + SBOM_REPO_PATH: sbom.json + SBOM_OUT_PATH: ${workdir}/sbom-with-vex-${branch_name}.json + SILKBOMB_COMMAND: augment + SILKBOMB_ARGS: --sbom-in /workdir/src/sbom.json --sbom-out /workdir/src/sbom-with-vex-${branch_name}.json --repo ${github_repo} --branch ${branch_name} + - command: subprocess.exec + display_name: Upload SBOM to Google Drive" + params: + binary: bash + args: + - "${workdir}/src/evergreen/run_python_script.sh" + - "${workdir}/src/evergreen/functions/security_reporting_scripts/upload_to_google_drive.py" + - "${workdir}/src/sbom-with-vex-${branch_name}.json" + env: + WORK_DIR: ${workdir} + GITHUB_COMMIT: ${github_commit} + TRIGGERED_BY_GIT_TAG: ${triggered_by_git_tag} + MONGODB_VERSION: ${version} + MONGODB_RELEASE_BRANCH: ${branch_name} + SBOM_OUT_PATH: ${workdir}/sbom-with-vex-${branch_name}.json + UPLOAD_FILE_NAME: "[${version}] MongoDB Server Enterprise SBOM" + SBOM_REPORT_TEST_GOOGLE_DRIVE_FOLDER_ID: ${SBOM_REPORT_TEST_GOOGLE_DRIVE_FOLDER_ID} + SBOM_REPORT_RELEASES_GOOGLE_DRIVE_FOLDER_ID: ${SBOM_REPORT_RELEASES_GOOGLE_DRIVE_FOLDER_ID} + SAST_REPORT_UPLOAD_GOOGLE_CLIENT_ID: ${SAST_REPORT_UPLOAD_GOOGLE_CLIENT_ID} + SAST_REPORT_UPLOAD_GOOGLE_CLIENT_REFRESH_TOKEN: ${SAST_REPORT_UPLOAD_GOOGLE_CLIENT_REFRESH_TOKEN} + SAST_REPORT_UPLOAD_GOOGLE_CLIENT_SECRET: ${SAST_REPORT_UPLOAD_GOOGLE_CLIENT_SECRET} diff --git a/etc/evergreen_yml_components/variants/misc/misc.yml b/etc/evergreen_yml_components/variants/misc/misc.yml index a9615bba0fe..e69350b0f0e 100644 --- a/etc/evergreen_yml_components/variants/misc/misc.yml +++ b/etc/evergreen_yml_components/variants/misc/misc.yml @@ -48,6 +48,7 @@ buildvariants: - devprod_coverity tasks: - name: publish-sast-report + - name: publish-augmented-sbom - name: ©bara-sync-between-repos copybara-sync-between-repos display_name: "* Copybara Sync Between Repos" diff --git a/etc/evergreen_yml_components/variants/release/release.yml b/etc/evergreen_yml_components/variants/release/release.yml index e20b0b6b599..5e306c06cd0 100644 --- a/etc/evergreen_yml_components/variants/release/release.yml +++ b/etc/evergreen_yml_components/variants/release/release.yml @@ -8,3 +8,4 @@ buildvariants: - devprod_coverity tasks: - name: publish-sast-report + - name: publish-augmented-sbom diff --git a/evergreen/functions/security_reporting_scripts/BUILD.bazel b/evergreen/functions/security_reporting_scripts/BUILD.bazel new file mode 100644 index 00000000000..9ca1bc981ff --- /dev/null +++ b/evergreen/functions/security_reporting_scripts/BUILD.bazel @@ -0,0 +1,17 @@ +package(default_visibility = ["//visibility:public"]) + +sh_binary( + name = "augment_sbom", + srcs = ["augment_sbom.sh"], +) + +sh_binary( + name = "write_aws_creds_to_silkbomb_env_file", + srcs = ["write_aws_creds_to_silkbomb_env_file.sh"], +) + +py_library( + name = "all_python_files", + srcs = glob(["*.py"]), + visibility = ["//visibility:public"], +) diff --git a/evergreen/functions/security_reporting_scripts/OWNERS.yml b/evergreen/functions/security_reporting_scripts/OWNERS.yml new file mode 100644 index 00000000000..14613f35dfc --- /dev/null +++ b/evergreen/functions/security_reporting_scripts/OWNERS.yml @@ -0,0 +1,5 @@ +version: 2.0.0 +filters: + - "*": + approvers: + - 10gen/platsec-server diff --git a/evergreen/functions/security_reporting_scripts/augment_sbom.sh b/evergreen/functions/security_reporting_scripts/augment_sbom.sh new file mode 100644 index 00000000000..103c748b395 --- /dev/null +++ b/evergreen/functions/security_reporting_scripts/augment_sbom.sh @@ -0,0 +1,55 @@ +# !/bin/bash +# Augment SBOM using SilkBomb inside a container. +# +# Usage: +# augment_sbom +# +# The script uses SilkBomb. +# See: https://docs.devprod.prod.corp.mongodb.com/mms/python/src/sbom/silkbomb/ +# +# Required system environment variables: +# AWS_ACCESS_KEY_ID +# AWS_SECRET_ACCESS_KEY +# AWS_SESSION_TOKEN +# +# Required script env variables: +# CONTAINER_COMMAND +# CONTAINER_OPTIONS +# CONTAINER_ENV_FILES +# CONTAINER_VOLUMES +# CONTAINER_IMAGE +# SBOM_REPO_PATH +# SBOM_OUT_PATH +# SILKBOMB_COMMAND +# SILKBOMB_ARGS +# requester +# branch_name +# github_org +# github_repo +# workdir + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)" +. "$DIR/../../prelude.sh" + +set -o errexit +set -o verbose +set -o pipefail + +read -ra OPTS_ARRAY <<< "$CONTAINER_OPTIONS" +read -ra VOLUMES_ARRAY <<< "$CONTAINER_VOLUMES" +read -ra ARGS_ARRAY <<< "$SILKBOMB_ARGS" + +echo "--> Logging in to AWS ECR..." +aws ecr get-login-password --region us-east-1 | "${CONTAINER_COMMAND}" login --username AWS --password-stdin 901841024863.dkr.ecr.us-east-1.amazonaws.com + +echo "--> Running the container..." +# The "${VAR[@]}" syntax expands arrays safely, with each element becoming a distinct argument. +"${CONTAINER_COMMAND}" run \ + "${OPTS_ARRAY[@]}" \ + --env-file "${CONTAINER_ENV_FILES}" \ + "${VOLUMES_ARRAY[@]}" \ + "${CONTAINER_IMAGE}" \ + "${SILKBOMB_COMMAND}" \ + "${ARGS_ARRAY[@]}" + +echo "--> Script finished successfully." diff --git a/evergreen/functions/security_reporting_scripts/upload_to_google_drive.py b/evergreen/functions/security_reporting_scripts/upload_to_google_drive.py new file mode 100644 index 00000000000..b0967284039 --- /dev/null +++ b/evergreen/functions/security_reporting_scripts/upload_to_google_drive.py @@ -0,0 +1,119 @@ +import os +import sys +from pathlib import Path + +import typer +from google.oauth2.credentials import Credentials +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError +from googleapiclient.http import MediaFileUpload + +app = typer.Typer(add_completion=False) + + +@app.command() +def upload( + input_file: Path = typer.Argument( + ..., + exists=True, + file_okay=True, + dir_okay=False, + readable=True, + resolve_path=True, + help="The path to the file to upload.", + ), + client_id: str = typer.Option( + ..., + envvar="SAST_REPORT_UPLOAD_GOOGLE_CLIENT_ID", + help="The OAuth2 client ID for Google API.", + ), + client_secret: str = typer.Option( + ..., + envvar="SAST_REPORT_UPLOAD_GOOGLE_CLIENT_SECRET", + help="The OAuth2 client secret for Google API.", + ), + refresh_token: str = typer.Option( + ..., + envvar="SAST_REPORT_UPLOAD_GOOGLE_CLIENT_REFRESH_TOKEN", + help="The OAuth2 refresh token for Google API.", + ), + branch: str = typer.Option( + ..., envvar="MONGODB_RELEASE_BRANCH", help="The MongoDB release branch." + ), + test_folder_id: str = typer.Option( + ..., + envvar="SBOM_REPORT_TEST_GOOGLE_DRIVE_FOLDER_ID", + help="The ID of the Google Drive folder for test uploads.", + ), + releases_folder_id: str = typer.Option( + ..., + envvar="SBOM_REPORT_RELEASES_GOOGLE_DRIVE_FOLDER_ID", + help="The ID of the Google Drive folder for releases.", + ), + triggered_by_tag: str = typer.Option( + "", + envvar="TRIGGERED_BY_GIT_TAG", + help="Indicates if the upload was triggered by a git tag.", + ), + version: str = typer.Option( + "", envvar="MONGODB_VERSION", help="The version of MongoDB being processed." + ), + upload_file_name: str = typer.Option( + None, + envvar="UPLOAD_FILE_NAME", + help="Optional upload file to use. If not provided, the input file name will be used.", + ), +): + print("Starting file upload process to Google Drive.") + + try: + creds_info = { + "client_id": client_id, + "client_secret": client_secret, + "refresh_token": refresh_token, + "token_uri": "https://oauth2.googleapis.com/token", + } + creds = Credentials.from_authorized_user_info( + info=creds_info, scopes=["https://www.googleapis.com/auth/drive"] + ) + drive_service = build("drive", "v3", credentials=creds) + print("Authenticated with Google Drive API successfully.") + except Exception as e: + print(f"Failed to authenticate with Google API: {e}") + sys.exit(1) + + folder_id = releases_folder_id if triggered_by_tag.lower() == "true" else test_folder_id + + if upload_file_name is None: + input_file_name_str = str(input_file.resolve().name) + else: + _, file_extension = os.path.splitext(input_file.resolve().name) + input_file_name_str = f"{upload_file_name}{file_extension}" + + file_metadata = {"name": input_file_name_str, "parents": [folder_id]} + media = MediaFileUpload(str(input_file), mimetype="text/html", resumable=True) + + try: + print(f"Uploading '{input_file}' to Google Drive...") + print(f"File name on Drive: '{input_file_name_str}'") + file = ( + drive_service.files() + .create( + body=file_metadata, + media_body=media, + fields="id, webViewLink", + supportsAllDrives=True, + ) + .execute() + ) + print("Upload complete.") + print(f"File ID: {file.get('id')}") + print(f"View Link: {file.get('webViewLink')}") + + except HttpError as error: + print(f"An API error occurred: {error}") + sys.exit(1) + + +if __name__ == "__main__": + app() diff --git a/evergreen/functions/security_reporting_scripts/write_aws_creds_to_silkbomb_env_file.sh b/evergreen/functions/security_reporting_scripts/write_aws_creds_to_silkbomb_env_file.sh new file mode 100644 index 00000000000..f3ff263a1d0 --- /dev/null +++ b/evergreen/functions/security_reporting_scripts/write_aws_creds_to_silkbomb_env_file.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This is an auxiliary script that writes AWS credentials to an env file. +# Being used by augment_sbom.sh script and SBOM upload tasks to prepare the env file for SilkBomb. +# +# Usage: +# write_aws_creds_to_silkbomb_env_file.sh +# +# Required system environment variables: +# AWS_ACCESS_KEY_ID +# AWS_SECRET_ACCESS_KEY +# AWS_SESSION_TOKEN + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)" +. "$DIR/../../prelude.sh" + +cat << EOF > "${workdir}/silkbomb.env" +AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} +AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} +AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} +EOF diff --git a/poetry.lock b/poetry.lock index 7e19754c39e..a21cca40ee9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -214,6 +214,18 @@ dev = ["CacheControl[filecache,redis]", "build", "cherrypy", "codespell[tomli]", filecache = ["filelock (>=3.8.0)"] redis = ["redis (>=2.10.5)"] +[[package]] +name = "cachetools" +version = "6.2.1" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.9" +groups = ["testing"] +files = [ + {file = "cachetools-6.2.1-py3-none-any.whl", hash = "sha256:09868944b6dde876dfd44e1d47e18484541eaf12f26f29b7af91b26cc892d701"}, + {file = "cachetools-6.2.1.tar.gz", hash = "sha256:3f391e4bd8f8bf0931169baf7456cc822705f4e2a31f840d218f445b9a854201"}, +] + [[package]] name = "certifi" version = "2024.2.2" @@ -1073,6 +1085,116 @@ gitdb = ">=4.0.1,<5" [package.extras] test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "sumtypes"] +[[package]] +name = "google-api-core" +version = "2.28.0" +description = "Google API client core library" +optional = false +python-versions = ">=3.7" +groups = ["testing"] +files = [ + {file = "google_api_core-2.28.0-py3-none-any.whl", hash = "sha256:b4362b0e2e6bc06037cfb0e2b28e2fe0c3f9d760dc311f314d5fb373768c7387"}, + {file = "google_api_core-2.28.0.tar.gz", hash = "sha256:4743b7d45fe8c0930e59928b1bade287242910f30b06ff9b22f139a3e33271b8"}, +] + +[package.dependencies] +google-auth = ">=2.14.1,<3.0.0" +googleapis-common-protos = ">=1.56.2,<2.0.0" +proto-plus = [ + {version = ">=1.22.3,<2.0.0", markers = "python_version < \"3.13\""}, + {version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""}, +] +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" +requests = ">=2.18.0,<3.0.0" + +[package.extras] +async-rest = ["google-auth[aiohttp] (>=2.35.0,<3.0.0)"] +grpc = ["grpcio (>=1.33.2,<2.0.0)", "grpcio (>=1.49.1,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "grpcio-status (>=1.33.2,<2.0.0)", "grpcio-status (>=1.49.1,<2.0.0)", "grpcio-status (>=1.75.1,<2.0.0)"] +grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.0)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.0)"] + +[[package]] +name = "google-api-python-client" +version = "2.123.0" +description = "Google API Client Library for Python" +optional = false +python-versions = ">=3.7" +groups = ["testing"] +files = [ + {file = "google-api-python-client-2.123.0.tar.gz", hash = "sha256:a17226b02f71de581afe045437b441844110a9cd91580b73549d41108cf1b9f0"}, + {file = "google_api_python_client-2.123.0-py2.py3-none-any.whl", hash = "sha256:1c2bcaa846acf5bac4d6f244d8373d4de9de73d64eb6e77b56767ab4cf681419"}, +] + +[package.dependencies] +google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0.dev0" +google-auth = ">=1.19.0,<3.0.0.dev0" +google-auth-httplib2 = ">=0.1.0" +httplib2 = ">=0.15.0,<1.dev0" +uritemplate = ">=3.0.1,<5" + +[[package]] +name = "google-auth" +version = "2.41.1" +description = "Google Authentication Library" +optional = false +python-versions = ">=3.7" +groups = ["testing"] +files = [ + {file = "google_auth-2.41.1-py2.py3-none-any.whl", hash = "sha256:754843be95575b9a19c604a848a41be03f7f2afd8c019f716dc1f51ee41c639d"}, + {file = "google_auth-2.41.1.tar.gz", hash = "sha256:b76b7b1f9e61f0cb7e88870d14f6a94aeef248959ef6992670efee37709cbfd2"}, +] + +[package.dependencies] +cachetools = ">=2.0.0,<7.0" +pyasn1-modules = ">=0.2.1" +rsa = ">=3.1.4,<5" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "requests (>=2.20.0,<3.0.0)"] +enterprise-cert = ["cryptography", "pyopenssl"] +pyjwt = ["cryptography (<39.0.0)", "cryptography (>=38.0.3)", "pyjwt (>=2.0)"] +pyopenssl = ["cryptography (<39.0.0)", "cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0)"] +testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0)", "cryptography (<39.0.0)", "cryptography (>=38.0.3)", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] +urllib3 = ["packaging", "urllib3"] + +[[package]] +name = "google-auth-httplib2" +version = "0.1.0" +description = "Google Authentication Library: httplib2 transport" +optional = false +python-versions = "*" +groups = ["testing"] +files = [ + {file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"}, + {file = "google_auth_httplib2-0.1.0-py2.py3-none-any.whl", hash = "sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10"}, +] + +[package.dependencies] +google-auth = "*" +httplib2 = ">=0.15.0" +six = "*" + +[[package]] +name = "google-auth-oauthlib" +version = "1.2.2" +description = "Google Authentication Library" +optional = false +python-versions = ">=3.6" +groups = ["testing"] +files = [ + {file = "google_auth_oauthlib-1.2.2-py3-none-any.whl", hash = "sha256:fd619506f4b3908b5df17b65f39ca8d66ea56986e5472eb5978fd8f3786f00a2"}, + {file = "google_auth_oauthlib-1.2.2.tar.gz", hash = "sha256:11046fb8d3348b296302dd939ace8af0a724042e8029c1b872d87fabc9f41684"}, +] + +[package.dependencies] +google-auth = ">=2.15.0" +requests-oauthlib = ">=0.7.0" + +[package.extras] +tool = ["click (>=6.0.0)"] + [[package]] name = "googleapis-common-protos" version = "1.62.0" @@ -1176,6 +1298,18 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] +[[package]] +name = "httplib2" +version = "0.18.1" +description = "A comprehensive HTTP client library." +optional = false +python-versions = "*" +groups = ["testing"] +files = [ + {file = "httplib2-0.18.1-py3-none-any.whl", hash = "sha256:ca2914b015b6247791c4866782fa6042f495b94401a0f0bd3e1d6e0ba2236782"}, + {file = "httplib2-0.18.1.tar.gz", hash = "sha256:8af66c1c52c7ffe1aa5dc4bcd7c769885254b0756e6e69f953c7f0ab49a70ba3"}, +] + [[package]] name = "hyperlink" version = "21.0.0" @@ -2319,6 +2453,24 @@ python-utils = ">=3.8.1" docs = ["sphinx (>=1.8.5)", "sphinx-autodoc-typehints (>=1.6.0)"] tests = ["dill (>=0.3.6)", "flake8 (>=3.7.7)", "freezegun (>=0.3.11)", "pytest (>=4.6.9)", "pytest-cov (>=2.6.1)", "pytest-mypy", "sphinx (>=1.8.5)"] +[[package]] +name = "proto-plus" +version = "1.26.1" +description = "Beautiful, Pythonic protocol buffers" +optional = false +python-versions = ">=3.7" +groups = ["testing"] +files = [ + {file = "proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66"}, + {file = "proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012"}, +] + +[package.dependencies] +protobuf = ">=3.19.0,<7.0.0" + +[package.extras] +testing = ["google-api-core (>=1.31.5)"] + [[package]] name = "protobuf" version = "4.25.2" @@ -2416,7 +2568,7 @@ version = "0.5.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -groups = ["external-auth"] +groups = ["external-auth", "testing"] files = [ {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, @@ -2428,7 +2580,7 @@ version = "0.3.0" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -groups = ["external-auth"] +groups = ["external-auth", "testing"] files = [ {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, @@ -3418,6 +3570,21 @@ files = [ {file = "rpds_py-0.17.1.tar.gz", hash = "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7"}, ] +[[package]] +name = "rsa" +version = "4.9.1" +description = "Pure-Python RSA implementation" +optional = false +python-versions = "<4,>=3.6" +groups = ["testing"] +files = [ + {file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"}, + {file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"}, +] + +[package.dependencies] +pyasn1 = ">=0.1.3" + [[package]] name = "s3transfer" version = "0.10.0" @@ -4019,6 +4186,18 @@ files = [ {file = "unittest_xml_reporting-3.0.4-py2.py3-none-any.whl", hash = "sha256:7bf515ea8cb244255a25100cd29db611a73f8d3d0aaf672ed3266307e14cc1ca"}, ] +[[package]] +name = "uritemplate" +version = "4.2.0" +description = "Implementation of RFC 6570 URI Templates" +optional = false +python-versions = ">=3.9" +groups = ["testing"] +files = [ + {file = "uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686"}, + {file = "uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e"}, +] + [[package]] name = "urllib3" version = "1.26.18" @@ -4423,4 +4602,4 @@ oldcrypt = [] [metadata] lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "3d68e8c7f9cd0f11850efa26c1a30e1d2273e8afa1857f802639543bf140e8c8" +content-hash = "788ff9b867ff983ca4544f1130137c872d40a7e56e441d041948a3a21c790b56" diff --git a/pyproject.toml b/pyproject.toml index 62f672023ff..7f76bc3006b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -168,6 +168,8 @@ geckodriver-autoinstaller = "^0.1.0" retry = "^0.9.2" gdbmongo = "^0.15.1" googleapis-common-protos = "^1.61.0" +google-api-python-client = "^2.19.0" +google-auth-oauthlib = "^1.2.1" opentelemetry-api = "*" opentelemetry-sdk = "*" opentelemetry-exporter-otlp-proto-common = "*"