diff --git a/.flake8 b/.flake8 index ed93163..29227d4 100644 --- a/.flake8 +++ b/.flake8 @@ -26,6 +26,7 @@ exclude = *_pb2.py # Standard linting exemptions. + **/.nox/** __pycache__, .git, *.pyc, diff --git a/.github/header-checker-lint.yml b/.github/header-checker-lint.yml new file mode 100644 index 0000000..fc281c0 --- /dev/null +++ b/.github/header-checker-lint.yml @@ -0,0 +1,15 @@ +{"allowedCopyrightHolders": ["Google LLC"], + "allowedLicenses": ["Apache-2.0", "MIT", "BSD-3"], + "ignoreFiles": ["**/requirements.txt", "**/requirements-test.txt"], + "sourceFileExtensions": [ + "ts", + "js", + "java", + "sh", + "Dockerfile", + "yaml", + "py", + "html", + "txt" + ] +} \ No newline at end of file diff --git a/.github/snippet-bot.yml b/.github/snippet-bot.yml new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore index b87e1ed..b4243ce 100644 --- a/.gitignore +++ b/.gitignore @@ -46,15 +46,18 @@ pip-log.txt # Built documentation docs/_build bigquery/docs/generated +docs.metadata # Virtual environment env/ + +# Test logs coverage.xml -sponge_log.xml +*sponge_log.xml # System test environment variables. system_tests/local_test_setup # Make sure a generated file isn't accidentally committed. pylintrc -pylintrc.test \ No newline at end of file +pylintrc.test diff --git a/.kokoro/build.sh b/.kokoro/build.sh index 61f3191..f50a89f 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -15,7 +15,11 @@ set -eo pipefail -cd github/python-websecurityscanner +if [[ -z "${PROJECT_ROOT:-}" ]]; then + PROJECT_ROOT="github/python-websecurityscanner" +fi + +cd "${PROJECT_ROOT}" # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 @@ -30,10 +34,26 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json") # Remove old nox -python3.6 -m pip uninstall --yes --quiet nox-automation +python3 -m pip uninstall --yes --quiet nox-automation # Install nox -python3.6 -m pip install --upgrade --quiet nox -python3.6 -m nox --version - -python3.6 -m nox +python3 -m pip install --upgrade --quiet nox +python3 -m nox --version + +# If this is a continuous build, send the test log to the FlakyBot. +# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. +if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then + cleanup() { + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + } + trap cleanup EXIT HUP +fi + +# If NOX_SESSION is set, it only runs the specified session, +# otherwise run all the sessions. +if [[ -n "${NOX_SESSION:-}" ]]; then + python3 -m nox -s ${NOX_SESSION:-} +else + python3 -m nox +fi diff --git a/.kokoro/docker/docs/Dockerfile b/.kokoro/docker/docs/Dockerfile new file mode 100644 index 0000000..412b0b5 --- /dev/null +++ b/.kokoro/docker/docs/Dockerfile @@ -0,0 +1,98 @@ +# Copyright 2020 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 ubuntu:20.04 + +ENV DEBIAN_FRONTEND noninteractive + +# Ensure local Python is preferred over distribution Python. +ENV PATH /usr/local/bin:$PATH + +# Install dependencies. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-transport-https \ + build-essential \ + ca-certificates \ + curl \ + dirmngr \ + git \ + gpg-agent \ + graphviz \ + libbz2-dev \ + libdb5.3-dev \ + libexpat1-dev \ + libffi-dev \ + liblzma-dev \ + libreadline-dev \ + libsnappy-dev \ + libssl-dev \ + libsqlite3-dev \ + portaudio19-dev \ + redis-server \ + software-properties-common \ + ssh \ + sudo \ + tcl \ + tcl-dev \ + tk \ + tk-dev \ + uuid-dev \ + wget \ + zlib1g-dev \ + && add-apt-repository universe \ + && apt-get update \ + && apt-get -y install jq \ + && apt-get clean autoclean \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -f /var/cache/apt/archives/*.deb + + +COPY fetch_gpg_keys.sh /tmp +# Install the desired versions of Python. +RUN set -ex \ + && export GNUPGHOME="$(mktemp -d)" \ + && echo "disable-ipv6" >> "${GNUPGHOME}/dirmngr.conf" \ + && /tmp/fetch_gpg_keys.sh \ + && for PYTHON_VERSION in 3.7.8 3.8.5; do \ + wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz" \ + && wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc" \ + && gpg --batch --verify python-${PYTHON_VERSION}.tar.xz.asc python-${PYTHON_VERSION}.tar.xz \ + && rm -r python-${PYTHON_VERSION}.tar.xz.asc \ + && mkdir -p /usr/src/python-${PYTHON_VERSION} \ + && tar -xJC /usr/src/python-${PYTHON_VERSION} --strip-components=1 -f python-${PYTHON_VERSION}.tar.xz \ + && rm python-${PYTHON_VERSION}.tar.xz \ + && cd /usr/src/python-${PYTHON_VERSION} \ + && ./configure \ + --enable-shared \ + # This works only on Python 2.7 and throws a warning on every other + # version, but seems otherwise harmless. + --enable-unicode=ucs4 \ + --with-system-ffi \ + --without-ensurepip \ + && make -j$(nproc) \ + && make install \ + && ldconfig \ + ; done \ + && rm -rf "${GNUPGHOME}" \ + && rm -rf /usr/src/python* \ + && rm -rf ~/.cache/ + +RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ + && python3.7 /tmp/get-pip.py \ + && python3.8 /tmp/get-pip.py \ + && rm /tmp/get-pip.py + +CMD ["python3.7"] diff --git a/.kokoro/docker/docs/fetch_gpg_keys.sh b/.kokoro/docker/docs/fetch_gpg_keys.sh new file mode 100755 index 0000000..d653dd8 --- /dev/null +++ b/.kokoro/docker/docs/fetch_gpg_keys.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright 2020 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. + +# A script to fetch gpg keys with retry. +# Avoid jinja parsing the file. +# + +function retry { + if [[ "${#}" -le 1 ]]; then + echo "Usage: ${0} retry_count commands.." + exit 1 + fi + local retries=${1} + local command="${@:2}" + until [[ "${retries}" -le 0 ]]; do + $command && return 0 + if [[ $? -ne 0 ]]; then + echo "command failed, retrying" + ((retries--)) + fi + done + return 1 +} + +# 3.6.9, 3.7.5 (Ned Deily) +retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ + 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D + +# 3.8.0 (Łukasz Langa) +retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ + E3FF2839C048B25C084DEBE9B26995E310250568 + +# diff --git a/.kokoro/docs/common.cfg b/.kokoro/docs/common.cfg index a264a93..5c41611 100644 --- a/.kokoro/docs/common.cfg +++ b/.kokoro/docs/common.cfg @@ -11,12 +11,12 @@ action { gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" # Use the trampoline script to run in docker. -build_file: "python-websecurityscanner/.kokoro/trampoline.sh" +build_file: "python-websecurityscanner/.kokoro/trampoline_v2.sh" # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" + value: "gcr.io/cloud-devrel-kokoro-resources/python-lib-docs" } env_vars: { key: "TRAMPOLINE_BUILD_FILE" @@ -28,6 +28,23 @@ env_vars: { value: "docs-staging" } +env_vars: { + key: "V2_STAGING_BUCKET" + value: "docs-staging-v2" +} + +# It will upload the docker image after successful builds. +env_vars: { + key: "TRAMPOLINE_IMAGE_UPLOAD" + value: "true" +} + +# It will always build the docker image. +env_vars: { + key: "TRAMPOLINE_DOCKERFILE" + value: ".kokoro/docker/docs/Dockerfile" +} + # Fetch the token needed for reporting release status to GitHub before_action { fetch_keystore { diff --git a/.kokoro/docs/docs-presubmit.cfg b/.kokoro/docs/docs-presubmit.cfg new file mode 100644 index 0000000..1c3c375 --- /dev/null +++ b/.kokoro/docs/docs-presubmit.cfg @@ -0,0 +1,28 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "STAGING_BUCKET" + value: "gcloud-python-test" +} + +env_vars: { + key: "V2_STAGING_BUCKET" + value: "gcloud-python-test" +} + +# We only upload the image in the main `docs` build. +env_vars: { + key: "TRAMPOLINE_IMAGE_UPLOAD" + value: "false" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-websecurityscanner/.kokoro/build.sh" +} + +# Only run this nox session. +env_vars: { + key: "NOX_SESSION" + value: "docs docfx" +} diff --git a/.kokoro/populate-secrets.sh b/.kokoro/populate-secrets.sh new file mode 100755 index 0000000..f525142 --- /dev/null +++ b/.kokoro/populate-secrets.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright 2020 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. + +set -eo pipefail + +function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;} +function msg { println "$*" >&2 ;} +function println { printf '%s\n' "$(now) $*" ;} + + +# Populates requested secrets set in SECRET_MANAGER_KEYS from service account: +# kokoro-trampoline@cloud-devrel-kokoro-resources.iam.gserviceaccount.com +SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager" +msg "Creating folder on disk for secrets: ${SECRET_LOCATION}" +mkdir -p ${SECRET_LOCATION} +for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g") +do + msg "Retrieving secret ${key}" + docker run --entrypoint=gcloud \ + --volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR} \ + gcr.io/google.com/cloudsdktool/cloud-sdk \ + secrets versions access latest \ + --project cloud-devrel-kokoro-resources \ + --secret ${key} > \ + "${SECRET_LOCATION}/${key}" + if [[ $? == 0 ]]; then + msg "Secret written to ${SECRET_LOCATION}/${key}" + else + msg "Error retrieving secret ${key}" + fi +done diff --git a/.kokoro/publish-docs.sh b/.kokoro/publish-docs.sh index e2cb7f3..8acb14e 100755 --- a/.kokoro/publish-docs.sh +++ b/.kokoro/publish-docs.sh @@ -18,26 +18,16 @@ set -eo pipefail # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 -cd github/python-websecurityscanner - -# Remove old nox -python3.6 -m pip uninstall --yes --quiet nox-automation +export PATH="${HOME}/.local/bin:${PATH}" # Install nox -python3.6 -m pip install --upgrade --quiet nox -python3.6 -m nox --version +python3 -m pip install --user --upgrade --quiet nox +python3 -m nox --version # build docs nox -s docs -python3 -m pip install gcp-docuploader - -# install a json parser -sudo apt-get update -sudo apt-get -y install software-properties-common -sudo add-apt-repository universe -sudo apt-get update -sudo apt-get -y install jq +python3 -m pip install --user gcp-docuploader # create metadata python3 -m docuploader create-metadata \ @@ -52,4 +42,23 @@ python3 -m docuploader create-metadata \ cat docs.metadata # upload docs -python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket docs-staging +python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" + + +# docfx yaml files +nox -s docfx + +# create metadata. +python3 -m docuploader create-metadata \ + --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ + --version=$(python3 setup.py --version) \ + --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ + --distribution-name=$(python3 setup.py --name) \ + --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ + --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ + --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) + +cat docs.metadata + +# upload docs +python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" diff --git a/.kokoro/release/common.cfg b/.kokoro/release/common.cfg index aa62d0a..6b49edb 100644 --- a/.kokoro/release/common.cfg +++ b/.kokoro/release/common.cfg @@ -23,42 +23,18 @@ env_vars: { value: "github/python-websecurityscanner/.kokoro/release.sh" } -# Fetch the token needed for reporting release status to GitHub -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "yoshi-automation-github-key" - } - } -} - -# Fetch PyPI password -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "google_cloud_pypi_password" - } - } -} - -# Fetch magictoken to use with Magic Github Proxy -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "releasetool-magictoken" - } - } +# Fetch PyPI password +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "google_cloud_pypi_password" + } + } } -# Fetch api key to use with Magic Github Proxy -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "magic-github-proxy-api-key" - } - } -} +# Tokens needed to report release status back to GitHub +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" +} \ No newline at end of file diff --git a/.kokoro/samples/python3.6/common.cfg b/.kokoro/samples/python3.6/common.cfg index d2f356c..57ad8a6 100644 --- a/.kokoro/samples/python3.6/common.cfg +++ b/.kokoro/samples/python3.6/common.cfg @@ -13,6 +13,12 @@ env_vars: { value: "py-3.6" } +# Declare build specific Cloud project. +env_vars: { + key: "BUILD_SPECIFIC_GCLOUD_PROJECT" + value: "python-docs-samples-tests-py36" +} + env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/python-websecurityscanner/.kokoro/test-samples.sh" diff --git a/.kokoro/samples/python3.6/periodic-head.cfg b/.kokoro/samples/python3.6/periodic-head.cfg new file mode 100644 index 0000000..f9cfcd3 --- /dev/null +++ b/.kokoro/samples/python3.6/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.7/common.cfg b/.kokoro/samples/python3.7/common.cfg index 44b50d9..8264629 100644 --- a/.kokoro/samples/python3.7/common.cfg +++ b/.kokoro/samples/python3.7/common.cfg @@ -13,6 +13,12 @@ env_vars: { value: "py-3.7" } +# Declare build specific Cloud project. +env_vars: { + key: "BUILD_SPECIFIC_GCLOUD_PROJECT" + value: "python-docs-samples-tests-py37" +} + env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/python-websecurityscanner/.kokoro/test-samples.sh" diff --git a/.kokoro/samples/python3.7/periodic-head.cfg b/.kokoro/samples/python3.7/periodic-head.cfg new file mode 100644 index 0000000..f9cfcd3 --- /dev/null +++ b/.kokoro/samples/python3.7/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.8/common.cfg b/.kokoro/samples/python3.8/common.cfg index 8b23298..fcb490e 100644 --- a/.kokoro/samples/python3.8/common.cfg +++ b/.kokoro/samples/python3.8/common.cfg @@ -13,6 +13,12 @@ env_vars: { value: "py-3.8" } +# Declare build specific Cloud project. +env_vars: { + key: "BUILD_SPECIFIC_GCLOUD_PROJECT" + value: "python-docs-samples-tests-py38" +} + env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/python-websecurityscanner/.kokoro/test-samples.sh" diff --git a/.kokoro/samples/python3.8/periodic-head.cfg b/.kokoro/samples/python3.8/periodic-head.cfg new file mode 100644 index 0000000..f9cfcd3 --- /dev/null +++ b/.kokoro/samples/python3.8/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/test-samples-against-head.sh b/.kokoro/test-samples-against-head.sh new file mode 100755 index 0000000..299f917 --- /dev/null +++ b/.kokoro/test-samples-against-head.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright 2020 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. + +# A customized test runner for samples. +# +# For periodic builds, you can specify this file for testing against head. + +# `-e` enables the script to automatically fail when a command fails +# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero +set -eo pipefail +# Enables `**` to include files nested inside sub-folders +shopt -s globstar + +cd github/python-websecurityscanner + +exec .kokoro/test-samples-impl.sh diff --git a/.kokoro/test-samples-impl.sh b/.kokoro/test-samples-impl.sh new file mode 100755 index 0000000..cf5de74 --- /dev/null +++ b/.kokoro/test-samples-impl.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# Copyright 2021 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. + + +# `-e` enables the script to automatically fail when a command fails +# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero +set -eo pipefail +# Enables `**` to include files nested inside sub-folders +shopt -s globstar + +# Exit early if samples directory doesn't exist +if [ ! -d "./samples" ]; then + echo "No tests run. `./samples` not found" + exit 0 +fi + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Debug: show build environment +env | grep KOKORO + +# Install nox +python3.6 -m pip install --upgrade --quiet nox + +# Use secrets acessor service account to get secrets +if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then + gcloud auth activate-service-account \ + --key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \ + --project="cloud-devrel-kokoro-resources" +fi + +# This script will create 3 files: +# - testing/test-env.sh +# - testing/service-account.json +# - testing/client-secrets.json +./scripts/decrypt-secrets.sh + +source ./testing/test-env.sh +export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json + +# For cloud-run session, we activate the service account for gcloud sdk. +gcloud auth activate-service-account \ + --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" + +export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json + +echo -e "\n******************** TESTING PROJECTS ********************" + +# Switch to 'fail at end' to allow all tests to complete before exiting. +set +e +# Use RTN to return a non-zero value if the test fails. +RTN=0 +ROOT=$(pwd) +# Find all requirements.txt in the samples directory (may break on whitespace). +for file in samples/**/requirements.txt; do + cd "$ROOT" + # Navigate to the project folder. + file=$(dirname "$file") + cd "$file" + + echo "------------------------------------------------------------" + echo "- testing $file" + echo "------------------------------------------------------------" + + # Use nox to execute the tests for the project. + python3.6 -m nox -s "$RUN_TESTS_SESSION" + EXIT=$? + + # If this is a periodic build, send the test log to the FlakyBot. + # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. + if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + fi + + if [[ $EXIT -ne 0 ]]; then + RTN=1 + echo -e "\n Testing failed: Nox returned a non-zero exit code. \n" + else + echo -e "\n Testing completed.\n" + fi + +done +cd "$ROOT" + +# Workaround for Kokoro permissions issue: delete secrets +rm testing/{test-env.sh,client-secrets.json,service-account.json} + +exit "$RTN" diff --git a/.kokoro/test-samples.sh b/.kokoro/test-samples.sh index 2c295cb..a9ac7b5 100755 --- a/.kokoro/test-samples.sh +++ b/.kokoro/test-samples.sh @@ -13,6 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +# The default test runner for samples. +# +# For periodic builds, we rewinds the repo to the latest release, and +# run test-samples-impl.sh. # `-e` enables the script to automatically fail when a command fails # `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero @@ -24,81 +28,19 @@ cd github/python-websecurityscanner # Run periodic samples tests at latest release if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then + # preserving the test runner implementation. + cp .kokoro/test-samples-impl.sh "${TMPDIR}/test-samples-impl.sh" + echo "--- IMPORTANT IMPORTANT IMPORTANT ---" + echo "Now we rewind the repo back to the latest release..." LATEST_RELEASE=$(git describe --abbrev=0 --tags) git checkout $LATEST_RELEASE -fi - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -# Debug: show build environment -env | grep KOKORO - -# Install nox -python3.6 -m pip install --upgrade --quiet nox - -# Use secrets acessor service account to get secrets -if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then - gcloud auth activate-service-account \ - --key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \ - --project="cloud-devrel-kokoro-resources" -fi - -# This script will create 3 files: -# - testing/test-env.sh -# - testing/service-account.json -# - testing/client-secrets.json -./scripts/decrypt-secrets.sh - -source ./testing/test-env.sh -export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json - -# For cloud-run session, we activate the service account for gcloud sdk. -gcloud auth activate-service-account \ - --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" - -export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json - -echo -e "\n******************** TESTING PROJECTS ********************" - -# Switch to 'fail at end' to allow all tests to complete before exiting. -set +e -# Use RTN to return a non-zero value if the test fails. -RTN=0 -ROOT=$(pwd) -# Find all requirements.txt in the samples directory (may break on whitespace). -for file in samples/**/requirements.txt; do - cd "$ROOT" - # Navigate to the project folder. - file=$(dirname "$file") - cd "$file" - - echo "------------------------------------------------------------" - echo "- testing $file" - echo "------------------------------------------------------------" - - # Use nox to execute the tests for the project. - python3.6 -m nox -s "$RUN_TESTS_SESSION" - EXIT=$? - - # If this is a periodic build, send the test log to the FlakyBot. - # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. - if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then - chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot - $KOKORO_GFILE_DIR/linux_amd64/flakybot + echo "The current head is: " + echo $(git rev-parse --verify HEAD) + echo "--- IMPORTANT IMPORTANT IMPORTANT ---" + # move back the test runner implementation if there's no file. + if [ ! -f .kokoro/test-samples-impl.sh ]; then + cp "${TMPDIR}/test-samples-impl.sh" .kokoro/test-samples-impl.sh fi +fi - if [[ $EXIT -ne 0 ]]; then - RTN=1 - echo -e "\n Testing failed: Nox returned a non-zero exit code. \n" - else - echo -e "\n Testing completed.\n" - fi - -done -cd "$ROOT" - -# Workaround for Kokoro permissions issue: delete secrets -rm testing/{test-env.sh,client-secrets.json,service-account.json} - -exit "$RTN" \ No newline at end of file +exec .kokoro/test-samples-impl.sh diff --git a/.kokoro/trampoline.sh b/.kokoro/trampoline.sh index e8c4251..f39236e 100755 --- a/.kokoro/trampoline.sh +++ b/.kokoro/trampoline.sh @@ -15,9 +15,14 @@ set -eo pipefail -python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" || ret_code=$? +# Always run the cleanup script, regardless of the success of bouncing into +# the container. +function cleanup() { + chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh + ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh + echo "cleanup"; +} +trap cleanup EXIT -chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh -${KOKORO_GFILE_DIR}/trampoline_cleanup.sh || true - -exit ${ret_code} +$(dirname $0)/populate-secrets.sh # Secret Manager secrets. +python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" \ No newline at end of file diff --git a/.kokoro/trampoline_v2.sh b/.kokoro/trampoline_v2.sh new file mode 100755 index 0000000..4af6cdc --- /dev/null +++ b/.kokoro/trampoline_v2.sh @@ -0,0 +1,487 @@ +#!/usr/bin/env bash +# Copyright 2020 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. + +# trampoline_v2.sh +# +# This script does 3 things. +# +# 1. Prepare the Docker image for the test +# 2. Run the Docker with appropriate flags to run the test +# 3. Upload the newly built Docker image +# +# in a way that is somewhat compatible with trampoline_v1. +# +# To run this script, first download few files from gcs to /dev/shm. +# (/dev/shm is passed into the container as KOKORO_GFILE_DIR). +# +# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/secrets_viewer_service_account.json /dev/shm +# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/automl_secrets.txt /dev/shm +# +# Then run the script. +# .kokoro/trampoline_v2.sh +# +# These environment variables are required: +# TRAMPOLINE_IMAGE: The docker image to use. +# TRAMPOLINE_DOCKERFILE: The location of the Dockerfile. +# +# You can optionally change these environment variables: +# TRAMPOLINE_IMAGE_UPLOAD: +# (true|false): Whether to upload the Docker image after the +# successful builds. +# TRAMPOLINE_BUILD_FILE: The script to run in the docker container. +# TRAMPOLINE_WORKSPACE: The workspace path in the docker container. +# Defaults to /workspace. +# Potentially there are some repo specific envvars in .trampolinerc in +# the project root. + + +set -euo pipefail + +TRAMPOLINE_VERSION="2.0.5" + +if command -v tput >/dev/null && [[ -n "${TERM:-}" ]]; then + readonly IO_COLOR_RED="$(tput setaf 1)" + readonly IO_COLOR_GREEN="$(tput setaf 2)" + readonly IO_COLOR_YELLOW="$(tput setaf 3)" + readonly IO_COLOR_RESET="$(tput sgr0)" +else + readonly IO_COLOR_RED="" + readonly IO_COLOR_GREEN="" + readonly IO_COLOR_YELLOW="" + readonly IO_COLOR_RESET="" +fi + +function function_exists { + [ $(LC_ALL=C type -t $1)"" == "function" ] +} + +# Logs a message using the given color. The first argument must be one +# of the IO_COLOR_* variables defined above, such as +# "${IO_COLOR_YELLOW}". The remaining arguments will be logged in the +# given color. The log message will also have an RFC-3339 timestamp +# prepended (in UTC). You can disable the color output by setting +# TERM=vt100. +function log_impl() { + local color="$1" + shift + local timestamp="$(date -u "+%Y-%m-%dT%H:%M:%SZ")" + echo "================================================================" + echo "${color}${timestamp}:" "$@" "${IO_COLOR_RESET}" + echo "================================================================" +} + +# Logs the given message with normal coloring and a timestamp. +function log() { + log_impl "${IO_COLOR_RESET}" "$@" +} + +# Logs the given message in green with a timestamp. +function log_green() { + log_impl "${IO_COLOR_GREEN}" "$@" +} + +# Logs the given message in yellow with a timestamp. +function log_yellow() { + log_impl "${IO_COLOR_YELLOW}" "$@" +} + +# Logs the given message in red with a timestamp. +function log_red() { + log_impl "${IO_COLOR_RED}" "$@" +} + +readonly tmpdir=$(mktemp -d -t ci-XXXXXXXX) +readonly tmphome="${tmpdir}/h" +mkdir -p "${tmphome}" + +function cleanup() { + rm -rf "${tmpdir}" +} +trap cleanup EXIT + +RUNNING_IN_CI="${RUNNING_IN_CI:-false}" + +# The workspace in the container, defaults to /workspace. +TRAMPOLINE_WORKSPACE="${TRAMPOLINE_WORKSPACE:-/workspace}" + +pass_down_envvars=( + # TRAMPOLINE_V2 variables. + # Tells scripts whether they are running as part of CI or not. + "RUNNING_IN_CI" + # Indicates which CI system we're in. + "TRAMPOLINE_CI" + # Indicates the version of the script. + "TRAMPOLINE_VERSION" +) + +log_yellow "Building with Trampoline ${TRAMPOLINE_VERSION}" + +# Detect which CI systems we're in. If we're in any of the CI systems +# we support, `RUNNING_IN_CI` will be true and `TRAMPOLINE_CI` will be +# the name of the CI system. Both envvars will be passing down to the +# container for telling which CI system we're in. +if [[ -n "${KOKORO_BUILD_ID:-}" ]]; then + # descriptive env var for indicating it's on CI. + RUNNING_IN_CI="true" + TRAMPOLINE_CI="kokoro" + if [[ "${TRAMPOLINE_USE_LEGACY_SERVICE_ACCOUNT:-}" == "true" ]]; then + if [[ ! -f "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" ]]; then + log_red "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json does not exist. Did you forget to mount cloud-devrel-kokoro-resources/trampoline? Aborting." + exit 1 + fi + # This service account will be activated later. + TRAMPOLINE_SERVICE_ACCOUNT="${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" + else + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + gcloud auth list + fi + log_yellow "Configuring Container Registry access" + gcloud auth configure-docker --quiet + fi + pass_down_envvars+=( + # KOKORO dynamic variables. + "KOKORO_BUILD_NUMBER" + "KOKORO_BUILD_ID" + "KOKORO_JOB_NAME" + "KOKORO_GIT_COMMIT" + "KOKORO_GITHUB_COMMIT" + "KOKORO_GITHUB_PULL_REQUEST_NUMBER" + "KOKORO_GITHUB_PULL_REQUEST_COMMIT" + # For FlakyBot + "KOKORO_GITHUB_COMMIT_URL" + "KOKORO_GITHUB_PULL_REQUEST_URL" + ) +elif [[ "${TRAVIS:-}" == "true" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="travis" + pass_down_envvars+=( + "TRAVIS_BRANCH" + "TRAVIS_BUILD_ID" + "TRAVIS_BUILD_NUMBER" + "TRAVIS_BUILD_WEB_URL" + "TRAVIS_COMMIT" + "TRAVIS_COMMIT_MESSAGE" + "TRAVIS_COMMIT_RANGE" + "TRAVIS_JOB_NAME" + "TRAVIS_JOB_NUMBER" + "TRAVIS_JOB_WEB_URL" + "TRAVIS_PULL_REQUEST" + "TRAVIS_PULL_REQUEST_BRANCH" + "TRAVIS_PULL_REQUEST_SHA" + "TRAVIS_PULL_REQUEST_SLUG" + "TRAVIS_REPO_SLUG" + "TRAVIS_SECURE_ENV_VARS" + "TRAVIS_TAG" + ) +elif [[ -n "${GITHUB_RUN_ID:-}" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="github-workflow" + pass_down_envvars+=( + "GITHUB_WORKFLOW" + "GITHUB_RUN_ID" + "GITHUB_RUN_NUMBER" + "GITHUB_ACTION" + "GITHUB_ACTIONS" + "GITHUB_ACTOR" + "GITHUB_REPOSITORY" + "GITHUB_EVENT_NAME" + "GITHUB_EVENT_PATH" + "GITHUB_SHA" + "GITHUB_REF" + "GITHUB_HEAD_REF" + "GITHUB_BASE_REF" + ) +elif [[ "${CIRCLECI:-}" == "true" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="circleci" + pass_down_envvars+=( + "CIRCLE_BRANCH" + "CIRCLE_BUILD_NUM" + "CIRCLE_BUILD_URL" + "CIRCLE_COMPARE_URL" + "CIRCLE_JOB" + "CIRCLE_NODE_INDEX" + "CIRCLE_NODE_TOTAL" + "CIRCLE_PREVIOUS_BUILD_NUM" + "CIRCLE_PROJECT_REPONAME" + "CIRCLE_PROJECT_USERNAME" + "CIRCLE_REPOSITORY_URL" + "CIRCLE_SHA1" + "CIRCLE_STAGE" + "CIRCLE_USERNAME" + "CIRCLE_WORKFLOW_ID" + "CIRCLE_WORKFLOW_JOB_ID" + "CIRCLE_WORKFLOW_UPSTREAM_JOB_IDS" + "CIRCLE_WORKFLOW_WORKSPACE_ID" + ) +fi + +# Configure the service account for pulling the docker image. +function repo_root() { + local dir="$1" + while [[ ! -d "${dir}/.git" ]]; do + dir="$(dirname "$dir")" + done + echo "${dir}" +} + +# Detect the project root. In CI builds, we assume the script is in +# the git tree and traverse from there, otherwise, traverse from `pwd` +# to find `.git` directory. +if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + PROGRAM_PATH="$(realpath "$0")" + PROGRAM_DIR="$(dirname "${PROGRAM_PATH}")" + PROJECT_ROOT="$(repo_root "${PROGRAM_DIR}")" +else + PROJECT_ROOT="$(repo_root $(pwd))" +fi + +log_yellow "Changing to the project root: ${PROJECT_ROOT}." +cd "${PROJECT_ROOT}" + +# To support relative path for `TRAMPOLINE_SERVICE_ACCOUNT`, we need +# to use this environment variable in `PROJECT_ROOT`. +if [[ -n "${TRAMPOLINE_SERVICE_ACCOUNT:-}" ]]; then + + mkdir -p "${tmpdir}/gcloud" + gcloud_config_dir="${tmpdir}/gcloud" + + log_yellow "Using isolated gcloud config: ${gcloud_config_dir}." + export CLOUDSDK_CONFIG="${gcloud_config_dir}" + + log_yellow "Using ${TRAMPOLINE_SERVICE_ACCOUNT} for authentication." + gcloud auth activate-service-account \ + --key-file "${TRAMPOLINE_SERVICE_ACCOUNT}" + log_yellow "Configuring Container Registry access" + gcloud auth configure-docker --quiet +fi + +required_envvars=( + # The basic trampoline configurations. + "TRAMPOLINE_IMAGE" + "TRAMPOLINE_BUILD_FILE" +) + +if [[ -f "${PROJECT_ROOT}/.trampolinerc" ]]; then + source "${PROJECT_ROOT}/.trampolinerc" +fi + +log_yellow "Checking environment variables." +for e in "${required_envvars[@]}" +do + if [[ -z "${!e:-}" ]]; then + log "Missing ${e} env var. Aborting." + exit 1 + fi +done + +# We want to support legacy style TRAMPOLINE_BUILD_FILE used with V1 +# script: e.g. "github/repo-name/.kokoro/run_tests.sh" +TRAMPOLINE_BUILD_FILE="${TRAMPOLINE_BUILD_FILE#github/*/}" +log_yellow "Using TRAMPOLINE_BUILD_FILE: ${TRAMPOLINE_BUILD_FILE}" + +# ignore error on docker operations and test execution +set +e + +log_yellow "Preparing Docker image." +# We only download the docker image in CI builds. +if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + # Download the docker image specified by `TRAMPOLINE_IMAGE` + + # We may want to add --max-concurrent-downloads flag. + + log_yellow "Start pulling the Docker image: ${TRAMPOLINE_IMAGE}." + if docker pull "${TRAMPOLINE_IMAGE}"; then + log_green "Finished pulling the Docker image: ${TRAMPOLINE_IMAGE}." + has_image="true" + else + log_red "Failed pulling the Docker image: ${TRAMPOLINE_IMAGE}." + has_image="false" + fi +else + # For local run, check if we have the image. + if docker images "${TRAMPOLINE_IMAGE}:latest" | grep "${TRAMPOLINE_IMAGE}"; then + has_image="true" + else + has_image="false" + fi +fi + + +# The default user for a Docker container has uid 0 (root). To avoid +# creating root-owned files in the build directory we tell docker to +# use the current user ID. +user_uid="$(id -u)" +user_gid="$(id -g)" +user_name="$(id -un)" + +# To allow docker in docker, we add the user to the docker group in +# the host os. +docker_gid=$(cut -d: -f3 < <(getent group docker)) + +update_cache="false" +if [[ "${TRAMPOLINE_DOCKERFILE:-none}" != "none" ]]; then + # Build the Docker image from the source. + context_dir=$(dirname "${TRAMPOLINE_DOCKERFILE}") + docker_build_flags=( + "-f" "${TRAMPOLINE_DOCKERFILE}" + "-t" "${TRAMPOLINE_IMAGE}" + "--build-arg" "UID=${user_uid}" + "--build-arg" "USERNAME=${user_name}" + ) + if [[ "${has_image}" == "true" ]]; then + docker_build_flags+=("--cache-from" "${TRAMPOLINE_IMAGE}") + fi + + log_yellow "Start building the docker image." + if [[ "${TRAMPOLINE_VERBOSE:-false}" == "true" ]]; then + echo "docker build" "${docker_build_flags[@]}" "${context_dir}" + fi + + # ON CI systems, we want to suppress docker build logs, only + # output the logs when it fails. + if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + if docker build "${docker_build_flags[@]}" "${context_dir}" \ + > "${tmpdir}/docker_build.log" 2>&1; then + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + cat "${tmpdir}/docker_build.log" + fi + + log_green "Finished building the docker image." + update_cache="true" + else + log_red "Failed to build the Docker image, aborting." + log_yellow "Dumping the build logs:" + cat "${tmpdir}/docker_build.log" + exit 1 + fi + else + if docker build "${docker_build_flags[@]}" "${context_dir}"; then + log_green "Finished building the docker image." + update_cache="true" + else + log_red "Failed to build the Docker image, aborting." + exit 1 + fi + fi +else + if [[ "${has_image}" != "true" ]]; then + log_red "We do not have ${TRAMPOLINE_IMAGE} locally, aborting." + exit 1 + fi +fi + +# We use an array for the flags so they are easier to document. +docker_flags=( + # Remove the container after it exists. + "--rm" + + # Use the host network. + "--network=host" + + # Run in priviledged mode. We are not using docker for sandboxing or + # isolation, just for packaging our dev tools. + "--privileged" + + # Run the docker script with the user id. Because the docker image gets to + # write in ${PWD} you typically want this to be your user id. + # To allow docker in docker, we need to use docker gid on the host. + "--user" "${user_uid}:${docker_gid}" + + # Pass down the USER. + "--env" "USER=${user_name}" + + # Mount the project directory inside the Docker container. + "--volume" "${PROJECT_ROOT}:${TRAMPOLINE_WORKSPACE}" + "--workdir" "${TRAMPOLINE_WORKSPACE}" + "--env" "PROJECT_ROOT=${TRAMPOLINE_WORKSPACE}" + + # Mount the temporary home directory. + "--volume" "${tmphome}:/h" + "--env" "HOME=/h" + + # Allow docker in docker. + "--volume" "/var/run/docker.sock:/var/run/docker.sock" + + # Mount the /tmp so that docker in docker can mount the files + # there correctly. + "--volume" "/tmp:/tmp" + # Pass down the KOKORO_GFILE_DIR and KOKORO_KEYSTORE_DIR + # TODO(tmatsuo): This part is not portable. + "--env" "TRAMPOLINE_SECRET_DIR=/secrets" + "--volume" "${KOKORO_GFILE_DIR:-/dev/shm}:/secrets/gfile" + "--env" "KOKORO_GFILE_DIR=/secrets/gfile" + "--volume" "${KOKORO_KEYSTORE_DIR:-/dev/shm}:/secrets/keystore" + "--env" "KOKORO_KEYSTORE_DIR=/secrets/keystore" +) + +# Add an option for nicer output if the build gets a tty. +if [[ -t 0 ]]; then + docker_flags+=("-it") +fi + +# Passing down env vars +for e in "${pass_down_envvars[@]}" +do + if [[ -n "${!e:-}" ]]; then + docker_flags+=("--env" "${e}=${!e}") + fi +done + +# If arguments are given, all arguments will become the commands run +# in the container, otherwise run TRAMPOLINE_BUILD_FILE. +if [[ $# -ge 1 ]]; then + log_yellow "Running the given commands '" "${@:1}" "' in the container." + readonly commands=("${@:1}") + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" + fi + docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" +else + log_yellow "Running the tests in a Docker container." + docker_flags+=("--entrypoint=${TRAMPOLINE_BUILD_FILE}") + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" + fi + docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" +fi + + +test_retval=$? + +if [[ ${test_retval} -eq 0 ]]; then + log_green "Build finished with ${test_retval}" +else + log_red "Build finished with ${test_retval}" +fi + +# Only upload it when the test passes. +if [[ "${update_cache}" == "true" ]] && \ + [[ $test_retval == 0 ]] && \ + [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]]; then + log_yellow "Uploading the Docker image." + if docker push "${TRAMPOLINE_IMAGE}"; then + log_green "Finished uploading the Docker image." + else + log_red "Failed uploading the Docker image." + fi + # Call trampoline_after_upload_hook if it's defined. + if function_exists trampoline_after_upload_hook; then + trampoline_after_upload_hook + fi + +fi + +exit "${test_retval}" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..32302e4 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml +- repo: https://github.com/psf/black + rev: 19.10b0 + hooks: + - id: black +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.9.0 + hooks: + - id: flake8 diff --git a/.trampolinerc b/.trampolinerc new file mode 100644 index 0000000..383b6ec --- /dev/null +++ b/.trampolinerc @@ -0,0 +1,52 @@ +# Copyright 2020 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. + +# Template for .trampolinerc + +# Add required env vars here. +required_envvars+=( + "STAGING_BUCKET" + "V2_STAGING_BUCKET" +) + +# Add env vars which are passed down into the container here. +pass_down_envvars+=( + "STAGING_BUCKET" + "V2_STAGING_BUCKET" + "NOX_SESSION" +) + +# Prevent unintentional override on the default image. +if [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]] && \ + [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then + echo "Please set TRAMPOLINE_IMAGE if you want to upload the Docker image." + exit 1 +fi + +# Define the default value if it makes sense. +if [[ -z "${TRAMPOLINE_IMAGE_UPLOAD:-}" ]]; then + TRAMPOLINE_IMAGE_UPLOAD="" +fi + +if [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then + TRAMPOLINE_IMAGE="" +fi + +if [[ -z "${TRAMPOLINE_DOCKERFILE:-}" ]]; then + TRAMPOLINE_DOCKERFILE="" +fi + +if [[ -z "${TRAMPOLINE_BUILD_FILE:-}" ]]; then + TRAMPOLINE_BUILD_FILE="" +fi diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b3d1f60..039f436 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,44 +1,95 @@ -# Contributor Code of Conduct +# Code of Conduct -As contributors and maintainers of this project, -and in the interest of fostering an open and welcoming community, -we pledge to respect all people who contribute through reporting issues, -posting feature requests, updating documentation, -submitting pull requests or patches, and other activities. +## Our Pledge -We are committed to making participation in this project -a harassment-free experience for everyone, -regardless of level of experience, gender, gender identity and expression, -sexual orientation, disability, personal appearance, -body size, race, ethnicity, age, religion, or nationality. +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of +experience, education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments -* Public or private harassment -* Publishing other's private information, -such as physical or electronic -addresses, without explicit permission -* Other unethical or unprofessional conduct. +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct. -By adopting this Code of Conduct, -project maintainers commit themselves to fairly and consistently -applying these principles to every aspect of managing this project. -Project maintainers who do not follow or enforce the Code of Conduct -may be permanently removed from the project team. - -This code of conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. - -Instances of abusive, harassing, or otherwise unacceptable behavior -may be reported by opening an issue -or contacting one or more of the project maintainers. - -This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, -available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to ban temporarily or permanently any +contributor for other behaviors that they deem inappropriate, threatening, +offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +This Code of Conduct also applies outside the project spaces when the Project +Steward has a reasonable belief that an individual's behavior may have a +negative impact on the project or its community. + +## Conflict Resolution + +We do not believe that all conflict is bad; healthy debate and disagreement +often yield positive results. However, it is never okay to be disrespectful or +to engage in behavior that violates the project’s code of conduct. + +If you see someone violating the code of conduct, you are encouraged to address +the behavior directly with those involved. Many issues can be resolved quickly +and easily, and this gives people more control over the outcome of their +dispute. If you are unable to resolve the matter for any reason, or if the +behavior is threatening or harassing, report it. We are dedicated to providing +an environment where participants feel welcome and safe. + + +Reports should be directed to *googleapis-stewards@google.com*, the +Project Steward(s) for *Google Cloud Client Libraries*. It is the Project Steward’s duty to +receive and address reported violations of the code of conduct. They will then +work with a committee consisting of representatives from the Open Source +Programs Office and the Google Open Source Strategy team. If for any reason you +are uncomfortable reaching out to the Project Steward, please email +opensource@google.com. + +We will investigate every complaint, but you may not receive a direct response. +We will use our discretion in determining when and how to follow up on reported +incidents, which may range from not taking action to permanent expulsion from +the project and project-sponsored spaces. We will notify the accused of the +report and provide them an opportunity to discuss it before any action is taken. +The identity of the reporter will be omitted from the details of the report +supplied to the accused. In potentially harmful situations, such as ongoing +harassment or threats to anyone's safety, we may take action without notice. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 1.4, +available at +https://www.contributor-covenant.org/version/1/4/code-of-conduct.html \ No newline at end of file diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index dfef5cb..f0226dd 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -21,8 +21,8 @@ In order to add a feature: - The feature must be documented in both the API and narrative documentation. -- The feature must work fully on the following CPython versions: 2.7, - 3.5, 3.6, 3.7 and 3.8 on both UNIX and Windows. +- The feature must work fully on the following CPython versions: + 3.6, 3.7, 3.8 and 3.9 on both UNIX and Windows. - The feature must not add unnecessary dependencies (where "unnecessary" is of course subjective, but new dependencies should @@ -70,9 +70,14 @@ We use `nox `__ to instrument our tests. - To test your changes, run unit tests with ``nox``:: $ nox -s unit-2.7 - $ nox -s unit-3.7 + $ nox -s unit-3.8 $ ... +- Args to pytest can be passed through the nox command separated by a `--`. For + example, to run a single test:: + + $ nox -s unit-3.8 -- -k + .. note:: The unit tests and system tests are described in the @@ -80,25 +85,6 @@ We use `nox `__ to instrument our tests. .. nox: https://pypi.org/project/nox/ -Note on Editable Installs / Develop Mode -======================================== - -- As mentioned previously, using ``setuptools`` in `develop mode`_ - or a ``pip`` `editable install`_ is not possible with this - library. This is because this library uses `namespace packages`_. - For context see `Issue #2316`_ and the relevant `PyPA issue`_. - - Since ``editable`` / ``develop`` mode can't be used, packages - need to be installed directly. Hence your changes to the source - tree don't get incorporated into the **already installed** - package. - -.. _namespace packages: https://www.python.org/dev/peps/pep-0420/ -.. _Issue #2316: https://github.com/GoogleCloudPlatform/google-cloud-python/issues/2316 -.. _PyPA issue: https://github.com/pypa/packaging-problems/issues/12 -.. _develop mode: https://setuptools.readthedocs.io/en/latest/setuptools.html#development-mode -.. _editable install: https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs - ***************************************** I'm getting weird errors... Can you help? ***************************************** @@ -112,8 +98,12 @@ On Debian/Ubuntu:: ************ Coding Style ************ +- We use the automatic code formatter ``black``. You can run it using + the nox session ``blacken``. This will eliminate many lint errors. Run via:: -- PEP8 compliance, with exceptions defined in the linter configuration. + $ nox -s blacken + +- PEP8 compliance is required, with exceptions defined in the linter configuration. If you have ``nox`` installed, you can test that you have not introduced any non-compliant code via:: @@ -130,6 +120,16 @@ Coding Style should point to the official ``googleapis`` checkout and the the branch should be the main branch on that remote (``master``). +- This repository contains configuration for the + `pre-commit `__ tool, which automates checking + our linters during a commit. If you have it installed on your ``$PATH``, + you can enable enforcing those checks via: + +.. code-block:: bash + + $ pre-commit install + pre-commit installed at .git/hooks/pre-commit + Exceptions to PEP8: - Many unit tests use a helper method, ``_call_fut`` ("FUT" is short for @@ -142,13 +142,18 @@ Running System Tests - To run system tests, you can execute:: - $ nox -s system-3.7 + # Run all system tests + $ nox -s system-3.8 $ nox -s system-2.7 + # Run a single system test + $ nox -s system-3.8 -- -k + + .. note:: System tests are only configured to run under Python 2.7 and - Python 3.7. For expediency, we do not run them in older versions + Python 3.8. For expediency, we do not run them in older versions of Python 3. This alone will not run the tests. You'll need to change some local @@ -211,25 +216,24 @@ Supported Python Versions We support: -- `Python 3.5`_ - `Python 3.6`_ - `Python 3.7`_ - `Python 3.8`_ +- `Python 3.9`_ -.. _Python 3.5: https://docs.python.org/3.5/ .. _Python 3.6: https://docs.python.org/3.6/ .. _Python 3.7: https://docs.python.org/3.7/ .. _Python 3.8: https://docs.python.org/3.8/ +.. _Python 3.9: https://docs.python.org/3.9/ Supported versions can be found in our ``noxfile.py`` `config`_. .. _config: https://github.com/googleapis/python-websecurityscanner/blob/master/noxfile.py -Python 2.7 support is deprecated. All code changes should maintain Python 2.7 compatibility until January 1, 2020. We also explicitly decided to support Python 3 beginning with version -3.5. Reasons for this include: +3.6. Reasons for this include: - Encouraging use of newest versions of Python 3 - Taking the lead of `prominent`_ open-source `projects`_ diff --git a/LICENSE b/LICENSE index a8ee855..d645695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ - Apache License + + Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -192,7 +193,7 @@ 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 + 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, diff --git a/MANIFEST.in b/MANIFEST.in index e9e29d1..e783f4c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -16,10 +16,10 @@ # Generated by synthtool. DO NOT EDIT! include README.rst LICENSE -recursive-include google *.json *.proto +recursive-include google *.json *.proto py.typed recursive-include tests * global-exclude *.py[co] global-exclude __pycache__ # Exclude scripts for samples readmegen -prune scripts/readme-gen \ No newline at end of file +prune scripts/readme-gen diff --git a/UPGRADING.md b/UPGRADING.md index 6e56181..073ccc1 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -17,10 +17,10 @@ The 1.0.0 release requires Python 3.6+. Methods expect request objects. We provide a script that will convert most common use cases. -* Install the library +* Install the library and `libcst`. ```py -python3 -m pip install google-cloud-websecurityscanner +python3 -m pip install google-cloud-websecurityscanner libcst ``` * The script `fixup_websecurityscanner_v1alpha_keywords.py` and `fixup_websecurityscanner_v1beta_keywords.py` are shipped with the library. It expects an input directory (with the code to convert) and an empty destination directory. diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 0abaf22..bcd37bb 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,4 +1,9 @@ div#python2-eol { border-color: red; border-width: medium; -} \ No newline at end of file +} + +/* Ensure minimum width for 'Parameters' / 'Returns' column */ +dl.field-list > dt { + min-width: 100px +} diff --git a/docs/conf.py b/docs/conf.py index 78c4e74..d700207 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,12 +20,16 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath("..")) +# For plugins that can not read conf.py. +# See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85 +sys.path.insert(0, os.path.abspath(".")) + __version__ = "" # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = "1.6.3" +needs_sphinx = "1.5.5" # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -35,6 +39,7 @@ "sphinx.ext.autosummary", "sphinx.ext.intersphinx", "sphinx.ext.coverage", + "sphinx.ext.doctest", "sphinx.ext.napoleon", "sphinx.ext.todo", "sphinx.ext.viewcode", @@ -90,7 +95,12 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ["_build"] +exclude_patterns = [ + "_build", + "samples/AUTHORING_GUIDE.md", + "samples/CONTRIBUTING.md", + "samples/snippets/README.rst", +] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -335,10 +345,11 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - "python": ("http://python.readthedocs.org/en/latest/", None), - "google-auth": ("https://google-auth.readthedocs.io/en/stable", None), + "python": ("https://python.readthedocs.org/en/latest/", None), + "google-auth": ("https://googleapis.dev/python/google-auth/latest/", None), "google.api_core": ("https://googleapis.dev/python/google-api-core/latest/", None,), - "grpc": ("https://grpc.io/grpc/python/", None), + "grpc": ("https://grpc.github.io/grpc/python/", None), + "proto-plus": ("https://proto-plus-python.readthedocs.io/en/latest/", None), } diff --git a/docs/websecurityscanner_v1alpha/services.rst b/docs/websecurityscanner_v1alpha/services.rst index 338bf5a..a4ad413 100644 --- a/docs/websecurityscanner_v1alpha/services.rst +++ b/docs/websecurityscanner_v1alpha/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Websecurityscanner v1alpha API ======================================================== +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.websecurityscanner_v1alpha.services.web_security_scanner - :members: - :inherited-members: + web_security_scanner diff --git a/docs/websecurityscanner_v1alpha/types.rst b/docs/websecurityscanner_v1alpha/types.rst index a4cf71b..0f6d569 100644 --- a/docs/websecurityscanner_v1alpha/types.rst +++ b/docs/websecurityscanner_v1alpha/types.rst @@ -3,3 +3,5 @@ Types for Google Cloud Websecurityscanner v1alpha API .. automodule:: google.cloud.websecurityscanner_v1alpha.types :members: + :undoc-members: + :show-inheritance: diff --git a/docs/websecurityscanner_v1alpha/web_security_scanner.rst b/docs/websecurityscanner_v1alpha/web_security_scanner.rst new file mode 100644 index 0000000..f4ac232 --- /dev/null +++ b/docs/websecurityscanner_v1alpha/web_security_scanner.rst @@ -0,0 +1,11 @@ +WebSecurityScanner +------------------------------------ + +.. automodule:: google.cloud.websecurityscanner_v1alpha.services.web_security_scanner + :members: + :inherited-members: + + +.. automodule:: google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers + :members: + :inherited-members: diff --git a/docs/websecurityscanner_v1beta/services.rst b/docs/websecurityscanner_v1beta/services.rst index 70be826..37adbdc 100644 --- a/docs/websecurityscanner_v1beta/services.rst +++ b/docs/websecurityscanner_v1beta/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Websecurityscanner v1beta API ======================================================= +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.websecurityscanner_v1beta.services.web_security_scanner - :members: - :inherited-members: + web_security_scanner diff --git a/docs/websecurityscanner_v1beta/types.rst b/docs/websecurityscanner_v1beta/types.rst index 912ef2b..0a1ff8f 100644 --- a/docs/websecurityscanner_v1beta/types.rst +++ b/docs/websecurityscanner_v1beta/types.rst @@ -3,3 +3,5 @@ Types for Google Cloud Websecurityscanner v1beta API .. automodule:: google.cloud.websecurityscanner_v1beta.types :members: + :undoc-members: + :show-inheritance: diff --git a/docs/websecurityscanner_v1beta/web_security_scanner.rst b/docs/websecurityscanner_v1beta/web_security_scanner.rst new file mode 100644 index 0000000..ed00e33 --- /dev/null +++ b/docs/websecurityscanner_v1beta/web_security_scanner.rst @@ -0,0 +1,11 @@ +WebSecurityScanner +------------------------------------ + +.. automodule:: google.cloud.websecurityscanner_v1beta.services.web_security_scanner + :members: + :inherited-members: + + +.. automodule:: google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers + :members: + :inherited-members: diff --git a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/async_client.py b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/async_client.py index c3b628e..ae8c9d8 100644 --- a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/async_client.py +++ b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/async_client.py @@ -40,7 +40,7 @@ from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import timestamp_pb2 as timestamp # type: ignore -from .transports.base import WebSecurityScannerTransport +from .transports.base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import WebSecurityScannerGrpcAsyncIOTransport from .client import WebSecurityScannerClient @@ -57,13 +57,85 @@ class WebSecurityScannerAsyncClient: DEFAULT_ENDPOINT = WebSecurityScannerClient.DEFAULT_ENDPOINT DEFAULT_MTLS_ENDPOINT = WebSecurityScannerClient.DEFAULT_MTLS_ENDPOINT + finding_path = staticmethod(WebSecurityScannerClient.finding_path) + parse_finding_path = staticmethod(WebSecurityScannerClient.parse_finding_path) + scan_config_path = staticmethod(WebSecurityScannerClient.scan_config_path) + parse_scan_config_path = staticmethod( + WebSecurityScannerClient.parse_scan_config_path + ) scan_run_path = staticmethod(WebSecurityScannerClient.scan_run_path) + parse_scan_run_path = staticmethod(WebSecurityScannerClient.parse_scan_run_path) - scan_config_path = staticmethod(WebSecurityScannerClient.scan_config_path) + common_billing_account_path = staticmethod( + WebSecurityScannerClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + WebSecurityScannerClient.parse_common_billing_account_path + ) + + common_folder_path = staticmethod(WebSecurityScannerClient.common_folder_path) + parse_common_folder_path = staticmethod( + WebSecurityScannerClient.parse_common_folder_path + ) + + common_organization_path = staticmethod( + WebSecurityScannerClient.common_organization_path + ) + parse_common_organization_path = staticmethod( + WebSecurityScannerClient.parse_common_organization_path + ) + + common_project_path = staticmethod(WebSecurityScannerClient.common_project_path) + parse_common_project_path = staticmethod( + WebSecurityScannerClient.parse_common_project_path + ) + + common_location_path = staticmethod(WebSecurityScannerClient.common_location_path) + parse_common_location_path = staticmethod( + WebSecurityScannerClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + WebSecurityScannerAsyncClient: The constructed client. + """ + return WebSecurityScannerClient.from_service_account_info.__func__(WebSecurityScannerAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + WebSecurityScannerAsyncClient: The constructed client. + """ + return WebSecurityScannerClient.from_service_account_file.__func__(WebSecurityScannerAsyncClient, filename, *args, **kwargs) # type: ignore - from_service_account_file = WebSecurityScannerClient.from_service_account_file from_service_account_json = from_service_account_file + @property + def transport(self) -> WebSecurityScannerTransport: + """Return the transport used by the client instance. + + Returns: + WebSecurityScannerTransport: The transport used by the client instance. + """ + return self._client.transport + get_transport_class = functools.partial( type(WebSecurityScannerClient).get_transport_class, type(WebSecurityScannerClient), @@ -75,6 +147,7 @@ def __init__( credentials: credentials.Credentials = None, transport: Union[str, WebSecurityScannerTransport] = "grpc_asyncio", client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the web security scanner client. @@ -90,16 +163,19 @@ def __init__( client_options (ClientOptions): Custom options for the client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. Raises: google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport @@ -107,7 +183,10 @@ def __init__( """ self._client = WebSecurityScannerClient( - credentials=credentials, transport=transport, client_options=client_options, + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, ) async def create_scan_config( @@ -123,7 +202,7 @@ async def create_scan_config( r"""Creates a new ScanConfig. Args: - request (:class:`~.web_security_scanner.CreateScanConfigRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.CreateScanConfigRequest`): The request object. Request for the `CreateScanConfig` method. parent (:class:`str`): @@ -131,12 +210,14 @@ async def create_scan_config( where the scan is created, which should be a project resource name in the format 'projects/{projectId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - scan_config (:class:`~.gcw_scan_config.ScanConfig`): + scan_config (:class:`google.cloud.websecurityscanner_v1alpha.types.ScanConfig`): Required. The ScanConfig to be created. + This corresponds to the ``scan_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -148,7 +229,7 @@ async def create_scan_config( sent along with the request as metadata. Returns: - ~.gcw_scan_config.ScanConfig: + google.cloud.websecurityscanner_v1alpha.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. next id: 12 @@ -157,7 +238,8 @@ async def create_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent, scan_config]): + has_flattened_params = any([parent, scan_config]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -178,7 +260,7 @@ async def create_scan_config( rpc = gapic_v1.method_async.wrap_method( self._client._transport.create_scan_config, default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -206,7 +288,7 @@ async def delete_scan_config( resources. Args: - request (:class:`~.web_security_scanner.DeleteScanConfigRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.DeleteScanConfigRequest`): The request object. Request for the `DeleteScanConfig` method. name (:class:`str`): @@ -214,6 +296,7 @@ async def delete_scan_config( ScanConfig to be deleted. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -227,7 +310,8 @@ async def delete_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -252,9 +336,10 @@ async def delete_scan_config( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -280,7 +365,7 @@ async def get_scan_config( r"""Gets a ScanConfig. Args: - request (:class:`~.web_security_scanner.GetScanConfigRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.GetScanConfigRequest`): The request object. Request for the `GetScanConfig` method. name (:class:`str`): @@ -288,6 +373,7 @@ async def get_scan_config( ScanConfig to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -299,7 +385,7 @@ async def get_scan_config( sent along with the request as metadata. Returns: - ~.scan_config.ScanConfig: + google.cloud.websecurityscanner_v1alpha.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. next id: 12 @@ -308,7 +394,8 @@ async def get_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -333,9 +420,10 @@ async def get_scan_config( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -362,13 +450,14 @@ async def list_scan_configs( r"""Lists ScanConfigs under a given project. Args: - request (:class:`~.web_security_scanner.ListScanConfigsRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsRequest`): The request object. Request for the `ListScanConfigs` method. parent (:class:`str`): Required. The parent resource name, which should be a project resource name in the format 'projects/{projectId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -380,8 +469,8 @@ async def list_scan_configs( sent along with the request as metadata. Returns: - ~.pagers.ListScanConfigsAsyncPager: - Response for the ``ListScanConfigs`` method. + google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers.ListScanConfigsAsyncPager: + Response for the ListScanConfigs method. Iterating over this object will yield results and resolve additional pages automatically. @@ -390,7 +479,8 @@ async def list_scan_configs( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -415,9 +505,10 @@ async def list_scan_configs( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -452,22 +543,24 @@ async def update_scan_config( update of a ScanConfig. Args: - request (:class:`~.web_security_scanner.UpdateScanConfigRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.UpdateScanConfigRequest`): The request object. Request for the `UpdateScanConfigRequest` method. - scan_config (:class:`~.gcw_scan_config.ScanConfig`): + scan_config (:class:`google.cloud.websecurityscanner_v1alpha.types.ScanConfig`): Required. The ScanConfig to be updated. The name field must be set to identify the resource to be updated. The values of fields not covered by the mask will be ignored. + This corresponds to the ``scan_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): Required. The update mask applies to the resource. For the ``FieldMask`` definition, see https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -479,7 +572,7 @@ async def update_scan_config( sent along with the request as metadata. Returns: - ~.gcw_scan_config.ScanConfig: + google.cloud.websecurityscanner_v1alpha.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. next id: 12 @@ -488,7 +581,8 @@ async def update_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([scan_config, update_mask]): + has_flattened_params = any([scan_config, update_mask]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -509,7 +603,7 @@ async def update_scan_config( rpc = gapic_v1.method_async.wrap_method( self._client._transport.update_scan_config, default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -538,7 +632,7 @@ async def start_scan_run( r"""Start a ScanRun according to the given ScanConfig. Args: - request (:class:`~.web_security_scanner.StartScanRunRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.StartScanRunRequest`): The request object. Request for the `StartScanRun` method. name (:class:`str`): @@ -546,6 +640,7 @@ async def start_scan_run( ScanConfig to be used. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -557,7 +652,7 @@ async def start_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1alpha.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. @@ -565,7 +660,8 @@ async def start_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -584,7 +680,7 @@ async def start_scan_run( rpc = gapic_v1.method_async.wrap_method( self._client._transport.start_scan_run, default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -611,13 +707,14 @@ async def get_scan_run( r"""Gets a ScanRun. Args: - request (:class:`~.web_security_scanner.GetScanRunRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.GetScanRunRequest`): The request object. Request for the `GetScanRun` method. name (:class:`str`): Required. The resource name of the ScanRun to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -629,7 +726,7 @@ async def get_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1alpha.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. @@ -637,7 +734,8 @@ async def get_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -662,9 +760,10 @@ async def get_scan_run( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -692,7 +791,7 @@ async def list_scan_runs( descending order of ScanRun stop time. Args: - request (:class:`~.web_security_scanner.ListScanRunsRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.ListScanRunsRequest`): The request object. Request for the `ListScanRuns` method. parent (:class:`str`): @@ -700,6 +799,7 @@ async def list_scan_runs( which should be a scan resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -711,8 +811,8 @@ async def list_scan_runs( sent along with the request as metadata. Returns: - ~.pagers.ListScanRunsAsyncPager: - Response for the ``ListScanRuns`` method. + google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers.ListScanRunsAsyncPager: + Response for the ListScanRuns method. Iterating over this object will yield results and resolve additional pages automatically. @@ -721,7 +821,8 @@ async def list_scan_runs( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -746,9 +847,10 @@ async def list_scan_runs( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -781,7 +883,7 @@ async def stop_scan_run( r"""Stops a ScanRun. The stopped ScanRun is returned. Args: - request (:class:`~.web_security_scanner.StopScanRunRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.StopScanRunRequest`): The request object. Request for the `StopScanRun` method. name (:class:`str`): @@ -789,6 +891,7 @@ async def stop_scan_run( ScanRun to be stopped. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -800,7 +903,7 @@ async def stop_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1alpha.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. @@ -808,7 +911,8 @@ async def stop_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -827,7 +931,7 @@ async def stop_scan_run( rpc = gapic_v1.method_async.wrap_method( self._client._transport.stop_scan_run, default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -854,7 +958,7 @@ async def list_crawled_urls( r"""List CrawledUrls under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListCrawledUrlsRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsRequest`): The request object. Request for the `ListCrawledUrls` method. parent (:class:`str`): @@ -862,6 +966,7 @@ async def list_crawled_urls( which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -873,8 +978,8 @@ async def list_crawled_urls( sent along with the request as metadata. Returns: - ~.pagers.ListCrawledUrlsAsyncPager: - Response for the ``ListCrawledUrls`` method. + google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers.ListCrawledUrlsAsyncPager: + Response for the ListCrawledUrls method. Iterating over this object will yield results and resolve additional pages automatically. @@ -883,7 +988,8 @@ async def list_crawled_urls( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -908,9 +1014,10 @@ async def list_crawled_urls( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -943,13 +1050,14 @@ async def get_finding( r"""Gets a Finding. Args: - request (:class:`~.web_security_scanner.GetFindingRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.GetFindingRequest`): The request object. Request for the `GetFinding` method. name (:class:`str`): Required. The resource name of the Finding to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}/findings/{findingId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -961,7 +1069,7 @@ async def get_finding( sent along with the request as metadata. Returns: - ~.finding.Finding: + google.cloud.websecurityscanner_v1alpha.types.Finding: A Finding resource represents a vulnerability instance identified during a ScanRun. @@ -970,7 +1078,8 @@ async def get_finding( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -995,9 +1104,10 @@ async def get_finding( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -1025,7 +1135,7 @@ async def list_findings( r"""List Findings under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListFindingsRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.ListFindingsRequest`): The request object. Request for the `ListFindings` method. parent (:class:`str`): @@ -1033,6 +1143,7 @@ async def list_findings( which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1040,6 +1151,7 @@ async def list_findings( Required. The filter expression. The expression must be in the format: . Supported field: 'finding_type'. Supported operator: '='. + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1051,8 +1163,8 @@ async def list_findings( sent along with the request as metadata. Returns: - ~.pagers.ListFindingsAsyncPager: - Response for the ``ListFindings`` method. + google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers.ListFindingsAsyncPager: + Response for the ListFindings method. Iterating over this object will yield results and resolve additional pages automatically. @@ -1061,7 +1173,8 @@ async def list_findings( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent, filter]): + has_flattened_params = any([parent, filter]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -1088,9 +1201,10 @@ async def list_findings( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -1123,7 +1237,7 @@ async def list_finding_type_stats( r"""List all FindingTypeStats under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListFindingTypeStatsRequest`): + request (:class:`google.cloud.websecurityscanner_v1alpha.types.ListFindingTypeStatsRequest`): The request object. Request for the `ListFindingTypeStats` method. parent (:class:`str`): @@ -1131,6 +1245,7 @@ async def list_finding_type_stats( which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1142,13 +1257,14 @@ async def list_finding_type_stats( sent along with the request as metadata. Returns: - ~.web_security_scanner.ListFindingTypeStatsResponse: - Response for the ``ListFindingTypeStats`` method. + google.cloud.websecurityscanner_v1alpha.types.ListFindingTypeStatsResponse: + Response for the ListFindingTypeStats method. """ # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -1173,9 +1289,10 @@ async def list_finding_type_stats( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -1192,13 +1309,13 @@ async def list_finding_type_stats( try: - _client_info = gapic_v1.client_info.ClientInfo( + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=pkg_resources.get_distribution( "google-cloud-websecurityscanner", ).version, ) except pkg_resources.DistributionNotFound: - _client_info = gapic_v1.client_info.ClientInfo() + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() __all__ = ("WebSecurityScannerAsyncClient",) diff --git a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/client.py b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/client.py index 7674177..23c8def 100644 --- a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/client.py +++ b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/client.py @@ -16,17 +16,19 @@ # from collections import OrderedDict +from distutils import util import os import re -from typing import Callable, Dict, Sequence, Tuple, Type, Union +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources -import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import client_options as client_options_lib # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore from google.auth import credentials # type: ignore from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore @@ -42,7 +44,7 @@ from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import timestamp_pb2 as timestamp # type: ignore -from .transports.base import WebSecurityScannerTransport +from .transports.base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO from .transports.grpc import WebSecurityScannerGrpcTransport from .transports.grpc_asyncio import WebSecurityScannerGrpcAsyncIOTransport @@ -123,6 +125,22 @@ def _get_default_mtls_endpoint(api_endpoint): DEFAULT_ENDPOINT ) + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + WebSecurityScannerClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials @@ -135,7 +153,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + WebSecurityScannerClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -143,6 +161,36 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): from_service_account_json = from_service_account_file + @property + def transport(self) -> WebSecurityScannerTransport: + """Return the transport used by the client instance. + + Returns: + WebSecurityScannerTransport: The transport used by the client instance. + """ + return self._transport + + @staticmethod + def finding_path( + project: str, scan_config: str, scan_run: str, finding: str, + ) -> str: + """Return a fully-qualified finding string.""" + return "projects/{project}/scanConfigs/{scan_config}/scanRuns/{scan_run}/findings/{finding}".format( + project=project, + scan_config=scan_config, + scan_run=scan_run, + finding=finding, + ) + + @staticmethod + def parse_finding_path(path: str) -> Dict[str, str]: + """Parse a finding path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/scanConfigs/(?P.+?)/scanRuns/(?P.+?)/findings/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def scan_config_path(project: str, scan_config: str,) -> str: """Return a fully-qualified scan_config string.""" @@ -174,12 +222,72 @@ def parse_scan_run_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def common_billing_account_path(billing_account: str,) -> str: + """Return a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str,) -> str: + """Return a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder,) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str,) -> str: + """Return a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization,) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str,) -> str: + """Return a fully-qualified project string.""" + return "projects/{project}".format(project=project,) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str,) -> str: + """Return a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + def __init__( self, *, - credentials: credentials.Credentials = None, - transport: Union[str, WebSecurityScannerTransport] = None, - client_options: ClientOptions = None, + credentials: Optional[credentials.Credentials] = None, + transport: Union[str, WebSecurityScannerTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the web security scanner client. @@ -189,51 +297,73 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - transport (Union[str, ~.WebSecurityScannerTransport]): The + transport (Union[str, WebSecurityScannerTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (ClientOptions): Custom options for the client. It - won't take effect if a ``transport`` instance is provided. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. Raises: google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ if isinstance(client_options, dict): - client_options = ClientOptions.from_dict(client_options) + client_options = client_options_lib.from_dict(client_options) if client_options is None: - client_options = ClientOptions.ClientOptions() + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool( + util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + ) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) - if client_options.api_endpoint is None: - use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never") + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") if use_mtls_env == "never": - client_options.api_endpoint = self.DEFAULT_ENDPOINT + api_endpoint = self.DEFAULT_ENDPOINT elif use_mtls_env == "always": - client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT + api_endpoint = self.DEFAULT_MTLS_ENDPOINT elif use_mtls_env == "auto": - has_client_cert_source = ( - client_options.client_cert_source is not None - or mtls.has_default_client_cert_source() - ) - client_options.api_endpoint = ( - self.DEFAULT_MTLS_ENDPOINT - if has_client_cert_source - else self.DEFAULT_ENDPOINT + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT ) else: raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always" + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" ) # Save or instantiate the transport. @@ -257,11 +387,11 @@ def __init__( self._transport = Transport( credentials=credentials, credentials_file=client_options.credentials_file, - host=client_options.api_endpoint, + host=api_endpoint, scopes=client_options.scopes, - api_mtls_endpoint=client_options.api_endpoint, - client_cert_source=client_options.client_cert_source, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, + client_info=client_info, ) def create_scan_config( @@ -277,20 +407,22 @@ def create_scan_config( r"""Creates a new ScanConfig. Args: - request (:class:`~.web_security_scanner.CreateScanConfigRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.CreateScanConfigRequest): The request object. Request for the `CreateScanConfig` method. - parent (:class:`str`): + parent (str): Required. The parent resource name where the scan is created, which should be a project resource name in the format 'projects/{projectId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - scan_config (:class:`~.gcw_scan_config.ScanConfig`): + scan_config (google.cloud.websecurityscanner_v1alpha.types.ScanConfig): Required. The ScanConfig to be created. + This corresponds to the ``scan_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -302,7 +434,7 @@ def create_scan_config( sent along with the request as metadata. Returns: - ~.gcw_scan_config.ScanConfig: + google.cloud.websecurityscanner_v1alpha.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. next id: 12 @@ -311,29 +443,31 @@ def create_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent, scan_config]): + has_flattened_params = any([parent, scan_config]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.CreateScanConfigRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.CreateScanConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.CreateScanConfigRequest): + request = web_security_scanner.CreateScanConfigRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent - if scan_config is not None: - request.scan_config = scan_config + if parent is not None: + request.parent = parent + if scan_config is not None: + request.scan_config = scan_config # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.create_scan_config, - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.create_scan_config] # Certain fields should be provided within the metadata header; # add these here. @@ -360,14 +494,15 @@ def delete_scan_config( resources. Args: - request (:class:`~.web_security_scanner.DeleteScanConfigRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.DeleteScanConfigRequest): The request object. Request for the `DeleteScanConfig` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanConfig to be deleted. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -381,35 +516,29 @@ def delete_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.DeleteScanConfigRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.DeleteScanConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.DeleteScanConfigRequest): + request = web_security_scanner.DeleteScanConfigRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.delete_scan_config, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.delete_scan_config] # Certain fields should be provided within the metadata header; # add these here. @@ -434,14 +563,15 @@ def get_scan_config( r"""Gets a ScanConfig. Args: - request (:class:`~.web_security_scanner.GetScanConfigRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.GetScanConfigRequest): The request object. Request for the `GetScanConfig` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanConfig to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -453,7 +583,7 @@ def get_scan_config( sent along with the request as metadata. Returns: - ~.scan_config.ScanConfig: + google.cloud.websecurityscanner_v1alpha.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. next id: 12 @@ -462,35 +592,29 @@ def get_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.GetScanConfigRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.GetScanConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.GetScanConfigRequest): + request = web_security_scanner.GetScanConfigRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.get_scan_config, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.get_scan_config] # Certain fields should be provided within the metadata header; # add these here. @@ -516,13 +640,14 @@ def list_scan_configs( r"""Lists ScanConfigs under a given project. Args: - request (:class:`~.web_security_scanner.ListScanConfigsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsRequest): The request object. Request for the `ListScanConfigs` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a project resource name in the format 'projects/{projectId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -534,8 +659,8 @@ def list_scan_configs( sent along with the request as metadata. Returns: - ~.pagers.ListScanConfigsPager: - Response for the ``ListScanConfigs`` method. + google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers.ListScanConfigsPager: + Response for the ListScanConfigs method. Iterating over this object will yield results and resolve additional pages automatically. @@ -544,35 +669,29 @@ def list_scan_configs( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListScanConfigsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListScanConfigsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListScanConfigsRequest): + request = web_security_scanner.ListScanConfigsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent + if parent is not None: + request.parent = parent # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_scan_configs, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_scan_configs] # Certain fields should be provided within the metadata header; # add these here. @@ -606,22 +725,24 @@ def update_scan_config( update of a ScanConfig. Args: - request (:class:`~.web_security_scanner.UpdateScanConfigRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.UpdateScanConfigRequest): The request object. Request for the `UpdateScanConfigRequest` method. - scan_config (:class:`~.gcw_scan_config.ScanConfig`): + scan_config (google.cloud.websecurityscanner_v1alpha.types.ScanConfig): Required. The ScanConfig to be updated. The name field must be set to identify the resource to be updated. The values of fields not covered by the mask will be ignored. + This corresponds to the ``scan_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The update mask applies to the resource. For the ``FieldMask`` definition, see https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -633,7 +754,7 @@ def update_scan_config( sent along with the request as metadata. Returns: - ~.gcw_scan_config.ScanConfig: + google.cloud.websecurityscanner_v1alpha.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. next id: 12 @@ -642,29 +763,31 @@ def update_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([scan_config, update_mask]): + has_flattened_params = any([scan_config, update_mask]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.UpdateScanConfigRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.UpdateScanConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.UpdateScanConfigRequest): + request = web_security_scanner.UpdateScanConfigRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if scan_config is not None: - request.scan_config = scan_config - if update_mask is not None: - request.update_mask = update_mask + if scan_config is not None: + request.scan_config = scan_config + if update_mask is not None: + request.update_mask = update_mask # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.update_scan_config, - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.update_scan_config] # Certain fields should be provided within the metadata header; # add these here. @@ -692,14 +815,15 @@ def start_scan_run( r"""Start a ScanRun according to the given ScanConfig. Args: - request (:class:`~.web_security_scanner.StartScanRunRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.StartScanRunRequest): The request object. Request for the `StartScanRun` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanConfig to be used. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -711,7 +835,7 @@ def start_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1alpha.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. @@ -719,27 +843,29 @@ def start_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.StartScanRunRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.StartScanRunRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.StartScanRunRequest): + request = web_security_scanner.StartScanRunRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.start_scan_run, - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.start_scan_run] # Certain fields should be provided within the metadata header; # add these here. @@ -765,13 +891,14 @@ def get_scan_run( r"""Gets a ScanRun. Args: - request (:class:`~.web_security_scanner.GetScanRunRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.GetScanRunRequest): The request object. Request for the `GetScanRun` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanRun to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -783,7 +910,7 @@ def get_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1alpha.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. @@ -791,35 +918,29 @@ def get_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.GetScanRunRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.GetScanRunRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.GetScanRunRequest): + request = web_security_scanner.GetScanRunRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.get_scan_run, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.get_scan_run] # Certain fields should be provided within the metadata header; # add these here. @@ -846,14 +967,15 @@ def list_scan_runs( descending order of ScanRun stop time. Args: - request (:class:`~.web_security_scanner.ListScanRunsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListScanRunsRequest): The request object. Request for the `ListScanRuns` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a scan resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -865,8 +987,8 @@ def list_scan_runs( sent along with the request as metadata. Returns: - ~.pagers.ListScanRunsPager: - Response for the ``ListScanRuns`` method. + google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers.ListScanRunsPager: + Response for the ListScanRuns method. Iterating over this object will yield results and resolve additional pages automatically. @@ -875,35 +997,29 @@ def list_scan_runs( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListScanRunsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListScanRunsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListScanRunsRequest): + request = web_security_scanner.ListScanRunsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent + if parent is not None: + request.parent = parent # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_scan_runs, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_scan_runs] # Certain fields should be provided within the metadata header; # add these here. @@ -935,14 +1051,15 @@ def stop_scan_run( r"""Stops a ScanRun. The stopped ScanRun is returned. Args: - request (:class:`~.web_security_scanner.StopScanRunRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.StopScanRunRequest): The request object. Request for the `StopScanRun` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanRun to be stopped. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -954,7 +1071,7 @@ def stop_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1alpha.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. @@ -962,27 +1079,29 @@ def stop_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.StopScanRunRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.StopScanRunRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.StopScanRunRequest): + request = web_security_scanner.StopScanRunRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.stop_scan_run, - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.stop_scan_run] # Certain fields should be provided within the metadata header; # add these here. @@ -1008,14 +1127,15 @@ def list_crawled_urls( r"""List CrawledUrls under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListCrawledUrlsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsRequest): The request object. Request for the `ListCrawledUrls` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1027,8 +1147,8 @@ def list_crawled_urls( sent along with the request as metadata. Returns: - ~.pagers.ListCrawledUrlsPager: - Response for the ``ListCrawledUrls`` method. + google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers.ListCrawledUrlsPager: + Response for the ListCrawledUrls method. Iterating over this object will yield results and resolve additional pages automatically. @@ -1037,35 +1157,29 @@ def list_crawled_urls( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListCrawledUrlsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListCrawledUrlsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListCrawledUrlsRequest): + request = web_security_scanner.ListCrawledUrlsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent + if parent is not None: + request.parent = parent # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_crawled_urls, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_crawled_urls] # Certain fields should be provided within the metadata header; # add these here. @@ -1097,13 +1211,14 @@ def get_finding( r"""Gets a Finding. Args: - request (:class:`~.web_security_scanner.GetFindingRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.GetFindingRequest): The request object. Request for the `GetFinding` method. - name (:class:`str`): + name (str): Required. The resource name of the Finding to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}/findings/{findingId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1115,7 +1230,7 @@ def get_finding( sent along with the request as metadata. Returns: - ~.finding.Finding: + google.cloud.websecurityscanner_v1alpha.types.Finding: A Finding resource represents a vulnerability instance identified during a ScanRun. @@ -1124,35 +1239,29 @@ def get_finding( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.GetFindingRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.GetFindingRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.GetFindingRequest): + request = web_security_scanner.GetFindingRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.get_finding, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.get_finding] # Certain fields should be provided within the metadata header; # add these here. @@ -1179,21 +1288,23 @@ def list_findings( r"""List Findings under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListFindingsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListFindingsRequest): The request object. Request for the `ListFindings` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - filter (:class:`str`): + filter (str): Required. The filter expression. The expression must be in the format: . Supported field: 'finding_type'. Supported operator: '='. + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1205,8 +1316,8 @@ def list_findings( sent along with the request as metadata. Returns: - ~.pagers.ListFindingsPager: - Response for the ``ListFindings`` method. + google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.pagers.ListFindingsPager: + Response for the ListFindings method. Iterating over this object will yield results and resolve additional pages automatically. @@ -1215,37 +1326,31 @@ def list_findings( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent, filter]): + has_flattened_params = any([parent, filter]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListFindingsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListFindingsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListFindingsRequest): + request = web_security_scanner.ListFindingsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent - if filter is not None: - request.filter = filter + if parent is not None: + request.parent = parent + if filter is not None: + request.filter = filter # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_findings, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_findings] # Certain fields should be provided within the metadata header; # add these here. @@ -1277,14 +1382,15 @@ def list_finding_type_stats( r"""List all FindingTypeStats under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListFindingTypeStatsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListFindingTypeStatsRequest): The request object. Request for the `ListFindingTypeStats` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1296,41 +1402,35 @@ def list_finding_type_stats( sent along with the request as metadata. Returns: - ~.web_security_scanner.ListFindingTypeStatsResponse: - Response for the ``ListFindingTypeStats`` method. + google.cloud.websecurityscanner_v1alpha.types.ListFindingTypeStatsResponse: + Response for the ListFindingTypeStats method. """ # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListFindingTypeStatsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListFindingTypeStatsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListFindingTypeStatsRequest): + request = web_security_scanner.ListFindingTypeStatsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent + if parent is not None: + request.parent = parent # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_finding_type_stats, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_finding_type_stats] # Certain fields should be provided within the metadata header; # add these here. @@ -1346,13 +1446,13 @@ def list_finding_type_stats( try: - _client_info = gapic_v1.client_info.ClientInfo( + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=pkg_resources.get_distribution( "google-cloud-websecurityscanner", ).version, ) except pkg_resources.DistributionNotFound: - _client_info = gapic_v1.client_info.ClientInfo() + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() __all__ = ("WebSecurityScannerClient",) diff --git a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/pagers.py b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/pagers.py index ab4cd2b..4b1fa68 100644 --- a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/pagers.py +++ b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.websecurityscanner_v1alpha.types import crawled_url from google.cloud.websecurityscanner_v1alpha.types import finding @@ -28,7 +37,7 @@ class ListScanConfigsPager: """A pager for iterating through ``list_scan_configs`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListScanConfigsResponse` object, and + :class:`google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsResponse` object, and provides an ``__iter__`` method to iterate through its ``scan_configs`` field. @@ -37,7 +46,7 @@ class ListScanConfigsPager: through the ``scan_configs`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListScanConfigsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -55,9 +64,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListScanConfigsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListScanConfigsResponse`): + response (google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -90,7 +99,7 @@ class ListScanConfigsAsyncPager: """A pager for iterating through ``list_scan_configs`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListScanConfigsResponse` object, and + :class:`google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsResponse` object, and provides an ``__aiter__`` method to iterate through its ``scan_configs`` field. @@ -99,7 +108,7 @@ class ListScanConfigsAsyncPager: through the ``scan_configs`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListScanConfigsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -117,9 +126,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListScanConfigsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListScanConfigsResponse`): + response (google.cloud.websecurityscanner_v1alpha.types.ListScanConfigsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -158,7 +167,7 @@ class ListScanRunsPager: """A pager for iterating through ``list_scan_runs`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListScanRunsResponse` object, and + :class:`google.cloud.websecurityscanner_v1alpha.types.ListScanRunsResponse` object, and provides an ``__iter__`` method to iterate through its ``scan_runs`` field. @@ -167,7 +176,7 @@ class ListScanRunsPager: through the ``scan_runs`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListScanRunsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1alpha.types.ListScanRunsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -185,9 +194,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListScanRunsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListScanRunsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListScanRunsResponse`): + response (google.cloud.websecurityscanner_v1alpha.types.ListScanRunsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -220,7 +229,7 @@ class ListScanRunsAsyncPager: """A pager for iterating through ``list_scan_runs`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListScanRunsResponse` object, and + :class:`google.cloud.websecurityscanner_v1alpha.types.ListScanRunsResponse` object, and provides an ``__aiter__`` method to iterate through its ``scan_runs`` field. @@ -229,7 +238,7 @@ class ListScanRunsAsyncPager: through the ``scan_runs`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListScanRunsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1alpha.types.ListScanRunsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -247,9 +256,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListScanRunsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListScanRunsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListScanRunsResponse`): + response (google.cloud.websecurityscanner_v1alpha.types.ListScanRunsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -286,7 +295,7 @@ class ListCrawledUrlsPager: """A pager for iterating through ``list_crawled_urls`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListCrawledUrlsResponse` object, and + :class:`google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsResponse` object, and provides an ``__iter__`` method to iterate through its ``crawled_urls`` field. @@ -295,7 +304,7 @@ class ListCrawledUrlsPager: through the ``crawled_urls`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListCrawledUrlsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -313,9 +322,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListCrawledUrlsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListCrawledUrlsResponse`): + response (google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -348,7 +357,7 @@ class ListCrawledUrlsAsyncPager: """A pager for iterating through ``list_crawled_urls`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListCrawledUrlsResponse` object, and + :class:`google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsResponse` object, and provides an ``__aiter__`` method to iterate through its ``crawled_urls`` field. @@ -357,7 +366,7 @@ class ListCrawledUrlsAsyncPager: through the ``crawled_urls`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListCrawledUrlsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -375,9 +384,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListCrawledUrlsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListCrawledUrlsResponse`): + response (google.cloud.websecurityscanner_v1alpha.types.ListCrawledUrlsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -416,7 +425,7 @@ class ListFindingsPager: """A pager for iterating through ``list_findings`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListFindingsResponse` object, and + :class:`google.cloud.websecurityscanner_v1alpha.types.ListFindingsResponse` object, and provides an ``__iter__`` method to iterate through its ``findings`` field. @@ -425,7 +434,7 @@ class ListFindingsPager: through the ``findings`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListFindingsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1alpha.types.ListFindingsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -443,9 +452,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListFindingsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListFindingsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListFindingsResponse`): + response (google.cloud.websecurityscanner_v1alpha.types.ListFindingsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -478,7 +487,7 @@ class ListFindingsAsyncPager: """A pager for iterating through ``list_findings`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListFindingsResponse` object, and + :class:`google.cloud.websecurityscanner_v1alpha.types.ListFindingsResponse` object, and provides an ``__aiter__`` method to iterate through its ``findings`` field. @@ -487,7 +496,7 @@ class ListFindingsAsyncPager: through the ``findings`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListFindingsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1alpha.types.ListFindingsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -505,9 +514,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListFindingsRequest`): + request (google.cloud.websecurityscanner_v1alpha.types.ListFindingsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListFindingsResponse`): + response (google.cloud.websecurityscanner_v1alpha.types.ListFindingsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/__init__.py b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/__init__.py index 788b2b3..caf0502 100644 --- a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/__init__.py +++ b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/__init__.py @@ -30,7 +30,6 @@ _transport_registry["grpc"] = WebSecurityScannerGrpcTransport _transport_registry["grpc_asyncio"] = WebSecurityScannerGrpcAsyncIOTransport - __all__ = ( "WebSecurityScannerTransport", "WebSecurityScannerGrpcTransport", diff --git a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/base.py b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/base.py index b7c0460..888581d 100644 --- a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/base.py +++ b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/base.py @@ -17,9 +17,12 @@ import abc import typing +import pkg_resources -from google import auth +from google import auth # type: ignore from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore from google.auth import credentials # type: ignore from google.cloud.websecurityscanner_v1alpha.types import finding @@ -30,6 +33,16 @@ from google.protobuf import empty_pb2 as empty # type: ignore +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-websecurityscanner", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + class WebSecurityScannerTransport(abc.ABC): """Abstract transport class for WebSecurityScanner.""" @@ -43,6 +56,7 @@ def __init__( credentials_file: typing.Optional[str] = None, scopes: typing.Optional[typing.Sequence[str]] = AUTH_SCOPES, quota_project_id: typing.Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, **kwargs, ) -> None: """Instantiate the transport. @@ -60,12 +74,20 @@ def __init__( scope (Optional[Sequence[str]]): A list of scopes. quota_project_id (Optional[str]): An optional project to use for billing and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. if ":" not in host: host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -75,17 +97,160 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.create_scan_config: gapic_v1.method.wrap_method( + self.create_scan_config, default_timeout=600.0, client_info=client_info, + ), + self.delete_scan_config: gapic_v1.method.wrap_method( + self.delete_scan_config, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.get_scan_config: gapic_v1.method.wrap_method( + self.get_scan_config, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_scan_configs: gapic_v1.method.wrap_method( + self.list_scan_configs, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.update_scan_config: gapic_v1.method.wrap_method( + self.update_scan_config, default_timeout=600.0, client_info=client_info, + ), + self.start_scan_run: gapic_v1.method.wrap_method( + self.start_scan_run, default_timeout=600.0, client_info=client_info, + ), + self.get_scan_run: gapic_v1.method.wrap_method( + self.get_scan_run, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_scan_runs: gapic_v1.method.wrap_method( + self.list_scan_runs, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.stop_scan_run: gapic_v1.method.wrap_method( + self.stop_scan_run, default_timeout=600.0, client_info=client_info, + ), + self.list_crawled_urls: gapic_v1.method.wrap_method( + self.list_crawled_urls, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.get_finding: gapic_v1.method.wrap_method( + self.get_finding, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_findings: gapic_v1.method.wrap_method( + self.list_findings, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_finding_type_stats: gapic_v1.method.wrap_method( + self.list_finding_type_stats, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + } + @property def create_scan_config( self, diff --git a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/grpc.py b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/grpc.py index 9b9d989..590745c 100644 --- a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/grpc.py +++ b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/grpc.py @@ -15,14 +15,15 @@ # limitations under the License. # +import warnings from typing import Callable, Dict, Optional, Sequence, Tuple from google.api_core import grpc_helpers # type: ignore +from google.api_core import gapic_v1 # type: ignore from google import auth # type: ignore from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - import grpc # type: ignore from google.cloud.websecurityscanner_v1alpha.types import finding @@ -32,7 +33,7 @@ from google.cloud.websecurityscanner_v1alpha.types import web_security_scanner from google.protobuf import empty_pb2 as empty # type: ignore -from .base import WebSecurityScannerTransport +from .base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO class WebSecurityScannerGrpcTransport(WebSecurityScannerTransport): @@ -63,7 +64,10 @@ def __init__( channel: grpc.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, - quota_project_id: Optional[str] = None + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the transport. @@ -82,16 +86,27 @@ def __init__( ignored if ``channel`` is provided. channel (Optional[grpc.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. Raises: google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport @@ -99,55 +114,69 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel - elif api_mtls_endpoint: - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - # Run the base constructor. + # The base transport sets the host, credentials and scopes super().__init__( host=host, credentials=credentials, credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, + scopes=scopes, quota_project_id=quota_project_id, + client_info=client_info, ) - self._stubs = {} # type: Dict[str, Callable] + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -157,11 +186,11 @@ def create_channel( credentials_file: str = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, - **kwargs + **kwargs, ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optionsl[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If @@ -191,24 +220,13 @@ def create_channel( credentials_file=credentials_file, scopes=scopes, quota_project_id=quota_project_id, - **kwargs + **kwargs, ) @property def grpc_channel(self) -> grpc.Channel: - """Create the channel designed to connect to this service. - - This property caches on the instance; repeated calls return - the same channel. + """Return the channel designed to connect to this service. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - - # Return the channel from cache. return self._grpc_channel @property diff --git a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/grpc_asyncio.py b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/grpc_asyncio.py index d08441d..790f807 100644 --- a/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/grpc_asyncio.py +++ b/google/cloud/websecurityscanner_v1alpha/services/web_security_scanner/transports/grpc_asyncio.py @@ -15,9 +15,12 @@ # limitations under the License. # +import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple +from google.api_core import gapic_v1 # type: ignore from google.api_core import grpc_helpers_async # type: ignore +from google import auth # type: ignore from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore @@ -31,7 +34,7 @@ from google.cloud.websecurityscanner_v1alpha.types import web_security_scanner from google.protobuf import empty_pb2 as empty # type: ignore -from .base import WebSecurityScannerTransport +from .base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO from .grpc import WebSecurityScannerGrpcTransport @@ -66,7 +69,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If @@ -105,7 +108,10 @@ def __init__( channel: aio.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the transport. @@ -125,16 +131,27 @@ def __init__( are passed to :func:`google.auth.default`. channel (Optional[aio.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. Raises: google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport @@ -142,50 +159,69 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel - elif api_mtls_endpoint: - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - # Run the base constructor. + # The base transport sets the host, credentials and scopes super().__init__( host=host, credentials=credentials, credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, + scopes=scopes, quota_project_id=quota_project_id, + client_info=client_info, ) - self._stubs = {} + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: @@ -194,13 +230,6 @@ def grpc_channel(self) -> aio.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/websecurityscanner_v1alpha/types/__init__.py b/google/cloud/websecurityscanner_v1alpha/types/__init__.py index 747bf33..987723d 100644 --- a/google/cloud/websecurityscanner_v1alpha/types/__init__.py +++ b/google/cloud/websecurityscanner_v1alpha/types/__init__.py @@ -16,66 +16,65 @@ # from .crawled_url import CrawledUrl +from .finding import Finding from .finding_addon import ( OutdatedLibrary, ViolatingResource, - VulnerableParameters, VulnerableHeaders, + VulnerableParameters, Xss, ) -from .finding import Finding from .finding_type_stats import FindingTypeStats -from .scan_run import ScanRun from .scan_config import ScanConfig +from .scan_run import ScanRun from .web_security_scanner import ( CreateScanConfigRequest, DeleteScanConfigRequest, + GetFindingRequest, GetScanConfigRequest, - ListScanConfigsRequest, - UpdateScanConfigRequest, - ListScanConfigsResponse, - StartScanRunRequest, GetScanRunRequest, - ListScanRunsRequest, - ListScanRunsResponse, - StopScanRunRequest, ListCrawledUrlsRequest, ListCrawledUrlsResponse, - GetFindingRequest, ListFindingsRequest, ListFindingsResponse, ListFindingTypeStatsRequest, ListFindingTypeStatsResponse, + ListScanConfigsRequest, + ListScanConfigsResponse, + ListScanRunsRequest, + ListScanRunsResponse, + StartScanRunRequest, + StopScanRunRequest, + UpdateScanConfigRequest, ) - __all__ = ( "CrawledUrl", + "Finding", "OutdatedLibrary", "ViolatingResource", - "VulnerableParameters", "VulnerableHeaders", + "VulnerableParameters", "Xss", - "Finding", "FindingTypeStats", - "ScanRun", "ScanConfig", + "ScanRun", "CreateScanConfigRequest", "DeleteScanConfigRequest", + "GetFindingRequest", "GetScanConfigRequest", - "ListScanConfigsRequest", - "UpdateScanConfigRequest", - "ListScanConfigsResponse", - "StartScanRunRequest", "GetScanRunRequest", - "ListScanRunsRequest", - "ListScanRunsResponse", - "StopScanRunRequest", "ListCrawledUrlsRequest", "ListCrawledUrlsResponse", - "GetFindingRequest", "ListFindingsRequest", "ListFindingsResponse", "ListFindingTypeStatsRequest", "ListFindingTypeStatsResponse", + "ListScanConfigsRequest", + "ListScanConfigsResponse", + "ListScanRunsRequest", + "ListScanRunsResponse", + "StartScanRunRequest", + "StopScanRunRequest", + "UpdateScanConfigRequest", ) diff --git a/google/cloud/websecurityscanner_v1alpha/types/finding.py b/google/cloud/websecurityscanner_v1alpha/types/finding.py index 8fb31b0..1f3c597 100644 --- a/google/cloud/websecurityscanner_v1alpha/types/finding.py +++ b/google/cloud/websecurityscanner_v1alpha/types/finding.py @@ -36,7 +36,7 @@ class Finding(proto.Message): follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanruns/{scanRunId}/findings/{findingId}'. The finding IDs are generated by the system. - finding_type (~.finding.Finding.FindingType): + finding_type (google.cloud.websecurityscanner_v1alpha.types.Finding.FindingType): The type of the Finding. http_method (str): The http method of the request that triggered @@ -64,21 +64,21 @@ class Finding(proto.Message): tracking_id (str): The tracking ID uniquely identifies a vulnerability instance across multiple ScanRuns. - outdated_library (~.finding_addon.OutdatedLibrary): + outdated_library (google.cloud.websecurityscanner_v1alpha.types.OutdatedLibrary): An addon containing information about outdated libraries. - violating_resource (~.finding_addon.ViolatingResource): + violating_resource (google.cloud.websecurityscanner_v1alpha.types.ViolatingResource): An addon containing detailed information regarding any resource causing the vulnerability such as JavaScript sources, image, audio files, etc. - vulnerable_headers (~.finding_addon.VulnerableHeaders): + vulnerable_headers (google.cloud.websecurityscanner_v1alpha.types.VulnerableHeaders): An addon containing information about vulnerable or missing HTTP headers. - vulnerable_parameters (~.finding_addon.VulnerableParameters): + vulnerable_parameters (google.cloud.websecurityscanner_v1alpha.types.VulnerableParameters): An addon containing information about request parameters which were found to be vulnerable. - xss (~.finding_addon.Xss): + xss (google.cloud.websecurityscanner_v1alpha.types.Xss): An addon containing information reported for an XSS, if any. """ diff --git a/google/cloud/websecurityscanner_v1alpha/types/finding_addon.py b/google/cloud/websecurityscanner_v1alpha/types/finding_addon.py index 4a0731c..254e73e 100644 --- a/google/cloud/websecurityscanner_v1alpha/types/finding_addon.py +++ b/google/cloud/websecurityscanner_v1alpha/types/finding_addon.py @@ -81,9 +81,9 @@ class VulnerableHeaders(proto.Message): r"""Information about vulnerable or missing HTTP Headers. Attributes: - headers (Sequence[~.finding_addon.VulnerableHeaders.Header]): + headers (Sequence[google.cloud.websecurityscanner_v1alpha.types.VulnerableHeaders.Header]): List of vulnerable headers. - missing_headers (Sequence[~.finding_addon.VulnerableHeaders.Header]): + missing_headers (Sequence[google.cloud.websecurityscanner_v1alpha.types.VulnerableHeaders.Header]): List of missing headers. """ diff --git a/google/cloud/websecurityscanner_v1alpha/types/finding_type_stats.py b/google/cloud/websecurityscanner_v1alpha/types/finding_type_stats.py index f60eb38..6b4c336 100644 --- a/google/cloud/websecurityscanner_v1alpha/types/finding_type_stats.py +++ b/google/cloud/websecurityscanner_v1alpha/types/finding_type_stats.py @@ -31,7 +31,7 @@ class FindingTypeStats(proto.Message): specific FindingType of Findings under a given ScanRun. Attributes: - finding_type (~.finding.Finding.FindingType): + finding_type (google.cloud.websecurityscanner_v1alpha.types.Finding.FindingType): The finding type associated with the stats. finding_count (int): The count of findings belonging to this diff --git a/google/cloud/websecurityscanner_v1alpha/types/scan_config.py b/google/cloud/websecurityscanner_v1alpha/types/scan_config.py index c55cd87..64315a5 100644 --- a/google/cloud/websecurityscanner_v1alpha/types/scan_config.py +++ b/google/cloud/websecurityscanner_v1alpha/types/scan_config.py @@ -48,22 +48,22 @@ class ScanConfig(proto.Message): starting_urls (Sequence[str]): Required. The starting URLs from which the scanner finds site pages. - authentication (~.scan_config.ScanConfig.Authentication): + authentication (google.cloud.websecurityscanner_v1alpha.types.ScanConfig.Authentication): The authentication configuration. If specified, service will use the authentication configuration during scanning. - user_agent (~.scan_config.ScanConfig.UserAgent): + user_agent (google.cloud.websecurityscanner_v1alpha.types.ScanConfig.UserAgent): The user agent used during scanning. blacklist_patterns (Sequence[str]): The blacklist URL patterns as described in https://cloud.google.com/security- scanner/docs/excluded-urls - schedule (~.scan_config.ScanConfig.Schedule): + schedule (google.cloud.websecurityscanner_v1alpha.types.ScanConfig.Schedule): The schedule of the ScanConfig. - target_platforms (Sequence[~.scan_config.ScanConfig.TargetPlatform]): + target_platforms (Sequence[google.cloud.websecurityscanner_v1alpha.types.ScanConfig.TargetPlatform]): Set of Cloud Platforms targeted by the scan. If empty, APP_ENGINE will be used as a default. - latest_run (~.scan_run.ScanRun): + latest_run (google.cloud.websecurityscanner_v1alpha.types.ScanRun): Latest ScanRun if available. """ @@ -84,9 +84,9 @@ class Authentication(proto.Message): r"""Scan authentication configuration. Attributes: - google_account (~.scan_config.ScanConfig.Authentication.GoogleAccount): + google_account (google.cloud.websecurityscanner_v1alpha.types.ScanConfig.Authentication.GoogleAccount): Authentication using a Google account. - custom_account (~.scan_config.ScanConfig.Authentication.CustomAccount): + custom_account (google.cloud.websecurityscanner_v1alpha.types.ScanConfig.Authentication.CustomAccount): Authentication using a custom account. """ @@ -150,7 +150,7 @@ class Schedule(proto.Message): r"""Scan schedule configuration. Attributes: - schedule_time (~.timestamp.Timestamp): + schedule_time (google.protobuf.timestamp_pb2.Timestamp): A timestamp indicates when the next run will be scheduled. The value is refreshed by the server after each run. If unspecified, it will diff --git a/google/cloud/websecurityscanner_v1alpha/types/scan_run.py b/google/cloud/websecurityscanner_v1alpha/types/scan_run.py index 6739d8b..fac0c85 100644 --- a/google/cloud/websecurityscanner_v1alpha/types/scan_run.py +++ b/google/cloud/websecurityscanner_v1alpha/types/scan_run.py @@ -36,15 +36,15 @@ class ScanRun(proto.Message): follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. The ScanRun IDs are generated by the system. - execution_state (~.scan_run.ScanRun.ExecutionState): + execution_state (google.cloud.websecurityscanner_v1alpha.types.ScanRun.ExecutionState): The execution state of the ScanRun. - result_state (~.scan_run.ScanRun.ResultState): + result_state (google.cloud.websecurityscanner_v1alpha.types.ScanRun.ResultState): The result state of the ScanRun. This field is only available after the execution state reaches "FINISHED". - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): The time at which the ScanRun started. - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): The time at which the ScanRun reached termination state - that the ScanRun is either finished or stopped by user. diff --git a/google/cloud/websecurityscanner_v1alpha/types/web_security_scanner.py b/google/cloud/websecurityscanner_v1alpha/types/web_security_scanner.py index ec2c7dd..f898e05 100644 --- a/google/cloud/websecurityscanner_v1alpha/types/web_security_scanner.py +++ b/google/cloud/websecurityscanner_v1alpha/types/web_security_scanner.py @@ -62,7 +62,7 @@ class CreateScanConfigRequest(proto.Message): scan is created, which should be a project resource name in the format 'projects/{projectId}'. - scan_config (~.gcw_scan_config.ScanConfig): + scan_config (google.cloud.websecurityscanner_v1alpha.types.ScanConfig): Required. The ScanConfig to be created. """ @@ -130,12 +130,12 @@ class UpdateScanConfigRequest(proto.Message): r"""Request for the ``UpdateScanConfigRequest`` method. Attributes: - scan_config (~.gcw_scan_config.ScanConfig): + scan_config (google.cloud.websecurityscanner_v1alpha.types.ScanConfig): Required. The ScanConfig to be updated. The name field must be set to identify the resource to be updated. The values of fields not covered by the mask will be ignored. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The update mask applies to the resource. For the ``FieldMask`` definition, see https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask @@ -152,7 +152,7 @@ class ListScanConfigsResponse(proto.Message): r"""Response for the ``ListScanConfigs`` method. Attributes: - scan_configs (Sequence[~.gcw_scan_config.ScanConfig]): + scan_configs (Sequence[google.cloud.websecurityscanner_v1alpha.types.ScanConfig]): The list of ScanConfigs returned. next_page_token (str): Token to retrieve the next page of results, @@ -228,7 +228,7 @@ class ListScanRunsResponse(proto.Message): r"""Response for the ``ListScanRuns`` method. Attributes: - scan_runs (Sequence[~.scan_run.ScanRun]): + scan_runs (Sequence[google.cloud.websecurityscanner_v1alpha.types.ScanRun]): The list of ScanRuns returned. next_page_token (str): Token to retrieve the next page of results, @@ -289,7 +289,7 @@ class ListCrawledUrlsResponse(proto.Message): r"""Response for the ``ListCrawledUrls`` method. Attributes: - crawled_urls (Sequence[~.crawled_url.CrawledUrl]): + crawled_urls (Sequence[google.cloud.websecurityscanner_v1alpha.types.CrawledUrl]): The list of CrawledUrls returned. next_page_token (str): Token to retrieve the next page of results, @@ -358,7 +358,7 @@ class ListFindingsResponse(proto.Message): r"""Response for the ``ListFindings`` method. Attributes: - findings (Sequence[~.finding.Finding]): + findings (Sequence[google.cloud.websecurityscanner_v1alpha.types.Finding]): The list of Findings returned. next_page_token (str): Token to retrieve the next page of results, @@ -392,7 +392,7 @@ class ListFindingTypeStatsResponse(proto.Message): r"""Response for the ``ListFindingTypeStats`` method. Attributes: - finding_type_stats (Sequence[~.gcw_finding_type_stats.FindingTypeStats]): + finding_type_stats (Sequence[google.cloud.websecurityscanner_v1alpha.types.FindingTypeStats]): The list of FindingTypeStats returned. """ diff --git a/google/cloud/websecurityscanner_v1beta/proto/crawled_url.proto b/google/cloud/websecurityscanner_v1beta/proto/crawled_url.proto index 9316f8b..cbfead4 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/crawled_url.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/crawled_url.proto @@ -17,11 +17,13 @@ syntax = "proto3"; package google.cloud.websecurityscanner.v1beta; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "CrawledUrlProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // A CrawledUrl resource represents a URL that was crawled during a ScanRun. Web // Security Scanner Service crawls the web applications, following all links diff --git a/google/cloud/websecurityscanner_v1beta/proto/finding.proto b/google/cloud/websecurityscanner_v1beta/proto/finding.proto index 5f86c9c..999e092 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/finding.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/finding.proto @@ -20,11 +20,13 @@ package google.cloud.websecurityscanner.v1beta; import "google/api/resource.proto"; import "google/cloud/websecurityscanner/v1beta/finding_addon.proto"; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "FindingProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // A Finding resource represents a vulnerability instance identified during a // ScanRun. diff --git a/google/cloud/websecurityscanner_v1beta/proto/finding_addon.proto b/google/cloud/websecurityscanner_v1beta/proto/finding_addon.proto index ea5989a..c29f6ca 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/finding_addon.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/finding_addon.proto @@ -17,11 +17,13 @@ syntax = "proto3"; package google.cloud.websecurityscanner.v1beta; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "FindingAddonProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // ! Information about a vulnerability with an HTML. message Form { diff --git a/google/cloud/websecurityscanner_v1beta/proto/finding_type_stats.proto b/google/cloud/websecurityscanner_v1beta/proto/finding_type_stats.proto index 97f4882..9b21576 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/finding_type_stats.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/finding_type_stats.proto @@ -17,11 +17,13 @@ syntax = "proto3"; package google.cloud.websecurityscanner.v1beta; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "FindingTypeStatsProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // A FindingTypeStats resource represents stats regarding a specific FindingType // of Findings under a given ScanRun. diff --git a/google/cloud/websecurityscanner_v1beta/proto/scan_config.proto b/google/cloud/websecurityscanner_v1beta/proto/scan_config.proto index c2b7dcb..b25c619 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/scan_config.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/scan_config.proto @@ -22,11 +22,13 @@ import "google/api/resource.proto"; import "google/cloud/websecurityscanner/v1beta/scan_run.proto"; import "google/protobuf/timestamp.proto"; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "ScanConfigProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // A ScanConfig resource contains the configurations to launch a scan. message ScanConfig { diff --git a/google/cloud/websecurityscanner_v1beta/proto/scan_config_error.proto b/google/cloud/websecurityscanner_v1beta/proto/scan_config_error.proto index a50bdca..3920b74 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/scan_config_error.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/scan_config_error.proto @@ -17,11 +17,13 @@ syntax = "proto3"; package google.cloud.websecurityscanner.v1beta; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "ScanConfigErrorProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // Defines a custom error message used by CreateScanConfig and UpdateScanConfig // APIs when scan configuration validation fails. It is also reported as part of diff --git a/google/cloud/websecurityscanner_v1beta/proto/scan_run.proto b/google/cloud/websecurityscanner_v1beta/proto/scan_run.proto index 84564c6..48800d2 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/scan_run.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/scan_run.proto @@ -22,11 +22,13 @@ import "google/cloud/websecurityscanner/v1beta/scan_run_error_trace.proto"; import "google/cloud/websecurityscanner/v1beta/scan_run_warning_trace.proto"; import "google/protobuf/timestamp.proto"; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "ScanRunProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // A ScanRun is a output-only resource representing an actual run of the scan. // Next id: 12 diff --git a/google/cloud/websecurityscanner_v1beta/proto/scan_run_error_trace.proto b/google/cloud/websecurityscanner_v1beta/proto/scan_run_error_trace.proto index 248967d..acbdef2 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/scan_run_error_trace.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/scan_run_error_trace.proto @@ -19,11 +19,13 @@ package google.cloud.websecurityscanner.v1beta; import "google/cloud/websecurityscanner/v1beta/scan_config_error.proto"; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "ScanRunErrorTraceProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // Output only. // Defines an error trace message for a ScanRun. diff --git a/google/cloud/websecurityscanner_v1beta/proto/scan_run_warning_trace.proto b/google/cloud/websecurityscanner_v1beta/proto/scan_run_warning_trace.proto index 8207a02..6ee6b34 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/scan_run_warning_trace.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/scan_run_warning_trace.proto @@ -17,11 +17,13 @@ syntax = "proto3"; package google.cloud.websecurityscanner.v1beta; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "ScanRunWarningTraceProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // Output only. // Defines a warning trace message for ScanRun. Warning traces provide customers diff --git a/google/cloud/websecurityscanner_v1beta/proto/web_security_scanner.proto b/google/cloud/websecurityscanner_v1beta/proto/web_security_scanner.proto index 9ea6207..79be175 100644 --- a/google/cloud/websecurityscanner_v1beta/proto/web_security_scanner.proto +++ b/google/cloud/websecurityscanner_v1beta/proto/web_security_scanner.proto @@ -29,11 +29,13 @@ import "google/cloud/websecurityscanner/v1beta/scan_run.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/field_mask.proto"; +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1Beta"; option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1beta;websecurityscanner"; option java_multiple_files = true; option java_outer_classname = "WebSecurityScannerProto"; option java_package = "com.google.cloud.websecurityscanner.v1beta"; option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1beta"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1beta"; // Cloud Web Security Scanner Service identifies security vulnerabilities in web // applications hosted on Google Cloud Platform. It crawls your application, and diff --git a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/async_client.py b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/async_client.py index 9f2250b..fe720d7 100644 --- a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/async_client.py +++ b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/async_client.py @@ -42,7 +42,7 @@ from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import timestamp_pb2 as timestamp # type: ignore -from .transports.base import WebSecurityScannerTransport +from .transports.base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import WebSecurityScannerGrpcAsyncIOTransport from .client import WebSecurityScannerClient @@ -59,13 +59,85 @@ class WebSecurityScannerAsyncClient: DEFAULT_ENDPOINT = WebSecurityScannerClient.DEFAULT_ENDPOINT DEFAULT_MTLS_ENDPOINT = WebSecurityScannerClient.DEFAULT_MTLS_ENDPOINT + finding_path = staticmethod(WebSecurityScannerClient.finding_path) + parse_finding_path = staticmethod(WebSecurityScannerClient.parse_finding_path) scan_config_path = staticmethod(WebSecurityScannerClient.scan_config_path) - + parse_scan_config_path = staticmethod( + WebSecurityScannerClient.parse_scan_config_path + ) scan_run_path = staticmethod(WebSecurityScannerClient.scan_run_path) + parse_scan_run_path = staticmethod(WebSecurityScannerClient.parse_scan_run_path) + + common_billing_account_path = staticmethod( + WebSecurityScannerClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + WebSecurityScannerClient.parse_common_billing_account_path + ) + + common_folder_path = staticmethod(WebSecurityScannerClient.common_folder_path) + parse_common_folder_path = staticmethod( + WebSecurityScannerClient.parse_common_folder_path + ) + + common_organization_path = staticmethod( + WebSecurityScannerClient.common_organization_path + ) + parse_common_organization_path = staticmethod( + WebSecurityScannerClient.parse_common_organization_path + ) + + common_project_path = staticmethod(WebSecurityScannerClient.common_project_path) + parse_common_project_path = staticmethod( + WebSecurityScannerClient.parse_common_project_path + ) + + common_location_path = staticmethod(WebSecurityScannerClient.common_location_path) + parse_common_location_path = staticmethod( + WebSecurityScannerClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + WebSecurityScannerAsyncClient: The constructed client. + """ + return WebSecurityScannerClient.from_service_account_info.__func__(WebSecurityScannerAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + WebSecurityScannerAsyncClient: The constructed client. + """ + return WebSecurityScannerClient.from_service_account_file.__func__(WebSecurityScannerAsyncClient, filename, *args, **kwargs) # type: ignore - from_service_account_file = WebSecurityScannerClient.from_service_account_file from_service_account_json = from_service_account_file + @property + def transport(self) -> WebSecurityScannerTransport: + """Return the transport used by the client instance. + + Returns: + WebSecurityScannerTransport: The transport used by the client instance. + """ + return self._client.transport + get_transport_class = functools.partial( type(WebSecurityScannerClient).get_transport_class, type(WebSecurityScannerClient), @@ -77,6 +149,7 @@ def __init__( credentials: credentials.Credentials = None, transport: Union[str, WebSecurityScannerTransport] = "grpc_asyncio", client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the web security scanner client. @@ -92,16 +165,19 @@ def __init__( client_options (ClientOptions): Custom options for the client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. Raises: google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport @@ -109,7 +185,10 @@ def __init__( """ self._client = WebSecurityScannerClient( - credentials=credentials, transport=transport, client_options=client_options, + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, ) async def create_scan_config( @@ -125,7 +204,7 @@ async def create_scan_config( r"""Creates a new ScanConfig. Args: - request (:class:`~.web_security_scanner.CreateScanConfigRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.CreateScanConfigRequest`): The request object. Request for the `CreateScanConfig` method. parent (:class:`str`): @@ -133,12 +212,14 @@ async def create_scan_config( where the scan is created, which should be a project resource name in the format 'projects/{projectId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - scan_config (:class:`~.gcw_scan_config.ScanConfig`): + scan_config (:class:`google.cloud.websecurityscanner_v1beta.types.ScanConfig`): Required. The ScanConfig to be created. + This corresponds to the ``scan_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -150,7 +231,7 @@ async def create_scan_config( sent along with the request as metadata. Returns: - ~.gcw_scan_config.ScanConfig: + google.cloud.websecurityscanner_v1beta.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. @@ -158,7 +239,8 @@ async def create_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent, scan_config]): + has_flattened_params = any([parent, scan_config]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -179,7 +261,7 @@ async def create_scan_config( rpc = gapic_v1.method_async.wrap_method( self._client._transport.create_scan_config, default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -207,7 +289,7 @@ async def delete_scan_config( resources. Args: - request (:class:`~.web_security_scanner.DeleteScanConfigRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.DeleteScanConfigRequest`): The request object. Request for the `DeleteScanConfig` method. name (:class:`str`): @@ -215,6 +297,7 @@ async def delete_scan_config( ScanConfig to be deleted. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -228,7 +311,8 @@ async def delete_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -251,11 +335,12 @@ async def delete_scan_config( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -281,7 +366,7 @@ async def get_scan_config( r"""Gets a ScanConfig. Args: - request (:class:`~.web_security_scanner.GetScanConfigRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.GetScanConfigRequest`): The request object. Request for the `GetScanConfig` method. name (:class:`str`): @@ -289,6 +374,7 @@ async def get_scan_config( ScanConfig to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -300,7 +386,7 @@ async def get_scan_config( sent along with the request as metadata. Returns: - ~.scan_config.ScanConfig: + google.cloud.websecurityscanner_v1beta.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. @@ -308,7 +394,8 @@ async def get_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -331,11 +418,12 @@ async def get_scan_config( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -362,13 +450,14 @@ async def list_scan_configs( r"""Lists ScanConfigs under a given project. Args: - request (:class:`~.web_security_scanner.ListScanConfigsRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.ListScanConfigsRequest`): The request object. Request for the `ListScanConfigs` method. parent (:class:`str`): Required. The parent resource name, which should be a project resource name in the format 'projects/{projectId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -380,8 +469,8 @@ async def list_scan_configs( sent along with the request as metadata. Returns: - ~.pagers.ListScanConfigsAsyncPager: - Response for the ``ListScanConfigs`` method. + google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers.ListScanConfigsAsyncPager: + Response for the ListScanConfigs method. Iterating over this object will yield results and resolve additional pages automatically. @@ -390,7 +479,8 @@ async def list_scan_configs( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -413,11 +503,12 @@ async def list_scan_configs( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -452,22 +543,24 @@ async def update_scan_config( update of a ScanConfig. Args: - request (:class:`~.web_security_scanner.UpdateScanConfigRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.UpdateScanConfigRequest`): The request object. Request for the `UpdateScanConfigRequest` method. - scan_config (:class:`~.gcw_scan_config.ScanConfig`): + scan_config (:class:`google.cloud.websecurityscanner_v1beta.types.ScanConfig`): Required. The ScanConfig to be updated. The name field must be set to identify the resource to be updated. The values of fields not covered by the mask will be ignored. + This corresponds to the ``scan_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): Required. The update mask applies to the resource. For the ``FieldMask`` definition, see https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -479,7 +572,7 @@ async def update_scan_config( sent along with the request as metadata. Returns: - ~.gcw_scan_config.ScanConfig: + google.cloud.websecurityscanner_v1beta.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. @@ -487,7 +580,8 @@ async def update_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([scan_config, update_mask]): + has_flattened_params = any([scan_config, update_mask]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -508,7 +602,7 @@ async def update_scan_config( rpc = gapic_v1.method_async.wrap_method( self._client._transport.update_scan_config, default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -537,7 +631,7 @@ async def start_scan_run( r"""Start a ScanRun according to the given ScanConfig. Args: - request (:class:`~.web_security_scanner.StartScanRunRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.StartScanRunRequest`): The request object. Request for the `StartScanRun` method. name (:class:`str`): @@ -545,6 +639,7 @@ async def start_scan_run( ScanConfig to be used. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -556,7 +651,7 @@ async def start_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1beta.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. Next id: 12 @@ -565,7 +660,8 @@ async def start_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -584,7 +680,7 @@ async def start_scan_run( rpc = gapic_v1.method_async.wrap_method( self._client._transport.start_scan_run, default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -611,13 +707,14 @@ async def get_scan_run( r"""Gets a ScanRun. Args: - request (:class:`~.web_security_scanner.GetScanRunRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.GetScanRunRequest`): The request object. Request for the `GetScanRun` method. name (:class:`str`): Required. The resource name of the ScanRun to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -629,7 +726,7 @@ async def get_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1beta.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. Next id: 12 @@ -638,7 +735,8 @@ async def get_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -661,11 +759,12 @@ async def get_scan_run( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -693,7 +792,7 @@ async def list_scan_runs( descending order of ScanRun stop time. Args: - request (:class:`~.web_security_scanner.ListScanRunsRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.ListScanRunsRequest`): The request object. Request for the `ListScanRuns` method. parent (:class:`str`): @@ -701,6 +800,7 @@ async def list_scan_runs( which should be a scan resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -712,8 +812,8 @@ async def list_scan_runs( sent along with the request as metadata. Returns: - ~.pagers.ListScanRunsAsyncPager: - Response for the ``ListScanRuns`` method. + google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers.ListScanRunsAsyncPager: + Response for the ListScanRuns method. Iterating over this object will yield results and resolve additional pages automatically. @@ -722,7 +822,8 @@ async def list_scan_runs( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -745,11 +846,12 @@ async def list_scan_runs( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -782,7 +884,7 @@ async def stop_scan_run( r"""Stops a ScanRun. The stopped ScanRun is returned. Args: - request (:class:`~.web_security_scanner.StopScanRunRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.StopScanRunRequest`): The request object. Request for the `StopScanRun` method. name (:class:`str`): @@ -790,6 +892,7 @@ async def stop_scan_run( ScanRun to be stopped. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -801,7 +904,7 @@ async def stop_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1beta.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. Next id: 12 @@ -810,7 +913,8 @@ async def stop_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -829,7 +933,7 @@ async def stop_scan_run( rpc = gapic_v1.method_async.wrap_method( self._client._transport.stop_scan_run, default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -856,7 +960,7 @@ async def list_crawled_urls( r"""List CrawledUrls under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListCrawledUrlsRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsRequest`): The request object. Request for the `ListCrawledUrls` method. parent (:class:`str`): @@ -864,6 +968,7 @@ async def list_crawled_urls( which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -875,8 +980,8 @@ async def list_crawled_urls( sent along with the request as metadata. Returns: - ~.pagers.ListCrawledUrlsAsyncPager: - Response for the ``ListCrawledUrls`` method. + google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers.ListCrawledUrlsAsyncPager: + Response for the ListCrawledUrls method. Iterating over this object will yield results and resolve additional pages automatically. @@ -885,7 +990,8 @@ async def list_crawled_urls( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -908,11 +1014,12 @@ async def list_crawled_urls( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -945,13 +1052,14 @@ async def get_finding( r"""Gets a Finding. Args: - request (:class:`~.web_security_scanner.GetFindingRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.GetFindingRequest`): The request object. Request for the `GetFinding` method. name (:class:`str`): Required. The resource name of the Finding to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}/findings/{findingId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -963,7 +1071,7 @@ async def get_finding( sent along with the request as metadata. Returns: - ~.finding.Finding: + google.cloud.websecurityscanner_v1beta.types.Finding: A Finding resource represents a vulnerability instance identified during a ScanRun. @@ -972,7 +1080,8 @@ async def get_finding( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -995,11 +1104,12 @@ async def get_finding( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -1027,7 +1137,7 @@ async def list_findings( r"""List Findings under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListFindingsRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.ListFindingsRequest`): The request object. Request for the `ListFindings` method. parent (:class:`str`): @@ -1035,6 +1145,7 @@ async def list_findings( which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1042,6 +1153,7 @@ async def list_findings( Required. The filter expression. The expression must be in the format: . Supported field: 'finding_type'. Supported operator: '='. + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1053,8 +1165,8 @@ async def list_findings( sent along with the request as metadata. Returns: - ~.pagers.ListFindingsAsyncPager: - Response for the ``ListFindings`` method. + google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers.ListFindingsAsyncPager: + Response for the ListFindings method. Iterating over this object will yield results and resolve additional pages automatically. @@ -1063,7 +1175,8 @@ async def list_findings( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent, filter]): + has_flattened_params = any([parent, filter]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -1088,11 +1201,12 @@ async def list_findings( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -1125,7 +1239,7 @@ async def list_finding_type_stats( r"""List all FindingTypeStats under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListFindingTypeStatsRequest`): + request (:class:`google.cloud.websecurityscanner_v1beta.types.ListFindingTypeStatsRequest`): The request object. Request for the `ListFindingTypeStats` method. parent (:class:`str`): @@ -1133,6 +1247,7 @@ async def list_finding_type_stats( which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1144,13 +1259,14 @@ async def list_finding_type_stats( sent along with the request as metadata. Returns: - ~.web_security_scanner.ListFindingTypeStatsResponse: - Response for the ``ListFindingTypeStats`` method. + google.cloud.websecurityscanner_v1beta.types.ListFindingTypeStatsResponse: + Response for the ListFindingTypeStats method. """ # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." @@ -1173,11 +1289,12 @@ async def list_finding_type_stats( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, - client_info=_client_info, + client_info=DEFAULT_CLIENT_INFO, ) # Certain fields should be provided within the metadata header; @@ -1194,13 +1311,13 @@ async def list_finding_type_stats( try: - _client_info = gapic_v1.client_info.ClientInfo( + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=pkg_resources.get_distribution( "google-cloud-websecurityscanner", ).version, ) except pkg_resources.DistributionNotFound: - _client_info = gapic_v1.client_info.ClientInfo() + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() __all__ = ("WebSecurityScannerAsyncClient",) diff --git a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/client.py b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/client.py index 9f28b31..fcf40a2 100644 --- a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/client.py +++ b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/client.py @@ -16,17 +16,19 @@ # from collections import OrderedDict +from distutils import util import os import re -from typing import Callable, Dict, Sequence, Tuple, Type, Union +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources -import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import client_options as client_options_lib # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore from google.auth import credentials # type: ignore from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore @@ -44,7 +46,7 @@ from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import timestamp_pb2 as timestamp # type: ignore -from .transports.base import WebSecurityScannerTransport +from .transports.base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO from .transports.grpc import WebSecurityScannerGrpcTransport from .transports.grpc_asyncio import WebSecurityScannerGrpcAsyncIOTransport @@ -125,6 +127,22 @@ def _get_default_mtls_endpoint(api_endpoint): DEFAULT_ENDPOINT ) + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + WebSecurityScannerClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials @@ -137,7 +155,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + WebSecurityScannerClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -145,6 +163,36 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): from_service_account_json = from_service_account_file + @property + def transport(self) -> WebSecurityScannerTransport: + """Return the transport used by the client instance. + + Returns: + WebSecurityScannerTransport: The transport used by the client instance. + """ + return self._transport + + @staticmethod + def finding_path( + project: str, scan_config: str, scan_run: str, finding: str, + ) -> str: + """Return a fully-qualified finding string.""" + return "projects/{project}/scanConfigs/{scan_config}/scanRuns/{scan_run}/findings/{finding}".format( + project=project, + scan_config=scan_config, + scan_run=scan_run, + finding=finding, + ) + + @staticmethod + def parse_finding_path(path: str) -> Dict[str, str]: + """Parse a finding path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/scanConfigs/(?P.+?)/scanRuns/(?P.+?)/findings/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def scan_config_path(project: str, scan_config: str,) -> str: """Return a fully-qualified scan_config string.""" @@ -176,12 +224,72 @@ def parse_scan_run_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def common_billing_account_path(billing_account: str,) -> str: + """Return a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str,) -> str: + """Return a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder,) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str,) -> str: + """Return a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization,) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str,) -> str: + """Return a fully-qualified project string.""" + return "projects/{project}".format(project=project,) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str,) -> str: + """Return a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + def __init__( self, *, - credentials: credentials.Credentials = None, - transport: Union[str, WebSecurityScannerTransport] = None, - client_options: ClientOptions = None, + credentials: Optional[credentials.Credentials] = None, + transport: Union[str, WebSecurityScannerTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the web security scanner client. @@ -191,51 +299,73 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - transport (Union[str, ~.WebSecurityScannerTransport]): The + transport (Union[str, WebSecurityScannerTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (ClientOptions): Custom options for the client. It - won't take effect if a ``transport`` instance is provided. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. Raises: google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ if isinstance(client_options, dict): - client_options = ClientOptions.from_dict(client_options) + client_options = client_options_lib.from_dict(client_options) if client_options is None: - client_options = ClientOptions.ClientOptions() + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool( + util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + ) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) - if client_options.api_endpoint is None: - use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never") + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") if use_mtls_env == "never": - client_options.api_endpoint = self.DEFAULT_ENDPOINT + api_endpoint = self.DEFAULT_ENDPOINT elif use_mtls_env == "always": - client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT + api_endpoint = self.DEFAULT_MTLS_ENDPOINT elif use_mtls_env == "auto": - has_client_cert_source = ( - client_options.client_cert_source is not None - or mtls.has_default_client_cert_source() - ) - client_options.api_endpoint = ( - self.DEFAULT_MTLS_ENDPOINT - if has_client_cert_source - else self.DEFAULT_ENDPOINT + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT ) else: raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always" + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" ) # Save or instantiate the transport. @@ -259,11 +389,11 @@ def __init__( self._transport = Transport( credentials=credentials, credentials_file=client_options.credentials_file, - host=client_options.api_endpoint, + host=api_endpoint, scopes=client_options.scopes, - api_mtls_endpoint=client_options.api_endpoint, - client_cert_source=client_options.client_cert_source, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, + client_info=client_info, ) def create_scan_config( @@ -279,20 +409,22 @@ def create_scan_config( r"""Creates a new ScanConfig. Args: - request (:class:`~.web_security_scanner.CreateScanConfigRequest`): + request (google.cloud.websecurityscanner_v1beta.types.CreateScanConfigRequest): The request object. Request for the `CreateScanConfig` method. - parent (:class:`str`): + parent (str): Required. The parent resource name where the scan is created, which should be a project resource name in the format 'projects/{projectId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - scan_config (:class:`~.gcw_scan_config.ScanConfig`): + scan_config (google.cloud.websecurityscanner_v1beta.types.ScanConfig): Required. The ScanConfig to be created. + This corresponds to the ``scan_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -304,7 +436,7 @@ def create_scan_config( sent along with the request as metadata. Returns: - ~.gcw_scan_config.ScanConfig: + google.cloud.websecurityscanner_v1beta.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. @@ -312,29 +444,31 @@ def create_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent, scan_config]): + has_flattened_params = any([parent, scan_config]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.CreateScanConfigRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.CreateScanConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.CreateScanConfigRequest): + request = web_security_scanner.CreateScanConfigRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent - if scan_config is not None: - request.scan_config = scan_config + if parent is not None: + request.parent = parent + if scan_config is not None: + request.scan_config = scan_config # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.create_scan_config, - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.create_scan_config] # Certain fields should be provided within the metadata header; # add these here. @@ -361,14 +495,15 @@ def delete_scan_config( resources. Args: - request (:class:`~.web_security_scanner.DeleteScanConfigRequest`): + request (google.cloud.websecurityscanner_v1beta.types.DeleteScanConfigRequest): The request object. Request for the `DeleteScanConfig` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanConfig to be deleted. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -382,35 +517,29 @@ def delete_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.DeleteScanConfigRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.DeleteScanConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.DeleteScanConfigRequest): + request = web_security_scanner.DeleteScanConfigRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.delete_scan_config, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.delete_scan_config] # Certain fields should be provided within the metadata header; # add these here. @@ -435,14 +564,15 @@ def get_scan_config( r"""Gets a ScanConfig. Args: - request (:class:`~.web_security_scanner.GetScanConfigRequest`): + request (google.cloud.websecurityscanner_v1beta.types.GetScanConfigRequest): The request object. Request for the `GetScanConfig` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanConfig to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -454,7 +584,7 @@ def get_scan_config( sent along with the request as metadata. Returns: - ~.scan_config.ScanConfig: + google.cloud.websecurityscanner_v1beta.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. @@ -462,35 +592,29 @@ def get_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.GetScanConfigRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.GetScanConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.GetScanConfigRequest): + request = web_security_scanner.GetScanConfigRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.get_scan_config, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.get_scan_config] # Certain fields should be provided within the metadata header; # add these here. @@ -516,13 +640,14 @@ def list_scan_configs( r"""Lists ScanConfigs under a given project. Args: - request (:class:`~.web_security_scanner.ListScanConfigsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListScanConfigsRequest): The request object. Request for the `ListScanConfigs` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a project resource name in the format 'projects/{projectId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -534,8 +659,8 @@ def list_scan_configs( sent along with the request as metadata. Returns: - ~.pagers.ListScanConfigsPager: - Response for the ``ListScanConfigs`` method. + google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers.ListScanConfigsPager: + Response for the ListScanConfigs method. Iterating over this object will yield results and resolve additional pages automatically. @@ -544,35 +669,29 @@ def list_scan_configs( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListScanConfigsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListScanConfigsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListScanConfigsRequest): + request = web_security_scanner.ListScanConfigsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent + if parent is not None: + request.parent = parent # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_scan_configs, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_scan_configs] # Certain fields should be provided within the metadata header; # add these here. @@ -606,22 +725,24 @@ def update_scan_config( update of a ScanConfig. Args: - request (:class:`~.web_security_scanner.UpdateScanConfigRequest`): + request (google.cloud.websecurityscanner_v1beta.types.UpdateScanConfigRequest): The request object. Request for the `UpdateScanConfigRequest` method. - scan_config (:class:`~.gcw_scan_config.ScanConfig`): + scan_config (google.cloud.websecurityscanner_v1beta.types.ScanConfig): Required. The ScanConfig to be updated. The name field must be set to identify the resource to be updated. The values of fields not covered by the mask will be ignored. + This corresponds to the ``scan_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The update mask applies to the resource. For the ``FieldMask`` definition, see https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -633,7 +754,7 @@ def update_scan_config( sent along with the request as metadata. Returns: - ~.gcw_scan_config.ScanConfig: + google.cloud.websecurityscanner_v1beta.types.ScanConfig: A ScanConfig resource contains the configurations to launch a scan. @@ -641,29 +762,31 @@ def update_scan_config( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([scan_config, update_mask]): + has_flattened_params = any([scan_config, update_mask]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.UpdateScanConfigRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.UpdateScanConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.UpdateScanConfigRequest): + request = web_security_scanner.UpdateScanConfigRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if scan_config is not None: - request.scan_config = scan_config - if update_mask is not None: - request.update_mask = update_mask + if scan_config is not None: + request.scan_config = scan_config + if update_mask is not None: + request.update_mask = update_mask # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.update_scan_config, - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.update_scan_config] # Certain fields should be provided within the metadata header; # add these here. @@ -691,14 +814,15 @@ def start_scan_run( r"""Start a ScanRun according to the given ScanConfig. Args: - request (:class:`~.web_security_scanner.StartScanRunRequest`): + request (google.cloud.websecurityscanner_v1beta.types.StartScanRunRequest): The request object. Request for the `StartScanRun` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanConfig to be used. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -710,7 +834,7 @@ def start_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1beta.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. Next id: 12 @@ -719,27 +843,29 @@ def start_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.StartScanRunRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.StartScanRunRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.StartScanRunRequest): + request = web_security_scanner.StartScanRunRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.start_scan_run, - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.start_scan_run] # Certain fields should be provided within the metadata header; # add these here. @@ -765,13 +891,14 @@ def get_scan_run( r"""Gets a ScanRun. Args: - request (:class:`~.web_security_scanner.GetScanRunRequest`): + request (google.cloud.websecurityscanner_v1beta.types.GetScanRunRequest): The request object. Request for the `GetScanRun` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanRun to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -783,7 +910,7 @@ def get_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1beta.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. Next id: 12 @@ -792,35 +919,29 @@ def get_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.GetScanRunRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.GetScanRunRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.GetScanRunRequest): + request = web_security_scanner.GetScanRunRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.get_scan_run, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.get_scan_run] # Certain fields should be provided within the metadata header; # add these here. @@ -847,14 +968,15 @@ def list_scan_runs( descending order of ScanRun stop time. Args: - request (:class:`~.web_security_scanner.ListScanRunsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListScanRunsRequest): The request object. Request for the `ListScanRuns` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a scan resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -866,8 +988,8 @@ def list_scan_runs( sent along with the request as metadata. Returns: - ~.pagers.ListScanRunsPager: - Response for the ``ListScanRuns`` method. + google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers.ListScanRunsPager: + Response for the ListScanRuns method. Iterating over this object will yield results and resolve additional pages automatically. @@ -876,35 +998,29 @@ def list_scan_runs( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListScanRunsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListScanRunsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListScanRunsRequest): + request = web_security_scanner.ListScanRunsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent + if parent is not None: + request.parent = parent # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_scan_runs, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_scan_runs] # Certain fields should be provided within the metadata header; # add these here. @@ -936,14 +1052,15 @@ def stop_scan_run( r"""Stops a ScanRun. The stopped ScanRun is returned. Args: - request (:class:`~.web_security_scanner.StopScanRunRequest`): + request (google.cloud.websecurityscanner_v1beta.types.StopScanRunRequest): The request object. Request for the `StopScanRun` method. - name (:class:`str`): + name (str): Required. The resource name of the ScanRun to be stopped. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -955,7 +1072,7 @@ def stop_scan_run( sent along with the request as metadata. Returns: - ~.scan_run.ScanRun: + google.cloud.websecurityscanner_v1beta.types.ScanRun: A ScanRun is a output-only resource representing an actual run of the scan. Next id: 12 @@ -964,27 +1081,29 @@ def stop_scan_run( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.StopScanRunRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.StopScanRunRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.StopScanRunRequest): + request = web_security_scanner.StopScanRunRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.stop_scan_run, - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.stop_scan_run] # Certain fields should be provided within the metadata header; # add these here. @@ -1010,14 +1129,15 @@ def list_crawled_urls( r"""List CrawledUrls under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListCrawledUrlsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsRequest): The request object. Request for the `ListCrawledUrls` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1029,8 +1149,8 @@ def list_crawled_urls( sent along with the request as metadata. Returns: - ~.pagers.ListCrawledUrlsPager: - Response for the ``ListCrawledUrls`` method. + google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers.ListCrawledUrlsPager: + Response for the ListCrawledUrls method. Iterating over this object will yield results and resolve additional pages automatically. @@ -1039,35 +1159,29 @@ def list_crawled_urls( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListCrawledUrlsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListCrawledUrlsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListCrawledUrlsRequest): + request = web_security_scanner.ListCrawledUrlsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent + if parent is not None: + request.parent = parent # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_crawled_urls, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_crawled_urls] # Certain fields should be provided within the metadata header; # add these here. @@ -1099,13 +1213,14 @@ def get_finding( r"""Gets a Finding. Args: - request (:class:`~.web_security_scanner.GetFindingRequest`): + request (google.cloud.websecurityscanner_v1beta.types.GetFindingRequest): The request object. Request for the `GetFinding` method. - name (:class:`str`): + name (str): Required. The resource name of the Finding to be returned. The name follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}/findings/{findingId}'. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1117,7 +1232,7 @@ def get_finding( sent along with the request as metadata. Returns: - ~.finding.Finding: + google.cloud.websecurityscanner_v1beta.types.Finding: A Finding resource represents a vulnerability instance identified during a ScanRun. @@ -1126,35 +1241,29 @@ def get_finding( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([name]): + has_flattened_params = any([name]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.GetFindingRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.GetFindingRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.GetFindingRequest): + request = web_security_scanner.GetFindingRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if name is not None: - request.name = name + if name is not None: + request.name = name # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.get_finding, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.get_finding] # Certain fields should be provided within the metadata header; # add these here. @@ -1181,21 +1290,23 @@ def list_findings( r"""List Findings under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListFindingsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListFindingsRequest): The request object. Request for the `ListFindings` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - filter (:class:`str`): + filter (str): Required. The filter expression. The expression must be in the format: . Supported field: 'finding_type'. Supported operator: '='. + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1207,8 +1318,8 @@ def list_findings( sent along with the request as metadata. Returns: - ~.pagers.ListFindingsPager: - Response for the ``ListFindings`` method. + google.cloud.websecurityscanner_v1beta.services.web_security_scanner.pagers.ListFindingsPager: + Response for the ListFindings method. Iterating over this object will yield results and resolve additional pages automatically. @@ -1217,37 +1328,31 @@ def list_findings( # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent, filter]): + has_flattened_params = any([parent, filter]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListFindingsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListFindingsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListFindingsRequest): + request = web_security_scanner.ListFindingsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent - if filter is not None: - request.filter = filter + if parent is not None: + request.parent = parent + if filter is not None: + request.filter = filter # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_findings, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_findings] # Certain fields should be provided within the metadata header; # add these here. @@ -1279,14 +1384,15 @@ def list_finding_type_stats( r"""List all FindingTypeStats under a given ScanRun. Args: - request (:class:`~.web_security_scanner.ListFindingTypeStatsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListFindingTypeStatsRequest): The request object. Request for the `ListFindingTypeStats` method. - parent (:class:`str`): + parent (str): Required. The parent resource name, which should be a scan run resource name in the format 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1298,41 +1404,35 @@ def list_finding_type_stats( sent along with the request as metadata. Returns: - ~.web_security_scanner.ListFindingTypeStatsResponse: - Response for the ``ListFindingTypeStats`` method. + google.cloud.websecurityscanner_v1beta.types.ListFindingTypeStatsResponse: + Response for the ListFindingTypeStats method. """ # Create or coerce a protobuf request object. # Sanity check: If we got a request object, we should *not* have # gotten any keyword arguments that map to the request. - if request is not None and any([parent]): + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: raise ValueError( "If the `request` argument is set, then none of " "the individual field arguments should be set." ) - request = web_security_scanner.ListFindingTypeStatsRequest(request) + # Minor optimization to avoid making a copy if the user passes + # in a web_security_scanner.ListFindingTypeStatsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, web_security_scanner.ListFindingTypeStatsRequest): + request = web_security_scanner.ListFindingTypeStatsRequest(request) - # If we have keyword arguments corresponding to fields on the - # request, apply these. + # If we have keyword arguments corresponding to fields on the + # request, apply these. - if parent is not None: - request.parent = parent + if parent is not None: + request.parent = parent # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_finding_type_stats, - default_retry=retries.Retry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - exceptions.ServiceUnavailable, exceptions.DeadlineExceeded, - ), - ), - default_timeout=600.0, - client_info=_client_info, - ) + rpc = self._transport._wrapped_methods[self._transport.list_finding_type_stats] # Certain fields should be provided within the metadata header; # add these here. @@ -1348,13 +1448,13 @@ def list_finding_type_stats( try: - _client_info = gapic_v1.client_info.ClientInfo( + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=pkg_resources.get_distribution( "google-cloud-websecurityscanner", ).version, ) except pkg_resources.DistributionNotFound: - _client_info = gapic_v1.client_info.ClientInfo() + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() __all__ = ("WebSecurityScannerClient",) diff --git a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/pagers.py b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/pagers.py index beea861..0c39cda 100644 --- a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/pagers.py +++ b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.websecurityscanner_v1beta.types import crawled_url from google.cloud.websecurityscanner_v1beta.types import finding @@ -28,7 +37,7 @@ class ListScanConfigsPager: """A pager for iterating through ``list_scan_configs`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListScanConfigsResponse` object, and + :class:`google.cloud.websecurityscanner_v1beta.types.ListScanConfigsResponse` object, and provides an ``__iter__`` method to iterate through its ``scan_configs`` field. @@ -37,7 +46,7 @@ class ListScanConfigsPager: through the ``scan_configs`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListScanConfigsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1beta.types.ListScanConfigsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -55,9 +64,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListScanConfigsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListScanConfigsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListScanConfigsResponse`): + response (google.cloud.websecurityscanner_v1beta.types.ListScanConfigsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -90,7 +99,7 @@ class ListScanConfigsAsyncPager: """A pager for iterating through ``list_scan_configs`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListScanConfigsResponse` object, and + :class:`google.cloud.websecurityscanner_v1beta.types.ListScanConfigsResponse` object, and provides an ``__aiter__`` method to iterate through its ``scan_configs`` field. @@ -99,7 +108,7 @@ class ListScanConfigsAsyncPager: through the ``scan_configs`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListScanConfigsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1beta.types.ListScanConfigsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -117,9 +126,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListScanConfigsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListScanConfigsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListScanConfigsResponse`): + response (google.cloud.websecurityscanner_v1beta.types.ListScanConfigsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -158,7 +167,7 @@ class ListScanRunsPager: """A pager for iterating through ``list_scan_runs`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListScanRunsResponse` object, and + :class:`google.cloud.websecurityscanner_v1beta.types.ListScanRunsResponse` object, and provides an ``__iter__`` method to iterate through its ``scan_runs`` field. @@ -167,7 +176,7 @@ class ListScanRunsPager: through the ``scan_runs`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListScanRunsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1beta.types.ListScanRunsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -185,9 +194,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListScanRunsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListScanRunsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListScanRunsResponse`): + response (google.cloud.websecurityscanner_v1beta.types.ListScanRunsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -220,7 +229,7 @@ class ListScanRunsAsyncPager: """A pager for iterating through ``list_scan_runs`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListScanRunsResponse` object, and + :class:`google.cloud.websecurityscanner_v1beta.types.ListScanRunsResponse` object, and provides an ``__aiter__`` method to iterate through its ``scan_runs`` field. @@ -229,7 +238,7 @@ class ListScanRunsAsyncPager: through the ``scan_runs`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListScanRunsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1beta.types.ListScanRunsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -247,9 +256,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListScanRunsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListScanRunsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListScanRunsResponse`): + response (google.cloud.websecurityscanner_v1beta.types.ListScanRunsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -286,7 +295,7 @@ class ListCrawledUrlsPager: """A pager for iterating through ``list_crawled_urls`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListCrawledUrlsResponse` object, and + :class:`google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsResponse` object, and provides an ``__iter__`` method to iterate through its ``crawled_urls`` field. @@ -295,7 +304,7 @@ class ListCrawledUrlsPager: through the ``crawled_urls`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListCrawledUrlsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -313,9 +322,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListCrawledUrlsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListCrawledUrlsResponse`): + response (google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -348,7 +357,7 @@ class ListCrawledUrlsAsyncPager: """A pager for iterating through ``list_crawled_urls`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListCrawledUrlsResponse` object, and + :class:`google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsResponse` object, and provides an ``__aiter__`` method to iterate through its ``crawled_urls`` field. @@ -357,7 +366,7 @@ class ListCrawledUrlsAsyncPager: through the ``crawled_urls`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListCrawledUrlsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -375,9 +384,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListCrawledUrlsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListCrawledUrlsResponse`): + response (google.cloud.websecurityscanner_v1beta.types.ListCrawledUrlsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -416,7 +425,7 @@ class ListFindingsPager: """A pager for iterating through ``list_findings`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListFindingsResponse` object, and + :class:`google.cloud.websecurityscanner_v1beta.types.ListFindingsResponse` object, and provides an ``__iter__`` method to iterate through its ``findings`` field. @@ -425,7 +434,7 @@ class ListFindingsPager: through the ``findings`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListFindingsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1beta.types.ListFindingsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -443,9 +452,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListFindingsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListFindingsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListFindingsResponse`): + response (google.cloud.websecurityscanner_v1beta.types.ListFindingsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -478,7 +487,7 @@ class ListFindingsAsyncPager: """A pager for iterating through ``list_findings`` requests. This class thinly wraps an initial - :class:`~.web_security_scanner.ListFindingsResponse` object, and + :class:`google.cloud.websecurityscanner_v1beta.types.ListFindingsResponse` object, and provides an ``__aiter__`` method to iterate through its ``findings`` field. @@ -487,7 +496,7 @@ class ListFindingsAsyncPager: through the ``findings`` field on the corresponding responses. - All the usual :class:`~.web_security_scanner.ListFindingsResponse` + All the usual :class:`google.cloud.websecurityscanner_v1beta.types.ListFindingsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -505,9 +514,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.web_security_scanner.ListFindingsRequest`): + request (google.cloud.websecurityscanner_v1beta.types.ListFindingsRequest): The initial request object. - response (:class:`~.web_security_scanner.ListFindingsResponse`): + response (google.cloud.websecurityscanner_v1beta.types.ListFindingsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/__init__.py b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/__init__.py index 788b2b3..caf0502 100644 --- a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/__init__.py +++ b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/__init__.py @@ -30,7 +30,6 @@ _transport_registry["grpc"] = WebSecurityScannerGrpcTransport _transport_registry["grpc_asyncio"] = WebSecurityScannerGrpcAsyncIOTransport - __all__ = ( "WebSecurityScannerTransport", "WebSecurityScannerGrpcTransport", diff --git a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/base.py b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/base.py index 6370070..f1de54a 100644 --- a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/base.py +++ b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/base.py @@ -17,9 +17,12 @@ import abc import typing +import pkg_resources -from google import auth +from google import auth # type: ignore from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore from google.auth import credentials # type: ignore from google.cloud.websecurityscanner_v1beta.types import finding @@ -30,6 +33,16 @@ from google.protobuf import empty_pb2 as empty # type: ignore +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-websecurityscanner", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + class WebSecurityScannerTransport(abc.ABC): """Abstract transport class for WebSecurityScanner.""" @@ -43,6 +56,7 @@ def __init__( credentials_file: typing.Optional[str] = None, scopes: typing.Optional[typing.Sequence[str]] = AUTH_SCOPES, quota_project_id: typing.Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, **kwargs, ) -> None: """Instantiate the transport. @@ -60,12 +74,20 @@ def __init__( scope (Optional[Sequence[str]]): A list of scopes. quota_project_id (Optional[str]): An optional project to use for billing and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. if ":" not in host: host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -75,17 +97,160 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.create_scan_config: gapic_v1.method.wrap_method( + self.create_scan_config, default_timeout=600.0, client_info=client_info, + ), + self.delete_scan_config: gapic_v1.method.wrap_method( + self.delete_scan_config, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.get_scan_config: gapic_v1.method.wrap_method( + self.get_scan_config, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_scan_configs: gapic_v1.method.wrap_method( + self.list_scan_configs, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.update_scan_config: gapic_v1.method.wrap_method( + self.update_scan_config, default_timeout=600.0, client_info=client_info, + ), + self.start_scan_run: gapic_v1.method.wrap_method( + self.start_scan_run, default_timeout=600.0, client_info=client_info, + ), + self.get_scan_run: gapic_v1.method.wrap_method( + self.get_scan_run, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_scan_runs: gapic_v1.method.wrap_method( + self.list_scan_runs, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.stop_scan_run: gapic_v1.method.wrap_method( + self.stop_scan_run, default_timeout=600.0, client_info=client_info, + ), + self.list_crawled_urls: gapic_v1.method.wrap_method( + self.list_crawled_urls, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.get_finding: gapic_v1.method.wrap_method( + self.get_finding, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_findings: gapic_v1.method.wrap_method( + self.list_findings, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_finding_type_stats: gapic_v1.method.wrap_method( + self.list_finding_type_stats, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + } + @property def create_scan_config( self, diff --git a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/grpc.py b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/grpc.py index 64ee056..f6977ea 100644 --- a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/grpc.py +++ b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/grpc.py @@ -15,14 +15,15 @@ # limitations under the License. # +import warnings from typing import Callable, Dict, Optional, Sequence, Tuple from google.api_core import grpc_helpers # type: ignore +from google.api_core import gapic_v1 # type: ignore from google import auth # type: ignore from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - import grpc # type: ignore from google.cloud.websecurityscanner_v1beta.types import finding @@ -32,7 +33,7 @@ from google.cloud.websecurityscanner_v1beta.types import web_security_scanner from google.protobuf import empty_pb2 as empty # type: ignore -from .base import WebSecurityScannerTransport +from .base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO class WebSecurityScannerGrpcTransport(WebSecurityScannerTransport): @@ -63,7 +64,10 @@ def __init__( channel: grpc.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, - quota_project_id: Optional[str] = None + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the transport. @@ -82,16 +86,27 @@ def __init__( ignored if ``channel`` is provided. channel (Optional[grpc.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. Raises: google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport @@ -99,55 +114,69 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel - elif api_mtls_endpoint: - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - # Run the base constructor. + # The base transport sets the host, credentials and scopes super().__init__( host=host, credentials=credentials, credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, + scopes=scopes, quota_project_id=quota_project_id, + client_info=client_info, ) - self._stubs = {} # type: Dict[str, Callable] + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -157,11 +186,11 @@ def create_channel( credentials_file: str = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, - **kwargs + **kwargs, ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optionsl[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If @@ -191,24 +220,13 @@ def create_channel( credentials_file=credentials_file, scopes=scopes, quota_project_id=quota_project_id, - **kwargs + **kwargs, ) @property def grpc_channel(self) -> grpc.Channel: - """Create the channel designed to connect to this service. - - This property caches on the instance; repeated calls return - the same channel. + """Return the channel designed to connect to this service. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - - # Return the channel from cache. return self._grpc_channel @property diff --git a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/grpc_asyncio.py b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/grpc_asyncio.py index 1a91005..f6055d5 100644 --- a/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/grpc_asyncio.py +++ b/google/cloud/websecurityscanner_v1beta/services/web_security_scanner/transports/grpc_asyncio.py @@ -15,9 +15,12 @@ # limitations under the License. # +import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple +from google.api_core import gapic_v1 # type: ignore from google.api_core import grpc_helpers_async # type: ignore +from google import auth # type: ignore from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore @@ -31,7 +34,7 @@ from google.cloud.websecurityscanner_v1beta.types import web_security_scanner from google.protobuf import empty_pb2 as empty # type: ignore -from .base import WebSecurityScannerTransport +from .base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO from .grpc import WebSecurityScannerGrpcTransport @@ -66,7 +69,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If @@ -105,7 +108,10 @@ def __init__( channel: aio.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the transport. @@ -125,16 +131,27 @@ def __init__( are passed to :func:`google.auth.default`. channel (Optional[aio.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. Raises: google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport @@ -142,50 +159,69 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel - elif api_mtls_endpoint: - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - # Run the base constructor. + # The base transport sets the host, credentials and scopes super().__init__( host=host, credentials=credentials, credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, + scopes=scopes, quota_project_id=quota_project_id, + client_info=client_info, ) - self._stubs = {} + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: @@ -194,13 +230,6 @@ def grpc_channel(self) -> aio.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/websecurityscanner_v1beta/types/__init__.py b/google/cloud/websecurityscanner_v1beta/types/__init__.py index adb9a0a..d1f7fe5 100644 --- a/google/cloud/websecurityscanner_v1beta/types/__init__.py +++ b/google/cloud/websecurityscanner_v1beta/types/__init__.py @@ -16,74 +16,73 @@ # from .crawled_url import CrawledUrl +from .finding import Finding from .finding_addon import ( Form, OutdatedLibrary, ViolatingResource, - VulnerableParameters, VulnerableHeaders, + VulnerableParameters, Xss, ) -from .finding import Finding from .finding_type_stats import FindingTypeStats +from .scan_config import ScanConfig from .scan_config_error import ScanConfigError +from .scan_run import ScanRun from .scan_run_error_trace import ScanRunErrorTrace from .scan_run_warning_trace import ScanRunWarningTrace -from .scan_run import ScanRun -from .scan_config import ScanConfig from .web_security_scanner import ( CreateScanConfigRequest, DeleteScanConfigRequest, + GetFindingRequest, GetScanConfigRequest, - ListScanConfigsRequest, - UpdateScanConfigRequest, - ListScanConfigsResponse, - StartScanRunRequest, GetScanRunRequest, - ListScanRunsRequest, - ListScanRunsResponse, - StopScanRunRequest, ListCrawledUrlsRequest, ListCrawledUrlsResponse, - GetFindingRequest, ListFindingsRequest, ListFindingsResponse, ListFindingTypeStatsRequest, ListFindingTypeStatsResponse, + ListScanConfigsRequest, + ListScanConfigsResponse, + ListScanRunsRequest, + ListScanRunsResponse, + StartScanRunRequest, + StopScanRunRequest, + UpdateScanConfigRequest, ) - __all__ = ( "CrawledUrl", + "Finding", "Form", "OutdatedLibrary", "ViolatingResource", - "VulnerableParameters", "VulnerableHeaders", + "VulnerableParameters", "Xss", - "Finding", "FindingTypeStats", + "ScanConfig", "ScanConfigError", + "ScanRun", "ScanRunErrorTrace", "ScanRunWarningTrace", - "ScanRun", - "ScanConfig", "CreateScanConfigRequest", "DeleteScanConfigRequest", + "GetFindingRequest", "GetScanConfigRequest", - "ListScanConfigsRequest", - "UpdateScanConfigRequest", - "ListScanConfigsResponse", - "StartScanRunRequest", "GetScanRunRequest", - "ListScanRunsRequest", - "ListScanRunsResponse", - "StopScanRunRequest", "ListCrawledUrlsRequest", "ListCrawledUrlsResponse", - "GetFindingRequest", "ListFindingsRequest", "ListFindingsResponse", "ListFindingTypeStatsRequest", "ListFindingTypeStatsResponse", + "ListScanConfigsRequest", + "ListScanConfigsResponse", + "ListScanRunsRequest", + "ListScanRunsResponse", + "StartScanRunRequest", + "StopScanRunRequest", + "UpdateScanConfigRequest", ) diff --git a/google/cloud/websecurityscanner_v1beta/types/finding.py b/google/cloud/websecurityscanner_v1beta/types/finding.py index 5a01b73..cc21be8 100644 --- a/google/cloud/websecurityscanner_v1beta/types/finding.py +++ b/google/cloud/websecurityscanner_v1beta/types/finding.py @@ -68,24 +68,24 @@ class Finding(proto.Message): tracking_id (str): The tracking ID uniquely identifies a vulnerability instance across multiple ScanRuns. - form (~.finding_addon.Form): + form (google.cloud.websecurityscanner_v1beta.types.Form): An addon containing information reported for a vulnerability with an HTML form, if any. - outdated_library (~.finding_addon.OutdatedLibrary): + outdated_library (google.cloud.websecurityscanner_v1beta.types.OutdatedLibrary): An addon containing information about outdated libraries. - violating_resource (~.finding_addon.ViolatingResource): + violating_resource (google.cloud.websecurityscanner_v1beta.types.ViolatingResource): An addon containing detailed information regarding any resource causing the vulnerability such as JavaScript sources, image, audio files, etc. - vulnerable_headers (~.finding_addon.VulnerableHeaders): + vulnerable_headers (google.cloud.websecurityscanner_v1beta.types.VulnerableHeaders): An addon containing information about vulnerable or missing HTTP headers. - vulnerable_parameters (~.finding_addon.VulnerableParameters): + vulnerable_parameters (google.cloud.websecurityscanner_v1beta.types.VulnerableParameters): An addon containing information about request parameters which were found to be vulnerable. - xss (~.finding_addon.Xss): + xss (google.cloud.websecurityscanner_v1beta.types.Xss): An addon containing information reported for an XSS, if any. """ diff --git a/google/cloud/websecurityscanner_v1beta/types/finding_addon.py b/google/cloud/websecurityscanner_v1beta/types/finding_addon.py index 6482c6e..71c6929 100644 --- a/google/cloud/websecurityscanner_v1beta/types/finding_addon.py +++ b/google/cloud/websecurityscanner_v1beta/types/finding_addon.py @@ -99,9 +99,9 @@ class VulnerableHeaders(proto.Message): r"""Information about vulnerable or missing HTTP Headers. Attributes: - headers (Sequence[~.finding_addon.VulnerableHeaders.Header]): + headers (Sequence[google.cloud.websecurityscanner_v1beta.types.VulnerableHeaders.Header]): List of vulnerable headers. - missing_headers (Sequence[~.finding_addon.VulnerableHeaders.Header]): + missing_headers (Sequence[google.cloud.websecurityscanner_v1beta.types.VulnerableHeaders.Header]): List of missing headers. """ diff --git a/google/cloud/websecurityscanner_v1beta/types/scan_config.py b/google/cloud/websecurityscanner_v1beta/types/scan_config.py index a03317e..99b1512 100644 --- a/google/cloud/websecurityscanner_v1beta/types/scan_config.py +++ b/google/cloud/websecurityscanner_v1beta/types/scan_config.py @@ -48,27 +48,27 @@ class ScanConfig(proto.Message): starting_urls (Sequence[str]): Required. The starting URLs from which the scanner finds site pages. - authentication (~.scan_config.ScanConfig.Authentication): + authentication (google.cloud.websecurityscanner_v1beta.types.ScanConfig.Authentication): The authentication configuration. If specified, service will use the authentication configuration during scanning. - user_agent (~.scan_config.ScanConfig.UserAgent): + user_agent (google.cloud.websecurityscanner_v1beta.types.ScanConfig.UserAgent): The user agent used during scanning. blacklist_patterns (Sequence[str]): The blacklist URL patterns as described in https://cloud.google.com/security- scanner/docs/excluded-urls - schedule (~.scan_config.ScanConfig.Schedule): + schedule (google.cloud.websecurityscanner_v1beta.types.ScanConfig.Schedule): The schedule of the ScanConfig. - target_platforms (Sequence[~.scan_config.ScanConfig.TargetPlatform]): + target_platforms (Sequence[google.cloud.websecurityscanner_v1beta.types.ScanConfig.TargetPlatform]): Set of Cloud Platforms targeted by the scan. If empty, APP_ENGINE will be used as a default. - export_to_security_command_center (~.scan_config.ScanConfig.ExportToSecurityCommandCenter): + export_to_security_command_center (google.cloud.websecurityscanner_v1beta.types.ScanConfig.ExportToSecurityCommandCenter): Controls export of scan configurations and results to Cloud Security Command Center. - latest_run (~.scan_run.ScanRun): + latest_run (google.cloud.websecurityscanner_v1beta.types.ScanRun): Latest ScanRun if available. - risk_level (~.scan_config.ScanConfig.RiskLevel): + risk_level (google.cloud.websecurityscanner_v1beta.types.ScanConfig.RiskLevel): The risk level selected for the scan """ @@ -107,9 +107,9 @@ class Authentication(proto.Message): r"""Scan authentication configuration. Attributes: - google_account (~.scan_config.ScanConfig.Authentication.GoogleAccount): + google_account (google.cloud.websecurityscanner_v1beta.types.ScanConfig.Authentication.GoogleAccount): Authentication using a Google account. - custom_account (~.scan_config.ScanConfig.Authentication.CustomAccount): + custom_account (google.cloud.websecurityscanner_v1beta.types.ScanConfig.Authentication.CustomAccount): Authentication using a custom account. """ @@ -173,7 +173,7 @@ class Schedule(proto.Message): r"""Scan schedule configuration. Attributes: - schedule_time (~.timestamp.Timestamp): + schedule_time (google.protobuf.timestamp_pb2.Timestamp): A timestamp indicates when the next run will be scheduled. The value is refreshed by the server after each run. If unspecified, it will diff --git a/google/cloud/websecurityscanner_v1beta/types/scan_config_error.py b/google/cloud/websecurityscanner_v1beta/types/scan_config_error.py index 1f2642a..c977169 100644 --- a/google/cloud/websecurityscanner_v1beta/types/scan_config_error.py +++ b/google/cloud/websecurityscanner_v1beta/types/scan_config_error.py @@ -30,7 +30,7 @@ class ScanConfigError(proto.Message): scan validation fails due to a scan configuration error. Attributes: - code (~.scan_config_error.ScanConfigError.Code): + code (google.cloud.websecurityscanner_v1beta.types.ScanConfigError.Code): Indicates the reason code for a configuration failure. field_name (str): @@ -45,6 +45,7 @@ class Code(proto.Enum): Defines an error reason code. Next id: 44 """ + _pb_options = {"allow_alias": True} CODE_UNSPECIFIED = 0 OK = 0 INTERNAL_ERROR = 1 diff --git a/google/cloud/websecurityscanner_v1beta/types/scan_run.py b/google/cloud/websecurityscanner_v1beta/types/scan_run.py index 7097998..99f5faa 100644 --- a/google/cloud/websecurityscanner_v1beta/types/scan_run.py +++ b/google/cloud/websecurityscanner_v1beta/types/scan_run.py @@ -38,15 +38,15 @@ class ScanRun(proto.Message): follows the format of 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. The ScanRun IDs are generated by the system. - execution_state (~.scan_run.ScanRun.ExecutionState): + execution_state (google.cloud.websecurityscanner_v1beta.types.ScanRun.ExecutionState): The execution state of the ScanRun. - result_state (~.scan_run.ScanRun.ResultState): + result_state (google.cloud.websecurityscanner_v1beta.types.ScanRun.ResultState): The result state of the ScanRun. This field is only available after the execution state reaches "FINISHED". - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): The time at which the ScanRun started. - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): The time at which the ScanRun reached termination state - that the ScanRun is either finished or stopped by user. @@ -71,11 +71,11 @@ class ScanRun(proto.Message): value is 0. If the scan is running, the value ranges from 0 to 100. If the scan is finished, the value is 100. - error_trace (~.scan_run_error_trace.ScanRunErrorTrace): + error_trace (google.cloud.websecurityscanner_v1beta.types.ScanRunErrorTrace): If result_state is an ERROR, this field provides the primary reason for scan's termination and more details, if such are available. - warning_traces (Sequence[~.scan_run_warning_trace.ScanRunWarningTrace]): + warning_traces (Sequence[google.cloud.websecurityscanner_v1beta.types.ScanRunWarningTrace]): A list of warnings, if such are encountered during this scan run. """ diff --git a/google/cloud/websecurityscanner_v1beta/types/scan_run_error_trace.py b/google/cloud/websecurityscanner_v1beta/types/scan_run_error_trace.py index a69f5ea..326f3e3 100644 --- a/google/cloud/websecurityscanner_v1beta/types/scan_run_error_trace.py +++ b/google/cloud/websecurityscanner_v1beta/types/scan_run_error_trace.py @@ -33,9 +33,9 @@ class ScanRunErrorTrace(proto.Message): Defines an error trace message for a ScanRun. Attributes: - code (~.scan_run_error_trace.ScanRunErrorTrace.Code): + code (google.cloud.websecurityscanner_v1beta.types.ScanRunErrorTrace.Code): Indicates the error reason code. - scan_config_error (~.gcw_scan_config_error.ScanConfigError): + scan_config_error (google.cloud.websecurityscanner_v1beta.types.ScanConfigError): If the scan encounters SCAN_CONFIG_ISSUE error, this field has the error message encountered during scan configuration validation that is performed before each scan run. diff --git a/google/cloud/websecurityscanner_v1beta/types/scan_run_warning_trace.py b/google/cloud/websecurityscanner_v1beta/types/scan_run_warning_trace.py index 933e88d..418bbb3 100644 --- a/google/cloud/websecurityscanner_v1beta/types/scan_run_warning_trace.py +++ b/google/cloud/websecurityscanner_v1beta/types/scan_run_warning_trace.py @@ -30,7 +30,7 @@ class ScanRunWarningTrace(proto.Message): scanning process more effective. Attributes: - code (~.scan_run_warning_trace.ScanRunWarningTrace.Code): + code (google.cloud.websecurityscanner_v1beta.types.ScanRunWarningTrace.Code): Indicates the warning code. """ diff --git a/google/cloud/websecurityscanner_v1beta/types/web_security_scanner.py b/google/cloud/websecurityscanner_v1beta/types/web_security_scanner.py index 6cb03bc..f2aa99e 100644 --- a/google/cloud/websecurityscanner_v1beta/types/web_security_scanner.py +++ b/google/cloud/websecurityscanner_v1beta/types/web_security_scanner.py @@ -62,7 +62,7 @@ class CreateScanConfigRequest(proto.Message): scan is created, which should be a project resource name in the format 'projects/{projectId}'. - scan_config (~.gcw_scan_config.ScanConfig): + scan_config (google.cloud.websecurityscanner_v1beta.types.ScanConfig): Required. The ScanConfig to be created. """ @@ -130,12 +130,12 @@ class UpdateScanConfigRequest(proto.Message): r"""Request for the ``UpdateScanConfigRequest`` method. Attributes: - scan_config (~.gcw_scan_config.ScanConfig): + scan_config (google.cloud.websecurityscanner_v1beta.types.ScanConfig): Required. The ScanConfig to be updated. The name field must be set to identify the resource to be updated. The values of fields not covered by the mask will be ignored. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The update mask applies to the resource. For the ``FieldMask`` definition, see https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask @@ -152,7 +152,7 @@ class ListScanConfigsResponse(proto.Message): r"""Response for the ``ListScanConfigs`` method. Attributes: - scan_configs (Sequence[~.gcw_scan_config.ScanConfig]): + scan_configs (Sequence[google.cloud.websecurityscanner_v1beta.types.ScanConfig]): The list of ScanConfigs returned. next_page_token (str): Token to retrieve the next page of results, @@ -228,7 +228,7 @@ class ListScanRunsResponse(proto.Message): r"""Response for the ``ListScanRuns`` method. Attributes: - scan_runs (Sequence[~.scan_run.ScanRun]): + scan_runs (Sequence[google.cloud.websecurityscanner_v1beta.types.ScanRun]): The list of ScanRuns returned. next_page_token (str): Token to retrieve the next page of results, @@ -289,7 +289,7 @@ class ListCrawledUrlsResponse(proto.Message): r"""Response for the ``ListCrawledUrls`` method. Attributes: - crawled_urls (Sequence[~.crawled_url.CrawledUrl]): + crawled_urls (Sequence[google.cloud.websecurityscanner_v1beta.types.CrawledUrl]): The list of CrawledUrls returned. next_page_token (str): Token to retrieve the next page of results, @@ -358,7 +358,7 @@ class ListFindingsResponse(proto.Message): r"""Response for the ``ListFindings`` method. Attributes: - findings (Sequence[~.finding.Finding]): + findings (Sequence[google.cloud.websecurityscanner_v1beta.types.Finding]): The list of Findings returned. next_page_token (str): Token to retrieve the next page of results, @@ -392,7 +392,7 @@ class ListFindingTypeStatsResponse(proto.Message): r"""Response for the ``ListFindingTypeStats`` method. Attributes: - finding_type_stats (Sequence[~.gcw_finding_type_stats.FindingTypeStats]): + finding_type_stats (Sequence[google.cloud.websecurityscanner_v1beta.types.FindingTypeStats]): The list of FindingTypeStats returned. """ diff --git a/noxfile.py b/noxfile.py index 25c0a06..43dd302 100644 --- a/noxfile.py +++ b/noxfile.py @@ -18,6 +18,7 @@ from __future__ import absolute_import import os +import pathlib import shutil import nox @@ -28,7 +29,23 @@ DEFAULT_PYTHON_VERSION = "3.8" SYSTEM_TEST_PYTHON_VERSIONS = ["3.8"] -UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8"] +UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9"] + +CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() + +# 'docfx' is excluded since it only needs to run in 'docs-presubmit' +nox.options.sessions = [ + "unit", + "system", + "cover", + "lint", + "lint_setup_py", + "blacken", + "docs", +] + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True @nox.session(python=DEFAULT_PYTHON_VERSION) @@ -70,18 +87,23 @@ def lint_setup_py(session): def default(session): # Install all test dependencies, then install this package in-place. - session.install("asyncmock", "pytest-asyncio") - session.install("mock", "pytest", "pytest-cov") - session.install("-e", ".") + constraints_path = str( + CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" + ) + session.install("asyncmock", "pytest-asyncio", "-c", constraints_path) + + session.install("mock", "pytest", "pytest-cov", "-c", constraints_path) + + session.install("-e", ".", "-c", constraints_path) # Run py.test against the unit tests. session.run( "py.test", "--quiet", - "--cov=google.cloud.websecurityscanner", - "--cov=google.cloud", - "--cov=tests.unit", + f"--junitxml=unit_{session.python}_sponge_log.xml", + "--cov=google/cloud", + "--cov=tests/unit", "--cov-append", "--cov-config=.coveragerc", "--cov-report=", @@ -100,11 +122,21 @@ def unit(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) def system(session): """Run the system test suite.""" + constraints_path = str( + CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" + ) system_test_path = os.path.join("tests", "system.py") system_test_folder_path = os.path.join("tests", "system") + + # Check the value of `RUN_SYSTEM_TESTS` env var. It defaults to true. + if os.environ.get("RUN_SYSTEM_TESTS", "true") == "false": + session.skip("RUN_SYSTEM_TESTS is set to false, skipping") # Sanity check: Only run tests if the environment variable is set. if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): session.skip("Credentials must be set via environment variable") + # Install pyopenssl for mTLS testing. + if os.environ.get("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true": + session.install("pyopenssl") system_test_exists = os.path.exists(system_test_path) system_test_folder_exists = os.path.exists(system_test_folder_path) @@ -117,16 +149,26 @@ def system(session): # Install all test dependencies, then install this package into the # virtualenv's dist-packages. - session.install( - "mock", "pytest", "google-cloud-testutils", - ) - session.install("-e", ".") + session.install("mock", "pytest", "google-cloud-testutils", "-c", constraints_path) + session.install("-e", ".", "-c", constraints_path) # Run py.test against the system tests. if system_test_exists: - session.run("py.test", "--quiet", system_test_path, *session.posargs) + session.run( + "py.test", + "--quiet", + f"--junitxml=system_{session.python}_sponge_log.xml", + system_test_path, + *session.posargs, + ) if system_test_folder_exists: - session.run("py.test", "--quiet", system_test_folder_path, *session.posargs) + session.run( + "py.test", + "--quiet", + f"--junitxml=system_{session.python}_sponge_log.xml", + system_test_folder_path, + *session.posargs, + ) @nox.session(python=DEFAULT_PYTHON_VERSION) @@ -137,7 +179,7 @@ def cover(session): test runs (not system test runs), and then erases coverage data. """ session.install("coverage", "pytest-cov") - session.run("coverage", "report", "--show-missing", "--fail-under=100") + session.run("coverage", "report", "--show-missing", "--fail-under=98") session.run("coverage", "erase") @@ -147,7 +189,7 @@ def docs(session): """Build the docs for this library.""" session.install("-e", ".") - session.install("sphinx<3.0.0", "alabaster", "recommonmark") + session.install("sphinx", "alabaster", "recommonmark") shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) session.run( @@ -162,3 +204,38 @@ def docs(session): os.path.join("docs", ""), os.path.join("docs", "_build", "html", ""), ) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def docfx(session): + """Build the docfx yaml files for this library.""" + + session.install("-e", ".") + # sphinx-docfx-yaml supports up to sphinx version 1.5.5. + # https://github.com/docascode/sphinx-docfx-yaml/issues/97 + session.install("sphinx==1.5.5", "alabaster", "recommonmark", "sphinx-docfx-yaml") + + shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) + session.run( + "sphinx-build", + "-T", # show full traceback on exception + "-N", # no colors + "-D", + ( + "extensions=sphinx.ext.autodoc," + "sphinx.ext.autosummary," + "docfx_yaml.extension," + "sphinx.ext.intersphinx," + "sphinx.ext.coverage," + "sphinx.ext.napoleon," + "sphinx.ext.todo," + "sphinx.ext.viewcode," + "recommonmark" + ), + "-b", + "html", + "-d", + os.path.join("docs", "_build", "doctrees", ""), + os.path.join("docs", ""), + os.path.join("docs", "_build", "html", ""), + ) diff --git a/renovate.json b/renovate.json index 4fa9493..f08bc22 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,6 @@ { "extends": [ "config:base", ":preserveSemverRanges" - ] + ], + "ignorePaths": [".pre-commit-config.yaml"] } diff --git a/scripts/decrypt-secrets.sh b/scripts/decrypt-secrets.sh index ff599eb..21f6d2a 100755 --- a/scripts/decrypt-secrets.sh +++ b/scripts/decrypt-secrets.sh @@ -20,14 +20,27 @@ ROOT=$( dirname "$DIR" ) # Work from the project root. cd $ROOT +# Prevent it from overriding files. +# We recommend that sample authors use their own service account files and cloud project. +# In that case, they are supposed to prepare these files by themselves. +if [[ -f "testing/test-env.sh" ]] || \ + [[ -f "testing/service-account.json" ]] || \ + [[ -f "testing/client-secrets.json" ]]; then + echo "One or more target files exist, aborting." + exit 1 +fi + # Use SECRET_MANAGER_PROJECT if set, fallback to cloud-devrel-kokoro-resources. PROJECT_ID="${SECRET_MANAGER_PROJECT:-cloud-devrel-kokoro-resources}" gcloud secrets versions access latest --secret="python-docs-samples-test-env" \ + --project="${PROJECT_ID}" \ > testing/test-env.sh gcloud secrets versions access latest \ --secret="python-docs-samples-service-account" \ + --project="${PROJECT_ID}" \ > testing/service-account.json gcloud secrets versions access latest \ --secret="python-docs-samples-client-secrets" \ - > testing/client-secrets.json \ No newline at end of file + --project="${PROJECT_ID}" \ + > testing/client-secrets.json diff --git a/scripts/fixup_websecurityscanner_v1alpha_keywords.py b/scripts/fixup_websecurityscanner_v1alpha_keywords.py index 871b0ca..26129c3 100644 --- a/scripts/fixup_websecurityscanner_v1alpha_keywords.py +++ b/scripts/fixup_websecurityscanner_v1alpha_keywords.py @@ -1,3 +1,4 @@ +#! /usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright 2020 Google LLC diff --git a/scripts/fixup_websecurityscanner_v1beta_keywords.py b/scripts/fixup_websecurityscanner_v1beta_keywords.py index 871b0ca..26129c3 100644 --- a/scripts/fixup_websecurityscanner_v1beta_keywords.py +++ b/scripts/fixup_websecurityscanner_v1beta_keywords.py @@ -1,3 +1,4 @@ +#! /usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright 2020 Google LLC diff --git a/setup.py b/setup.py index 49b5cd0..68290f9 100644 --- a/setup.py +++ b/setup.py @@ -27,11 +27,10 @@ # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta' # 'Development Status :: 5 - Production/Stable' -release_status = "Development Status :: 3 - Alpha" +release_status = "Development Status :: 4 - Beta" dependencies = [ - "google-api-core[grpc] >= 1.22.0, < 2.0.0dev", - "proto-plus >= 0.4.0", - "libcst >= 0.2.5", + "google-api-core[grpc] >= 1.22.2, < 2.0.0dev", + "proto-plus >= 1.15.0", ] extras = {} @@ -70,7 +69,7 @@ classifiers=[ release_status, "Intended Audience :: Developers", - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", diff --git a/synth.metadata b/synth.metadata index c18f2bc..0e215fe 100644 --- a/synth.metadata +++ b/synth.metadata @@ -3,15 +3,23 @@ { "git": { "name": ".", - "remote": "https://github.com/googleapis/python-websecurityscanner.git", - "sha": "bd5365c10f681b2300a834c13a9a970e71c74b03" + "remote": "git@github.com:googleapis/python-websecurityscanner", + "sha": "c051344a2a83b0e22794984a6502cec59b97fe54" + } + }, + { + "git": { + "name": "googleapis", + "remote": "https://github.com/googleapis/googleapis.git", + "sha": "d5c594f49d7ce6c698807c3602551e56b45f0b33", + "internalRef": "365084845" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "d07b7b7afa718686db7b095317f608a2f1b6b1cb" + "sha": "bb854b6c048619e3be4e8b8ce8ed10aa74ea78ef" } } ], diff --git a/synth.py b/synth.py index f01c751..f11b4c2 100644 --- a/synth.py +++ b/synth.py @@ -42,12 +42,10 @@ # Add templated files # ---------------------------------------------------------------------------- templated_files = common.py_library( + cov_level=98, samples=False, # set to True only if there are samples microgenerator=True, ) s.move(templated_files, excludes=[".coveragerc"]) # microgenerator has a good .coveragerc file -# TODO(busunkim): Use latest sphinx after microgenerator transition -s.replace("noxfile.py", """['"]sphinx['"]""", '"sphinx<3.0.0"') - s.shell.run(["nox", "-s", "blacken"], hide_output=False) diff --git a/testing/constraints-3.10.txt b/testing/constraints-3.10.txt new file mode 100644 index 0000000..e69de29 diff --git a/testing/constraints-3.11.txt b/testing/constraints-3.11.txt new file mode 100644 index 0000000..e69de29 diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt new file mode 100644 index 0000000..54c4f8c --- /dev/null +++ b/testing/constraints-3.6.txt @@ -0,0 +1,9 @@ +# This constraints file is used to check that lower bounds +# are correct in setup.py +# List *all* library dependencies and extras in this file. +# Pin the version to the lower bound. +# +# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", +# Then this file should have foo==1.14.0 +google-api-core==1.22.2 +proto-plus==1.16.0 diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt new file mode 100644 index 0000000..e69de29 diff --git a/testing/constraints-3.8.txt b/testing/constraints-3.8.txt new file mode 100644 index 0000000..e69de29 diff --git a/testing/constraints-3.9.txt b/testing/constraints-3.9.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/gapic/websecurityscanner_v1alpha/__init__.py b/tests/unit/gapic/websecurityscanner_v1alpha/__init__.py index e69de29..42ffdf2 100644 --- a/tests/unit/gapic/websecurityscanner_v1alpha/__init__.py +++ b/tests/unit/gapic/websecurityscanner_v1alpha/__init__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 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/unit/gapic/websecurityscanner_v1alpha/test_web_security_scanner.py b/tests/unit/gapic/websecurityscanner_v1alpha/test_web_security_scanner.py index 1642c75..905949e 100644 --- a/tests/unit/gapic/websecurityscanner_v1alpha/test_web_security_scanner.py +++ b/tests/unit/gapic/websecurityscanner_v1alpha/test_web_security_scanner.py @@ -59,6 +59,17 @@ def client_cert_source_callback(): return b"cert bytes", b"key bytes" +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return ( + "foo.googleapis.com" + if ("localhost" in client.DEFAULT_ENDPOINT) + else client.DEFAULT_ENDPOINT + ) + + def test__get_default_mtls_endpoint(): api_endpoint = "example.googleapis.com" api_mtls_endpoint = "example.mtls.googleapis.com" @@ -90,7 +101,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [WebSecurityScannerClient, WebSecurityScannerAsyncClient] + "client_class", [WebSecurityScannerClient, WebSecurityScannerAsyncClient,] +) +def test_web_security_scanner_client_from_service_account_info(client_class): + creds = credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_info" + ) as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == "websecurityscanner.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [WebSecurityScannerClient, WebSecurityScannerAsyncClient,] ) def test_web_security_scanner_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -99,17 +127,22 @@ def test_web_security_scanner_client_from_service_account_file(client_class): ) as factory: factory.return_value = creds client = client_class.from_service_account_file("dummy/file/path.json") - assert client._transport._credentials == creds + assert client.transport._credentials == creds + assert isinstance(client, client_class) client = client_class.from_service_account_json("dummy/file/path.json") - assert client._transport._credentials == creds + assert client.transport._credentials == creds + assert isinstance(client, client_class) - assert client._transport._host == "websecurityscanner.googleapis.com:443" + assert client.transport._host == "websecurityscanner.googleapis.com:443" def test_web_security_scanner_client_get_transport_class(): transport = WebSecurityScannerClient.get_transport_class() - assert transport == transports.WebSecurityScannerGrpcTransport + available_transports = [ + transports.WebSecurityScannerGrpcTransport, + ] + assert transport in available_transports transport = WebSecurityScannerClient.get_transport_class("grpc") assert transport == transports.WebSecurityScannerGrpcTransport @@ -126,6 +159,16 @@ def test_web_security_scanner_client_get_transport_class(): ), ], ) +@mock.patch.object( + WebSecurityScannerClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(WebSecurityScannerClient), +) +@mock.patch.object( + WebSecurityScannerAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(WebSecurityScannerAsyncClient), +) def test_web_security_scanner_client_client_options( client_class, transport_class, transport_name ): @@ -150,14 +193,14 @@ def test_web_security_scanner_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "never". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "never"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -166,14 +209,14 @@ def test_web_security_scanner_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "always". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "always"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -182,53 +225,152 @@ def test_web_security_scanner_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + ( + WebSecurityScannerClient, + transports.WebSecurityScannerGrpcTransport, + "grpc", + "true", + ), + ( + WebSecurityScannerAsyncClient, + transports.WebSecurityScannerGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + ( + WebSecurityScannerClient, + transports.WebSecurityScannerGrpcTransport, + "grpc", + "false", + ), + ( + WebSecurityScannerAsyncClient, + transports.WebSecurityScannerGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + WebSecurityScannerClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(WebSecurityScannerClient), +) +@mock.patch.object( + WebSecurityScannerAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(WebSecurityScannerAsyncClient), +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_web_security_scanner_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): options = client_options.ClientOptions( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class(client_options=options) + + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT + patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, + host=expected_host, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=client_cert_source_callback, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and default_client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( "google.auth.transport.mtls.has_default_client_cert_source", return_value=True, ): - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, - quota_project_id=None, - ) - - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", but client_cert_source and default_client_cert_source are None. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback + + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( "google.auth.transport.mtls.has_default_client_cert_source", @@ -241,32 +383,11 @@ def test_web_security_scanner_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS has - # unsupported value. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "Unsupported"}): - with pytest.raises(MutualTLSChannelError): - client = client_class() - - # Check the case quota_project_id is provided - options = client_options.ClientOptions(quota_project_id="octopus") - with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id="octopus", - ) - @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -292,9 +413,9 @@ def test_web_security_scanner_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -322,9 +443,9 @@ def test_web_security_scanner_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -341,24 +462,26 @@ def test_web_security_scanner_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) -def test_create_scan_config(transport: str = "grpc"): +def test_create_scan_config( + transport: str = "grpc", request_type=web_security_scanner.CreateScanConfigRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.CreateScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig( @@ -377,9 +500,10 @@ def test_create_scan_config(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.CreateScanConfigRequest() # Establish that the response is the type that we expect. + assert isinstance(response, gcw_scan_config.ScanConfig) assert response.name == "name_value" @@ -399,19 +523,44 @@ def test_create_scan_config(transport: str = "grpc"): ] +def test_create_scan_config_from_dict(): + test_create_scan_config(request_type=dict) + + +def test_create_scan_config_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_scan_config), "__call__" + ) as call: + client.create_scan_config() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.CreateScanConfigRequest() + + @pytest.mark.asyncio -async def test_create_scan_config_async(transport: str = "grpc_asyncio"): +async def test_create_scan_config_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.CreateScanConfigRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.CreateScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -432,7 +581,7 @@ async def test_create_scan_config_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.CreateScanConfigRequest() # Establish that the response is the type that we expect. assert isinstance(response, gcw_scan_config.ScanConfig) @@ -454,6 +603,11 @@ async def test_create_scan_config_async(transport: str = "grpc_asyncio"): ] +@pytest.mark.asyncio +async def test_create_scan_config_async_from_dict(): + await test_create_scan_config_async(request_type=dict) + + def test_create_scan_config_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -464,7 +618,7 @@ def test_create_scan_config_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: call.return_value = gcw_scan_config.ScanConfig() @@ -493,7 +647,7 @@ async def test_create_scan_config_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( gcw_scan_config.ScanConfig() @@ -516,7 +670,7 @@ def test_create_scan_config_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig() @@ -559,7 +713,7 @@ async def test_create_scan_config_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig() @@ -600,18 +754,20 @@ async def test_create_scan_config_flattened_error_async(): ) -def test_delete_scan_config(transport: str = "grpc"): +def test_delete_scan_config( + transport: str = "grpc", request_type=web_security_scanner.DeleteScanConfigRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.DeleteScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = None @@ -622,25 +778,50 @@ def test_delete_scan_config(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.DeleteScanConfigRequest() # Establish that the response is the type that we expect. assert response is None +def test_delete_scan_config_from_dict(): + test_delete_scan_config(request_type=dict) + + +def test_delete_scan_config_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_scan_config), "__call__" + ) as call: + client.delete_scan_config() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.DeleteScanConfigRequest() + + @pytest.mark.asyncio -async def test_delete_scan_config_async(transport: str = "grpc_asyncio"): +async def test_delete_scan_config_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.DeleteScanConfigRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.DeleteScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) @@ -651,12 +832,17 @@ async def test_delete_scan_config_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.DeleteScanConfigRequest() # Establish that the response is the type that we expect. assert response is None +@pytest.mark.asyncio +async def test_delete_scan_config_async_from_dict(): + await test_delete_scan_config_async(request_type=dict) + + def test_delete_scan_config_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -667,7 +853,7 @@ def test_delete_scan_config_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: call.return_value = None @@ -696,7 +882,7 @@ async def test_delete_scan_config_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) @@ -717,7 +903,7 @@ def test_delete_scan_config_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = None @@ -753,7 +939,7 @@ async def test_delete_scan_config_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = None @@ -785,17 +971,19 @@ async def test_delete_scan_config_flattened_error_async(): ) -def test_get_scan_config(transport: str = "grpc"): +def test_get_scan_config( + transport: str = "grpc", request_type=web_security_scanner.GetScanConfigRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_config), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_config.ScanConfig( name="name_value", @@ -813,9 +1001,10 @@ def test_get_scan_config(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetScanConfigRequest() # Establish that the response is the type that we expect. + assert isinstance(response, scan_config.ScanConfig) assert response.name == "name_value" @@ -835,20 +1024,41 @@ def test_get_scan_config(transport: str = "grpc"): ] +def test_get_scan_config_from_dict(): + test_get_scan_config(request_type=dict) + + +def test_get_scan_config_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: + client.get_scan_config() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.GetScanConfigRequest() + + @pytest.mark.asyncio -async def test_get_scan_config_async(transport: str = "grpc_asyncio"): +async def test_get_scan_config_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.GetScanConfigRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_config), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_config.ScanConfig( @@ -868,7 +1078,7 @@ async def test_get_scan_config_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetScanConfigRequest() # Establish that the response is the type that we expect. assert isinstance(response, scan_config.ScanConfig) @@ -890,6 +1100,11 @@ async def test_get_scan_config_async(transport: str = "grpc_asyncio"): ] +@pytest.mark.asyncio +async def test_get_scan_config_async_from_dict(): + await test_get_scan_config_async(request_type=dict) + + def test_get_scan_config_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -899,7 +1114,7 @@ def test_get_scan_config_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_config), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: call.return_value = scan_config.ScanConfig() client.get_scan_config(request) @@ -926,9 +1141,7 @@ async def test_get_scan_config_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_config), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_config.ScanConfig() ) @@ -949,7 +1162,7 @@ def test_get_scan_config_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_config), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_config.ScanConfig() @@ -983,9 +1196,7 @@ async def test_get_scan_config_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_config), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_config.ScanConfig() @@ -1018,18 +1229,20 @@ async def test_get_scan_config_flattened_error_async(): ) -def test_list_scan_configs(transport: str = "grpc"): +def test_list_scan_configs( + transport: str = "grpc", request_type=web_security_scanner.ListScanConfigsRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListScanConfigsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanConfigsResponse( @@ -1042,27 +1255,53 @@ def test_list_scan_configs(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListScanConfigsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListScanConfigsPager) assert response.next_page_token == "next_page_token_value" +def test_list_scan_configs_from_dict(): + test_list_scan_configs(request_type=dict) + + +def test_list_scan_configs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_scan_configs), "__call__" + ) as call: + client.list_scan_configs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListScanConfigsRequest() + + @pytest.mark.asyncio -async def test_list_scan_configs_async(transport: str = "grpc_asyncio"): +async def test_list_scan_configs_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListScanConfigsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListScanConfigsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -1077,7 +1316,7 @@ async def test_list_scan_configs_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListScanConfigsRequest() # Establish that the response is the type that we expect. assert isinstance(response, pagers.ListScanConfigsAsyncPager) @@ -1085,6 +1324,11 @@ async def test_list_scan_configs_async(transport: str = "grpc_asyncio"): assert response.next_page_token == "next_page_token_value" +@pytest.mark.asyncio +async def test_list_scan_configs_async_from_dict(): + await test_list_scan_configs_async(request_type=dict) + + def test_list_scan_configs_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -1095,7 +1339,7 @@ def test_list_scan_configs_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: call.return_value = web_security_scanner.ListScanConfigsResponse() @@ -1124,7 +1368,7 @@ async def test_list_scan_configs_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListScanConfigsResponse() @@ -1147,7 +1391,7 @@ def test_list_scan_configs_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanConfigsResponse() @@ -1183,7 +1427,7 @@ async def test_list_scan_configs_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanConfigsResponse() @@ -1222,7 +1466,7 @@ def test_list_scan_configs_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -1264,7 +1508,7 @@ def test_list_scan_configs_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -1288,8 +1532,8 @@ def test_list_scan_configs_pages(): RuntimeError, ) pages = list(client.list_scan_configs(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -1300,7 +1544,7 @@ async def test_list_scan_configs_async_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), + type(client.transport.list_scan_configs), "__call__", new_callable=mock.AsyncMock, ) as call: @@ -1343,7 +1587,7 @@ async def test_list_scan_configs_async_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), + type(client.transport.list_scan_configs), "__call__", new_callable=mock.AsyncMock, ) as call: @@ -1369,24 +1613,26 @@ async def test_list_scan_configs_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_scan_configs(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_scan_configs(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token -def test_update_scan_config(transport: str = "grpc"): +def test_update_scan_config( + transport: str = "grpc", request_type=web_security_scanner.UpdateScanConfigRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.UpdateScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig( @@ -1405,9 +1651,10 @@ def test_update_scan_config(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.UpdateScanConfigRequest() # Establish that the response is the type that we expect. + assert isinstance(response, gcw_scan_config.ScanConfig) assert response.name == "name_value" @@ -1427,19 +1674,44 @@ def test_update_scan_config(transport: str = "grpc"): ] +def test_update_scan_config_from_dict(): + test_update_scan_config(request_type=dict) + + +def test_update_scan_config_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_scan_config), "__call__" + ) as call: + client.update_scan_config() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.UpdateScanConfigRequest() + + @pytest.mark.asyncio -async def test_update_scan_config_async(transport: str = "grpc_asyncio"): +async def test_update_scan_config_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.UpdateScanConfigRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.UpdateScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -1460,7 +1732,7 @@ async def test_update_scan_config_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.UpdateScanConfigRequest() # Establish that the response is the type that we expect. assert isinstance(response, gcw_scan_config.ScanConfig) @@ -1482,6 +1754,11 @@ async def test_update_scan_config_async(transport: str = "grpc_asyncio"): ] +@pytest.mark.asyncio +async def test_update_scan_config_async_from_dict(): + await test_update_scan_config_async(request_type=dict) + + def test_update_scan_config_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -1492,7 +1769,7 @@ def test_update_scan_config_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: call.return_value = gcw_scan_config.ScanConfig() @@ -1523,7 +1800,7 @@ async def test_update_scan_config_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( gcw_scan_config.ScanConfig() @@ -1548,7 +1825,7 @@ def test_update_scan_config_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig() @@ -1591,7 +1868,7 @@ async def test_update_scan_config_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig() @@ -1632,17 +1909,19 @@ async def test_update_scan_config_flattened_error_async(): ) -def test_start_scan_run(transport: str = "grpc"): +def test_start_scan_run( + transport: str = "grpc", request_type=web_security_scanner.StartScanRunRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.StartScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.start_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun( name="name_value", @@ -1660,9 +1939,10 @@ def test_start_scan_run(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.StartScanRunRequest() # Establish that the response is the type that we expect. + assert isinstance(response, scan_run.ScanRun) assert response.name == "name_value" @@ -1680,20 +1960,41 @@ def test_start_scan_run(transport: str = "grpc"): assert response.progress_percent == 1733 +def test_start_scan_run_from_dict(): + test_start_scan_run(request_type=dict) + + +def test_start_scan_run_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: + client.start_scan_run() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.StartScanRunRequest() + + @pytest.mark.asyncio -async def test_start_scan_run_async(transport: str = "grpc_asyncio"): +async def test_start_scan_run_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.StartScanRunRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.StartScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.start_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_run.ScanRun( @@ -1713,7 +2014,7 @@ async def test_start_scan_run_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.StartScanRunRequest() # Establish that the response is the type that we expect. assert isinstance(response, scan_run.ScanRun) @@ -1733,6 +2034,11 @@ async def test_start_scan_run_async(transport: str = "grpc_asyncio"): assert response.progress_percent == 1733 +@pytest.mark.asyncio +async def test_start_scan_run_async_from_dict(): + await test_start_scan_run_async(request_type=dict) + + def test_start_scan_run_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -1742,7 +2048,7 @@ def test_start_scan_run_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.start_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: call.return_value = scan_run.ScanRun() client.start_scan_run(request) @@ -1769,9 +2075,7 @@ async def test_start_scan_run_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.start_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) await client.start_scan_run(request) @@ -1790,7 +2094,7 @@ def test_start_scan_run_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.start_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -1824,9 +2128,7 @@ async def test_start_scan_run_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.start_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -1857,17 +2159,19 @@ async def test_start_scan_run_flattened_error_async(): ) -def test_get_scan_run(transport: str = "grpc"): +def test_get_scan_run( + transport: str = "grpc", request_type=web_security_scanner.GetScanRunRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun( name="name_value", @@ -1885,9 +2189,10 @@ def test_get_scan_run(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetScanRunRequest() # Establish that the response is the type that we expect. + assert isinstance(response, scan_run.ScanRun) assert response.name == "name_value" @@ -1905,20 +2210,40 @@ def test_get_scan_run(transport: str = "grpc"): assert response.progress_percent == 1733 +def test_get_scan_run_from_dict(): + test_get_scan_run(request_type=dict) + + +def test_get_scan_run_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: + client.get_scan_run() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.GetScanRunRequest() + + @pytest.mark.asyncio -async def test_get_scan_run_async(transport: str = "grpc_asyncio"): +async def test_get_scan_run_async( + transport: str = "grpc_asyncio", request_type=web_security_scanner.GetScanRunRequest +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_run.ScanRun( @@ -1938,7 +2263,7 @@ async def test_get_scan_run_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetScanRunRequest() # Establish that the response is the type that we expect. assert isinstance(response, scan_run.ScanRun) @@ -1958,7 +2283,12 @@ async def test_get_scan_run_async(transport: str = "grpc_asyncio"): assert response.progress_percent == 1733 -def test_get_scan_run_field_headers(): +@pytest.mark.asyncio +async def test_get_scan_run_async_from_dict(): + await test_get_scan_run_async(request_type=dict) + + +def test_get_scan_run_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Any value that is part of the HTTP/1.1 URI should be sent as @@ -1967,7 +2297,7 @@ def test_get_scan_run_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: call.return_value = scan_run.ScanRun() client.get_scan_run(request) @@ -1994,9 +2324,7 @@ async def test_get_scan_run_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) await client.get_scan_run(request) @@ -2015,7 +2343,7 @@ def test_get_scan_run_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -2049,9 +2377,7 @@ async def test_get_scan_run_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -2082,17 +2408,19 @@ async def test_get_scan_run_flattened_error_async(): ) -def test_list_scan_runs(transport: str = "grpc"): +def test_list_scan_runs( + transport: str = "grpc", request_type=web_security_scanner.ListScanRunsRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListScanRunsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanRunsResponse( next_page_token="next_page_token_value", @@ -2104,28 +2432,50 @@ def test_list_scan_runs(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListScanRunsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListScanRunsPager) assert response.next_page_token == "next_page_token_value" +def test_list_scan_runs_from_dict(): + test_list_scan_runs(request_type=dict) + + +def test_list_scan_runs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: + client.list_scan_runs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListScanRunsRequest() + + @pytest.mark.asyncio -async def test_list_scan_runs_async(transport: str = "grpc_asyncio"): +async def test_list_scan_runs_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListScanRunsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListScanRunsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_scan_runs), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListScanRunsResponse( @@ -2139,7 +2489,7 @@ async def test_list_scan_runs_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListScanRunsRequest() # Establish that the response is the type that we expect. assert isinstance(response, pagers.ListScanRunsAsyncPager) @@ -2147,6 +2497,11 @@ async def test_list_scan_runs_async(transport: str = "grpc_asyncio"): assert response.next_page_token == "next_page_token_value" +@pytest.mark.asyncio +async def test_list_scan_runs_async_from_dict(): + await test_list_scan_runs_async(request_type=dict) + + def test_list_scan_runs_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -2156,7 +2511,7 @@ def test_list_scan_runs_field_headers(): request.parent = "parent/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: call.return_value = web_security_scanner.ListScanRunsResponse() client.list_scan_runs(request) @@ -2183,9 +2538,7 @@ async def test_list_scan_runs_field_headers_async(): request.parent = "parent/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_scan_runs), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListScanRunsResponse() ) @@ -2206,7 +2559,7 @@ def test_list_scan_runs_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanRunsResponse() @@ -2240,9 +2593,7 @@ async def test_list_scan_runs_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_scan_runs), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanRunsResponse() @@ -2279,7 +2630,7 @@ def test_list_scan_runs_pager(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials,) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Set the response to a series of pages. call.side_effect = ( web_security_scanner.ListScanRunsResponse( @@ -2315,7 +2666,7 @@ def test_list_scan_runs_pages(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials,) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Set the response to a series of pages. call.side_effect = ( web_security_scanner.ListScanRunsResponse( @@ -2334,8 +2685,8 @@ def test_list_scan_runs_pages(): RuntimeError, ) pages = list(client.list_scan_runs(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -2346,9 +2697,7 @@ async def test_list_scan_runs_async_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_runs), - "__call__", - new_callable=mock.AsyncMock, + type(client.transport.list_scan_runs), "__call__", new_callable=mock.AsyncMock ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -2385,9 +2734,7 @@ async def test_list_scan_runs_async_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_runs), - "__call__", - new_callable=mock.AsyncMock, + type(client.transport.list_scan_runs), "__call__", new_callable=mock.AsyncMock ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -2407,23 +2754,25 @@ async def test_list_scan_runs_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_scan_runs(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_scan_runs(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token -def test_stop_scan_run(transport: str = "grpc"): +def test_stop_scan_run( + transport: str = "grpc", request_type=web_security_scanner.StopScanRunRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.StopScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.stop_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun( name="name_value", @@ -2441,9 +2790,10 @@ def test_stop_scan_run(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.StopScanRunRequest() # Establish that the response is the type that we expect. + assert isinstance(response, scan_run.ScanRun) assert response.name == "name_value" @@ -2461,20 +2811,41 @@ def test_stop_scan_run(transport: str = "grpc"): assert response.progress_percent == 1733 +def test_stop_scan_run_from_dict(): + test_stop_scan_run(request_type=dict) + + +def test_stop_scan_run_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: + client.stop_scan_run() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.StopScanRunRequest() + + @pytest.mark.asyncio -async def test_stop_scan_run_async(transport: str = "grpc_asyncio"): +async def test_stop_scan_run_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.StopScanRunRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.StopScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.stop_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_run.ScanRun( @@ -2494,7 +2865,7 @@ async def test_stop_scan_run_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.StopScanRunRequest() # Establish that the response is the type that we expect. assert isinstance(response, scan_run.ScanRun) @@ -2514,6 +2885,11 @@ async def test_stop_scan_run_async(transport: str = "grpc_asyncio"): assert response.progress_percent == 1733 +@pytest.mark.asyncio +async def test_stop_scan_run_async_from_dict(): + await test_stop_scan_run_async(request_type=dict) + + def test_stop_scan_run_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -2523,7 +2899,7 @@ def test_stop_scan_run_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.stop_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: call.return_value = scan_run.ScanRun() client.stop_scan_run(request) @@ -2550,9 +2926,7 @@ async def test_stop_scan_run_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.stop_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) await client.stop_scan_run(request) @@ -2571,7 +2945,7 @@ def test_stop_scan_run_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.stop_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -2605,9 +2979,7 @@ async def test_stop_scan_run_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.stop_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -2638,18 +3010,20 @@ async def test_stop_scan_run_flattened_error_async(): ) -def test_list_crawled_urls(transport: str = "grpc"): +def test_list_crawled_urls( + transport: str = "grpc", request_type=web_security_scanner.ListCrawledUrlsRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListCrawledUrlsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListCrawledUrlsResponse( @@ -2662,27 +3036,53 @@ def test_list_crawled_urls(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListCrawledUrlsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListCrawledUrlsPager) assert response.next_page_token == "next_page_token_value" +def test_list_crawled_urls_from_dict(): + test_list_crawled_urls(request_type=dict) + + +def test_list_crawled_urls_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_crawled_urls), "__call__" + ) as call: + client.list_crawled_urls() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListCrawledUrlsRequest() + + @pytest.mark.asyncio -async def test_list_crawled_urls_async(transport: str = "grpc_asyncio"): +async def test_list_crawled_urls_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListCrawledUrlsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListCrawledUrlsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -2697,7 +3097,7 @@ async def test_list_crawled_urls_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListCrawledUrlsRequest() # Establish that the response is the type that we expect. assert isinstance(response, pagers.ListCrawledUrlsAsyncPager) @@ -2705,6 +3105,11 @@ async def test_list_crawled_urls_async(transport: str = "grpc_asyncio"): assert response.next_page_token == "next_page_token_value" +@pytest.mark.asyncio +async def test_list_crawled_urls_async_from_dict(): + await test_list_crawled_urls_async(request_type=dict) + + def test_list_crawled_urls_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -2715,7 +3120,7 @@ def test_list_crawled_urls_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: call.return_value = web_security_scanner.ListCrawledUrlsResponse() @@ -2744,7 +3149,7 @@ async def test_list_crawled_urls_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListCrawledUrlsResponse() @@ -2767,7 +3172,7 @@ def test_list_crawled_urls_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListCrawledUrlsResponse() @@ -2803,7 +3208,7 @@ async def test_list_crawled_urls_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListCrawledUrlsResponse() @@ -2842,7 +3247,7 @@ def test_list_crawled_urls_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -2884,7 +3289,7 @@ def test_list_crawled_urls_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -2908,8 +3313,8 @@ def test_list_crawled_urls_pages(): RuntimeError, ) pages = list(client.list_crawled_urls(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -2920,7 +3325,7 @@ async def test_list_crawled_urls_async_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), + type(client.transport.list_crawled_urls), "__call__", new_callable=mock.AsyncMock, ) as call: @@ -2963,7 +3368,7 @@ async def test_list_crawled_urls_async_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), + type(client.transport.list_crawled_urls), "__call__", new_callable=mock.AsyncMock, ) as call: @@ -2989,23 +3394,25 @@ async def test_list_crawled_urls_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_crawled_urls(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_crawled_urls(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token -def test_get_finding(transport: str = "grpc"): +def test_get_finding( + transport: str = "grpc", request_type=web_security_scanner.GetFindingRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetFindingRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_finding), "__call__") as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = finding.Finding( name="name_value", @@ -3026,9 +3433,10 @@ def test_get_finding(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetFindingRequest() # Establish that the response is the type that we expect. + assert isinstance(response, finding.Finding) assert response.name == "name_value" @@ -3052,20 +3460,40 @@ def test_get_finding(transport: str = "grpc"): assert response.tracking_id == "tracking_id_value" +def test_get_finding_from_dict(): + test_get_finding(request_type=dict) + + +def test_get_finding_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: + client.get_finding() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.GetFindingRequest() + + @pytest.mark.asyncio -async def test_get_finding_async(transport: str = "grpc_asyncio"): +async def test_get_finding_async( + transport: str = "grpc_asyncio", request_type=web_security_scanner.GetFindingRequest +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetFindingRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_finding), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( finding.Finding( @@ -3088,7 +3516,7 @@ async def test_get_finding_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetFindingRequest() # Establish that the response is the type that we expect. assert isinstance(response, finding.Finding) @@ -3114,6 +3542,11 @@ async def test_get_finding_async(transport: str = "grpc_asyncio"): assert response.tracking_id == "tracking_id_value" +@pytest.mark.asyncio +async def test_get_finding_async_from_dict(): + await test_get_finding_async(request_type=dict) + + def test_get_finding_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -3123,7 +3556,7 @@ def test_get_finding_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_finding), "__call__") as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: call.return_value = finding.Finding() client.get_finding(request) @@ -3150,9 +3583,7 @@ async def test_get_finding_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_finding), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(finding.Finding()) await client.get_finding(request) @@ -3171,7 +3602,7 @@ def test_get_finding_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_finding), "__call__") as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = finding.Finding() @@ -3205,9 +3636,7 @@ async def test_get_finding_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_finding), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = finding.Finding() @@ -3238,17 +3667,19 @@ async def test_get_finding_flattened_error_async(): ) -def test_list_findings(transport: str = "grpc"): +def test_list_findings( + transport: str = "grpc", request_type=web_security_scanner.ListFindingsRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListFindingsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingsResponse( next_page_token="next_page_token_value", @@ -3260,28 +3691,50 @@ def test_list_findings(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListFindingsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListFindingsPager) assert response.next_page_token == "next_page_token_value" +def test_list_findings_from_dict(): + test_list_findings(request_type=dict) + + +def test_list_findings_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: + client.list_findings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListFindingsRequest() + + @pytest.mark.asyncio -async def test_list_findings_async(transport: str = "grpc_asyncio"): +async def test_list_findings_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListFindingsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListFindingsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_findings), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListFindingsResponse( @@ -3295,7 +3748,7 @@ async def test_list_findings_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListFindingsRequest() # Establish that the response is the type that we expect. assert isinstance(response, pagers.ListFindingsAsyncPager) @@ -3303,6 +3756,11 @@ async def test_list_findings_async(transport: str = "grpc_asyncio"): assert response.next_page_token == "next_page_token_value" +@pytest.mark.asyncio +async def test_list_findings_async_from_dict(): + await test_list_findings_async(request_type=dict) + + def test_list_findings_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -3312,7 +3770,7 @@ def test_list_findings_field_headers(): request.parent = "parent/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: call.return_value = web_security_scanner.ListFindingsResponse() client.list_findings(request) @@ -3339,9 +3797,7 @@ async def test_list_findings_field_headers_async(): request.parent = "parent/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_findings), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListFindingsResponse() ) @@ -3362,7 +3818,7 @@ def test_list_findings_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingsResponse() @@ -3402,9 +3858,7 @@ async def test_list_findings_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_findings), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingsResponse() @@ -3447,7 +3901,7 @@ def test_list_findings_pager(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials,) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Set the response to a series of pages. call.side_effect = ( web_security_scanner.ListFindingsResponse( @@ -3483,7 +3937,7 @@ def test_list_findings_pages(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials,) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Set the response to a series of pages. call.side_effect = ( web_security_scanner.ListFindingsResponse( @@ -3502,8 +3956,8 @@ def test_list_findings_pages(): RuntimeError, ) pages = list(client.list_findings(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -3514,9 +3968,7 @@ async def test_list_findings_async_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_findings), - "__call__", - new_callable=mock.AsyncMock, + type(client.transport.list_findings), "__call__", new_callable=mock.AsyncMock ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -3553,9 +4005,7 @@ async def test_list_findings_async_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_findings), - "__call__", - new_callable=mock.AsyncMock, + type(client.transport.list_findings), "__call__", new_callable=mock.AsyncMock ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -3575,24 +4025,27 @@ async def test_list_findings_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_findings(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_findings(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token -def test_list_finding_type_stats(transport: str = "grpc"): +def test_list_finding_type_stats( + transport: str = "grpc", + request_type=web_security_scanner.ListFindingTypeStatsRequest, +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListFindingTypeStatsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingTypeStatsResponse() @@ -3603,25 +4056,51 @@ def test_list_finding_type_stats(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListFindingTypeStatsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, web_security_scanner.ListFindingTypeStatsResponse) +def test_list_finding_type_stats_from_dict(): + test_list_finding_type_stats(request_type=dict) + + +def test_list_finding_type_stats_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_finding_type_stats), "__call__" + ) as call: + client.list_finding_type_stats() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListFindingTypeStatsRequest() + + @pytest.mark.asyncio -async def test_list_finding_type_stats_async(transport: str = "grpc_asyncio"): +async def test_list_finding_type_stats_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListFindingTypeStatsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListFindingTypeStatsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -3634,12 +4113,17 @@ async def test_list_finding_type_stats_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListFindingTypeStatsRequest() # Establish that the response is the type that we expect. assert isinstance(response, web_security_scanner.ListFindingTypeStatsResponse) +@pytest.mark.asyncio +async def test_list_finding_type_stats_async_from_dict(): + await test_list_finding_type_stats_async(request_type=dict) + + def test_list_finding_type_stats_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -3650,7 +4134,7 @@ def test_list_finding_type_stats_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: call.return_value = web_security_scanner.ListFindingTypeStatsResponse() @@ -3679,7 +4163,7 @@ async def test_list_finding_type_stats_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListFindingTypeStatsResponse() @@ -3702,7 +4186,7 @@ def test_list_finding_type_stats_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingTypeStatsResponse() @@ -3738,7 +4222,7 @@ async def test_list_finding_type_stats_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingTypeStatsResponse() @@ -3808,7 +4292,7 @@ def test_transport_instance(): credentials=credentials.AnonymousCredentials(), ) client = WebSecurityScannerClient(transport=transport) - assert client._transport is transport + assert client.transport is transport def test_transport_get_channel(): @@ -3826,10 +4310,25 @@ def test_transport_get_channel(): assert channel +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + def test_transport_grpc_default(): # A client should use the gRPC transport by default. client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) - assert isinstance(client._transport, transports.WebSecurityScannerGrpcTransport,) + assert isinstance(client.transport, transports.WebSecurityScannerGrpcTransport,) def test_web_security_scanner_base_transport_error(): @@ -3843,9 +4342,13 @@ def test_web_security_scanner_base_transport_error(): def test_web_security_scanner_base_transport(): # Instantiate the base transport. - transport = transports.WebSecurityScannerTransport( - credentials=credentials.AnonymousCredentials(), - ) + with mock.patch( + "google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.transports.WebSecurityScannerTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.WebSecurityScannerTransport( + credentials=credentials.AnonymousCredentials(), + ) # Every method on the transport should just blindly # raise NotImplementedError. @@ -3871,7 +4374,12 @@ def test_web_security_scanner_base_transport(): def test_web_security_scanner_base_transport_with_credentials_file(): # Instantiate the base transport with a credentials file - with mock.patch.object(auth, "load_credentials_from_file") as load_creds: + with mock.patch.object( + auth, "load_credentials_from_file" + ) as load_creds, mock.patch( + "google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.transports.WebSecurityScannerTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None load_creds.return_value = (credentials.AnonymousCredentials(), None) transport = transports.WebSecurityScannerTransport( credentials_file="credentials.json", quota_project_id="octopus", @@ -3883,6 +4391,17 @@ def test_web_security_scanner_base_transport_with_credentials_file(): ) +def test_web_security_scanner_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(auth, "default") as adc, mock.patch( + "google.cloud.websecurityscanner_v1alpha.services.web_security_scanner.transports.WebSecurityScannerTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.WebSecurityScannerTransport() + adc.assert_called_once() + + def test_web_security_scanner_auth_adc(): # If no credentials are provided, we should use ADC credentials. with mock.patch.object(auth, "default") as adc: @@ -3908,6 +4427,53 @@ def test_web_security_scanner_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], +) +def test_web_security_scanner_grpc_transport_client_cert_source_for_mtls( + transport_class, +): + cred = credentials.AnonymousCredentials() + + # Check ssl_channel_credentials is used if provided. + with mock.patch.object(transport_class, "create_channel") as mock_create_channel: + mock_ssl_channel_creds = mock.Mock() + transport_class( + host="squid.clam.whelk", + credentials=cred, + ssl_channel_credentials=mock_ssl_channel_creds, + ) + mock_create_channel.assert_called_once_with( + "squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + def test_web_security_scanner_host_no_port(): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), @@ -3915,7 +4481,7 @@ def test_web_security_scanner_host_no_port(): api_endpoint="websecurityscanner.googleapis.com" ), ) - assert client._transport._host == "websecurityscanner.googleapis.com:443" + assert client.transport._host == "websecurityscanner.googleapis.com:443" def test_web_security_scanner_host_with_port(): @@ -3925,185 +4491,183 @@ def test_web_security_scanner_host_with_port(): api_endpoint="websecurityscanner.googleapis.com:8000" ), ) - assert client._transport._host == "websecurityscanner.googleapis.com:8000" + assert client.transport._host == "websecurityscanner.googleapis.com:8000" def test_web_security_scanner_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.WebSecurityScannerGrpcTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called + assert transport._ssl_channel_credentials == None def test_web_security_scanner_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.WebSecurityScannerGrpcAsyncIOTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called + assert transport._ssl_channel_credentials == None -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_web_security_scanner_grpc_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], +) +def test_web_security_scanner_transport_channel_mtls_with_client_cert_source( + transport_class, ): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + assert transport._ssl_channel_credentials == mock_ssl_cred + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], +) +def test_web_security_scanner_transport_channel_mtls_with_adc(transport_class): mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel - transport = transports.WebSecurityScannerGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel +def test_finding_path(): + project = "squid" + scan_config = "clam" + scan_run = "whelk" + finding = "octopus" -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_web_security_scanner_grpc_asyncio_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() + expected = "projects/{project}/scanConfigs/{scan_config}/scanRuns/{scan_run}/findings/{finding}".format( + project=project, scan_config=scan_config, scan_run=scan_run, finding=finding, + ) + actual = WebSecurityScannerClient.finding_path( + project, scan_config, scan_run, finding + ) + assert expected == actual - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel +def test_parse_finding_path(): + expected = { + "project": "oyster", + "scan_config": "nudibranch", + "scan_run": "cuttlefish", + "finding": "mussel", + } + path = WebSecurityScannerClient.finding_path(**expected) - transport = transports.WebSecurityScannerGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_finding_path(path) + assert expected == actual -@pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] -) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_web_security_scanner_grpc_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel +def test_scan_config_path(): + project = "winkle" + scan_config = "nautilus" - # Mock google.auth.transport.grpc.SslCredentials class. - mock_ssl_cred = mock.Mock() - with mock.patch.multiple( - "google.auth.transport.grpc.SslCredentials", - __init__=mock.Mock(return_value=None), - ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), - ): - mock_cred = mock.Mock() - transport = transports.WebSecurityScannerGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + expected = "projects/{project}/scanConfigs/{scan_config}".format( + project=project, scan_config=scan_config, + ) + actual = WebSecurityScannerClient.scan_config_path(project, scan_config) + assert expected == actual -@pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] -) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_web_security_scanner_grpc_asyncio_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel +def test_parse_scan_config_path(): + expected = { + "project": "scallop", + "scan_config": "abalone", + } + path = WebSecurityScannerClient.scan_config_path(**expected) - # Mock google.auth.transport.grpc.SslCredentials class. - mock_ssl_cred = mock.Mock() - with mock.patch.multiple( - "google.auth.transport.grpc.SslCredentials", - __init__=mock.Mock(return_value=None), - ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), - ): - mock_cred = mock.Mock() - transport = transports.WebSecurityScannerGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_scan_config_path(path) + assert expected == actual def test_scan_run_path(): @@ -4131,24 +4695,123 @@ def test_parse_scan_run_path(): assert expected == actual -def test_scan_config_path(): +def test_common_billing_account_path(): + billing_account = "cuttlefish" + + expected = "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + actual = WebSecurityScannerClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "mussel", + } + path = WebSecurityScannerClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_billing_account_path(path) + assert expected == actual + + +def test_common_folder_path(): + folder = "winkle" + + expected = "folders/{folder}".format(folder=folder,) + actual = WebSecurityScannerClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "nautilus", + } + path = WebSecurityScannerClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_folder_path(path) + assert expected == actual + + +def test_common_organization_path(): + organization = "scallop" + + expected = "organizations/{organization}".format(organization=organization,) + actual = WebSecurityScannerClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "abalone", + } + path = WebSecurityScannerClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_organization_path(path) + assert expected == actual + + +def test_common_project_path(): project = "squid" - scan_config = "clam" - expected = "projects/{project}/scanConfigs/{scan_config}".format( - project=project, scan_config=scan_config, + expected = "projects/{project}".format(project=project,) + actual = WebSecurityScannerClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "clam", + } + path = WebSecurityScannerClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_project_path(path) + assert expected == actual + + +def test_common_location_path(): + project = "whelk" + location = "octopus" + + expected = "projects/{project}/locations/{location}".format( + project=project, location=location, ) - actual = WebSecurityScannerClient.scan_config_path(project, scan_config) + actual = WebSecurityScannerClient.common_location_path(project, location) assert expected == actual -def test_parse_scan_config_path(): +def test_parse_common_location_path(): expected = { - "project": "whelk", - "scan_config": "octopus", + "project": "oyster", + "location": "nudibranch", } - path = WebSecurityScannerClient.scan_config_path(**expected) + path = WebSecurityScannerClient.common_location_path(**expected) # Check that the path construction is reversible. - actual = WebSecurityScannerClient.parse_scan_config_path(path) + actual = WebSecurityScannerClient.parse_common_location_path(path) assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object( + transports.WebSecurityScannerTransport, "_prep_wrapped_messages" + ) as prep: + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object( + transports.WebSecurityScannerTransport, "_prep_wrapped_messages" + ) as prep: + transport_class = WebSecurityScannerClient.get_transport_class() + transport = transport_class( + credentials=credentials.AnonymousCredentials(), client_info=client_info, + ) + prep.assert_called_once_with(client_info) diff --git a/tests/unit/gapic/websecurityscanner_v1beta/__init__.py b/tests/unit/gapic/websecurityscanner_v1beta/__init__.py index e69de29..42ffdf2 100644 --- a/tests/unit/gapic/websecurityscanner_v1beta/__init__.py +++ b/tests/unit/gapic/websecurityscanner_v1beta/__init__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 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/unit/gapic/websecurityscanner_v1beta/test_web_security_scanner.py b/tests/unit/gapic/websecurityscanner_v1beta/test_web_security_scanner.py index aa9695e..7952c4b 100644 --- a/tests/unit/gapic/websecurityscanner_v1beta/test_web_security_scanner.py +++ b/tests/unit/gapic/websecurityscanner_v1beta/test_web_security_scanner.py @@ -49,9 +49,6 @@ from google.cloud.websecurityscanner_v1beta.types import scan_config from google.cloud.websecurityscanner_v1beta.types import scan_config as gcw_scan_config from google.cloud.websecurityscanner_v1beta.types import scan_config_error -from google.cloud.websecurityscanner_v1beta.types import ( - scan_config_error as gcw_scan_config_error, -) from google.cloud.websecurityscanner_v1beta.types import scan_run from google.cloud.websecurityscanner_v1beta.types import scan_run_error_trace from google.cloud.websecurityscanner_v1beta.types import scan_run_warning_trace @@ -65,6 +62,17 @@ def client_cert_source_callback(): return b"cert bytes", b"key bytes" +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return ( + "foo.googleapis.com" + if ("localhost" in client.DEFAULT_ENDPOINT) + else client.DEFAULT_ENDPOINT + ) + + def test__get_default_mtls_endpoint(): api_endpoint = "example.googleapis.com" api_mtls_endpoint = "example.mtls.googleapis.com" @@ -96,7 +104,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [WebSecurityScannerClient, WebSecurityScannerAsyncClient] + "client_class", [WebSecurityScannerClient, WebSecurityScannerAsyncClient,] +) +def test_web_security_scanner_client_from_service_account_info(client_class): + creds = credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_info" + ) as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == "websecurityscanner.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [WebSecurityScannerClient, WebSecurityScannerAsyncClient,] ) def test_web_security_scanner_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -105,17 +130,22 @@ def test_web_security_scanner_client_from_service_account_file(client_class): ) as factory: factory.return_value = creds client = client_class.from_service_account_file("dummy/file/path.json") - assert client._transport._credentials == creds + assert client.transport._credentials == creds + assert isinstance(client, client_class) client = client_class.from_service_account_json("dummy/file/path.json") - assert client._transport._credentials == creds + assert client.transport._credentials == creds + assert isinstance(client, client_class) - assert client._transport._host == "websecurityscanner.googleapis.com:443" + assert client.transport._host == "websecurityscanner.googleapis.com:443" def test_web_security_scanner_client_get_transport_class(): transport = WebSecurityScannerClient.get_transport_class() - assert transport == transports.WebSecurityScannerGrpcTransport + available_transports = [ + transports.WebSecurityScannerGrpcTransport, + ] + assert transport in available_transports transport = WebSecurityScannerClient.get_transport_class("grpc") assert transport == transports.WebSecurityScannerGrpcTransport @@ -132,6 +162,16 @@ def test_web_security_scanner_client_get_transport_class(): ), ], ) +@mock.patch.object( + WebSecurityScannerClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(WebSecurityScannerClient), +) +@mock.patch.object( + WebSecurityScannerAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(WebSecurityScannerAsyncClient), +) def test_web_security_scanner_client_client_options( client_class, transport_class, transport_name ): @@ -156,14 +196,14 @@ def test_web_security_scanner_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "never". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "never"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -172,14 +212,14 @@ def test_web_security_scanner_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "always". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "always"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -188,53 +228,152 @@ def test_web_security_scanner_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + ( + WebSecurityScannerClient, + transports.WebSecurityScannerGrpcTransport, + "grpc", + "true", + ), + ( + WebSecurityScannerAsyncClient, + transports.WebSecurityScannerGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + ( + WebSecurityScannerClient, + transports.WebSecurityScannerGrpcTransport, + "grpc", + "false", + ), + ( + WebSecurityScannerAsyncClient, + transports.WebSecurityScannerGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + WebSecurityScannerClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(WebSecurityScannerClient), +) +@mock.patch.object( + WebSecurityScannerAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(WebSecurityScannerAsyncClient), +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_web_security_scanner_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): options = client_options.ClientOptions( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class(client_options=options) + + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT + patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, + host=expected_host, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=client_cert_source_callback, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and default_client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( "google.auth.transport.mtls.has_default_client_cert_source", return_value=True, ): - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, - quota_project_id=None, - ) - - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", but client_cert_source and default_client_cert_source are None. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback + + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( "google.auth.transport.mtls.has_default_client_cert_source", @@ -247,32 +386,11 @@ def test_web_security_scanner_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS has - # unsupported value. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "Unsupported"}): - with pytest.raises(MutualTLSChannelError): - client = client_class() - - # Check the case quota_project_id is provided - options = client_options.ClientOptions(quota_project_id="octopus") - with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id="octopus", - ) - @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -298,9 +416,9 @@ def test_web_security_scanner_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -328,9 +446,9 @@ def test_web_security_scanner_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -347,24 +465,26 @@ def test_web_security_scanner_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + client_cert_source_for_mtls=None, quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, ) -def test_create_scan_config(transport: str = "grpc"): +def test_create_scan_config( + transport: str = "grpc", request_type=web_security_scanner.CreateScanConfigRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.CreateScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig( @@ -385,9 +505,10 @@ def test_create_scan_config(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.CreateScanConfigRequest() # Establish that the response is the type that we expect. + assert isinstance(response, gcw_scan_config.ScanConfig) assert response.name == "name_value" @@ -414,19 +535,44 @@ def test_create_scan_config(transport: str = "grpc"): assert response.risk_level == gcw_scan_config.ScanConfig.RiskLevel.NORMAL +def test_create_scan_config_from_dict(): + test_create_scan_config(request_type=dict) + + +def test_create_scan_config_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_scan_config), "__call__" + ) as call: + client.create_scan_config() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.CreateScanConfigRequest() + + @pytest.mark.asyncio -async def test_create_scan_config_async(transport: str = "grpc_asyncio"): +async def test_create_scan_config_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.CreateScanConfigRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.CreateScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -449,7 +595,7 @@ async def test_create_scan_config_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.CreateScanConfigRequest() # Establish that the response is the type that we expect. assert isinstance(response, gcw_scan_config.ScanConfig) @@ -478,6 +624,11 @@ async def test_create_scan_config_async(transport: str = "grpc_asyncio"): assert response.risk_level == gcw_scan_config.ScanConfig.RiskLevel.NORMAL +@pytest.mark.asyncio +async def test_create_scan_config_async_from_dict(): + await test_create_scan_config_async(request_type=dict) + + def test_create_scan_config_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -488,7 +639,7 @@ def test_create_scan_config_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: call.return_value = gcw_scan_config.ScanConfig() @@ -517,7 +668,7 @@ async def test_create_scan_config_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( gcw_scan_config.ScanConfig() @@ -540,7 +691,7 @@ def test_create_scan_config_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig() @@ -583,7 +734,7 @@ async def test_create_scan_config_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.create_scan_config), "__call__" + type(client.transport.create_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig() @@ -624,18 +775,20 @@ async def test_create_scan_config_flattened_error_async(): ) -def test_delete_scan_config(transport: str = "grpc"): +def test_delete_scan_config( + transport: str = "grpc", request_type=web_security_scanner.DeleteScanConfigRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.DeleteScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = None @@ -646,25 +799,50 @@ def test_delete_scan_config(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.DeleteScanConfigRequest() # Establish that the response is the type that we expect. assert response is None +def test_delete_scan_config_from_dict(): + test_delete_scan_config(request_type=dict) + + +def test_delete_scan_config_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_scan_config), "__call__" + ) as call: + client.delete_scan_config() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.DeleteScanConfigRequest() + + @pytest.mark.asyncio -async def test_delete_scan_config_async(transport: str = "grpc_asyncio"): +async def test_delete_scan_config_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.DeleteScanConfigRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.DeleteScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) @@ -675,12 +853,17 @@ async def test_delete_scan_config_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.DeleteScanConfigRequest() # Establish that the response is the type that we expect. assert response is None +@pytest.mark.asyncio +async def test_delete_scan_config_async_from_dict(): + await test_delete_scan_config_async(request_type=dict) + + def test_delete_scan_config_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -691,7 +874,7 @@ def test_delete_scan_config_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: call.return_value = None @@ -720,7 +903,7 @@ async def test_delete_scan_config_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) @@ -741,7 +924,7 @@ def test_delete_scan_config_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = None @@ -777,7 +960,7 @@ async def test_delete_scan_config_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.delete_scan_config), "__call__" + type(client.transport.delete_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = None @@ -809,17 +992,19 @@ async def test_delete_scan_config_flattened_error_async(): ) -def test_get_scan_config(transport: str = "grpc"): +def test_get_scan_config( + transport: str = "grpc", request_type=web_security_scanner.GetScanConfigRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_config), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_config.ScanConfig( name="name_value", @@ -839,9 +1024,10 @@ def test_get_scan_config(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetScanConfigRequest() # Establish that the response is the type that we expect. + assert isinstance(response, scan_config.ScanConfig) assert response.name == "name_value" @@ -868,20 +1054,41 @@ def test_get_scan_config(transport: str = "grpc"): assert response.risk_level == scan_config.ScanConfig.RiskLevel.NORMAL +def test_get_scan_config_from_dict(): + test_get_scan_config(request_type=dict) + + +def test_get_scan_config_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: + client.get_scan_config() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.GetScanConfigRequest() + + @pytest.mark.asyncio -async def test_get_scan_config_async(transport: str = "grpc_asyncio"): +async def test_get_scan_config_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.GetScanConfigRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_config), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_config.ScanConfig( @@ -903,7 +1110,7 @@ async def test_get_scan_config_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetScanConfigRequest() # Establish that the response is the type that we expect. assert isinstance(response, scan_config.ScanConfig) @@ -932,6 +1139,11 @@ async def test_get_scan_config_async(transport: str = "grpc_asyncio"): assert response.risk_level == scan_config.ScanConfig.RiskLevel.NORMAL +@pytest.mark.asyncio +async def test_get_scan_config_async_from_dict(): + await test_get_scan_config_async(request_type=dict) + + def test_get_scan_config_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -941,7 +1153,7 @@ def test_get_scan_config_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_config), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: call.return_value = scan_config.ScanConfig() client.get_scan_config(request) @@ -968,9 +1180,7 @@ async def test_get_scan_config_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_config), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_config.ScanConfig() ) @@ -991,7 +1201,7 @@ def test_get_scan_config_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_config), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_config.ScanConfig() @@ -1025,9 +1235,7 @@ async def test_get_scan_config_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_config), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_config), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_config.ScanConfig() @@ -1060,18 +1268,20 @@ async def test_get_scan_config_flattened_error_async(): ) -def test_list_scan_configs(transport: str = "grpc"): +def test_list_scan_configs( + transport: str = "grpc", request_type=web_security_scanner.ListScanConfigsRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListScanConfigsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanConfigsResponse( @@ -1084,27 +1294,53 @@ def test_list_scan_configs(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListScanConfigsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListScanConfigsPager) assert response.next_page_token == "next_page_token_value" +def test_list_scan_configs_from_dict(): + test_list_scan_configs(request_type=dict) + + +def test_list_scan_configs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_scan_configs), "__call__" + ) as call: + client.list_scan_configs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListScanConfigsRequest() + + @pytest.mark.asyncio -async def test_list_scan_configs_async(transport: str = "grpc_asyncio"): +async def test_list_scan_configs_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListScanConfigsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListScanConfigsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -1119,7 +1355,7 @@ async def test_list_scan_configs_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListScanConfigsRequest() # Establish that the response is the type that we expect. assert isinstance(response, pagers.ListScanConfigsAsyncPager) @@ -1127,6 +1363,11 @@ async def test_list_scan_configs_async(transport: str = "grpc_asyncio"): assert response.next_page_token == "next_page_token_value" +@pytest.mark.asyncio +async def test_list_scan_configs_async_from_dict(): + await test_list_scan_configs_async(request_type=dict) + + def test_list_scan_configs_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -1137,7 +1378,7 @@ def test_list_scan_configs_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: call.return_value = web_security_scanner.ListScanConfigsResponse() @@ -1166,7 +1407,7 @@ async def test_list_scan_configs_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListScanConfigsResponse() @@ -1189,7 +1430,7 @@ def test_list_scan_configs_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanConfigsResponse() @@ -1225,7 +1466,7 @@ async def test_list_scan_configs_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanConfigsResponse() @@ -1264,7 +1505,7 @@ def test_list_scan_configs_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -1306,7 +1547,7 @@ def test_list_scan_configs_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_scan_configs), "__call__" + type(client.transport.list_scan_configs), "__call__" ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -1330,8 +1571,8 @@ def test_list_scan_configs_pages(): RuntimeError, ) pages = list(client.list_scan_configs(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -1342,7 +1583,7 @@ async def test_list_scan_configs_async_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), + type(client.transport.list_scan_configs), "__call__", new_callable=mock.AsyncMock, ) as call: @@ -1385,7 +1626,7 @@ async def test_list_scan_configs_async_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_configs), + type(client.transport.list_scan_configs), "__call__", new_callable=mock.AsyncMock, ) as call: @@ -1411,24 +1652,26 @@ async def test_list_scan_configs_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_scan_configs(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_scan_configs(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token -def test_update_scan_config(transport: str = "grpc"): +def test_update_scan_config( + transport: str = "grpc", request_type=web_security_scanner.UpdateScanConfigRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.UpdateScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig( @@ -1449,9 +1692,10 @@ def test_update_scan_config(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.UpdateScanConfigRequest() # Establish that the response is the type that we expect. + assert isinstance(response, gcw_scan_config.ScanConfig) assert response.name == "name_value" @@ -1478,19 +1722,44 @@ def test_update_scan_config(transport: str = "grpc"): assert response.risk_level == gcw_scan_config.ScanConfig.RiskLevel.NORMAL +def test_update_scan_config_from_dict(): + test_update_scan_config(request_type=dict) + + +def test_update_scan_config_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_scan_config), "__call__" + ) as call: + client.update_scan_config() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.UpdateScanConfigRequest() + + @pytest.mark.asyncio -async def test_update_scan_config_async(transport: str = "grpc_asyncio"): +async def test_update_scan_config_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.UpdateScanConfigRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.UpdateScanConfigRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -1513,7 +1782,7 @@ async def test_update_scan_config_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.UpdateScanConfigRequest() # Establish that the response is the type that we expect. assert isinstance(response, gcw_scan_config.ScanConfig) @@ -1542,6 +1811,11 @@ async def test_update_scan_config_async(transport: str = "grpc_asyncio"): assert response.risk_level == gcw_scan_config.ScanConfig.RiskLevel.NORMAL +@pytest.mark.asyncio +async def test_update_scan_config_async_from_dict(): + await test_update_scan_config_async(request_type=dict) + + def test_update_scan_config_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -1552,7 +1826,7 @@ def test_update_scan_config_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: call.return_value = gcw_scan_config.ScanConfig() @@ -1583,7 +1857,7 @@ async def test_update_scan_config_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( gcw_scan_config.ScanConfig() @@ -1608,7 +1882,7 @@ def test_update_scan_config_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig() @@ -1651,7 +1925,7 @@ async def test_update_scan_config_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.update_scan_config), "__call__" + type(client.transport.update_scan_config), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = gcw_scan_config.ScanConfig() @@ -1692,17 +1966,19 @@ async def test_update_scan_config_flattened_error_async(): ) -def test_start_scan_run(transport: str = "grpc"): +def test_start_scan_run( + transport: str = "grpc", request_type=web_security_scanner.StartScanRunRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.StartScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.start_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun( name="name_value", @@ -1720,9 +1996,10 @@ def test_start_scan_run(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.StartScanRunRequest() # Establish that the response is the type that we expect. + assert isinstance(response, scan_run.ScanRun) assert response.name == "name_value" @@ -1740,20 +2017,41 @@ def test_start_scan_run(transport: str = "grpc"): assert response.progress_percent == 1733 +def test_start_scan_run_from_dict(): + test_start_scan_run(request_type=dict) + + +def test_start_scan_run_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: + client.start_scan_run() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.StartScanRunRequest() + + @pytest.mark.asyncio -async def test_start_scan_run_async(transport: str = "grpc_asyncio"): +async def test_start_scan_run_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.StartScanRunRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.StartScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.start_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_run.ScanRun( @@ -1773,7 +2071,7 @@ async def test_start_scan_run_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.StartScanRunRequest() # Establish that the response is the type that we expect. assert isinstance(response, scan_run.ScanRun) @@ -1793,6 +2091,11 @@ async def test_start_scan_run_async(transport: str = "grpc_asyncio"): assert response.progress_percent == 1733 +@pytest.mark.asyncio +async def test_start_scan_run_async_from_dict(): + await test_start_scan_run_async(request_type=dict) + + def test_start_scan_run_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -1802,7 +2105,7 @@ def test_start_scan_run_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.start_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: call.return_value = scan_run.ScanRun() client.start_scan_run(request) @@ -1829,9 +2132,7 @@ async def test_start_scan_run_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.start_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) await client.start_scan_run(request) @@ -1850,7 +2151,7 @@ def test_start_scan_run_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.start_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -1884,9 +2185,7 @@ async def test_start_scan_run_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.start_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.start_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -1917,17 +2216,19 @@ async def test_start_scan_run_flattened_error_async(): ) -def test_get_scan_run(transport: str = "grpc"): +def test_get_scan_run( + transport: str = "grpc", request_type=web_security_scanner.GetScanRunRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun( name="name_value", @@ -1945,9 +2246,10 @@ def test_get_scan_run(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetScanRunRequest() # Establish that the response is the type that we expect. + assert isinstance(response, scan_run.ScanRun) assert response.name == "name_value" @@ -1965,20 +2267,40 @@ def test_get_scan_run(transport: str = "grpc"): assert response.progress_percent == 1733 +def test_get_scan_run_from_dict(): + test_get_scan_run(request_type=dict) + + +def test_get_scan_run_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: + client.get_scan_run() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.GetScanRunRequest() + + @pytest.mark.asyncio -async def test_get_scan_run_async(transport: str = "grpc_asyncio"): +async def test_get_scan_run_async( + transport: str = "grpc_asyncio", request_type=web_security_scanner.GetScanRunRequest +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_run.ScanRun( @@ -1998,7 +2320,7 @@ async def test_get_scan_run_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetScanRunRequest() # Establish that the response is the type that we expect. assert isinstance(response, scan_run.ScanRun) @@ -2018,6 +2340,11 @@ async def test_get_scan_run_async(transport: str = "grpc_asyncio"): assert response.progress_percent == 1733 +@pytest.mark.asyncio +async def test_get_scan_run_async_from_dict(): + await test_get_scan_run_async(request_type=dict) + + def test_get_scan_run_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -2027,7 +2354,7 @@ def test_get_scan_run_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: call.return_value = scan_run.ScanRun() client.get_scan_run(request) @@ -2054,9 +2381,7 @@ async def test_get_scan_run_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) await client.get_scan_run(request) @@ -2075,7 +2400,7 @@ def test_get_scan_run_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -2109,9 +2434,7 @@ async def test_get_scan_run_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -2142,17 +2465,19 @@ async def test_get_scan_run_flattened_error_async(): ) -def test_list_scan_runs(transport: str = "grpc"): +def test_list_scan_runs( + transport: str = "grpc", request_type=web_security_scanner.ListScanRunsRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListScanRunsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanRunsResponse( next_page_token="next_page_token_value", @@ -2164,28 +2489,50 @@ def test_list_scan_runs(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListScanRunsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListScanRunsPager) assert response.next_page_token == "next_page_token_value" +def test_list_scan_runs_from_dict(): + test_list_scan_runs(request_type=dict) + + +def test_list_scan_runs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: + client.list_scan_runs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListScanRunsRequest() + + @pytest.mark.asyncio -async def test_list_scan_runs_async(transport: str = "grpc_asyncio"): +async def test_list_scan_runs_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListScanRunsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListScanRunsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_scan_runs), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListScanRunsResponse( @@ -2199,7 +2546,7 @@ async def test_list_scan_runs_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListScanRunsRequest() # Establish that the response is the type that we expect. assert isinstance(response, pagers.ListScanRunsAsyncPager) @@ -2207,6 +2554,11 @@ async def test_list_scan_runs_async(transport: str = "grpc_asyncio"): assert response.next_page_token == "next_page_token_value" +@pytest.mark.asyncio +async def test_list_scan_runs_async_from_dict(): + await test_list_scan_runs_async(request_type=dict) + + def test_list_scan_runs_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -2216,7 +2568,7 @@ def test_list_scan_runs_field_headers(): request.parent = "parent/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: call.return_value = web_security_scanner.ListScanRunsResponse() client.list_scan_runs(request) @@ -2243,9 +2595,7 @@ async def test_list_scan_runs_field_headers_async(): request.parent = "parent/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_scan_runs), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListScanRunsResponse() ) @@ -2266,7 +2616,7 @@ def test_list_scan_runs_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanRunsResponse() @@ -2300,9 +2650,7 @@ async def test_list_scan_runs_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_scan_runs), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListScanRunsResponse() @@ -2339,7 +2687,7 @@ def test_list_scan_runs_pager(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials,) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Set the response to a series of pages. call.side_effect = ( web_security_scanner.ListScanRunsResponse( @@ -2375,7 +2723,7 @@ def test_list_scan_runs_pages(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials,) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_scan_runs), "__call__") as call: + with mock.patch.object(type(client.transport.list_scan_runs), "__call__") as call: # Set the response to a series of pages. call.side_effect = ( web_security_scanner.ListScanRunsResponse( @@ -2394,8 +2742,8 @@ def test_list_scan_runs_pages(): RuntimeError, ) pages = list(client.list_scan_runs(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -2406,9 +2754,7 @@ async def test_list_scan_runs_async_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_runs), - "__call__", - new_callable=mock.AsyncMock, + type(client.transport.list_scan_runs), "__call__", new_callable=mock.AsyncMock ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -2445,9 +2791,7 @@ async def test_list_scan_runs_async_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_scan_runs), - "__call__", - new_callable=mock.AsyncMock, + type(client.transport.list_scan_runs), "__call__", new_callable=mock.AsyncMock ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -2467,23 +2811,25 @@ async def test_list_scan_runs_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_scan_runs(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_scan_runs(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token -def test_stop_scan_run(transport: str = "grpc"): +def test_stop_scan_run( + transport: str = "grpc", request_type=web_security_scanner.StopScanRunRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.StopScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.stop_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun( name="name_value", @@ -2501,9 +2847,10 @@ def test_stop_scan_run(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.StopScanRunRequest() # Establish that the response is the type that we expect. + assert isinstance(response, scan_run.ScanRun) assert response.name == "name_value" @@ -2521,20 +2868,41 @@ def test_stop_scan_run(transport: str = "grpc"): assert response.progress_percent == 1733 +def test_stop_scan_run_from_dict(): + test_stop_scan_run(request_type=dict) + + +def test_stop_scan_run_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: + client.stop_scan_run() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.StopScanRunRequest() + + @pytest.mark.asyncio -async def test_stop_scan_run_async(transport: str = "grpc_asyncio"): +async def test_stop_scan_run_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.StopScanRunRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.StopScanRunRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.stop_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( scan_run.ScanRun( @@ -2554,7 +2922,7 @@ async def test_stop_scan_run_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.StopScanRunRequest() # Establish that the response is the type that we expect. assert isinstance(response, scan_run.ScanRun) @@ -2574,6 +2942,11 @@ async def test_stop_scan_run_async(transport: str = "grpc_asyncio"): assert response.progress_percent == 1733 +@pytest.mark.asyncio +async def test_stop_scan_run_async_from_dict(): + await test_stop_scan_run_async(request_type=dict) + + def test_stop_scan_run_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -2583,7 +2956,7 @@ def test_stop_scan_run_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.stop_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: call.return_value = scan_run.ScanRun() client.stop_scan_run(request) @@ -2610,9 +2983,7 @@ async def test_stop_scan_run_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.stop_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) await client.stop_scan_run(request) @@ -2631,7 +3002,7 @@ def test_stop_scan_run_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.stop_scan_run), "__call__") as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -2665,9 +3036,7 @@ async def test_stop_scan_run_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.stop_scan_run), "__call__" - ) as call: + with mock.patch.object(type(client.transport.stop_scan_run), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = scan_run.ScanRun() @@ -2698,18 +3067,20 @@ async def test_stop_scan_run_flattened_error_async(): ) -def test_list_crawled_urls(transport: str = "grpc"): +def test_list_crawled_urls( + transport: str = "grpc", request_type=web_security_scanner.ListCrawledUrlsRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListCrawledUrlsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListCrawledUrlsResponse( @@ -2722,27 +3093,53 @@ def test_list_crawled_urls(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListCrawledUrlsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListCrawledUrlsPager) assert response.next_page_token == "next_page_token_value" +def test_list_crawled_urls_from_dict(): + test_list_crawled_urls(request_type=dict) + + +def test_list_crawled_urls_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_crawled_urls), "__call__" + ) as call: + client.list_crawled_urls() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListCrawledUrlsRequest() + + @pytest.mark.asyncio -async def test_list_crawled_urls_async(transport: str = "grpc_asyncio"): +async def test_list_crawled_urls_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListCrawledUrlsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListCrawledUrlsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -2757,7 +3154,7 @@ async def test_list_crawled_urls_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListCrawledUrlsRequest() # Establish that the response is the type that we expect. assert isinstance(response, pagers.ListCrawledUrlsAsyncPager) @@ -2765,6 +3162,11 @@ async def test_list_crawled_urls_async(transport: str = "grpc_asyncio"): assert response.next_page_token == "next_page_token_value" +@pytest.mark.asyncio +async def test_list_crawled_urls_async_from_dict(): + await test_list_crawled_urls_async(request_type=dict) + + def test_list_crawled_urls_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -2775,7 +3177,7 @@ def test_list_crawled_urls_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: call.return_value = web_security_scanner.ListCrawledUrlsResponse() @@ -2804,7 +3206,7 @@ async def test_list_crawled_urls_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListCrawledUrlsResponse() @@ -2827,7 +3229,7 @@ def test_list_crawled_urls_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListCrawledUrlsResponse() @@ -2863,7 +3265,7 @@ async def test_list_crawled_urls_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListCrawledUrlsResponse() @@ -2902,7 +3304,7 @@ def test_list_crawled_urls_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -2944,7 +3346,7 @@ def test_list_crawled_urls_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_crawled_urls), "__call__" + type(client.transport.list_crawled_urls), "__call__" ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -2968,8 +3370,8 @@ def test_list_crawled_urls_pages(): RuntimeError, ) pages = list(client.list_crawled_urls(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -2980,7 +3382,7 @@ async def test_list_crawled_urls_async_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), + type(client.transport.list_crawled_urls), "__call__", new_callable=mock.AsyncMock, ) as call: @@ -3023,7 +3425,7 @@ async def test_list_crawled_urls_async_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_crawled_urls), + type(client.transport.list_crawled_urls), "__call__", new_callable=mock.AsyncMock, ) as call: @@ -3049,23 +3451,25 @@ async def test_list_crawled_urls_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_crawled_urls(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_crawled_urls(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token -def test_get_finding(transport: str = "grpc"): +def test_get_finding( + transport: str = "grpc", request_type=web_security_scanner.GetFindingRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetFindingRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_finding), "__call__") as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = finding.Finding( name="name_value", @@ -3086,9 +3490,10 @@ def test_get_finding(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetFindingRequest() # Establish that the response is the type that we expect. + assert isinstance(response, finding.Finding) assert response.name == "name_value" @@ -3112,20 +3517,40 @@ def test_get_finding(transport: str = "grpc"): assert response.tracking_id == "tracking_id_value" +def test_get_finding_from_dict(): + test_get_finding(request_type=dict) + + +def test_get_finding_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: + client.get_finding() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.GetFindingRequest() + + @pytest.mark.asyncio -async def test_get_finding_async(transport: str = "grpc_asyncio"): +async def test_get_finding_async( + transport: str = "grpc_asyncio", request_type=web_security_scanner.GetFindingRequest +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.GetFindingRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_finding), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( finding.Finding( @@ -3148,7 +3573,7 @@ async def test_get_finding_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.GetFindingRequest() # Establish that the response is the type that we expect. assert isinstance(response, finding.Finding) @@ -3174,6 +3599,11 @@ async def test_get_finding_async(transport: str = "grpc_asyncio"): assert response.tracking_id == "tracking_id_value" +@pytest.mark.asyncio +async def test_get_finding_async_from_dict(): + await test_get_finding_async(request_type=dict) + + def test_get_finding_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -3183,7 +3613,7 @@ def test_get_finding_field_headers(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_finding), "__call__") as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: call.return_value = finding.Finding() client.get_finding(request) @@ -3210,9 +3640,7 @@ async def test_get_finding_field_headers_async(): request.name = "name/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_finding), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(finding.Finding()) await client.get_finding(request) @@ -3231,7 +3659,7 @@ def test_get_finding_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.get_finding), "__call__") as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = finding.Finding() @@ -3265,9 +3693,7 @@ async def test_get_finding_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.get_finding), "__call__" - ) as call: + with mock.patch.object(type(client.transport.get_finding), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = finding.Finding() @@ -3298,17 +3724,19 @@ async def test_get_finding_flattened_error_async(): ) -def test_list_findings(transport: str = "grpc"): +def test_list_findings( + transport: str = "grpc", request_type=web_security_scanner.ListFindingsRequest +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListFindingsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingsResponse( next_page_token="next_page_token_value", @@ -3320,28 +3748,50 @@ def test_list_findings(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListFindingsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListFindingsPager) assert response.next_page_token == "next_page_token_value" +def test_list_findings_from_dict(): + test_list_findings(request_type=dict) + + +def test_list_findings_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: + client.list_findings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListFindingsRequest() + + @pytest.mark.asyncio -async def test_list_findings_async(transport: str = "grpc_asyncio"): +async def test_list_findings_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListFindingsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListFindingsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_findings), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListFindingsResponse( @@ -3355,7 +3805,7 @@ async def test_list_findings_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListFindingsRequest() # Establish that the response is the type that we expect. assert isinstance(response, pagers.ListFindingsAsyncPager) @@ -3363,6 +3813,11 @@ async def test_list_findings_async(transport: str = "grpc_asyncio"): assert response.next_page_token == "next_page_token_value" +@pytest.mark.asyncio +async def test_list_findings_async_from_dict(): + await test_list_findings_async(request_type=dict) + + def test_list_findings_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -3372,7 +3827,7 @@ def test_list_findings_field_headers(): request.parent = "parent/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: call.return_value = web_security_scanner.ListFindingsResponse() client.list_findings(request) @@ -3399,9 +3854,7 @@ async def test_list_findings_field_headers_async(): request.parent = "parent/value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_findings), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListFindingsResponse() ) @@ -3422,7 +3875,7 @@ def test_list_findings_flattened(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingsResponse() @@ -3462,9 +3915,7 @@ async def test_list_findings_flattened_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._client._transport.list_findings), "__call__" - ) as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingsResponse() @@ -3507,7 +3958,7 @@ def test_list_findings_pager(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials,) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Set the response to a series of pages. call.side_effect = ( web_security_scanner.ListFindingsResponse( @@ -3543,7 +3994,7 @@ def test_list_findings_pages(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials,) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client._transport.list_findings), "__call__") as call: + with mock.patch.object(type(client.transport.list_findings), "__call__") as call: # Set the response to a series of pages. call.side_effect = ( web_security_scanner.ListFindingsResponse( @@ -3562,8 +4013,8 @@ def test_list_findings_pages(): RuntimeError, ) pages = list(client.list_findings(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -3574,9 +4025,7 @@ async def test_list_findings_async_pager(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_findings), - "__call__", - new_callable=mock.AsyncMock, + type(client.transport.list_findings), "__call__", new_callable=mock.AsyncMock ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -3613,9 +4062,7 @@ async def test_list_findings_async_pages(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_findings), - "__call__", - new_callable=mock.AsyncMock, + type(client.transport.list_findings), "__call__", new_callable=mock.AsyncMock ) as call: # Set the response to a series of pages. call.side_effect = ( @@ -3635,24 +4082,27 @@ async def test_list_findings_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_findings(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_findings(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token -def test_list_finding_type_stats(transport: str = "grpc"): +def test_list_finding_type_stats( + transport: str = "grpc", + request_type=web_security_scanner.ListFindingTypeStatsRequest, +): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListFindingTypeStatsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingTypeStatsResponse() @@ -3663,25 +4113,51 @@ def test_list_finding_type_stats(transport: str = "grpc"): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListFindingTypeStatsRequest() # Establish that the response is the type that we expect. + assert isinstance(response, web_security_scanner.ListFindingTypeStatsResponse) +def test_list_finding_type_stats_from_dict(): + test_list_finding_type_stats(request_type=dict) + + +def test_list_finding_type_stats_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_finding_type_stats), "__call__" + ) as call: + client.list_finding_type_stats() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListFindingTypeStatsRequest() + + @pytest.mark.asyncio -async def test_list_finding_type_stats_async(transport: str = "grpc_asyncio"): +async def test_list_finding_type_stats_async( + transport: str = "grpc_asyncio", + request_type=web_security_scanner.ListFindingTypeStatsRequest, +): client = WebSecurityScannerAsyncClient( credentials=credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. - request = web_security_scanner.ListFindingTypeStatsRequest() + request = request_type() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -3694,12 +4170,17 @@ async def test_list_finding_type_stats_async(transport: str = "grpc_asyncio"): assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == request + assert args[0] == web_security_scanner.ListFindingTypeStatsRequest() # Establish that the response is the type that we expect. assert isinstance(response, web_security_scanner.ListFindingTypeStatsResponse) +@pytest.mark.asyncio +async def test_list_finding_type_stats_async_from_dict(): + await test_list_finding_type_stats_async(request_type=dict) + + def test_list_finding_type_stats_field_headers(): client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) @@ -3710,7 +4191,7 @@ def test_list_finding_type_stats_field_headers(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: call.return_value = web_security_scanner.ListFindingTypeStatsResponse() @@ -3739,7 +4220,7 @@ async def test_list_finding_type_stats_field_headers_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( web_security_scanner.ListFindingTypeStatsResponse() @@ -3762,7 +4243,7 @@ def test_list_finding_type_stats_flattened(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingTypeStatsResponse() @@ -3798,7 +4279,7 @@ async def test_list_finding_type_stats_flattened_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client._client._transport.list_finding_type_stats), "__call__" + type(client.transport.list_finding_type_stats), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = web_security_scanner.ListFindingTypeStatsResponse() @@ -3868,7 +4349,7 @@ def test_transport_instance(): credentials=credentials.AnonymousCredentials(), ) client = WebSecurityScannerClient(transport=transport) - assert client._transport is transport + assert client.transport is transport def test_transport_get_channel(): @@ -3886,10 +4367,25 @@ def test_transport_get_channel(): assert channel +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + def test_transport_grpc_default(): # A client should use the gRPC transport by default. client = WebSecurityScannerClient(credentials=credentials.AnonymousCredentials(),) - assert isinstance(client._transport, transports.WebSecurityScannerGrpcTransport,) + assert isinstance(client.transport, transports.WebSecurityScannerGrpcTransport,) def test_web_security_scanner_base_transport_error(): @@ -3903,9 +4399,13 @@ def test_web_security_scanner_base_transport_error(): def test_web_security_scanner_base_transport(): # Instantiate the base transport. - transport = transports.WebSecurityScannerTransport( - credentials=credentials.AnonymousCredentials(), - ) + with mock.patch( + "google.cloud.websecurityscanner_v1beta.services.web_security_scanner.transports.WebSecurityScannerTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.WebSecurityScannerTransport( + credentials=credentials.AnonymousCredentials(), + ) # Every method on the transport should just blindly # raise NotImplementedError. @@ -3931,7 +4431,12 @@ def test_web_security_scanner_base_transport(): def test_web_security_scanner_base_transport_with_credentials_file(): # Instantiate the base transport with a credentials file - with mock.patch.object(auth, "load_credentials_from_file") as load_creds: + with mock.patch.object( + auth, "load_credentials_from_file" + ) as load_creds, mock.patch( + "google.cloud.websecurityscanner_v1beta.services.web_security_scanner.transports.WebSecurityScannerTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None load_creds.return_value = (credentials.AnonymousCredentials(), None) transport = transports.WebSecurityScannerTransport( credentials_file="credentials.json", quota_project_id="octopus", @@ -3943,6 +4448,17 @@ def test_web_security_scanner_base_transport_with_credentials_file(): ) +def test_web_security_scanner_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(auth, "default") as adc, mock.patch( + "google.cloud.websecurityscanner_v1beta.services.web_security_scanner.transports.WebSecurityScannerTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.WebSecurityScannerTransport() + adc.assert_called_once() + + def test_web_security_scanner_auth_adc(): # If no credentials are provided, we should use ADC credentials. with mock.patch.object(auth, "default") as adc: @@ -3968,6 +4484,53 @@ def test_web_security_scanner_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], +) +def test_web_security_scanner_grpc_transport_client_cert_source_for_mtls( + transport_class, +): + cred = credentials.AnonymousCredentials() + + # Check ssl_channel_credentials is used if provided. + with mock.patch.object(transport_class, "create_channel") as mock_create_channel: + mock_ssl_channel_creds = mock.Mock() + transport_class( + host="squid.clam.whelk", + credentials=cred, + ssl_channel_credentials=mock_ssl_channel_creds, + ) + mock_create_channel.assert_called_once_with( + "squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + def test_web_security_scanner_host_no_port(): client = WebSecurityScannerClient( credentials=credentials.AnonymousCredentials(), @@ -3975,7 +4538,7 @@ def test_web_security_scanner_host_no_port(): api_endpoint="websecurityscanner.googleapis.com" ), ) - assert client._transport._host == "websecurityscanner.googleapis.com:443" + assert client.transport._host == "websecurityscanner.googleapis.com:443" def test_web_security_scanner_host_with_port(): @@ -3985,190 +4548,165 @@ def test_web_security_scanner_host_with_port(): api_endpoint="websecurityscanner.googleapis.com:8000" ), ) - assert client._transport._host == "websecurityscanner.googleapis.com:8000" + assert client.transport._host == "websecurityscanner.googleapis.com:8000" def test_web_security_scanner_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.WebSecurityScannerGrpcTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called + assert transport._ssl_channel_credentials == None def test_web_security_scanner_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.WebSecurityScannerGrpcAsyncIOTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_web_security_scanner_grpc_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.WebSecurityScannerGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_web_security_scanner_grpc_asyncio_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.WebSecurityScannerGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], ) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_web_security_scanner_grpc_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint +def test_web_security_scanner_transport_channel_mtls_with_client_cert_source( + transport_class, ): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. - mock_ssl_cred = mock.Mock() - with mock.patch.multiple( - "google.auth.transport.grpc.SslCredentials", - __init__=mock.Mock(return_value=None), - ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), - ): - mock_cred = mock.Mock() - transport = transports.WebSecurityScannerGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], ) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_web_security_scanner_grpc_asyncio_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. +def test_web_security_scanner_transport_channel_mtls_with_adc(transport_class): mock_ssl_cred = mock.Mock() with mock.patch.multiple( "google.auth.transport.grpc.SslCredentials", __init__=mock.Mock(return_value=None), ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): - mock_cred = mock.Mock() - transport = transports.WebSecurityScannerGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel -def test_scan_config_path(): +def test_finding_path(): project = "squid" scan_config = "clam" + scan_run = "whelk" + finding = "octopus" + + expected = "projects/{project}/scanConfigs/{scan_config}/scanRuns/{scan_run}/findings/{finding}".format( + project=project, scan_config=scan_config, scan_run=scan_run, finding=finding, + ) + actual = WebSecurityScannerClient.finding_path( + project, scan_config, scan_run, finding + ) + assert expected == actual + + +def test_parse_finding_path(): + expected = { + "project": "oyster", + "scan_config": "nudibranch", + "scan_run": "cuttlefish", + "finding": "mussel", + } + path = WebSecurityScannerClient.finding_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_finding_path(path) + assert expected == actual + + +def test_scan_config_path(): + project = "winkle" + scan_config = "nautilus" expected = "projects/{project}/scanConfigs/{scan_config}".format( project=project, scan_config=scan_config, @@ -4179,8 +4717,8 @@ def test_scan_config_path(): def test_parse_scan_config_path(): expected = { - "project": "whelk", - "scan_config": "octopus", + "project": "scallop", + "scan_config": "abalone", } path = WebSecurityScannerClient.scan_config_path(**expected) @@ -4212,3 +4750,125 @@ def test_parse_scan_run_path(): # Check that the path construction is reversible. actual = WebSecurityScannerClient.parse_scan_run_path(path) assert expected == actual + + +def test_common_billing_account_path(): + billing_account = "cuttlefish" + + expected = "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + actual = WebSecurityScannerClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "mussel", + } + path = WebSecurityScannerClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_billing_account_path(path) + assert expected == actual + + +def test_common_folder_path(): + folder = "winkle" + + expected = "folders/{folder}".format(folder=folder,) + actual = WebSecurityScannerClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "nautilus", + } + path = WebSecurityScannerClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_folder_path(path) + assert expected == actual + + +def test_common_organization_path(): + organization = "scallop" + + expected = "organizations/{organization}".format(organization=organization,) + actual = WebSecurityScannerClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "abalone", + } + path = WebSecurityScannerClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_organization_path(path) + assert expected == actual + + +def test_common_project_path(): + project = "squid" + + expected = "projects/{project}".format(project=project,) + actual = WebSecurityScannerClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "clam", + } + path = WebSecurityScannerClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_project_path(path) + assert expected == actual + + +def test_common_location_path(): + project = "whelk" + location = "octopus" + + expected = "projects/{project}/locations/{location}".format( + project=project, location=location, + ) + actual = WebSecurityScannerClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "oyster", + "location": "nudibranch", + } + path = WebSecurityScannerClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = WebSecurityScannerClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object( + transports.WebSecurityScannerTransport, "_prep_wrapped_messages" + ) as prep: + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object( + transports.WebSecurityScannerTransport, "_prep_wrapped_messages" + ) as prep: + transport_class = WebSecurityScannerClient.get_transport_class() + transport = transport_class( + credentials=credentials.AnonymousCredentials(), client_info=client_info, + ) + prep.assert_called_once_with(client_info)