From 8993d4136b906179d852b9b7d688dd2d1df27ba0 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Tue, 30 Mar 2021 09:49:53 -0600 Subject: [PATCH] feat: add v1 (#42) --- docs/index.rst | 16 +- docs/websecurityscanner_v1/services.rst | 6 + docs/websecurityscanner_v1/types.rst | 7 + .../web_security_scanner.rst | 11 + .../cloud/websecurityscanner_v1/__init__.py | 87 + .../proto/crawled_url.proto | 40 + .../websecurityscanner_v1/proto/finding.proto | 119 + .../proto/finding_addon.proto | 147 + .../proto/finding_type_stats.proto | 35 + .../proto/scan_config.proto | 188 + .../proto/scan_config_error.proto | 189 + .../proto/scan_run.proto | 110 + .../proto/scan_run_error_trace.proto | 75 + .../proto/scan_run_warning_trace.proto | 58 + .../proto/web_security_scanner.proto | 337 ++ google/cloud/websecurityscanner_v1/py.typed | 2 + .../services/__init__.py | 16 + .../services/web_security_scanner/__init__.py | 24 + .../web_security_scanner/async_client.py | 971 +++++ .../services/web_security_scanner/client.py | 1083 +++++ .../services/web_security_scanner/pagers.py | 549 +++ .../transports/__init__.py | 37 + .../web_security_scanner/transports/base.py | 386 ++ .../web_security_scanner/transports/grpc.py | 592 +++ .../transports/grpc_asyncio.py | 608 +++ .../websecurityscanner_v1/types/__init__.py | 88 + .../types/crawled_url.py | 50 + .../websecurityscanner_v1/types/finding.py | 152 + .../types/finding_addon.py | 173 + .../types/finding_type_stats.py | 44 + .../types/scan_config.py | 257 ++ .../types/scan_config_error.py | 97 + .../websecurityscanner_v1/types/scan_run.py | 127 + .../types/scan_run_error_trace.py | 72 + .../types/scan_run_warning_trace.py | 51 + .../types/web_security_scanner.py | 403 ++ .../fixup_websecurityscanner_v1_keywords.py | 191 + synth.metadata | 15 +- synth.py | 2 +- .../gapic/websecurityscanner_v1/__init__.py | 16 + .../test_web_security_scanner.py | 3857 +++++++++++++++++ 41 files changed, 11281 insertions(+), 7 deletions(-) create mode 100644 docs/websecurityscanner_v1/services.rst create mode 100644 docs/websecurityscanner_v1/types.rst create mode 100644 docs/websecurityscanner_v1/web_security_scanner.rst create mode 100644 google/cloud/websecurityscanner_v1/__init__.py create mode 100644 google/cloud/websecurityscanner_v1/proto/crawled_url.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/finding.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/finding_addon.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/finding_type_stats.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/scan_config.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/scan_config_error.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/scan_run.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/scan_run_error_trace.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/scan_run_warning_trace.proto create mode 100644 google/cloud/websecurityscanner_v1/proto/web_security_scanner.proto create mode 100644 google/cloud/websecurityscanner_v1/py.typed create mode 100644 google/cloud/websecurityscanner_v1/services/__init__.py create mode 100644 google/cloud/websecurityscanner_v1/services/web_security_scanner/__init__.py create mode 100644 google/cloud/websecurityscanner_v1/services/web_security_scanner/async_client.py create mode 100644 google/cloud/websecurityscanner_v1/services/web_security_scanner/client.py create mode 100644 google/cloud/websecurityscanner_v1/services/web_security_scanner/pagers.py create mode 100644 google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/__init__.py create mode 100644 google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/base.py create mode 100644 google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/grpc.py create mode 100644 google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/grpc_asyncio.py create mode 100644 google/cloud/websecurityscanner_v1/types/__init__.py create mode 100644 google/cloud/websecurityscanner_v1/types/crawled_url.py create mode 100644 google/cloud/websecurityscanner_v1/types/finding.py create mode 100644 google/cloud/websecurityscanner_v1/types/finding_addon.py create mode 100644 google/cloud/websecurityscanner_v1/types/finding_type_stats.py create mode 100644 google/cloud/websecurityscanner_v1/types/scan_config.py create mode 100644 google/cloud/websecurityscanner_v1/types/scan_config_error.py create mode 100644 google/cloud/websecurityscanner_v1/types/scan_run.py create mode 100644 google/cloud/websecurityscanner_v1/types/scan_run_error_trace.py create mode 100644 google/cloud/websecurityscanner_v1/types/scan_run_warning_trace.py create mode 100644 google/cloud/websecurityscanner_v1/types/web_security_scanner.py create mode 100644 scripts/fixup_websecurityscanner_v1_keywords.py create mode 100644 tests/unit/gapic/websecurityscanner_v1/__init__.py create mode 100644 tests/unit/gapic/websecurityscanner_v1/test_web_security_scanner.py diff --git a/docs/index.rst b/docs/index.rst index 6774b3d..096e842 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,17 +2,27 @@ .. include:: multiprocessing.rst -Api Reference +API Reference ------------- -This package includes clients for multiple versions of the Web Security Scanner API. By default, you will get ``v1beta``, the latest version. +This package includes clients for multiple versions of the Web Security Scanner API. By default, you will get ``v1``, the latest version. +.. toctree:: + :maxdepth: 2 + + websecurityscanner_v1/services + websecurityscanner_v1/types + +The previous releases spelled ``v1beta`` and ``v1alpha`` are provided to continue to support code previously written against it. In order to use it, you will want to import from it e.g., ``google.cloud.websecurityscanner_v1alpha`` in lieu of ``google.cloud.websecurityscanner`` (or the equivalent ``google.cloud.websecurityscanner_v1``). + + +v1beta +~~~~~~~ .. toctree:: :maxdepth: 2 websecurityscanner_v1beta/services websecurityscanner_v1beta/types -The previous alpha release, spelled ``v1alpha`` is provided to continue to support code previously written against it. In order to use it, you will want to import from it e.g., ``google.cloud.websecurityscanner_v1alpha`` in lieu of ``google.cloud.websecurityscanner`` (or the equivalent ``google.cloud.websecurityscanner_v1beta``). v1alpha ~~~~~~~ diff --git a/docs/websecurityscanner_v1/services.rst b/docs/websecurityscanner_v1/services.rst new file mode 100644 index 0000000..6fb98e6 --- /dev/null +++ b/docs/websecurityscanner_v1/services.rst @@ -0,0 +1,6 @@ +Services for Google Cloud Websecurityscanner v1 API +=================================================== +.. toctree:: + :maxdepth: 2 + + web_security_scanner diff --git a/docs/websecurityscanner_v1/types.rst b/docs/websecurityscanner_v1/types.rst new file mode 100644 index 0000000..aadd787 --- /dev/null +++ b/docs/websecurityscanner_v1/types.rst @@ -0,0 +1,7 @@ +Types for Google Cloud Websecurityscanner v1 API +================================================ + +.. automodule:: google.cloud.websecurityscanner_v1.types + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/websecurityscanner_v1/web_security_scanner.rst b/docs/websecurityscanner_v1/web_security_scanner.rst new file mode 100644 index 0000000..659c139 --- /dev/null +++ b/docs/websecurityscanner_v1/web_security_scanner.rst @@ -0,0 +1,11 @@ +WebSecurityScanner +------------------------------------ + +.. automodule:: google.cloud.websecurityscanner_v1.services.web_security_scanner + :members: + :inherited-members: + + +.. automodule:: google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers + :members: + :inherited-members: diff --git a/google/cloud/websecurityscanner_v1/__init__.py b/google/cloud/websecurityscanner_v1/__init__.py new file mode 100644 index 0000000..c5228bc --- /dev/null +++ b/google/cloud/websecurityscanner_v1/__init__.py @@ -0,0 +1,87 @@ +# -*- 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. +# + +from .services.web_security_scanner import WebSecurityScannerClient +from .types.crawled_url import CrawledUrl +from .types.finding import Finding +from .types.finding_addon import Form +from .types.finding_addon import OutdatedLibrary +from .types.finding_addon import ViolatingResource +from .types.finding_addon import VulnerableHeaders +from .types.finding_addon import VulnerableParameters +from .types.finding_addon import Xss +from .types.finding_type_stats import FindingTypeStats +from .types.scan_config import ScanConfig +from .types.scan_config_error import ScanConfigError +from .types.scan_run import ScanRun +from .types.scan_run_error_trace import ScanRunErrorTrace +from .types.scan_run_warning_trace import ScanRunWarningTrace +from .types.web_security_scanner import CreateScanConfigRequest +from .types.web_security_scanner import DeleteScanConfigRequest +from .types.web_security_scanner import GetFindingRequest +from .types.web_security_scanner import GetScanConfigRequest +from .types.web_security_scanner import GetScanRunRequest +from .types.web_security_scanner import ListCrawledUrlsRequest +from .types.web_security_scanner import ListCrawledUrlsResponse +from .types.web_security_scanner import ListFindingTypeStatsRequest +from .types.web_security_scanner import ListFindingTypeStatsResponse +from .types.web_security_scanner import ListFindingsRequest +from .types.web_security_scanner import ListFindingsResponse +from .types.web_security_scanner import ListScanConfigsRequest +from .types.web_security_scanner import ListScanConfigsResponse +from .types.web_security_scanner import ListScanRunsRequest +from .types.web_security_scanner import ListScanRunsResponse +from .types.web_security_scanner import StartScanRunRequest +from .types.web_security_scanner import StopScanRunRequest +from .types.web_security_scanner import UpdateScanConfigRequest + + +__all__ = ( + "CrawledUrl", + "CreateScanConfigRequest", + "DeleteScanConfigRequest", + "Finding", + "FindingTypeStats", + "Form", + "GetFindingRequest", + "GetScanConfigRequest", + "GetScanRunRequest", + "ListCrawledUrlsRequest", + "ListCrawledUrlsResponse", + "ListFindingTypeStatsRequest", + "ListFindingTypeStatsResponse", + "ListFindingsRequest", + "ListFindingsResponse", + "ListScanConfigsRequest", + "ListScanConfigsResponse", + "ListScanRunsRequest", + "ListScanRunsResponse", + "OutdatedLibrary", + "ScanConfig", + "ScanConfigError", + "ScanRun", + "ScanRunErrorTrace", + "ScanRunWarningTrace", + "StartScanRunRequest", + "StopScanRunRequest", + "UpdateScanConfigRequest", + "ViolatingResource", + "VulnerableHeaders", + "VulnerableParameters", + "Xss", + "WebSecurityScannerClient", +) diff --git a/google/cloud/websecurityscanner_v1/proto/crawled_url.proto b/google/cloud/websecurityscanner_v1/proto/crawled_url.proto new file mode 100644 index 0000000..37724b8 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/crawled_url.proto @@ -0,0 +1,40 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "CrawledUrlProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// A CrawledUrl resource represents a URL that was crawled during a ScanRun. Web +// Security Scanner Service crawls the web applications, following all links +// within the scope of sites, to find the URLs to test against. +message CrawledUrl { + // Output only. The http method of the request that was used to visit the URL, in + // uppercase. + string http_method = 1; + + // Output only. The URL that was crawled. + string url = 2; + + // Output only. The body of the request that was used to visit the URL. + string body = 3; +} diff --git a/google/cloud/websecurityscanner_v1/proto/finding.proto b/google/cloud/websecurityscanner_v1/proto/finding.proto new file mode 100644 index 0000000..32bd5d8 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/finding.proto @@ -0,0 +1,119 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/cloud/websecurityscanner/v1/finding_addon.proto"; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "FindingProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// A Finding resource represents a vulnerability instance identified during a +// ScanRun. +message Finding { + option (google.api.resource) = { + type: "websecurityscanner.googleapis.com/Finding" + pattern: "projects/{project}/scanConfigs/{scan_config}/scanRuns/{scan_run}/findings/{finding}" + }; + + // The severity level of a vulnerability. + enum Severity { + // No severity specified. The default value. + SEVERITY_UNSPECIFIED = 0; + + // Critical severity. + CRITICAL = 1; + + // High severity. + HIGH = 2; + + // Medium severity. + MEDIUM = 3; + + // Low severity. + LOW = 4; + } + + // Output only. The resource name of the Finding. The name follows the format of + // 'projects/{projectId}/scanConfigs/{scanConfigId}/scanruns/{scanRunId}/findings/{findingId}'. + // The finding IDs are generated by the system. + string name = 1; + + // Output only. The type of the Finding. + // Detailed and up-to-date information on findings can be found here: + // https://cloud.google.com/security-command-center/docs/how-to-remediate-web-security-scanner-findings + string finding_type = 2; + + // Output only. The severity level of the reported vulnerability. + Severity severity = 17 [(google.api.field_behavior) = OUTPUT_ONLY]; + + // Output only. The http method of the request that triggered the vulnerability, in + // uppercase. + string http_method = 3; + + // Output only. The URL produced by the server-side fuzzer and used in the request that + // triggered the vulnerability. + string fuzzed_url = 4; + + // Output only. The body of the request that triggered the vulnerability. + string body = 5; + + // Output only. The description of the vulnerability. + string description = 6; + + // Output only. The URL containing human-readable payload that user can leverage to + // reproduce the vulnerability. + string reproduction_url = 7; + + // Output only. If the vulnerability was originated from nested IFrame, the immediate + // parent IFrame is reported. + string frame_url = 8; + + // Output only. The URL where the browser lands when the vulnerability is detected. + string final_url = 9; + + // Output only. The tracking ID uniquely identifies a vulnerability instance across + // multiple ScanRuns. + string tracking_id = 10; + + // Output only. An addon containing information reported for a vulnerability with an HTML + // form, if any. + Form form = 16; + + // Output only. An addon containing information about outdated libraries. + OutdatedLibrary outdated_library = 11; + + // Output only. An addon containing detailed information regarding any resource causing the + // vulnerability such as JavaScript sources, image, audio files, etc. + ViolatingResource violating_resource = 12; + + // Output only. An addon containing information about vulnerable or missing HTTP headers. + VulnerableHeaders vulnerable_headers = 15; + + // Output only. An addon containing information about request parameters which were found + // to be vulnerable. + VulnerableParameters vulnerable_parameters = 13; + + // Output only. An addon containing information reported for an XSS, if any. + Xss xss = 14; +} diff --git a/google/cloud/websecurityscanner_v1/proto/finding_addon.proto b/google/cloud/websecurityscanner_v1/proto/finding_addon.proto new file mode 100644 index 0000000..4fb7ec1 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/finding_addon.proto @@ -0,0 +1,147 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "FindingAddonProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// ! Information about a vulnerability with an HTML. +message Form { + // ! The URI where to send the form when it's submitted. + string action_uri = 1; + + // ! The names of form fields related to the vulnerability. + repeated string fields = 2; +} + +// Information reported for an outdated library. +message OutdatedLibrary { + // The name of the outdated library. + string library_name = 1; + + // The version number. + string version = 2; + + // URLs to learn more information about the vulnerabilities in the library. + repeated string learn_more_urls = 3; +} + +// Information regarding any resource causing the vulnerability such +// as JavaScript sources, image, audio files, etc. +message ViolatingResource { + // The MIME type of this resource. + string content_type = 1; + + // URL of this violating resource. + string resource_url = 2; +} + +// Information about vulnerable request parameters. +message VulnerableParameters { + // The vulnerable parameter names. + repeated string parameter_names = 1; +} + +// Information about vulnerable or missing HTTP Headers. +message VulnerableHeaders { + // Describes a HTTP Header. + message Header { + // Header name. + string name = 1; + + // Header value. + string value = 2; + } + + // List of vulnerable headers. + repeated Header headers = 1; + + // List of missing headers. + repeated Header missing_headers = 2; +} + +// Information reported for an XSS. +message Xss { + // Types of XSS attack vector. + enum AttackVector { + // Unknown attack vector. + ATTACK_VECTOR_UNSPECIFIED = 0; + + // The attack comes from fuzzing the browser's localStorage. + LOCAL_STORAGE = 1; + + // The attack comes from fuzzing the browser's sessionStorage. + SESSION_STORAGE = 2; + + // The attack comes from fuzzing the window's name property. + WINDOW_NAME = 3; + + // The attack comes from fuzzing the referrer property. + REFERRER = 4; + + // The attack comes from fuzzing an input element. + FORM_INPUT = 5; + + // The attack comes from fuzzing the browser's cookies. + COOKIE = 6; + + // The attack comes from hijacking the post messaging mechanism. + POST_MESSAGE = 7; + + // The attack comes from fuzzing parameters in the url. + GET_PARAMETERS = 8; + + // The attack comes from fuzzing the fragment in the url. + URL_FRAGMENT = 9; + + // The attack comes from fuzzing the HTML comments. + HTML_COMMENT = 10; + + // The attack comes from fuzzing the POST parameters. + POST_PARAMETERS = 11; + + // The attack comes from fuzzing the protocol. + PROTOCOL = 12; + + // The attack comes from the server side and is stored. + STORED_XSS = 13; + + // The attack is a Same-Origin Method Execution attack via a GET parameter. + SAME_ORIGIN = 14; + + // The attack payload is received from a third-party host via a URL that is + // user-controllable + USER_CONTROLLABLE_URL = 15; + } + + // Stack traces leading to the point where the XSS occurred. + repeated string stack_traces = 1; + + // An error message generated by a javascript breakage. + string error_message = 2; + + // The attack vector of the payload triggering this XSS. + AttackVector attack_vector = 3; + + // The reproduction url for the seeding POST request of a Stored XSS. + string stored_xss_seeding_url = 4; +} diff --git a/google/cloud/websecurityscanner_v1/proto/finding_type_stats.proto b/google/cloud/websecurityscanner_v1/proto/finding_type_stats.proto new file mode 100644 index 0000000..7eca01e --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/finding_type_stats.proto @@ -0,0 +1,35 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "FindingTypeStatsProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// A FindingTypeStats resource represents stats regarding a specific FindingType +// of Findings under a given ScanRun. +message FindingTypeStats { + // Output only. The finding type associated with the stats. + string finding_type = 1; + + // Output only. The count of findings belonging to this finding type. + int32 finding_count = 2; +} diff --git a/google/cloud/websecurityscanner_v1/proto/scan_config.proto b/google/cloud/websecurityscanner_v1/proto/scan_config.proto new file mode 100644 index 0000000..901d01e --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/scan_config.proto @@ -0,0 +1,188 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +import "google/api/field_behavior.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "ScanConfigProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// A ScanConfig resource contains the configurations to launch a scan. +message ScanConfig { + // Scan authentication configuration. + message Authentication { + // Describes authentication configuration that uses a Google account. + message GoogleAccount { + // Required. The user name of the Google account. + string username = 1; + + // Required. Input only. The password of the Google account. The credential is stored encrypted + // and not returned in any response nor included in audit logs. + string password = 2; + } + + // Describes authentication configuration that uses a custom account. + message CustomAccount { + // Required. The user name of the custom account. + string username = 1; + + // Required. Input only. The password of the custom account. The credential is stored encrypted + // and not returned in any response nor included in audit logs. + string password = 2; + + // Required. The login form URL of the website. + string login_url = 3; + } + + // Describes authentication configuration for Identity-Aware-Proxy (IAP). + message IapCredential { + // Describes authentication configuration when Web-Security-Scanner + // service account is added in Identity-Aware-Proxy (IAP) access policies. + message IapTestServiceAccountInfo { + // Required. Describes OAuth2 client id of resources protected by + // Identity-Aware-Proxy (IAP). + string target_audience_client_id = 1 [(google.api.field_behavior) = REQUIRED]; + } + + // Identity-Aware-Proxy (IAP) Authentication Configuration + oneof iap_credentials { + // Authentication configuration when Web-Security-Scanner service + // account is added in Identity-Aware-Proxy (IAP) access policies. + IapTestServiceAccountInfo iap_test_service_account_info = 1; + } + } + + // Required. + // Authentication configuration + oneof authentication { + // Authentication using a Google account. + GoogleAccount google_account = 1; + + // Authentication using a custom account. + CustomAccount custom_account = 2; + + // Authentication using Identity-Aware-Proxy (IAP). + IapCredential iap_credential = 4; + } + } + + // Scan schedule configuration. + message Schedule { + // A timestamp indicates when the next run will be scheduled. The value is + // refreshed by the server after each run. If unspecified, it will default + // to current server time, which means the scan will be scheduled to start + // immediately. + google.protobuf.Timestamp schedule_time = 1; + + // Required. The duration of time between executions in days. + int32 interval_duration_days = 2; + } + + // Type of user agents used for scanning. + enum UserAgent { + // The user agent is unknown. Service will default to CHROME_LINUX. + USER_AGENT_UNSPECIFIED = 0; + + // Chrome on Linux. This is the service default if unspecified. + CHROME_LINUX = 1; + + // Chrome on Android. + CHROME_ANDROID = 2; + + // Safari on IPhone. + SAFARI_IPHONE = 3; + } + + // Scan risk levels supported by Web Security Scanner. LOW impact + // scanning will minimize requests with the potential to modify data. To + // achieve the maximum scan coverage, NORMAL risk level is recommended. + enum RiskLevel { + // Use default, which is NORMAL. + RISK_LEVEL_UNSPECIFIED = 0; + + // Normal scanning (Recommended) + NORMAL = 1; + + // Lower impact scanning + LOW = 2; + } + + // Controls export of scan configurations and results to Security + // Command Center. + enum ExportToSecurityCommandCenter { + // Use default, which is ENABLED. + EXPORT_TO_SECURITY_COMMAND_CENTER_UNSPECIFIED = 0; + + // Export results of this scan to Security Command Center. + ENABLED = 1; + + // Do not export results of this scan to Security Command Center. + DISABLED = 2; + } + + // The resource name of the ScanConfig. The name follows the format of + // 'projects/{projectId}/scanConfigs/{scanConfigId}'. The ScanConfig IDs are + // generated by the system. + string name = 1; + + // Required. The user provided display name of the ScanConfig. + string display_name = 2; + + // The maximum QPS during scanning. A valid value ranges from 5 to 20 + // inclusively. If the field is unspecified or its value is set 0, server will + // default to 15. Other values outside of [5, 20] range will be rejected with + // INVALID_ARGUMENT error. + int32 max_qps = 3; + + // Required. The starting URLs from which the scanner finds site pages. + repeated string starting_urls = 4; + + // The authentication configuration. If specified, service will use the + // authentication configuration during scanning. + Authentication authentication = 5; + + // The user agent used during scanning. + UserAgent user_agent = 6; + + // The excluded URL patterns as described in + // https://cloud.google.com/security-command-center/docs/how-to-use-web-security-scanner#excluding_urls + repeated string blacklist_patterns = 7; + + // The schedule of the ScanConfig. + Schedule schedule = 8; + + // Controls export of scan configurations and results to Security + // Command Center. + ExportToSecurityCommandCenter export_to_security_command_center = 10; + + // The risk level selected for the scan + RiskLevel risk_level = 12; + + // Whether the scan config is managed by Web Security Scanner, output + // only. + bool managed_scan = 13; + + // Whether the scan configuration has enabled static IP address scan feature. + // If enabled, the scanner will access applications from static IP addresses. + bool static_ip_scan = 14; +} diff --git a/google/cloud/websecurityscanner_v1/proto/scan_config_error.proto b/google/cloud/websecurityscanner_v1/proto/scan_config_error.proto new file mode 100644 index 0000000..5d54457 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/scan_config_error.proto @@ -0,0 +1,189 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "ScanConfigErrorProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// Defines a custom error message used by CreateScanConfig and UpdateScanConfig +// APIs when scan configuration validation fails. It is also reported as part of +// a ScanRunErrorTrace message if scan validation fails due to a scan +// configuration error. +message ScanConfigError { + // Output only. + // Defines an error reason code. + // Next id: 44 + enum Code { + option allow_alias = true; + + // There is no error. + CODE_UNSPECIFIED = 0; + + // There is no error. + OK = 0; + + // Indicates an internal server error. + // Please DO NOT USE THIS ERROR CODE unless the root cause is truly unknown. + INTERNAL_ERROR = 1; + + // One of the seed URLs is an App Engine URL but we cannot validate the scan + // settings due to an App Engine API backend error. + APPENGINE_API_BACKEND_ERROR = 2; + + // One of the seed URLs is an App Engine URL but we cannot access the + // App Engine API to validate scan settings. + APPENGINE_API_NOT_ACCESSIBLE = 3; + + // One of the seed URLs is an App Engine URL but the Default Host of the + // App Engine is not set. + APPENGINE_DEFAULT_HOST_MISSING = 4; + + // Google corporate accounts can not be used for scanning. + CANNOT_USE_GOOGLE_COM_ACCOUNT = 6; + + // The account of the scan creator can not be used for scanning. + CANNOT_USE_OWNER_ACCOUNT = 7; + + // This scan targets Compute Engine, but we cannot validate scan settings + // due to a Compute Engine API backend error. + COMPUTE_API_BACKEND_ERROR = 8; + + // This scan targets Compute Engine, but we cannot access the Compute Engine + // API to validate the scan settings. + COMPUTE_API_NOT_ACCESSIBLE = 9; + + // The Custom Login URL does not belong to the current project. + CUSTOM_LOGIN_URL_DOES_NOT_BELONG_TO_CURRENT_PROJECT = 10; + + // The Custom Login URL is malformed (can not be parsed). + CUSTOM_LOGIN_URL_MALFORMED = 11; + + // The Custom Login URL is mapped to a non-routable IP address in DNS. + CUSTOM_LOGIN_URL_MAPPED_TO_NON_ROUTABLE_ADDRESS = 12; + + // The Custom Login URL is mapped to an IP address which is not reserved for + // the current project. + CUSTOM_LOGIN_URL_MAPPED_TO_UNRESERVED_ADDRESS = 13; + + // The Custom Login URL has a non-routable IP address. + CUSTOM_LOGIN_URL_HAS_NON_ROUTABLE_IP_ADDRESS = 14; + + // The Custom Login URL has an IP address which is not reserved for the + // current project. + CUSTOM_LOGIN_URL_HAS_UNRESERVED_IP_ADDRESS = 15; + + // Another scan with the same name (case-sensitive) already exists. + DUPLICATE_SCAN_NAME = 16; + + // A field is set to an invalid value. + INVALID_FIELD_VALUE = 18; + + // There was an error trying to authenticate to the scan target. + FAILED_TO_AUTHENTICATE_TO_TARGET = 19; + + // Finding type value is not specified in the list findings request. + FINDING_TYPE_UNSPECIFIED = 20; + + // Scan targets Compute Engine, yet current project was not whitelisted for + // Google Compute Engine Scanning Alpha access. + FORBIDDEN_TO_SCAN_COMPUTE = 21; + + // User tries to update managed scan + FORBIDDEN_UPDATE_TO_MANAGED_SCAN = 43; + + // The supplied filter is malformed. For example, it can not be parsed, does + // not have a filter type in expression, or the same filter type appears + // more than once. + MALFORMED_FILTER = 22; + + // The supplied resource name is malformed (can not be parsed). + MALFORMED_RESOURCE_NAME = 23; + + // The current project is not in an active state. + PROJECT_INACTIVE = 24; + + // A required field is not set. + REQUIRED_FIELD = 25; + + // Project id, scanconfig id, scanrun id, or finding id are not consistent + // with each other in resource name. + RESOURCE_NAME_INCONSISTENT = 26; + + // The scan being requested to start is already running. + SCAN_ALREADY_RUNNING = 27; + + // The scan that was requested to be stopped is not running. + SCAN_NOT_RUNNING = 28; + + // One of the seed URLs does not belong to the current project. + SEED_URL_DOES_NOT_BELONG_TO_CURRENT_PROJECT = 29; + + // One of the seed URLs is malformed (can not be parsed). + SEED_URL_MALFORMED = 30; + + // One of the seed URLs is mapped to a non-routable IP address in DNS. + SEED_URL_MAPPED_TO_NON_ROUTABLE_ADDRESS = 31; + + // One of the seed URLs is mapped to an IP address which is not reserved + // for the current project. + SEED_URL_MAPPED_TO_UNRESERVED_ADDRESS = 32; + + // One of the seed URLs has on-routable IP address. + SEED_URL_HAS_NON_ROUTABLE_IP_ADDRESS = 33; + + // One of the seed URLs has an IP address that is not reserved + // for the current project. + SEED_URL_HAS_UNRESERVED_IP_ADDRESS = 35; + + // The Web Security Scanner service account is not configured under the + // project. + SERVICE_ACCOUNT_NOT_CONFIGURED = 36; + + // A project has reached the maximum number of scans. + TOO_MANY_SCANS = 37; + + // Resolving the details of the current project fails. + UNABLE_TO_RESOLVE_PROJECT_INFO = 38; + + // One or more blacklist patterns were in the wrong format. + UNSUPPORTED_BLACKLIST_PATTERN_FORMAT = 39; + + // The supplied filter is not supported. + UNSUPPORTED_FILTER = 40; + + // The supplied finding type is not supported. For example, we do not + // provide findings of the given finding type. + UNSUPPORTED_FINDING_TYPE = 41; + + // The URL scheme of one or more of the supplied URLs is not supported. + UNSUPPORTED_URL_SCHEME = 42; + } + + // Output only. Indicates the reason code for a configuration failure. + Code code = 1; + + // Output only. Indicates the full name of the ScanConfig field that triggers this error, + // for example "scan_config.max_qps". This field is provided for + // troubleshooting purposes only and its actual value can change in the + // future. + string field_name = 2; +} diff --git a/google/cloud/websecurityscanner_v1/proto/scan_run.proto b/google/cloud/websecurityscanner_v1/proto/scan_run.proto new file mode 100644 index 0000000..465c6cb --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/scan_run.proto @@ -0,0 +1,110 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +import "google/cloud/websecurityscanner/v1/scan_run_error_trace.proto"; +import "google/cloud/websecurityscanner/v1/scan_run_warning_trace.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "ScanRunProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// A ScanRun is a output-only resource representing an actual run of the scan. +// Next id: 12 +message ScanRun { + // Types of ScanRun execution state. + enum ExecutionState { + // Represents an invalid state caused by internal server error. This value + // should never be returned. + EXECUTION_STATE_UNSPECIFIED = 0; + + // The scan is waiting in the queue. + QUEUED = 1; + + // The scan is in progress. + SCANNING = 2; + + // The scan is either finished or stopped by user. + FINISHED = 3; + } + + // Types of ScanRun result state. + enum ResultState { + // Default value. This value is returned when the ScanRun is not yet + // finished. + RESULT_STATE_UNSPECIFIED = 0; + + // The scan finished without errors. + SUCCESS = 1; + + // The scan finished with errors. + ERROR = 2; + + // The scan was terminated by user. + KILLED = 3; + } + + // Output only. The resource name of the ScanRun. The name follows the format of + // 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + // The ScanRun IDs are generated by the system. + string name = 1; + + // Output only. The execution state of the ScanRun. + ExecutionState execution_state = 2; + + // Output only. The result state of the ScanRun. This field is only available after the + // execution state reaches "FINISHED". + ResultState result_state = 3; + + // Output only. The time at which the ScanRun started. + google.protobuf.Timestamp start_time = 4; + + // Output only. The time at which the ScanRun reached termination state - that the ScanRun + // is either finished or stopped by user. + google.protobuf.Timestamp end_time = 5; + + // Output only. The number of URLs crawled during this ScanRun. If the scan is in progress, + // the value represents the number of URLs crawled up to now. + int64 urls_crawled_count = 6; + + // Output only. The number of URLs tested during this ScanRun. If the scan is in progress, + // the value represents the number of URLs tested up to now. The number of + // URLs tested is usually larger than the number URLS crawled because + // typically a crawled URL is tested with multiple test payloads. + int64 urls_tested_count = 7; + + // Output only. Whether the scan run has found any vulnerabilities. + bool has_vulnerabilities = 8; + + // Output only. The percentage of total completion ranging from 0 to 100. + // If the scan is in queue, the value is 0. + // If the scan is running, the value ranges from 0 to 100. + // If the scan is finished, the value is 100. + int32 progress_percent = 9; + + // Output only. If result_state is an ERROR, this field provides the primary reason for + // scan's termination and more details, if such are available. + ScanRunErrorTrace error_trace = 10; + + // Output only. A list of warnings, if such are encountered during this scan run. + repeated ScanRunWarningTrace warning_traces = 11; +} diff --git a/google/cloud/websecurityscanner_v1/proto/scan_run_error_trace.proto b/google/cloud/websecurityscanner_v1/proto/scan_run_error_trace.proto new file mode 100644 index 0000000..5234eee --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/scan_run_error_trace.proto @@ -0,0 +1,75 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +import "google/cloud/websecurityscanner/v1/scan_config_error.proto"; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "ScanRunErrorTraceProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// Output only. +// Defines an error trace message for a ScanRun. +message ScanRunErrorTrace { + // Output only. + // Defines an error reason code. + // Next id: 7 + enum Code { + // Default value is never used. + CODE_UNSPECIFIED = 0; + + // Indicates that the scan run failed due to an internal server error. + INTERNAL_ERROR = 1; + + // Indicates a scan configuration error, usually due to outdated ScanConfig + // settings, such as starting_urls or the DNS configuration. + SCAN_CONFIG_ISSUE = 2; + + // Indicates an authentication error, usually due to outdated ScanConfig + // authentication settings. + AUTHENTICATION_CONFIG_ISSUE = 3; + + // Indicates a scan operation timeout, usually caused by a very large site. + TIMED_OUT_WHILE_SCANNING = 4; + + // Indicates that a scan encountered excessive redirects, either to + // authentication or some other page outside of the scan scope. + TOO_MANY_REDIRECTS = 5; + + // Indicates that a scan encountered numerous errors from the web site + // pages. When available, most_common_http_error_code field indicates the + // most common HTTP error code encountered during the scan. + TOO_MANY_HTTP_ERRORS = 6; + } + + // Output only. Indicates the error reason code. + Code code = 1; + + // Output only. 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. + ScanConfigError scan_config_error = 2; + + // Output only. If the scan encounters TOO_MANY_HTTP_ERRORS, this field indicates the most + // common HTTP error code, if such is available. For example, if this code is + // 404, the scan has encountered too many NOT_FOUND responses. + int32 most_common_http_error_code = 3; +} diff --git a/google/cloud/websecurityscanner_v1/proto/scan_run_warning_trace.proto b/google/cloud/websecurityscanner_v1/proto/scan_run_warning_trace.proto new file mode 100644 index 0000000..43a5017 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/scan_run_warning_trace.proto @@ -0,0 +1,58 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "ScanRunWarningTraceProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// Output only. +// Defines a warning trace message for ScanRun. Warning traces provide customers +// with useful information that helps make the scanning process more effective. +message ScanRunWarningTrace { + // Output only. + // Defines a warning message code. + // Next id: 6 + enum Code { + // Default value is never used. + CODE_UNSPECIFIED = 0; + + // Indicates that a scan discovered an unexpectedly low number of URLs. This + // is sometimes caused by complex navigation features or by using a single + // URL for numerous pages. + INSUFFICIENT_CRAWL_RESULTS = 1; + + // Indicates that a scan discovered too many URLs to test, or excessive + // redundant URLs. + TOO_MANY_CRAWL_RESULTS = 2; + + // Indicates that too many tests have been generated for the scan. Customer + // should try reducing the number of starting URLs, increasing the QPS rate, + // or narrowing down the scope of the scan using the excluded patterns. + TOO_MANY_FUZZ_TASKS = 3; + + // Indicates that a scan is blocked by IAP. + BLOCKED_BY_IAP = 4; + } + + // Output only. Indicates the warning code. + Code code = 1; +} diff --git a/google/cloud/websecurityscanner_v1/proto/web_security_scanner.proto b/google/cloud/websecurityscanner_v1/proto/web_security_scanner.proto new file mode 100644 index 0000000..5f1bfcd --- /dev/null +++ b/google/cloud/websecurityscanner_v1/proto/web_security_scanner.proto @@ -0,0 +1,337 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.websecurityscanner.v1; + +import "google/api/annotations.proto"; +import "google/cloud/websecurityscanner/v1/crawled_url.proto"; +import "google/cloud/websecurityscanner/v1/finding.proto"; +import "google/cloud/websecurityscanner/v1/finding_type_stats.proto"; +import "google/cloud/websecurityscanner/v1/scan_config.proto"; +import "google/cloud/websecurityscanner/v1/scan_run.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/field_mask.proto"; +import "google/api/client.proto"; + +option csharp_namespace = "Google.Cloud.WebSecurityScanner.V1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/websecurityscanner/v1;websecurityscanner"; +option java_multiple_files = true; +option java_outer_classname = "WebSecurityScannerProto"; +option java_package = "com.google.cloud.websecurityscanner.v1"; +option php_namespace = "Google\\Cloud\\WebSecurityScanner\\V1"; +option ruby_package = "Google::Cloud::WebSecurityScanner::V1"; + +// Web Security Scanner Service identifies security vulnerabilities in web +// applications hosted on Google Cloud. It crawls your application, and +// attempts to exercise as many user inputs and event handlers as possible. +service WebSecurityScanner { + option (google.api.default_host) = "websecurityscanner.googleapis.com"; + option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/cloud-platform"; + + // Creates a new ScanConfig. + rpc CreateScanConfig(CreateScanConfigRequest) returns (ScanConfig) { + option (google.api.http) = { + post: "/v1/{parent=projects/*}/scanConfigs" + body: "scan_config" + }; + } + + // Deletes an existing ScanConfig and its child resources. + rpc DeleteScanConfig(DeleteScanConfigRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{name=projects/*/scanConfigs/*}" + }; + } + + // Gets a ScanConfig. + rpc GetScanConfig(GetScanConfigRequest) returns (ScanConfig) { + option (google.api.http) = { + get: "/v1/{name=projects/*/scanConfigs/*}" + }; + } + + // Lists ScanConfigs under a given project. + rpc ListScanConfigs(ListScanConfigsRequest) returns (ListScanConfigsResponse) { + option (google.api.http) = { + get: "/v1/{parent=projects/*}/scanConfigs" + }; + } + + // Updates a ScanConfig. This method support partial update of a ScanConfig. + rpc UpdateScanConfig(UpdateScanConfigRequest) returns (ScanConfig) { + option (google.api.http) = { + patch: "/v1/{scan_config.name=projects/*/scanConfigs/*}" + body: "scan_config" + }; + } + + // Start a ScanRun according to the given ScanConfig. + rpc StartScanRun(StartScanRunRequest) returns (ScanRun) { + option (google.api.http) = { + post: "/v1/{name=projects/*/scanConfigs/*}:start" + body: "*" + }; + } + + // Gets a ScanRun. + rpc GetScanRun(GetScanRunRequest) returns (ScanRun) { + option (google.api.http) = { + get: "/v1/{name=projects/*/scanConfigs/*/scanRuns/*}" + }; + } + + // Lists ScanRuns under a given ScanConfig, in descending order of ScanRun + // stop time. + rpc ListScanRuns(ListScanRunsRequest) returns (ListScanRunsResponse) { + option (google.api.http) = { + get: "/v1/{parent=projects/*/scanConfigs/*}/scanRuns" + }; + } + + // Stops a ScanRun. The stopped ScanRun is returned. + rpc StopScanRun(StopScanRunRequest) returns (ScanRun) { + option (google.api.http) = { + post: "/v1/{name=projects/*/scanConfigs/*/scanRuns/*}:stop" + body: "*" + }; + } + + // List CrawledUrls under a given ScanRun. + rpc ListCrawledUrls(ListCrawledUrlsRequest) returns (ListCrawledUrlsResponse) { + option (google.api.http) = { + get: "/v1/{parent=projects/*/scanConfigs/*/scanRuns/*}/crawledUrls" + }; + } + + // Gets a Finding. + rpc GetFinding(GetFindingRequest) returns (Finding) { + option (google.api.http) = { + get: "/v1/{name=projects/*/scanConfigs/*/scanRuns/*/findings/*}" + }; + } + + // List Findings under a given ScanRun. + rpc ListFindings(ListFindingsRequest) returns (ListFindingsResponse) { + option (google.api.http) = { + get: "/v1/{parent=projects/*/scanConfigs/*/scanRuns/*}/findings" + }; + } + + // List all FindingTypeStats under a given ScanRun. + rpc ListFindingTypeStats(ListFindingTypeStatsRequest) returns (ListFindingTypeStatsResponse) { + option (google.api.http) = { + get: "/v1/{parent=projects/*/scanConfigs/*/scanRuns/*}/findingTypeStats" + }; + } +} + +// Request for the `CreateScanConfig` method. +message CreateScanConfigRequest { + // Required. The parent resource name where the scan is created, which should be a + // project resource name in the format 'projects/{projectId}'. + string parent = 1; + + // Required. The ScanConfig to be created. + ScanConfig scan_config = 2; +} + +// Request for the `DeleteScanConfig` method. +message DeleteScanConfigRequest { + // Required. The resource name of the ScanConfig to be deleted. The name follows the + // format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + string name = 1; +} + +// Request for the `GetScanConfig` method. +message GetScanConfigRequest { + // Required. The resource name of the ScanConfig to be returned. The name follows the + // format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + string name = 1; +} + +// Request for the `ListScanConfigs` method. +message ListScanConfigsRequest { + // Required. The parent resource name, which should be a project resource name in the + // format 'projects/{projectId}'. + string parent = 1; + + // A token identifying a page of results to be returned. This should be a + // `next_page_token` value returned from a previous List request. + // If unspecified, the first page of results is returned. + string page_token = 2; + + // The maximum number of ScanConfigs to return, can be limited by server. + // If not specified or not positive, the implementation will select a + // reasonable value. + int32 page_size = 3; +} + +// Request for the `UpdateScanConfigRequest` method. +message UpdateScanConfigRequest { + // 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. + ScanConfig scan_config = 2; + + // Required. The update mask applies to the resource. For the `FieldMask` definition, + // see + // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask + google.protobuf.FieldMask update_mask = 3; +} + +// Response for the `ListScanConfigs` method. +message ListScanConfigsResponse { + // The list of ScanConfigs returned. + repeated ScanConfig scan_configs = 1; + + // Token to retrieve the next page of results, or empty if there are no + // more results in the list. + string next_page_token = 2; +} + +// Request for the `StartScanRun` method. +message StartScanRunRequest { + // Required. The resource name of the ScanConfig to be used. The name follows the + // format of 'projects/{projectId}/scanConfigs/{scanConfigId}'. + string name = 1; +} + +// Request for the `GetScanRun` method. +message GetScanRunRequest { + // Required. The resource name of the ScanRun to be returned. The name follows the + // format of + // 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + string name = 1; +} + +// Request for the `ListScanRuns` method. +message ListScanRunsRequest { + // Required. The parent resource name, which should be a scan resource name in the + // format 'projects/{projectId}/scanConfigs/{scanConfigId}'. + string parent = 1; + + // A token identifying a page of results to be returned. This should be a + // `next_page_token` value returned from a previous List request. + // If unspecified, the first page of results is returned. + string page_token = 2; + + // The maximum number of ScanRuns to return, can be limited by server. + // If not specified or not positive, the implementation will select a + // reasonable value. + int32 page_size = 3; +} + +// Response for the `ListScanRuns` method. +message ListScanRunsResponse { + // The list of ScanRuns returned. + repeated ScanRun scan_runs = 1; + + // Token to retrieve the next page of results, or empty if there are no + // more results in the list. + string next_page_token = 2; +} + +// Request for the `StopScanRun` method. +message StopScanRunRequest { + // Required. The resource name of the ScanRun to be stopped. The name follows the + // format of + // 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + string name = 1; +} + +// Request for the `ListCrawledUrls` method. +message ListCrawledUrlsRequest { + // Required. The parent resource name, which should be a scan run resource name in the + // format + // 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + string parent = 1; + + // A token identifying a page of results to be returned. This should be a + // `next_page_token` value returned from a previous List request. + // If unspecified, the first page of results is returned. + string page_token = 2; + + // The maximum number of CrawledUrls to return, can be limited by server. + // If not specified or not positive, the implementation will select a + // reasonable value. + int32 page_size = 3; +} + +// Response for the `ListCrawledUrls` method. +message ListCrawledUrlsResponse { + // The list of CrawledUrls returned. + repeated CrawledUrl crawled_urls = 1; + + // Token to retrieve the next page of results, or empty if there are no + // more results in the list. + string next_page_token = 2; +} + +// Request for the `GetFinding` method. +message GetFindingRequest { + // Required. The resource name of the Finding to be returned. The name follows the + // format of + // 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}/findings/{findingId}'. + string name = 1; +} + +// Request for the `ListFindings` method. +message ListFindingsRequest { + // Required. The parent resource name, which should be a scan run resource name in the + // format + // 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + string parent = 1; + + // The filter expression. The expression must be in the format: + // . + // Supported field: 'finding_type'. + // Supported operator: '='. + string filter = 2; + + // A token identifying a page of results to be returned. This should be a + // `next_page_token` value returned from a previous List request. + // If unspecified, the first page of results is returned. + string page_token = 3; + + // The maximum number of Findings to return, can be limited by server. + // If not specified or not positive, the implementation will select a + // reasonable value. + int32 page_size = 4; +} + +// Response for the `ListFindings` method. +message ListFindingsResponse { + // The list of Findings returned. + repeated Finding findings = 1; + + // Token to retrieve the next page of results, or empty if there are no + // more results in the list. + string next_page_token = 2; +} + +// Request for the `ListFindingTypeStats` method. +message ListFindingTypeStatsRequest { + // Required. The parent resource name, which should be a scan run resource name in the + // format + // 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + string parent = 1; +} + +// Response for the `ListFindingTypeStats` method. +message ListFindingTypeStatsResponse { + // The list of FindingTypeStats returned. + repeated FindingTypeStats finding_type_stats = 1; +} diff --git a/google/cloud/websecurityscanner_v1/py.typed b/google/cloud/websecurityscanner_v1/py.typed new file mode 100644 index 0000000..8cfb5d2 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-websecurityscanner package uses inline types. diff --git a/google/cloud/websecurityscanner_v1/services/__init__.py b/google/cloud/websecurityscanner_v1/services/__init__.py new file mode 100644 index 0000000..42ffdf2 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/__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/google/cloud/websecurityscanner_v1/services/web_security_scanner/__init__.py b/google/cloud/websecurityscanner_v1/services/web_security_scanner/__init__.py new file mode 100644 index 0000000..d841cb5 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/web_security_scanner/__init__.py @@ -0,0 +1,24 @@ +# -*- 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. +# + +from .client import WebSecurityScannerClient +from .async_client import WebSecurityScannerAsyncClient + +__all__ = ( + "WebSecurityScannerClient", + "WebSecurityScannerAsyncClient", +) diff --git a/google/cloud/websecurityscanner_v1/services/web_security_scanner/async_client.py b/google/cloud/websecurityscanner_v1/services/web_security_scanner/async_client.py new file mode 100644 index 0000000..125c55f --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/web_security_scanner/async_client.py @@ -0,0 +1,971 @@ +# -*- 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. +# + +from collections import OrderedDict +import functools +import re +from typing import Dict, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # 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.oauth2 import service_account # type: ignore + +from google.cloud.websecurityscanner_v1.services.web_security_scanner import pagers +from google.cloud.websecurityscanner_v1.types import crawled_url +from google.cloud.websecurityscanner_v1.types import finding +from google.cloud.websecurityscanner_v1.types import finding_addon +from google.cloud.websecurityscanner_v1.types import finding_type_stats +from google.cloud.websecurityscanner_v1.types import scan_config +from google.cloud.websecurityscanner_v1.types import scan_run +from google.cloud.websecurityscanner_v1.types import scan_run_error_trace +from google.cloud.websecurityscanner_v1.types import scan_run_warning_trace +from google.cloud.websecurityscanner_v1.types import web_security_scanner +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + +from .transports.base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import WebSecurityScannerGrpcAsyncIOTransport +from .client import WebSecurityScannerClient + + +class WebSecurityScannerAsyncClient: + """Web Security Scanner Service identifies security + vulnerabilities in web applications hosted on Google Cloud. It + crawls your application, and attempts to exercise as many user + inputs and event handlers as possible. + """ + + _client: WebSecurityScannerClient + + 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) + + 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_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), + ) + + def __init__( + self, + *, + 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. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + 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 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. + (1) The ``api_endpoint`` property can be used to override the + 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) 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 + creation failed for any reason. + """ + + self._client = WebSecurityScannerClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def create_scan_config( + self, + request: web_security_scanner.CreateScanConfigRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_config.ScanConfig: + r"""Creates a new ScanConfig. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.CreateScanConfigRequest`): + The request object. Request for the `CreateScanConfig` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanConfig: + A ScanConfig resource contains the + configurations to launch a scan. + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.CreateScanConfigRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_scan_config, + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def delete_scan_config( + self, + request: web_security_scanner.DeleteScanConfigRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes an existing ScanConfig and its child + resources. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.DeleteScanConfigRequest`): + The request object. Request for the `DeleteScanConfig` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.DeleteScanConfigRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, retry=retry, timeout=timeout, metadata=metadata, + ) + + async def get_scan_config( + self, + request: web_security_scanner.GetScanConfigRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_config.ScanConfig: + r"""Gets a ScanConfig. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.GetScanConfigRequest`): + The request object. Request for the `GetScanConfig` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanConfig: + A ScanConfig resource contains the + configurations to launch a scan. + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.GetScanConfigRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def list_scan_configs( + self, + request: web_security_scanner.ListScanConfigsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListScanConfigsAsyncPager: + r"""Lists ScanConfigs under a given project. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.ListScanConfigsRequest`): + The request object. Request for the `ListScanConfigs` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers.ListScanConfigsAsyncPager: + Response for the ListScanConfigs method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.ListScanConfigsRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListScanConfigsAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + async def update_scan_config( + self, + request: web_security_scanner.UpdateScanConfigRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_config.ScanConfig: + r"""Updates a ScanConfig. This method support partial + update of a ScanConfig. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.UpdateScanConfigRequest`): + The request object. Request for the + `UpdateScanConfigRequest` method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanConfig: + A ScanConfig resource contains the + configurations to launch a scan. + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.UpdateScanConfigRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_scan_config, + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("scan_config.name", request.scan_config.name),) + ), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def start_scan_run( + self, + request: web_security_scanner.StartScanRunRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_run.ScanRun: + r"""Start a ScanRun according to the given ScanConfig. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.StartScanRunRequest`): + The request object. Request for the `StartScanRun` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanRun: + A ScanRun is a output-only resource + representing an actual run of the scan. + Next id: 12 + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.StartScanRunRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.start_scan_run, + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def get_scan_run( + self, + request: web_security_scanner.GetScanRunRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_run.ScanRun: + r"""Gets a ScanRun. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.GetScanRunRequest`): + The request object. Request for the `GetScanRun` method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanRun: + A ScanRun is a output-only resource + representing an actual run of the scan. + Next id: 12 + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.GetScanRunRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def list_scan_runs( + self, + request: web_security_scanner.ListScanRunsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListScanRunsAsyncPager: + r"""Lists ScanRuns under a given ScanConfig, in + descending order of ScanRun stop time. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.ListScanRunsRequest`): + The request object. Request for the `ListScanRuns` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers.ListScanRunsAsyncPager: + Response for the ListScanRuns method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.ListScanRunsRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListScanRunsAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + async def stop_scan_run( + self, + request: web_security_scanner.StopScanRunRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_run.ScanRun: + r"""Stops a ScanRun. The stopped ScanRun is returned. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.StopScanRunRequest`): + The request object. Request for the `StopScanRun` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanRun: + A ScanRun is a output-only resource + representing an actual run of the scan. + Next id: 12 + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.StopScanRunRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.stop_scan_run, + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def list_crawled_urls( + self, + request: web_security_scanner.ListCrawledUrlsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListCrawledUrlsAsyncPager: + r"""List CrawledUrls under a given ScanRun. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.ListCrawledUrlsRequest`): + The request object. Request for the `ListCrawledUrls` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers.ListCrawledUrlsAsyncPager: + Response for the ListCrawledUrls method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.ListCrawledUrlsRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListCrawledUrlsAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_finding( + self, + request: web_security_scanner.GetFindingRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> finding.Finding: + r"""Gets a Finding. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.GetFindingRequest`): + The request object. Request for the `GetFinding` method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.Finding: + A Finding resource represents a + vulnerability instance identified during + a ScanRun. + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.GetFindingRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def list_findings( + self, + request: web_security_scanner.ListFindingsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListFindingsAsyncPager: + r"""List Findings under a given ScanRun. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.ListFindingsRequest`): + The request object. Request for the `ListFindings` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers.ListFindingsAsyncPager: + Response for the ListFindings method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.ListFindingsRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListFindingsAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_finding_type_stats( + self, + request: web_security_scanner.ListFindingTypeStatsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> web_security_scanner.ListFindingTypeStatsResponse: + r"""List all FindingTypeStats under a given ScanRun. + + Args: + request (:class:`google.cloud.websecurityscanner_v1.types.ListFindingTypeStatsRequest`): + The request object. Request for the + `ListFindingTypeStats` method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ListFindingTypeStatsResponse: + Response for the ListFindingTypeStats method. + """ + # Create or coerce a protobuf request object. + + request = web_security_scanner.ListFindingTypeStatsRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._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, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + +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() + + +__all__ = ("WebSecurityScannerAsyncClient",) diff --git a/google/cloud/websecurityscanner_v1/services/web_security_scanner/client.py b/google/cloud/websecurityscanner_v1/services/web_security_scanner/client.py new file mode 100644 index 0000000..4b2ebd6 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/web_security_scanner/client.py @@ -0,0 +1,1083 @@ +# -*- 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. +# + +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +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 + +from google.cloud.websecurityscanner_v1.services.web_security_scanner import pagers +from google.cloud.websecurityscanner_v1.types import crawled_url +from google.cloud.websecurityscanner_v1.types import finding +from google.cloud.websecurityscanner_v1.types import finding_addon +from google.cloud.websecurityscanner_v1.types import finding_type_stats +from google.cloud.websecurityscanner_v1.types import scan_config +from google.cloud.websecurityscanner_v1.types import scan_run +from google.cloud.websecurityscanner_v1.types import scan_run_error_trace +from google.cloud.websecurityscanner_v1.types import scan_run_warning_trace +from google.cloud.websecurityscanner_v1.types import web_security_scanner +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + +from .transports.base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import WebSecurityScannerGrpcTransport +from .transports.grpc_asyncio import WebSecurityScannerGrpcAsyncIOTransport + + +class WebSecurityScannerClientMeta(type): + """Metaclass for the WebSecurityScanner client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = ( + OrderedDict() + ) # type: Dict[str, Type[WebSecurityScannerTransport]] + _transport_registry["grpc"] = WebSecurityScannerGrpcTransport + _transport_registry["grpc_asyncio"] = WebSecurityScannerGrpcAsyncIOTransport + + def get_transport_class( + cls, label: str = None, + ) -> Type[WebSecurityScannerTransport]: + """Return an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class WebSecurityScannerClient(metaclass=WebSecurityScannerClientMeta): + """Web Security Scanner Service identifies security + vulnerabilities in web applications hosted on Google Cloud. It + crawls your application, and attempts to exercise as many user + inputs and event handlers as possible. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Convert api endpoint to mTLS endpoint. + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "websecurityscanner.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + 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 + 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: + WebSecurityScannerClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*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 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: 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. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + 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 to use. If set to None, a transport is chosen + automatically. + 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_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) 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 = client_options_lib.from_dict(client_options) + if client_options is None: + 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 + ) + + # 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": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT + ) + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, WebSecurityScannerTransport): + # transport is a WebSecurityScannerTransport instance. + if credentials or client_options.credentials_file: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, " + "provide its scopes directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + 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( + self, + request: web_security_scanner.CreateScanConfigRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_config.ScanConfig: + r"""Creates a new ScanConfig. + + Args: + request (google.cloud.websecurityscanner_v1.types.CreateScanConfigRequest): + The request object. Request for the `CreateScanConfig` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanConfig: + A ScanConfig resource contains the + configurations to launch a scan. + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_scan_config] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def delete_scan_config( + self, + request: web_security_scanner.DeleteScanConfigRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes an existing ScanConfig and its child + resources. + + Args: + request (google.cloud.websecurityscanner_v1.types.DeleteScanConfigRequest): + The request object. Request for the `DeleteScanConfig` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_scan_config] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, retry=retry, timeout=timeout, metadata=metadata, + ) + + def get_scan_config( + self, + request: web_security_scanner.GetScanConfigRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_config.ScanConfig: + r"""Gets a ScanConfig. + + Args: + request (google.cloud.websecurityscanner_v1.types.GetScanConfigRequest): + The request object. Request for the `GetScanConfig` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanConfig: + A ScanConfig resource contains the + configurations to launch a scan. + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_scan_config] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def list_scan_configs( + self, + request: web_security_scanner.ListScanConfigsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListScanConfigsPager: + r"""Lists ScanConfigs under a given project. + + Args: + request (google.cloud.websecurityscanner_v1.types.ListScanConfigsRequest): + The request object. Request for the `ListScanConfigs` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers.ListScanConfigsPager: + Response for the ListScanConfigs method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_scan_configs] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListScanConfigsPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + def update_scan_config( + self, + request: web_security_scanner.UpdateScanConfigRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_config.ScanConfig: + r"""Updates a ScanConfig. This method support partial + update of a ScanConfig. + + Args: + request (google.cloud.websecurityscanner_v1.types.UpdateScanConfigRequest): + The request object. Request for the + `UpdateScanConfigRequest` method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanConfig: + A ScanConfig resource contains the + configurations to launch a scan. + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_scan_config] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("scan_config.name", request.scan_config.name),) + ), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def start_scan_run( + self, + request: web_security_scanner.StartScanRunRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_run.ScanRun: + r"""Start a ScanRun according to the given ScanConfig. + + Args: + request (google.cloud.websecurityscanner_v1.types.StartScanRunRequest): + The request object. Request for the `StartScanRun` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanRun: + A ScanRun is a output-only resource + representing an actual run of the scan. + Next id: 12 + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.start_scan_run] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def get_scan_run( + self, + request: web_security_scanner.GetScanRunRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_run.ScanRun: + r"""Gets a ScanRun. + + Args: + request (google.cloud.websecurityscanner_v1.types.GetScanRunRequest): + The request object. Request for the `GetScanRun` method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanRun: + A ScanRun is a output-only resource + representing an actual run of the scan. + Next id: 12 + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_scan_run] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def list_scan_runs( + self, + request: web_security_scanner.ListScanRunsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListScanRunsPager: + r"""Lists ScanRuns under a given ScanConfig, in + descending order of ScanRun stop time. + + Args: + request (google.cloud.websecurityscanner_v1.types.ListScanRunsRequest): + The request object. Request for the `ListScanRuns` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers.ListScanRunsPager: + Response for the ListScanRuns method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_scan_runs] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListScanRunsPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + def stop_scan_run( + self, + request: web_security_scanner.StopScanRunRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> scan_run.ScanRun: + r"""Stops a ScanRun. The stopped ScanRun is returned. + + Args: + request (google.cloud.websecurityscanner_v1.types.StopScanRunRequest): + The request object. Request for the `StopScanRun` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ScanRun: + A ScanRun is a output-only resource + representing an actual run of the scan. + Next id: 12 + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.stop_scan_run] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def list_crawled_urls( + self, + request: web_security_scanner.ListCrawledUrlsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListCrawledUrlsPager: + r"""List CrawledUrls under a given ScanRun. + + Args: + request (google.cloud.websecurityscanner_v1.types.ListCrawledUrlsRequest): + The request object. Request for the `ListCrawledUrls` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers.ListCrawledUrlsPager: + Response for the ListCrawledUrls method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_crawled_urls] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListCrawledUrlsPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + def get_finding( + self, + request: web_security_scanner.GetFindingRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> finding.Finding: + r"""Gets a Finding. + + Args: + request (google.cloud.websecurityscanner_v1.types.GetFindingRequest): + The request object. Request for the `GetFinding` method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.Finding: + A Finding resource represents a + vulnerability instance identified during + a ScanRun. + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_finding] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def list_findings( + self, + request: web_security_scanner.ListFindingsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListFindingsPager: + r"""List Findings under a given ScanRun. + + Args: + request (google.cloud.websecurityscanner_v1.types.ListFindingsRequest): + The request object. Request for the `ListFindings` + method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.services.web_security_scanner.pagers.ListFindingsPager: + Response for the ListFindings method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_findings] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListFindingsPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + def list_finding_type_stats( + self, + request: web_security_scanner.ListFindingTypeStatsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> web_security_scanner.ListFindingTypeStatsResponse: + r"""List all FindingTypeStats under a given ScanRun. + + Args: + request (google.cloud.websecurityscanner_v1.types.ListFindingTypeStatsRequest): + The request object. Request for the + `ListFindingTypeStats` method. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.websecurityscanner_v1.types.ListFindingTypeStatsResponse: + Response for the ListFindingTypeStats method. + """ + # Create or coerce a protobuf request object. + + # 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) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_finding_type_stats] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + +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() + + +__all__ = ("WebSecurityScannerClient",) diff --git a/google/cloud/websecurityscanner_v1/services/web_security_scanner/pagers.py b/google/cloud/websecurityscanner_v1/services/web_security_scanner/pagers.py new file mode 100644 index 0000000..7b59634 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/web_security_scanner/pagers.py @@ -0,0 +1,549 @@ +# -*- 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. +# + +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) + +from google.cloud.websecurityscanner_v1.types import crawled_url +from google.cloud.websecurityscanner_v1.types import finding +from google.cloud.websecurityscanner_v1.types import scan_config +from google.cloud.websecurityscanner_v1.types import scan_run +from google.cloud.websecurityscanner_v1.types import web_security_scanner + + +class ListScanConfigsPager: + """A pager for iterating through ``list_scan_configs`` requests. + + This class thinly wraps an initial + :class:`google.cloud.websecurityscanner_v1.types.ListScanConfigsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``scan_configs`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListScanConfigs`` requests and continue to iterate + through the ``scan_configs`` field on the + corresponding responses. + + All the usual :class:`google.cloud.websecurityscanner_v1.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. + """ + + def __init__( + self, + method: Callable[..., web_security_scanner.ListScanConfigsResponse], + request: web_security_scanner.ListScanConfigsRequest, + response: web_security_scanner.ListScanConfigsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.websecurityscanner_v1.types.ListScanConfigsRequest): + The initial request object. + response (google.cloud.websecurityscanner_v1.types.ListScanConfigsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = web_security_scanner.ListScanConfigsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[web_security_scanner.ListScanConfigsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[scan_config.ScanConfig]: + for page in self.pages: + yield from page.scan_configs + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListScanConfigsAsyncPager: + """A pager for iterating through ``list_scan_configs`` requests. + + This class thinly wraps an initial + :class:`google.cloud.websecurityscanner_v1.types.ListScanConfigsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``scan_configs`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListScanConfigs`` requests and continue to iterate + through the ``scan_configs`` field on the + corresponding responses. + + All the usual :class:`google.cloud.websecurityscanner_v1.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. + """ + + def __init__( + self, + method: Callable[..., Awaitable[web_security_scanner.ListScanConfigsResponse]], + request: web_security_scanner.ListScanConfigsRequest, + response: web_security_scanner.ListScanConfigsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.websecurityscanner_v1.types.ListScanConfigsRequest): + The initial request object. + response (google.cloud.websecurityscanner_v1.types.ListScanConfigsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = web_security_scanner.ListScanConfigsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages( + self, + ) -> AsyncIterable[web_security_scanner.ListScanConfigsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[scan_config.ScanConfig]: + async def async_generator(): + async for page in self.pages: + for response in page.scan_configs: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListScanRunsPager: + """A pager for iterating through ``list_scan_runs`` requests. + + This class thinly wraps an initial + :class:`google.cloud.websecurityscanner_v1.types.ListScanRunsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``scan_runs`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListScanRuns`` requests and continue to iterate + through the ``scan_runs`` field on the + corresponding responses. + + All the usual :class:`google.cloud.websecurityscanner_v1.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. + """ + + def __init__( + self, + method: Callable[..., web_security_scanner.ListScanRunsResponse], + request: web_security_scanner.ListScanRunsRequest, + response: web_security_scanner.ListScanRunsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.websecurityscanner_v1.types.ListScanRunsRequest): + The initial request object. + response (google.cloud.websecurityscanner_v1.types.ListScanRunsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = web_security_scanner.ListScanRunsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[web_security_scanner.ListScanRunsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[scan_run.ScanRun]: + for page in self.pages: + yield from page.scan_runs + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListScanRunsAsyncPager: + """A pager for iterating through ``list_scan_runs`` requests. + + This class thinly wraps an initial + :class:`google.cloud.websecurityscanner_v1.types.ListScanRunsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``scan_runs`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListScanRuns`` requests and continue to iterate + through the ``scan_runs`` field on the + corresponding responses. + + All the usual :class:`google.cloud.websecurityscanner_v1.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. + """ + + def __init__( + self, + method: Callable[..., Awaitable[web_security_scanner.ListScanRunsResponse]], + request: web_security_scanner.ListScanRunsRequest, + response: web_security_scanner.ListScanRunsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.websecurityscanner_v1.types.ListScanRunsRequest): + The initial request object. + response (google.cloud.websecurityscanner_v1.types.ListScanRunsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = web_security_scanner.ListScanRunsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterable[web_security_scanner.ListScanRunsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[scan_run.ScanRun]: + async def async_generator(): + async for page in self.pages: + for response in page.scan_runs: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListCrawledUrlsPager: + """A pager for iterating through ``list_crawled_urls`` requests. + + This class thinly wraps an initial + :class:`google.cloud.websecurityscanner_v1.types.ListCrawledUrlsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``crawled_urls`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListCrawledUrls`` requests and continue to iterate + through the ``crawled_urls`` field on the + corresponding responses. + + All the usual :class:`google.cloud.websecurityscanner_v1.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. + """ + + def __init__( + self, + method: Callable[..., web_security_scanner.ListCrawledUrlsResponse], + request: web_security_scanner.ListCrawledUrlsRequest, + response: web_security_scanner.ListCrawledUrlsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.websecurityscanner_v1.types.ListCrawledUrlsRequest): + The initial request object. + response (google.cloud.websecurityscanner_v1.types.ListCrawledUrlsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = web_security_scanner.ListCrawledUrlsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[web_security_scanner.ListCrawledUrlsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[crawled_url.CrawledUrl]: + for page in self.pages: + yield from page.crawled_urls + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListCrawledUrlsAsyncPager: + """A pager for iterating through ``list_crawled_urls`` requests. + + This class thinly wraps an initial + :class:`google.cloud.websecurityscanner_v1.types.ListCrawledUrlsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``crawled_urls`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListCrawledUrls`` requests and continue to iterate + through the ``crawled_urls`` field on the + corresponding responses. + + All the usual :class:`google.cloud.websecurityscanner_v1.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. + """ + + def __init__( + self, + method: Callable[..., Awaitable[web_security_scanner.ListCrawledUrlsResponse]], + request: web_security_scanner.ListCrawledUrlsRequest, + response: web_security_scanner.ListCrawledUrlsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.websecurityscanner_v1.types.ListCrawledUrlsRequest): + The initial request object. + response (google.cloud.websecurityscanner_v1.types.ListCrawledUrlsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = web_security_scanner.ListCrawledUrlsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages( + self, + ) -> AsyncIterable[web_security_scanner.ListCrawledUrlsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[crawled_url.CrawledUrl]: + async def async_generator(): + async for page in self.pages: + for response in page.crawled_urls: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListFindingsPager: + """A pager for iterating through ``list_findings`` requests. + + This class thinly wraps an initial + :class:`google.cloud.websecurityscanner_v1.types.ListFindingsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``findings`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListFindings`` requests and continue to iterate + through the ``findings`` field on the + corresponding responses. + + All the usual :class:`google.cloud.websecurityscanner_v1.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. + """ + + def __init__( + self, + method: Callable[..., web_security_scanner.ListFindingsResponse], + request: web_security_scanner.ListFindingsRequest, + response: web_security_scanner.ListFindingsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.websecurityscanner_v1.types.ListFindingsRequest): + The initial request object. + response (google.cloud.websecurityscanner_v1.types.ListFindingsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = web_security_scanner.ListFindingsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[web_security_scanner.ListFindingsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[finding.Finding]: + for page in self.pages: + yield from page.findings + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListFindingsAsyncPager: + """A pager for iterating through ``list_findings`` requests. + + This class thinly wraps an initial + :class:`google.cloud.websecurityscanner_v1.types.ListFindingsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``findings`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListFindings`` requests and continue to iterate + through the ``findings`` field on the + corresponding responses. + + All the usual :class:`google.cloud.websecurityscanner_v1.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. + """ + + def __init__( + self, + method: Callable[..., Awaitable[web_security_scanner.ListFindingsResponse]], + request: web_security_scanner.ListFindingsRequest, + response: web_security_scanner.ListFindingsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.websecurityscanner_v1.types.ListFindingsRequest): + The initial request object. + response (google.cloud.websecurityscanner_v1.types.ListFindingsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = web_security_scanner.ListFindingsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterable[web_security_scanner.ListFindingsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[finding.Finding]: + async def async_generator(): + async for page in self.pages: + for response in page.findings: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/__init__.py b/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/__init__.py new file mode 100644 index 0000000..caf0502 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/__init__.py @@ -0,0 +1,37 @@ +# -*- 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. +# + +from collections import OrderedDict +from typing import Dict, Type + +from .base import WebSecurityScannerTransport +from .grpc import WebSecurityScannerGrpcTransport +from .grpc_asyncio import WebSecurityScannerGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = ( + OrderedDict() +) # type: Dict[str, Type[WebSecurityScannerTransport]] +_transport_registry["grpc"] = WebSecurityScannerGrpcTransport +_transport_registry["grpc_asyncio"] = WebSecurityScannerGrpcAsyncIOTransport + +__all__ = ( + "WebSecurityScannerTransport", + "WebSecurityScannerGrpcTransport", + "WebSecurityScannerGrpcAsyncIOTransport", +) diff --git a/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/base.py b/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/base.py new file mode 100644 index 0000000..801b65b --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/base.py @@ -0,0 +1,386 @@ +# -*- 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. +# + +import abc +import typing +import pkg_resources + +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_v1.types import finding +from google.cloud.websecurityscanner_v1.types import scan_config +from google.cloud.websecurityscanner_v1.types import scan_run +from google.cloud.websecurityscanner_v1.types import web_security_scanner +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.""" + + AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + def __init__( + self, + *, + host: str = "websecurityscanner.googleapis.com", + credentials: credentials.Credentials = None, + 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. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + 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: + raise exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = auth.load_credentials_from_file( + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = auth.default( + 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, + ) -> typing.Callable[ + [web_security_scanner.CreateScanConfigRequest], + typing.Union[scan_config.ScanConfig, typing.Awaitable[scan_config.ScanConfig]], + ]: + raise NotImplementedError() + + @property + def delete_scan_config( + self, + ) -> typing.Callable[ + [web_security_scanner.DeleteScanConfigRequest], + typing.Union[empty.Empty, typing.Awaitable[empty.Empty]], + ]: + raise NotImplementedError() + + @property + def get_scan_config( + self, + ) -> typing.Callable[ + [web_security_scanner.GetScanConfigRequest], + typing.Union[scan_config.ScanConfig, typing.Awaitable[scan_config.ScanConfig]], + ]: + raise NotImplementedError() + + @property + def list_scan_configs( + self, + ) -> typing.Callable[ + [web_security_scanner.ListScanConfigsRequest], + typing.Union[ + web_security_scanner.ListScanConfigsResponse, + typing.Awaitable[web_security_scanner.ListScanConfigsResponse], + ], + ]: + raise NotImplementedError() + + @property + def update_scan_config( + self, + ) -> typing.Callable[ + [web_security_scanner.UpdateScanConfigRequest], + typing.Union[scan_config.ScanConfig, typing.Awaitable[scan_config.ScanConfig]], + ]: + raise NotImplementedError() + + @property + def start_scan_run( + self, + ) -> typing.Callable[ + [web_security_scanner.StartScanRunRequest], + typing.Union[scan_run.ScanRun, typing.Awaitable[scan_run.ScanRun]], + ]: + raise NotImplementedError() + + @property + def get_scan_run( + self, + ) -> typing.Callable[ + [web_security_scanner.GetScanRunRequest], + typing.Union[scan_run.ScanRun, typing.Awaitable[scan_run.ScanRun]], + ]: + raise NotImplementedError() + + @property + def list_scan_runs( + self, + ) -> typing.Callable[ + [web_security_scanner.ListScanRunsRequest], + typing.Union[ + web_security_scanner.ListScanRunsResponse, + typing.Awaitable[web_security_scanner.ListScanRunsResponse], + ], + ]: + raise NotImplementedError() + + @property + def stop_scan_run( + self, + ) -> typing.Callable[ + [web_security_scanner.StopScanRunRequest], + typing.Union[scan_run.ScanRun, typing.Awaitable[scan_run.ScanRun]], + ]: + raise NotImplementedError() + + @property + def list_crawled_urls( + self, + ) -> typing.Callable[ + [web_security_scanner.ListCrawledUrlsRequest], + typing.Union[ + web_security_scanner.ListCrawledUrlsResponse, + typing.Awaitable[web_security_scanner.ListCrawledUrlsResponse], + ], + ]: + raise NotImplementedError() + + @property + def get_finding( + self, + ) -> typing.Callable[ + [web_security_scanner.GetFindingRequest], + typing.Union[finding.Finding, typing.Awaitable[finding.Finding]], + ]: + raise NotImplementedError() + + @property + def list_findings( + self, + ) -> typing.Callable[ + [web_security_scanner.ListFindingsRequest], + typing.Union[ + web_security_scanner.ListFindingsResponse, + typing.Awaitable[web_security_scanner.ListFindingsResponse], + ], + ]: + raise NotImplementedError() + + @property + def list_finding_type_stats( + self, + ) -> typing.Callable[ + [web_security_scanner.ListFindingTypeStatsRequest], + typing.Union[ + web_security_scanner.ListFindingTypeStatsResponse, + typing.Awaitable[web_security_scanner.ListFindingTypeStatsResponse], + ], + ]: + raise NotImplementedError() + + +__all__ = ("WebSecurityScannerTransport",) diff --git a/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/grpc.py b/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/grpc.py new file mode 100644 index 0000000..05d0e96 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/grpc.py @@ -0,0 +1,592 @@ +# -*- 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. +# + +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_v1.types import finding +from google.cloud.websecurityscanner_v1.types import scan_config +from google.cloud.websecurityscanner_v1.types import scan_run +from google.cloud.websecurityscanner_v1.types import web_security_scanner +from google.protobuf import empty_pb2 as empty # type: ignore + +from .base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO + + +class WebSecurityScannerGrpcTransport(WebSecurityScannerTransport): + """gRPC backend transport for WebSecurityScanner. + + Web Security Scanner Service identifies security + vulnerabilities in web applications hosted on Google Cloud. It + crawls your application, and attempts to exercise as many user + inputs and event handlers as possible. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "websecurityscanner.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.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: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + 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]]]): + 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 + creation failed for any reason. + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + 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 + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) + + 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( + cls, + host: str = "websecurityscanner.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + 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 + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + scopes = scopes or cls.AUTH_SCOPES + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def create_scan_config( + self, + ) -> Callable[ + [web_security_scanner.CreateScanConfigRequest], scan_config.ScanConfig + ]: + r"""Return a callable for the create scan config method over gRPC. + + Creates a new ScanConfig. + + Returns: + Callable[[~.CreateScanConfigRequest], + ~.ScanConfig]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_scan_config" not in self._stubs: + self._stubs["create_scan_config"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/CreateScanConfig", + request_serializer=web_security_scanner.CreateScanConfigRequest.serialize, + response_deserializer=scan_config.ScanConfig.deserialize, + ) + return self._stubs["create_scan_config"] + + @property + def delete_scan_config( + self, + ) -> Callable[[web_security_scanner.DeleteScanConfigRequest], empty.Empty]: + r"""Return a callable for the delete scan config method over gRPC. + + Deletes an existing ScanConfig and its child + resources. + + Returns: + Callable[[~.DeleteScanConfigRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_scan_config" not in self._stubs: + self._stubs["delete_scan_config"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/DeleteScanConfig", + request_serializer=web_security_scanner.DeleteScanConfigRequest.serialize, + response_deserializer=empty.Empty.FromString, + ) + return self._stubs["delete_scan_config"] + + @property + def get_scan_config( + self, + ) -> Callable[[web_security_scanner.GetScanConfigRequest], scan_config.ScanConfig]: + r"""Return a callable for the get scan config method over gRPC. + + Gets a ScanConfig. + + Returns: + Callable[[~.GetScanConfigRequest], + ~.ScanConfig]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_scan_config" not in self._stubs: + self._stubs["get_scan_config"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/GetScanConfig", + request_serializer=web_security_scanner.GetScanConfigRequest.serialize, + response_deserializer=scan_config.ScanConfig.deserialize, + ) + return self._stubs["get_scan_config"] + + @property + def list_scan_configs( + self, + ) -> Callable[ + [web_security_scanner.ListScanConfigsRequest], + web_security_scanner.ListScanConfigsResponse, + ]: + r"""Return a callable for the list scan configs method over gRPC. + + Lists ScanConfigs under a given project. + + Returns: + Callable[[~.ListScanConfigsRequest], + ~.ListScanConfigsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_scan_configs" not in self._stubs: + self._stubs["list_scan_configs"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListScanConfigs", + request_serializer=web_security_scanner.ListScanConfigsRequest.serialize, + response_deserializer=web_security_scanner.ListScanConfigsResponse.deserialize, + ) + return self._stubs["list_scan_configs"] + + @property + def update_scan_config( + self, + ) -> Callable[ + [web_security_scanner.UpdateScanConfigRequest], scan_config.ScanConfig + ]: + r"""Return a callable for the update scan config method over gRPC. + + Updates a ScanConfig. This method support partial + update of a ScanConfig. + + Returns: + Callable[[~.UpdateScanConfigRequest], + ~.ScanConfig]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_scan_config" not in self._stubs: + self._stubs["update_scan_config"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/UpdateScanConfig", + request_serializer=web_security_scanner.UpdateScanConfigRequest.serialize, + response_deserializer=scan_config.ScanConfig.deserialize, + ) + return self._stubs["update_scan_config"] + + @property + def start_scan_run( + self, + ) -> Callable[[web_security_scanner.StartScanRunRequest], scan_run.ScanRun]: + r"""Return a callable for the start scan run method over gRPC. + + Start a ScanRun according to the given ScanConfig. + + Returns: + Callable[[~.StartScanRunRequest], + ~.ScanRun]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "start_scan_run" not in self._stubs: + self._stubs["start_scan_run"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/StartScanRun", + request_serializer=web_security_scanner.StartScanRunRequest.serialize, + response_deserializer=scan_run.ScanRun.deserialize, + ) + return self._stubs["start_scan_run"] + + @property + def get_scan_run( + self, + ) -> Callable[[web_security_scanner.GetScanRunRequest], scan_run.ScanRun]: + r"""Return a callable for the get scan run method over gRPC. + + Gets a ScanRun. + + Returns: + Callable[[~.GetScanRunRequest], + ~.ScanRun]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_scan_run" not in self._stubs: + self._stubs["get_scan_run"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/GetScanRun", + request_serializer=web_security_scanner.GetScanRunRequest.serialize, + response_deserializer=scan_run.ScanRun.deserialize, + ) + return self._stubs["get_scan_run"] + + @property + def list_scan_runs( + self, + ) -> Callable[ + [web_security_scanner.ListScanRunsRequest], + web_security_scanner.ListScanRunsResponse, + ]: + r"""Return a callable for the list scan runs method over gRPC. + + Lists ScanRuns under a given ScanConfig, in + descending order of ScanRun stop time. + + Returns: + Callable[[~.ListScanRunsRequest], + ~.ListScanRunsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_scan_runs" not in self._stubs: + self._stubs["list_scan_runs"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListScanRuns", + request_serializer=web_security_scanner.ListScanRunsRequest.serialize, + response_deserializer=web_security_scanner.ListScanRunsResponse.deserialize, + ) + return self._stubs["list_scan_runs"] + + @property + def stop_scan_run( + self, + ) -> Callable[[web_security_scanner.StopScanRunRequest], scan_run.ScanRun]: + r"""Return a callable for the stop scan run method over gRPC. + + Stops a ScanRun. The stopped ScanRun is returned. + + Returns: + Callable[[~.StopScanRunRequest], + ~.ScanRun]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "stop_scan_run" not in self._stubs: + self._stubs["stop_scan_run"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/StopScanRun", + request_serializer=web_security_scanner.StopScanRunRequest.serialize, + response_deserializer=scan_run.ScanRun.deserialize, + ) + return self._stubs["stop_scan_run"] + + @property + def list_crawled_urls( + self, + ) -> Callable[ + [web_security_scanner.ListCrawledUrlsRequest], + web_security_scanner.ListCrawledUrlsResponse, + ]: + r"""Return a callable for the list crawled urls method over gRPC. + + List CrawledUrls under a given ScanRun. + + Returns: + Callable[[~.ListCrawledUrlsRequest], + ~.ListCrawledUrlsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_crawled_urls" not in self._stubs: + self._stubs["list_crawled_urls"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListCrawledUrls", + request_serializer=web_security_scanner.ListCrawledUrlsRequest.serialize, + response_deserializer=web_security_scanner.ListCrawledUrlsResponse.deserialize, + ) + return self._stubs["list_crawled_urls"] + + @property + def get_finding( + self, + ) -> Callable[[web_security_scanner.GetFindingRequest], finding.Finding]: + r"""Return a callable for the get finding method over gRPC. + + Gets a Finding. + + Returns: + Callable[[~.GetFindingRequest], + ~.Finding]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_finding" not in self._stubs: + self._stubs["get_finding"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/GetFinding", + request_serializer=web_security_scanner.GetFindingRequest.serialize, + response_deserializer=finding.Finding.deserialize, + ) + return self._stubs["get_finding"] + + @property + def list_findings( + self, + ) -> Callable[ + [web_security_scanner.ListFindingsRequest], + web_security_scanner.ListFindingsResponse, + ]: + r"""Return a callable for the list findings method over gRPC. + + List Findings under a given ScanRun. + + Returns: + Callable[[~.ListFindingsRequest], + ~.ListFindingsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_findings" not in self._stubs: + self._stubs["list_findings"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListFindings", + request_serializer=web_security_scanner.ListFindingsRequest.serialize, + response_deserializer=web_security_scanner.ListFindingsResponse.deserialize, + ) + return self._stubs["list_findings"] + + @property + def list_finding_type_stats( + self, + ) -> Callable[ + [web_security_scanner.ListFindingTypeStatsRequest], + web_security_scanner.ListFindingTypeStatsResponse, + ]: + r"""Return a callable for the list finding type stats method over gRPC. + + List all FindingTypeStats under a given ScanRun. + + Returns: + Callable[[~.ListFindingTypeStatsRequest], + ~.ListFindingTypeStatsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_finding_type_stats" not in self._stubs: + self._stubs["list_finding_type_stats"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListFindingTypeStats", + request_serializer=web_security_scanner.ListFindingTypeStatsRequest.serialize, + response_deserializer=web_security_scanner.ListFindingTypeStatsResponse.deserialize, + ) + return self._stubs["list_finding_type_stats"] + + +__all__ = ("WebSecurityScannerGrpcTransport",) diff --git a/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/grpc_asyncio.py b/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/grpc_asyncio.py new file mode 100644 index 0000000..22da14d --- /dev/null +++ b/google/cloud/websecurityscanner_v1/services/web_security_scanner/transports/grpc_asyncio.py @@ -0,0 +1,608 @@ +# -*- 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. +# + +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 + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.websecurityscanner_v1.types import finding +from google.cloud.websecurityscanner_v1.types import scan_config +from google.cloud.websecurityscanner_v1.types import scan_run +from google.cloud.websecurityscanner_v1.types import web_security_scanner +from google.protobuf import empty_pb2 as empty # type: ignore + +from .base import WebSecurityScannerTransport, DEFAULT_CLIENT_INFO +from .grpc import WebSecurityScannerGrpcTransport + + +class WebSecurityScannerGrpcAsyncIOTransport(WebSecurityScannerTransport): + """gRPC AsyncIO backend transport for WebSecurityScanner. + + Web Security Scanner Service identifies security + vulnerabilities in web applications hosted on Google Cloud. It + crawls your application, and attempts to exercise as many user + inputs and event handlers as possible. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "websecurityscanner.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + 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 + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + scopes = scopes or cls.AUTH_SCOPES + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "websecurityscanner.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + 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. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + 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]]]): + 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 + creation failed for any reason. + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + 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 + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) + + 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: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def create_scan_config( + self, + ) -> Callable[ + [web_security_scanner.CreateScanConfigRequest], + Awaitable[scan_config.ScanConfig], + ]: + r"""Return a callable for the create scan config method over gRPC. + + Creates a new ScanConfig. + + Returns: + Callable[[~.CreateScanConfigRequest], + Awaitable[~.ScanConfig]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_scan_config" not in self._stubs: + self._stubs["create_scan_config"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/CreateScanConfig", + request_serializer=web_security_scanner.CreateScanConfigRequest.serialize, + response_deserializer=scan_config.ScanConfig.deserialize, + ) + return self._stubs["create_scan_config"] + + @property + def delete_scan_config( + self, + ) -> Callable[ + [web_security_scanner.DeleteScanConfigRequest], Awaitable[empty.Empty] + ]: + r"""Return a callable for the delete scan config method over gRPC. + + Deletes an existing ScanConfig and its child + resources. + + Returns: + Callable[[~.DeleteScanConfigRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_scan_config" not in self._stubs: + self._stubs["delete_scan_config"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/DeleteScanConfig", + request_serializer=web_security_scanner.DeleteScanConfigRequest.serialize, + response_deserializer=empty.Empty.FromString, + ) + return self._stubs["delete_scan_config"] + + @property + def get_scan_config( + self, + ) -> Callable[ + [web_security_scanner.GetScanConfigRequest], Awaitable[scan_config.ScanConfig] + ]: + r"""Return a callable for the get scan config method over gRPC. + + Gets a ScanConfig. + + Returns: + Callable[[~.GetScanConfigRequest], + Awaitable[~.ScanConfig]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_scan_config" not in self._stubs: + self._stubs["get_scan_config"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/GetScanConfig", + request_serializer=web_security_scanner.GetScanConfigRequest.serialize, + response_deserializer=scan_config.ScanConfig.deserialize, + ) + return self._stubs["get_scan_config"] + + @property + def list_scan_configs( + self, + ) -> Callable[ + [web_security_scanner.ListScanConfigsRequest], + Awaitable[web_security_scanner.ListScanConfigsResponse], + ]: + r"""Return a callable for the list scan configs method over gRPC. + + Lists ScanConfigs under a given project. + + Returns: + Callable[[~.ListScanConfigsRequest], + Awaitable[~.ListScanConfigsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_scan_configs" not in self._stubs: + self._stubs["list_scan_configs"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListScanConfigs", + request_serializer=web_security_scanner.ListScanConfigsRequest.serialize, + response_deserializer=web_security_scanner.ListScanConfigsResponse.deserialize, + ) + return self._stubs["list_scan_configs"] + + @property + def update_scan_config( + self, + ) -> Callable[ + [web_security_scanner.UpdateScanConfigRequest], + Awaitable[scan_config.ScanConfig], + ]: + r"""Return a callable for the update scan config method over gRPC. + + Updates a ScanConfig. This method support partial + update of a ScanConfig. + + Returns: + Callable[[~.UpdateScanConfigRequest], + Awaitable[~.ScanConfig]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_scan_config" not in self._stubs: + self._stubs["update_scan_config"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/UpdateScanConfig", + request_serializer=web_security_scanner.UpdateScanConfigRequest.serialize, + response_deserializer=scan_config.ScanConfig.deserialize, + ) + return self._stubs["update_scan_config"] + + @property + def start_scan_run( + self, + ) -> Callable[ + [web_security_scanner.StartScanRunRequest], Awaitable[scan_run.ScanRun] + ]: + r"""Return a callable for the start scan run method over gRPC. + + Start a ScanRun according to the given ScanConfig. + + Returns: + Callable[[~.StartScanRunRequest], + Awaitable[~.ScanRun]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "start_scan_run" not in self._stubs: + self._stubs["start_scan_run"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/StartScanRun", + request_serializer=web_security_scanner.StartScanRunRequest.serialize, + response_deserializer=scan_run.ScanRun.deserialize, + ) + return self._stubs["start_scan_run"] + + @property + def get_scan_run( + self, + ) -> Callable[ + [web_security_scanner.GetScanRunRequest], Awaitable[scan_run.ScanRun] + ]: + r"""Return a callable for the get scan run method over gRPC. + + Gets a ScanRun. + + Returns: + Callable[[~.GetScanRunRequest], + Awaitable[~.ScanRun]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_scan_run" not in self._stubs: + self._stubs["get_scan_run"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/GetScanRun", + request_serializer=web_security_scanner.GetScanRunRequest.serialize, + response_deserializer=scan_run.ScanRun.deserialize, + ) + return self._stubs["get_scan_run"] + + @property + def list_scan_runs( + self, + ) -> Callable[ + [web_security_scanner.ListScanRunsRequest], + Awaitable[web_security_scanner.ListScanRunsResponse], + ]: + r"""Return a callable for the list scan runs method over gRPC. + + Lists ScanRuns under a given ScanConfig, in + descending order of ScanRun stop time. + + Returns: + Callable[[~.ListScanRunsRequest], + Awaitable[~.ListScanRunsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_scan_runs" not in self._stubs: + self._stubs["list_scan_runs"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListScanRuns", + request_serializer=web_security_scanner.ListScanRunsRequest.serialize, + response_deserializer=web_security_scanner.ListScanRunsResponse.deserialize, + ) + return self._stubs["list_scan_runs"] + + @property + def stop_scan_run( + self, + ) -> Callable[ + [web_security_scanner.StopScanRunRequest], Awaitable[scan_run.ScanRun] + ]: + r"""Return a callable for the stop scan run method over gRPC. + + Stops a ScanRun. The stopped ScanRun is returned. + + Returns: + Callable[[~.StopScanRunRequest], + Awaitable[~.ScanRun]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "stop_scan_run" not in self._stubs: + self._stubs["stop_scan_run"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/StopScanRun", + request_serializer=web_security_scanner.StopScanRunRequest.serialize, + response_deserializer=scan_run.ScanRun.deserialize, + ) + return self._stubs["stop_scan_run"] + + @property + def list_crawled_urls( + self, + ) -> Callable[ + [web_security_scanner.ListCrawledUrlsRequest], + Awaitable[web_security_scanner.ListCrawledUrlsResponse], + ]: + r"""Return a callable for the list crawled urls method over gRPC. + + List CrawledUrls under a given ScanRun. + + Returns: + Callable[[~.ListCrawledUrlsRequest], + Awaitable[~.ListCrawledUrlsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_crawled_urls" not in self._stubs: + self._stubs["list_crawled_urls"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListCrawledUrls", + request_serializer=web_security_scanner.ListCrawledUrlsRequest.serialize, + response_deserializer=web_security_scanner.ListCrawledUrlsResponse.deserialize, + ) + return self._stubs["list_crawled_urls"] + + @property + def get_finding( + self, + ) -> Callable[[web_security_scanner.GetFindingRequest], Awaitable[finding.Finding]]: + r"""Return a callable for the get finding method over gRPC. + + Gets a Finding. + + Returns: + Callable[[~.GetFindingRequest], + Awaitable[~.Finding]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_finding" not in self._stubs: + self._stubs["get_finding"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/GetFinding", + request_serializer=web_security_scanner.GetFindingRequest.serialize, + response_deserializer=finding.Finding.deserialize, + ) + return self._stubs["get_finding"] + + @property + def list_findings( + self, + ) -> Callable[ + [web_security_scanner.ListFindingsRequest], + Awaitable[web_security_scanner.ListFindingsResponse], + ]: + r"""Return a callable for the list findings method over gRPC. + + List Findings under a given ScanRun. + + Returns: + Callable[[~.ListFindingsRequest], + Awaitable[~.ListFindingsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_findings" not in self._stubs: + self._stubs["list_findings"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListFindings", + request_serializer=web_security_scanner.ListFindingsRequest.serialize, + response_deserializer=web_security_scanner.ListFindingsResponse.deserialize, + ) + return self._stubs["list_findings"] + + @property + def list_finding_type_stats( + self, + ) -> Callable[ + [web_security_scanner.ListFindingTypeStatsRequest], + Awaitable[web_security_scanner.ListFindingTypeStatsResponse], + ]: + r"""Return a callable for the list finding type stats method over gRPC. + + List all FindingTypeStats under a given ScanRun. + + Returns: + Callable[[~.ListFindingTypeStatsRequest], + Awaitable[~.ListFindingTypeStatsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_finding_type_stats" not in self._stubs: + self._stubs["list_finding_type_stats"] = self.grpc_channel.unary_unary( + "/google.cloud.websecurityscanner.v1.WebSecurityScanner/ListFindingTypeStats", + request_serializer=web_security_scanner.ListFindingTypeStatsRequest.serialize, + response_deserializer=web_security_scanner.ListFindingTypeStatsResponse.deserialize, + ) + return self._stubs["list_finding_type_stats"] + + +__all__ = ("WebSecurityScannerGrpcAsyncIOTransport",) diff --git a/google/cloud/websecurityscanner_v1/types/__init__.py b/google/cloud/websecurityscanner_v1/types/__init__.py new file mode 100644 index 0000000..d1f7fe5 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/__init__.py @@ -0,0 +1,88 @@ +# -*- 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. +# + +from .crawled_url import CrawledUrl +from .finding import Finding +from .finding_addon import ( + Form, + OutdatedLibrary, + ViolatingResource, + VulnerableHeaders, + VulnerableParameters, + Xss, +) +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 .web_security_scanner import ( + CreateScanConfigRequest, + DeleteScanConfigRequest, + GetFindingRequest, + GetScanConfigRequest, + GetScanRunRequest, + ListCrawledUrlsRequest, + ListCrawledUrlsResponse, + ListFindingsRequest, + ListFindingsResponse, + ListFindingTypeStatsRequest, + ListFindingTypeStatsResponse, + ListScanConfigsRequest, + ListScanConfigsResponse, + ListScanRunsRequest, + ListScanRunsResponse, + StartScanRunRequest, + StopScanRunRequest, + UpdateScanConfigRequest, +) + +__all__ = ( + "CrawledUrl", + "Finding", + "Form", + "OutdatedLibrary", + "ViolatingResource", + "VulnerableHeaders", + "VulnerableParameters", + "Xss", + "FindingTypeStats", + "ScanConfig", + "ScanConfigError", + "ScanRun", + "ScanRunErrorTrace", + "ScanRunWarningTrace", + "CreateScanConfigRequest", + "DeleteScanConfigRequest", + "GetFindingRequest", + "GetScanConfigRequest", + "GetScanRunRequest", + "ListCrawledUrlsRequest", + "ListCrawledUrlsResponse", + "ListFindingsRequest", + "ListFindingsResponse", + "ListFindingTypeStatsRequest", + "ListFindingTypeStatsResponse", + "ListScanConfigsRequest", + "ListScanConfigsResponse", + "ListScanRunsRequest", + "ListScanRunsResponse", + "StartScanRunRequest", + "StopScanRunRequest", + "UpdateScanConfigRequest", +) diff --git a/google/cloud/websecurityscanner_v1/types/crawled_url.py b/google/cloud/websecurityscanner_v1/types/crawled_url.py new file mode 100644 index 0000000..d66c7e8 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/crawled_url.py @@ -0,0 +1,50 @@ +# -*- 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. +# + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", manifest={"CrawledUrl",}, +) + + +class CrawledUrl(proto.Message): + r"""A CrawledUrl resource represents a URL that was crawled + during a ScanRun. Web Security Scanner Service crawls the web + applications, following all links within the scope of sites, to + find the URLs to test against. + + Attributes: + http_method (str): + Output only. The http method of the request + that was used to visit the URL, in uppercase. + url (str): + Output only. The URL that was crawled. + body (str): + Output only. The body of the request that was + used to visit the URL. + """ + + http_method = proto.Field(proto.STRING, number=1) + + url = proto.Field(proto.STRING, number=2) + + body = proto.Field(proto.STRING, number=3) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/finding.py b/google/cloud/websecurityscanner_v1/types/finding.py new file mode 100644 index 0000000..e11e57d --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/finding.py @@ -0,0 +1,152 @@ +# -*- 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. +# + +import proto # type: ignore + + +from google.cloud.websecurityscanner_v1.types import finding_addon + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", manifest={"Finding",}, +) + + +class Finding(proto.Message): + r"""A Finding resource represents a vulnerability instance + identified during a ScanRun. + + Attributes: + name (str): + Output only. The resource name of the + Finding. The name follows the format of + 'projects/{projectId}/scanConfigs/{scanConfigId}/scanruns/{scanRunId}/findings/{findingId}'. + The finding IDs are generated by the system. + finding_type (str): + Output only. The type of the Finding. + Detailed and up-to-date information on findings + can be found here: + https://cloud.google.com/security-command- + center/docs/how-to-remediate-web-security- + scanner-findings + severity (google.cloud.websecurityscanner_v1.types.Finding.Severity): + Output only. The severity level of the + reported vulnerability. + http_method (str): + Output only. The http method of the request + that triggered the vulnerability, in uppercase. + fuzzed_url (str): + Output only. The URL produced by the server- + ide fuzzer and used in the request that + triggered the vulnerability. + body (str): + Output only. The body of the request that + triggered the vulnerability. + description (str): + Output only. The description of the + vulnerability. + reproduction_url (str): + Output only. The URL containing human- + eadable payload that user can leverage to + reproduce the vulnerability. + frame_url (str): + Output only. If the vulnerability was + originated from nested IFrame, the immediate + parent IFrame is reported. + final_url (str): + Output only. The URL where the browser lands + when the vulnerability is detected. + tracking_id (str): + Output only. The tracking ID uniquely + identifies a vulnerability instance across + multiple ScanRuns. + form (google.cloud.websecurityscanner_v1.types.Form): + Output only. An addon containing information + reported for a vulnerability with an HTML form, + if any. + outdated_library (google.cloud.websecurityscanner_v1.types.OutdatedLibrary): + Output only. An addon containing information + about outdated libraries. + violating_resource (google.cloud.websecurityscanner_v1.types.ViolatingResource): + Output only. An addon containing detailed + information regarding any resource causing the + vulnerability such as JavaScript sources, image, + audio files, etc. + vulnerable_headers (google.cloud.websecurityscanner_v1.types.VulnerableHeaders): + Output only. An addon containing information + about vulnerable or missing HTTP headers. + vulnerable_parameters (google.cloud.websecurityscanner_v1.types.VulnerableParameters): + Output only. An addon containing information + about request parameters which were found to be + vulnerable. + xss (google.cloud.websecurityscanner_v1.types.Xss): + Output only. An addon containing information + reported for an XSS, if any. + """ + + class Severity(proto.Enum): + r"""The severity level of a vulnerability.""" + SEVERITY_UNSPECIFIED = 0 + CRITICAL = 1 + HIGH = 2 + MEDIUM = 3 + LOW = 4 + + name = proto.Field(proto.STRING, number=1) + + finding_type = proto.Field(proto.STRING, number=2) + + severity = proto.Field(proto.ENUM, number=17, enum=Severity,) + + http_method = proto.Field(proto.STRING, number=3) + + fuzzed_url = proto.Field(proto.STRING, number=4) + + body = proto.Field(proto.STRING, number=5) + + description = proto.Field(proto.STRING, number=6) + + reproduction_url = proto.Field(proto.STRING, number=7) + + frame_url = proto.Field(proto.STRING, number=8) + + final_url = proto.Field(proto.STRING, number=9) + + tracking_id = proto.Field(proto.STRING, number=10) + + form = proto.Field(proto.MESSAGE, number=16, message=finding_addon.Form,) + + outdated_library = proto.Field( + proto.MESSAGE, number=11, message=finding_addon.OutdatedLibrary, + ) + + violating_resource = proto.Field( + proto.MESSAGE, number=12, message=finding_addon.ViolatingResource, + ) + + vulnerable_headers = proto.Field( + proto.MESSAGE, number=15, message=finding_addon.VulnerableHeaders, + ) + + vulnerable_parameters = proto.Field( + proto.MESSAGE, number=13, message=finding_addon.VulnerableParameters, + ) + + xss = proto.Field(proto.MESSAGE, number=14, message=finding_addon.Xss,) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/finding_addon.py b/google/cloud/websecurityscanner_v1/types/finding_addon.py new file mode 100644 index 0000000..a743d39 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/finding_addon.py @@ -0,0 +1,173 @@ +# -*- 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. +# + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", + manifest={ + "Form", + "OutdatedLibrary", + "ViolatingResource", + "VulnerableParameters", + "VulnerableHeaders", + "Xss", + }, +) + + +class Form(proto.Message): + r"""! Information about a vulnerability with an HTML. + + Attributes: + action_uri (str): + ! The URI where to send the form when it's + submitted. + fields (Sequence[str]): + ! The names of form fields related to the + vulnerability. + """ + + action_uri = proto.Field(proto.STRING, number=1) + + fields = proto.RepeatedField(proto.STRING, number=2) + + +class OutdatedLibrary(proto.Message): + r"""Information reported for an outdated library. + + Attributes: + library_name (str): + The name of the outdated library. + version (str): + The version number. + learn_more_urls (Sequence[str]): + URLs to learn more information about the + vulnerabilities in the library. + """ + + library_name = proto.Field(proto.STRING, number=1) + + version = proto.Field(proto.STRING, number=2) + + learn_more_urls = proto.RepeatedField(proto.STRING, number=3) + + +class ViolatingResource(proto.Message): + r"""Information regarding any resource causing the vulnerability + such as JavaScript sources, image, audio files, etc. + + Attributes: + content_type (str): + The MIME type of this resource. + resource_url (str): + URL of this violating resource. + """ + + content_type = proto.Field(proto.STRING, number=1) + + resource_url = proto.Field(proto.STRING, number=2) + + +class VulnerableParameters(proto.Message): + r"""Information about vulnerable request parameters. + + Attributes: + parameter_names (Sequence[str]): + The vulnerable parameter names. + """ + + parameter_names = proto.RepeatedField(proto.STRING, number=1) + + +class VulnerableHeaders(proto.Message): + r"""Information about vulnerable or missing HTTP Headers. + + Attributes: + headers (Sequence[google.cloud.websecurityscanner_v1.types.VulnerableHeaders.Header]): + List of vulnerable headers. + missing_headers (Sequence[google.cloud.websecurityscanner_v1.types.VulnerableHeaders.Header]): + List of missing headers. + """ + + class Header(proto.Message): + r"""Describes a HTTP Header. + + Attributes: + name (str): + Header name. + value (str): + Header value. + """ + + name = proto.Field(proto.STRING, number=1) + + value = proto.Field(proto.STRING, number=2) + + headers = proto.RepeatedField(proto.MESSAGE, number=1, message=Header,) + + missing_headers = proto.RepeatedField(proto.MESSAGE, number=2, message=Header,) + + +class Xss(proto.Message): + r"""Information reported for an XSS. + + Attributes: + stack_traces (Sequence[str]): + Stack traces leading to the point where the + XSS occurred. + error_message (str): + An error message generated by a javascript + breakage. + attack_vector (google.cloud.websecurityscanner_v1.types.Xss.AttackVector): + The attack vector of the payload triggering + this XSS. + stored_xss_seeding_url (str): + The reproduction url for the seeding POST + request of a Stored XSS. + """ + + class AttackVector(proto.Enum): + r"""Types of XSS attack vector.""" + ATTACK_VECTOR_UNSPECIFIED = 0 + LOCAL_STORAGE = 1 + SESSION_STORAGE = 2 + WINDOW_NAME = 3 + REFERRER = 4 + FORM_INPUT = 5 + COOKIE = 6 + POST_MESSAGE = 7 + GET_PARAMETERS = 8 + URL_FRAGMENT = 9 + HTML_COMMENT = 10 + POST_PARAMETERS = 11 + PROTOCOL = 12 + STORED_XSS = 13 + SAME_ORIGIN = 14 + USER_CONTROLLABLE_URL = 15 + + stack_traces = proto.RepeatedField(proto.STRING, number=1) + + error_message = proto.Field(proto.STRING, number=2) + + attack_vector = proto.Field(proto.ENUM, number=3, enum=AttackVector,) + + stored_xss_seeding_url = proto.Field(proto.STRING, number=4) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/finding_type_stats.py b/google/cloud/websecurityscanner_v1/types/finding_type_stats.py new file mode 100644 index 0000000..5f69387 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/finding_type_stats.py @@ -0,0 +1,44 @@ +# -*- 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. +# + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", manifest={"FindingTypeStats",}, +) + + +class FindingTypeStats(proto.Message): + r"""A FindingTypeStats resource represents stats regarding a + specific FindingType of Findings under a given ScanRun. + + Attributes: + finding_type (str): + Output only. The finding type associated with + the stats. + finding_count (int): + Output only. The count of findings belonging + to this finding type. + """ + + finding_type = proto.Field(proto.STRING, number=1) + + finding_count = proto.Field(proto.INT32, number=2) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/scan_config.py b/google/cloud/websecurityscanner_v1/types/scan_config.py new file mode 100644 index 0000000..05286f0 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/scan_config.py @@ -0,0 +1,257 @@ +# -*- 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. +# + +import proto # type: ignore + + +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", manifest={"ScanConfig",}, +) + + +class ScanConfig(proto.Message): + r"""A ScanConfig resource contains the configurations to launch a + scan. + + Attributes: + name (str): + The resource name of the ScanConfig. The name + follows the format of + 'projects/{projectId}/scanConfigs/{scanConfigId}'. + The ScanConfig IDs are generated by the system. + display_name (str): + Required. The user provided display name of + the ScanConfig. + max_qps (int): + The maximum QPS during scanning. A valid value ranges from 5 + to 20 inclusively. If the field is unspecified or its value + is set 0, server will default to 15. Other values outside of + [5, 20] range will be rejected with INVALID_ARGUMENT error. + starting_urls (Sequence[str]): + Required. The starting URLs from which the + scanner finds site pages. + authentication (google.cloud.websecurityscanner_v1.types.ScanConfig.Authentication): + The authentication configuration. If + specified, service will use the authentication + configuration during scanning. + user_agent (google.cloud.websecurityscanner_v1.types.ScanConfig.UserAgent): + The user agent used during scanning. + blacklist_patterns (Sequence[str]): + The excluded URL patterns as described in + https://cloud.google.com/security-command-center/docs/how-to-use-web-security-scanner#excluding_urls + schedule (google.cloud.websecurityscanner_v1.types.ScanConfig.Schedule): + The schedule of the ScanConfig. + export_to_security_command_center (google.cloud.websecurityscanner_v1.types.ScanConfig.ExportToSecurityCommandCenter): + Controls export of scan configurations and + results to Security Command Center. + risk_level (google.cloud.websecurityscanner_v1.types.ScanConfig.RiskLevel): + The risk level selected for the scan + managed_scan (bool): + Whether the scan config is managed by Web + Security Scanner, output only. + static_ip_scan (bool): + Whether the scan configuration has enabled + static IP address scan feature. If enabled, the + scanner will access applications from static IP + addresses. + """ + + class UserAgent(proto.Enum): + r"""Type of user agents used for scanning.""" + USER_AGENT_UNSPECIFIED = 0 + CHROME_LINUX = 1 + CHROME_ANDROID = 2 + SAFARI_IPHONE = 3 + + class RiskLevel(proto.Enum): + r"""Scan risk levels supported by Web Security Scanner. LOW + impact scanning will minimize requests with the potential to + modify data. To achieve the maximum scan coverage, NORMAL risk + level is recommended. + """ + RISK_LEVEL_UNSPECIFIED = 0 + NORMAL = 1 + LOW = 2 + + class ExportToSecurityCommandCenter(proto.Enum): + r"""Controls export of scan configurations and results to + Security Command Center. + """ + EXPORT_TO_SECURITY_COMMAND_CENTER_UNSPECIFIED = 0 + ENABLED = 1 + DISABLED = 2 + + class Authentication(proto.Message): + r"""Scan authentication configuration. + + Attributes: + google_account (google.cloud.websecurityscanner_v1.types.ScanConfig.Authentication.GoogleAccount): + Authentication using a Google account. + custom_account (google.cloud.websecurityscanner_v1.types.ScanConfig.Authentication.CustomAccount): + Authentication using a custom account. + iap_credential (google.cloud.websecurityscanner_v1.types.ScanConfig.Authentication.IapCredential): + Authentication using Identity-Aware-Proxy + (IAP). + """ + + class GoogleAccount(proto.Message): + r"""Describes authentication configuration that uses a Google + account. + + Attributes: + username (str): + Required. The user name of the Google + account. + password (str): + Required. Input only. The password of the + Google account. The credential is stored + encrypted and not returned in any response nor + included in audit logs. + """ + + username = proto.Field(proto.STRING, number=1) + + password = proto.Field(proto.STRING, number=2) + + class CustomAccount(proto.Message): + r"""Describes authentication configuration that uses a custom + account. + + Attributes: + username (str): + Required. The user name of the custom + account. + password (str): + Required. Input only. The password of the + custom account. The credential is stored + encrypted and not returned in any response nor + included in audit logs. + login_url (str): + Required. The login form URL of the website. + """ + + username = proto.Field(proto.STRING, number=1) + + password = proto.Field(proto.STRING, number=2) + + login_url = proto.Field(proto.STRING, number=3) + + class IapCredential(proto.Message): + r"""Describes authentication configuration for Identity-Aware- + roxy (IAP). + + Attributes: + iap_test_service_account_info (google.cloud.websecurityscanner_v1.types.ScanConfig.Authentication.IapCredential.IapTestServiceAccountInfo): + Authentication configuration when Web- + ecurity-Scanner service account is added in + Identity-Aware-Proxy (IAP) access policies. + """ + + class IapTestServiceAccountInfo(proto.Message): + r"""Describes authentication configuration when Web-Security- + canner service account is added in Identity-Aware-Proxy (IAP) + access policies. + + Attributes: + target_audience_client_id (str): + Required. Describes OAuth2 client id of + resources protected by Identity-Aware-Proxy + (IAP). + """ + + target_audience_client_id = proto.Field(proto.STRING, number=1) + + iap_test_service_account_info = proto.Field( + proto.MESSAGE, + number=1, + oneof="iap_credentials", + message="ScanConfig.Authentication.IapCredential.IapTestServiceAccountInfo", + ) + + google_account = proto.Field( + proto.MESSAGE, + number=1, + oneof="authentication", + message="ScanConfig.Authentication.GoogleAccount", + ) + + custom_account = proto.Field( + proto.MESSAGE, + number=2, + oneof="authentication", + message="ScanConfig.Authentication.CustomAccount", + ) + + iap_credential = proto.Field( + proto.MESSAGE, + number=4, + oneof="authentication", + message="ScanConfig.Authentication.IapCredential", + ) + + class Schedule(proto.Message): + r"""Scan schedule configuration. + + Attributes: + 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 + default to current server time, which means the + scan will be scheduled to start immediately. + interval_duration_days (int): + Required. The duration of time between + executions in days. + """ + + schedule_time = proto.Field( + proto.MESSAGE, number=1, message=timestamp.Timestamp, + ) + + interval_duration_days = proto.Field(proto.INT32, number=2) + + name = proto.Field(proto.STRING, number=1) + + display_name = proto.Field(proto.STRING, number=2) + + max_qps = proto.Field(proto.INT32, number=3) + + starting_urls = proto.RepeatedField(proto.STRING, number=4) + + authentication = proto.Field(proto.MESSAGE, number=5, message=Authentication,) + + user_agent = proto.Field(proto.ENUM, number=6, enum=UserAgent,) + + blacklist_patterns = proto.RepeatedField(proto.STRING, number=7) + + schedule = proto.Field(proto.MESSAGE, number=8, message=Schedule,) + + export_to_security_command_center = proto.Field( + proto.ENUM, number=10, enum=ExportToSecurityCommandCenter, + ) + + risk_level = proto.Field(proto.ENUM, number=12, enum=RiskLevel,) + + managed_scan = proto.Field(proto.BOOL, number=13) + + static_ip_scan = proto.Field(proto.BOOL, number=14) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/scan_config_error.py b/google/cloud/websecurityscanner_v1/types/scan_config_error.py new file mode 100644 index 0000000..10237a0 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/scan_config_error.py @@ -0,0 +1,97 @@ +# -*- 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. +# + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", manifest={"ScanConfigError",}, +) + + +class ScanConfigError(proto.Message): + r"""Defines a custom error message used by CreateScanConfig and + UpdateScanConfig APIs when scan configuration validation fails. + It is also reported as part of a ScanRunErrorTrace message if + scan validation fails due to a scan configuration error. + + Attributes: + code (google.cloud.websecurityscanner_v1.types.ScanConfigError.Code): + Output only. Indicates the reason code for a + configuration failure. + field_name (str): + Output only. Indicates the full name of the ScanConfig field + that triggers this error, for example "scan_config.max_qps". + This field is provided for troubleshooting purposes only and + its actual value can change in the future. + """ + + class Code(proto.Enum): + r"""Output only. + Defines an error reason code. + Next id: 44 + """ + _pb_options = {"allow_alias": True} + CODE_UNSPECIFIED = 0 + OK = 0 + INTERNAL_ERROR = 1 + APPENGINE_API_BACKEND_ERROR = 2 + APPENGINE_API_NOT_ACCESSIBLE = 3 + APPENGINE_DEFAULT_HOST_MISSING = 4 + CANNOT_USE_GOOGLE_COM_ACCOUNT = 6 + CANNOT_USE_OWNER_ACCOUNT = 7 + COMPUTE_API_BACKEND_ERROR = 8 + COMPUTE_API_NOT_ACCESSIBLE = 9 + CUSTOM_LOGIN_URL_DOES_NOT_BELONG_TO_CURRENT_PROJECT = 10 + CUSTOM_LOGIN_URL_MALFORMED = 11 + CUSTOM_LOGIN_URL_MAPPED_TO_NON_ROUTABLE_ADDRESS = 12 + CUSTOM_LOGIN_URL_MAPPED_TO_UNRESERVED_ADDRESS = 13 + CUSTOM_LOGIN_URL_HAS_NON_ROUTABLE_IP_ADDRESS = 14 + CUSTOM_LOGIN_URL_HAS_UNRESERVED_IP_ADDRESS = 15 + DUPLICATE_SCAN_NAME = 16 + INVALID_FIELD_VALUE = 18 + FAILED_TO_AUTHENTICATE_TO_TARGET = 19 + FINDING_TYPE_UNSPECIFIED = 20 + FORBIDDEN_TO_SCAN_COMPUTE = 21 + FORBIDDEN_UPDATE_TO_MANAGED_SCAN = 43 + MALFORMED_FILTER = 22 + MALFORMED_RESOURCE_NAME = 23 + PROJECT_INACTIVE = 24 + REQUIRED_FIELD = 25 + RESOURCE_NAME_INCONSISTENT = 26 + SCAN_ALREADY_RUNNING = 27 + SCAN_NOT_RUNNING = 28 + SEED_URL_DOES_NOT_BELONG_TO_CURRENT_PROJECT = 29 + SEED_URL_MALFORMED = 30 + SEED_URL_MAPPED_TO_NON_ROUTABLE_ADDRESS = 31 + SEED_URL_MAPPED_TO_UNRESERVED_ADDRESS = 32 + SEED_URL_HAS_NON_ROUTABLE_IP_ADDRESS = 33 + SEED_URL_HAS_UNRESERVED_IP_ADDRESS = 35 + SERVICE_ACCOUNT_NOT_CONFIGURED = 36 + TOO_MANY_SCANS = 37 + UNABLE_TO_RESOLVE_PROJECT_INFO = 38 + UNSUPPORTED_BLACKLIST_PATTERN_FORMAT = 39 + UNSUPPORTED_FILTER = 40 + UNSUPPORTED_FINDING_TYPE = 41 + UNSUPPORTED_URL_SCHEME = 42 + + code = proto.Field(proto.ENUM, number=1, enum=Code,) + + field_name = proto.Field(proto.STRING, number=2) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/scan_run.py b/google/cloud/websecurityscanner_v1/types/scan_run.py new file mode 100644 index 0000000..0328dc6 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/scan_run.py @@ -0,0 +1,127 @@ +# -*- 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. +# + +import proto # type: ignore + + +from google.cloud.websecurityscanner_v1.types import scan_run_error_trace +from google.cloud.websecurityscanner_v1.types import scan_run_warning_trace +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", manifest={"ScanRun",}, +) + + +class ScanRun(proto.Message): + r"""A ScanRun is a output-only resource representing an actual + run of the scan. Next id: 12 + + Attributes: + name (str): + Output only. The resource name of the + ScanRun. The name follows the format of + 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + The ScanRun IDs are generated by the system. + execution_state (google.cloud.websecurityscanner_v1.types.ScanRun.ExecutionState): + Output only. The execution state of the + ScanRun. + result_state (google.cloud.websecurityscanner_v1.types.ScanRun.ResultState): + Output only. The result state of the ScanRun. + This field is only available after the execution + state reaches "FINISHED". + start_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The time at which the ScanRun + started. + end_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The time at which the ScanRun + reached termination state - that the ScanRun is + either finished or stopped by user. + urls_crawled_count (int): + Output only. The number of URLs crawled + during this ScanRun. If the scan is in progress, + the value represents the number of URLs crawled + up to now. + urls_tested_count (int): + Output only. The number of URLs tested during + this ScanRun. If the scan is in progress, the + value represents the number of URLs tested up to + now. The number of URLs tested is usually larger + than the number URLS crawled because typically a + crawled URL is tested with multiple test + payloads. + has_vulnerabilities (bool): + Output only. Whether the scan run has found + any vulnerabilities. + progress_percent (int): + Output only. The percentage of total + completion ranging from 0 to 100. If the scan is + in queue, the 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 (google.cloud.websecurityscanner_v1.types.ScanRunErrorTrace): + Output only. 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[google.cloud.websecurityscanner_v1.types.ScanRunWarningTrace]): + Output only. A list of warnings, if such are + encountered during this scan run. + """ + + class ExecutionState(proto.Enum): + r"""Types of ScanRun execution state.""" + EXECUTION_STATE_UNSPECIFIED = 0 + QUEUED = 1 + SCANNING = 2 + FINISHED = 3 + + class ResultState(proto.Enum): + r"""Types of ScanRun result state.""" + RESULT_STATE_UNSPECIFIED = 0 + SUCCESS = 1 + ERROR = 2 + KILLED = 3 + + name = proto.Field(proto.STRING, number=1) + + execution_state = proto.Field(proto.ENUM, number=2, enum=ExecutionState,) + + result_state = proto.Field(proto.ENUM, number=3, enum=ResultState,) + + start_time = proto.Field(proto.MESSAGE, number=4, message=timestamp.Timestamp,) + + end_time = proto.Field(proto.MESSAGE, number=5, message=timestamp.Timestamp,) + + urls_crawled_count = proto.Field(proto.INT64, number=6) + + urls_tested_count = proto.Field(proto.INT64, number=7) + + has_vulnerabilities = proto.Field(proto.BOOL, number=8) + + progress_percent = proto.Field(proto.INT32, number=9) + + error_trace = proto.Field( + proto.MESSAGE, number=10, message=scan_run_error_trace.ScanRunErrorTrace, + ) + + warning_traces = proto.RepeatedField( + proto.MESSAGE, number=11, message=scan_run_warning_trace.ScanRunWarningTrace, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/scan_run_error_trace.py b/google/cloud/websecurityscanner_v1/types/scan_run_error_trace.py new file mode 100644 index 0000000..3f22a86 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/scan_run_error_trace.py @@ -0,0 +1,72 @@ +# -*- 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. +# + +import proto # type: ignore + + +from google.cloud.websecurityscanner_v1.types import ( + scan_config_error as gcw_scan_config_error, +) + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", manifest={"ScanRunErrorTrace",}, +) + + +class ScanRunErrorTrace(proto.Message): + r"""Output only. + Defines an error trace message for a ScanRun. + + Attributes: + code (google.cloud.websecurityscanner_v1.types.ScanRunErrorTrace.Code): + Output only. Indicates the error reason code. + scan_config_error (google.cloud.websecurityscanner_v1.types.ScanConfigError): + Output only. 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. + most_common_http_error_code (int): + Output only. If the scan encounters TOO_MANY_HTTP_ERRORS, + this field indicates the most common HTTP error code, if + such is available. For example, if this code is 404, the + scan has encountered too many NOT_FOUND responses. + """ + + class Code(proto.Enum): + r"""Output only. + Defines an error reason code. + Next id: 7 + """ + CODE_UNSPECIFIED = 0 + INTERNAL_ERROR = 1 + SCAN_CONFIG_ISSUE = 2 + AUTHENTICATION_CONFIG_ISSUE = 3 + TIMED_OUT_WHILE_SCANNING = 4 + TOO_MANY_REDIRECTS = 5 + TOO_MANY_HTTP_ERRORS = 6 + + code = proto.Field(proto.ENUM, number=1, enum=Code,) + + scan_config_error = proto.Field( + proto.MESSAGE, number=2, message=gcw_scan_config_error.ScanConfigError, + ) + + most_common_http_error_code = proto.Field(proto.INT32, number=3) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/scan_run_warning_trace.py b/google/cloud/websecurityscanner_v1/types/scan_run_warning_trace.py new file mode 100644 index 0000000..0c95acf --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/scan_run_warning_trace.py @@ -0,0 +1,51 @@ +# -*- 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. +# + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", manifest={"ScanRunWarningTrace",}, +) + + +class ScanRunWarningTrace(proto.Message): + r"""Output only. + Defines a warning trace message for ScanRun. Warning traces + provide customers with useful information that helps make the + scanning process more effective. + + Attributes: + code (google.cloud.websecurityscanner_v1.types.ScanRunWarningTrace.Code): + Output only. Indicates the warning code. + """ + + class Code(proto.Enum): + r"""Output only. + Defines a warning message code. + Next id: 6 + """ + CODE_UNSPECIFIED = 0 + INSUFFICIENT_CRAWL_RESULTS = 1 + TOO_MANY_CRAWL_RESULTS = 2 + TOO_MANY_FUZZ_TASKS = 3 + BLOCKED_BY_IAP = 4 + + code = proto.Field(proto.ENUM, number=1, enum=Code,) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/websecurityscanner_v1/types/web_security_scanner.py b/google/cloud/websecurityscanner_v1/types/web_security_scanner.py new file mode 100644 index 0000000..c783f42 --- /dev/null +++ b/google/cloud/websecurityscanner_v1/types/web_security_scanner.py @@ -0,0 +1,403 @@ +# -*- 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. +# + +import proto # type: ignore + + +from google.cloud.websecurityscanner_v1.types import crawled_url +from google.cloud.websecurityscanner_v1.types import finding +from google.cloud.websecurityscanner_v1.types import ( + finding_type_stats as gcw_finding_type_stats, +) +from google.cloud.websecurityscanner_v1.types import scan_config as gcw_scan_config +from google.cloud.websecurityscanner_v1.types import scan_run +from google.protobuf import field_mask_pb2 as field_mask # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.websecurityscanner.v1", + manifest={ + "CreateScanConfigRequest", + "DeleteScanConfigRequest", + "GetScanConfigRequest", + "ListScanConfigsRequest", + "UpdateScanConfigRequest", + "ListScanConfigsResponse", + "StartScanRunRequest", + "GetScanRunRequest", + "ListScanRunsRequest", + "ListScanRunsResponse", + "StopScanRunRequest", + "ListCrawledUrlsRequest", + "ListCrawledUrlsResponse", + "GetFindingRequest", + "ListFindingsRequest", + "ListFindingsResponse", + "ListFindingTypeStatsRequest", + "ListFindingTypeStatsResponse", + }, +) + + +class CreateScanConfigRequest(proto.Message): + r"""Request for the ``CreateScanConfig`` method. + + Attributes: + parent (str): + Required. The parent resource name where the + scan is created, which should be a project + resource name in the format + 'projects/{projectId}'. + scan_config (google.cloud.websecurityscanner_v1.types.ScanConfig): + Required. The ScanConfig to be created. + """ + + parent = proto.Field(proto.STRING, number=1) + + scan_config = proto.Field( + proto.MESSAGE, number=2, message=gcw_scan_config.ScanConfig, + ) + + +class DeleteScanConfigRequest(proto.Message): + r"""Request for the ``DeleteScanConfig`` method. + + Attributes: + name (str): + Required. The resource name of the ScanConfig + to be deleted. The name follows the format of + 'projects/{projectId}/scanConfigs/{scanConfigId}'. + """ + + name = proto.Field(proto.STRING, number=1) + + +class GetScanConfigRequest(proto.Message): + r"""Request for the ``GetScanConfig`` method. + + Attributes: + name (str): + Required. The resource name of the ScanConfig + to be returned. The name follows the format of + 'projects/{projectId}/scanConfigs/{scanConfigId}'. + """ + + name = proto.Field(proto.STRING, number=1) + + +class ListScanConfigsRequest(proto.Message): + r"""Request for the ``ListScanConfigs`` method. + + Attributes: + parent (str): + Required. The parent resource name, which + should be a project resource name in the format + 'projects/{projectId}'. + page_token (str): + A token identifying a page of results to be returned. This + should be a ``next_page_token`` value returned from a + previous List request. If unspecified, the first page of + results is returned. + page_size (int): + The maximum number of ScanConfigs to return, + can be limited by server. If not specified or + not positive, the implementation will select a + reasonable value. + """ + + parent = proto.Field(proto.STRING, number=1) + + page_token = proto.Field(proto.STRING, number=2) + + page_size = proto.Field(proto.INT32, number=3) + + +class UpdateScanConfigRequest(proto.Message): + r"""Request for the ``UpdateScanConfigRequest`` method. + + Attributes: + scan_config (google.cloud.websecurityscanner_v1.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 (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 + """ + + scan_config = proto.Field( + proto.MESSAGE, number=2, message=gcw_scan_config.ScanConfig, + ) + + update_mask = proto.Field(proto.MESSAGE, number=3, message=field_mask.FieldMask,) + + +class ListScanConfigsResponse(proto.Message): + r"""Response for the ``ListScanConfigs`` method. + + Attributes: + scan_configs (Sequence[google.cloud.websecurityscanner_v1.types.ScanConfig]): + The list of ScanConfigs returned. + next_page_token (str): + Token to retrieve the next page of results, + or empty if there are no more results in the + list. + """ + + @property + def raw_page(self): + return self + + scan_configs = proto.RepeatedField( + proto.MESSAGE, number=1, message=gcw_scan_config.ScanConfig, + ) + + next_page_token = proto.Field(proto.STRING, number=2) + + +class StartScanRunRequest(proto.Message): + r"""Request for the ``StartScanRun`` method. + + Attributes: + name (str): + Required. The resource name of the ScanConfig + to be used. The name follows the format of + 'projects/{projectId}/scanConfigs/{scanConfigId}'. + """ + + name = proto.Field(proto.STRING, number=1) + + +class GetScanRunRequest(proto.Message): + r"""Request for the ``GetScanRun`` method. + + Attributes: + name (str): + Required. The resource name of the ScanRun to + be returned. The name follows the format of + 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + """ + + name = proto.Field(proto.STRING, number=1) + + +class ListScanRunsRequest(proto.Message): + r"""Request for the ``ListScanRuns`` method. + + Attributes: + parent (str): + Required. The parent resource name, which + should be a scan resource name in the format + 'projects/{projectId}/scanConfigs/{scanConfigId}'. + page_token (str): + A token identifying a page of results to be returned. This + should be a ``next_page_token`` value returned from a + previous List request. If unspecified, the first page of + results is returned. + page_size (int): + The maximum number of ScanRuns to return, can + be limited by server. If not specified or not + positive, the implementation will select a + reasonable value. + """ + + parent = proto.Field(proto.STRING, number=1) + + page_token = proto.Field(proto.STRING, number=2) + + page_size = proto.Field(proto.INT32, number=3) + + +class ListScanRunsResponse(proto.Message): + r"""Response for the ``ListScanRuns`` method. + + Attributes: + scan_runs (Sequence[google.cloud.websecurityscanner_v1.types.ScanRun]): + The list of ScanRuns returned. + next_page_token (str): + Token to retrieve the next page of results, + or empty if there are no more results in the + list. + """ + + @property + def raw_page(self): + return self + + scan_runs = proto.RepeatedField(proto.MESSAGE, number=1, message=scan_run.ScanRun,) + + next_page_token = proto.Field(proto.STRING, number=2) + + +class StopScanRunRequest(proto.Message): + r"""Request for the ``StopScanRun`` method. + + Attributes: + name (str): + Required. The resource name of the ScanRun to + be stopped. The name follows the format of + 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + """ + + name = proto.Field(proto.STRING, number=1) + + +class ListCrawledUrlsRequest(proto.Message): + r"""Request for the ``ListCrawledUrls`` method. + + Attributes: + parent (str): + Required. The parent resource name, which + should be a scan run resource name in the format + 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + page_token (str): + A token identifying a page of results to be returned. This + should be a ``next_page_token`` value returned from a + previous List request. If unspecified, the first page of + results is returned. + page_size (int): + The maximum number of CrawledUrls to return, + can be limited by server. If not specified or + not positive, the implementation will select a + reasonable value. + """ + + parent = proto.Field(proto.STRING, number=1) + + page_token = proto.Field(proto.STRING, number=2) + + page_size = proto.Field(proto.INT32, number=3) + + +class ListCrawledUrlsResponse(proto.Message): + r"""Response for the ``ListCrawledUrls`` method. + + Attributes: + crawled_urls (Sequence[google.cloud.websecurityscanner_v1.types.CrawledUrl]): + The list of CrawledUrls returned. + next_page_token (str): + Token to retrieve the next page of results, + or empty if there are no more results in the + list. + """ + + @property + def raw_page(self): + return self + + crawled_urls = proto.RepeatedField( + proto.MESSAGE, number=1, message=crawled_url.CrawledUrl, + ) + + next_page_token = proto.Field(proto.STRING, number=2) + + +class GetFindingRequest(proto.Message): + r"""Request for the ``GetFinding`` method. + + Attributes: + 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}'. + """ + + name = proto.Field(proto.STRING, number=1) + + +class ListFindingsRequest(proto.Message): + r"""Request for the ``ListFindings`` method. + + Attributes: + parent (str): + Required. The parent resource name, which + should be a scan run resource name in the format + 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + filter (str): + The filter expression. The expression must be in the format: + . Supported field: 'finding_type'. Supported operator: '='. + page_token (str): + A token identifying a page of results to be returned. This + should be a ``next_page_token`` value returned from a + previous List request. If unspecified, the first page of + results is returned. + page_size (int): + The maximum number of Findings to return, can + be limited by server. If not specified or not + positive, the implementation will select a + reasonable value. + """ + + parent = proto.Field(proto.STRING, number=1) + + filter = proto.Field(proto.STRING, number=2) + + page_token = proto.Field(proto.STRING, number=3) + + page_size = proto.Field(proto.INT32, number=4) + + +class ListFindingsResponse(proto.Message): + r"""Response for the ``ListFindings`` method. + + Attributes: + findings (Sequence[google.cloud.websecurityscanner_v1.types.Finding]): + The list of Findings returned. + next_page_token (str): + Token to retrieve the next page of results, + or empty if there are no more results in the + list. + """ + + @property + def raw_page(self): + return self + + findings = proto.RepeatedField(proto.MESSAGE, number=1, message=finding.Finding,) + + next_page_token = proto.Field(proto.STRING, number=2) + + +class ListFindingTypeStatsRequest(proto.Message): + r"""Request for the ``ListFindingTypeStats`` method. + + Attributes: + parent (str): + Required. The parent resource name, which + should be a scan run resource name in the format + 'projects/{projectId}/scanConfigs/{scanConfigId}/scanRuns/{scanRunId}'. + """ + + parent = proto.Field(proto.STRING, number=1) + + +class ListFindingTypeStatsResponse(proto.Message): + r"""Response for the ``ListFindingTypeStats`` method. + + Attributes: + finding_type_stats (Sequence[google.cloud.websecurityscanner_v1.types.FindingTypeStats]): + The list of FindingTypeStats returned. + """ + + finding_type_stats = proto.RepeatedField( + proto.MESSAGE, number=1, message=gcw_finding_type_stats.FindingTypeStats, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/scripts/fixup_websecurityscanner_v1_keywords.py b/scripts/fixup_websecurityscanner_v1_keywords.py new file mode 100644 index 0000000..26129c3 --- /dev/null +++ b/scripts/fixup_websecurityscanner_v1_keywords.py @@ -0,0 +1,191 @@ +#! /usr/bin/env python3 +# -*- 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. +# + +import argparse +import os +import libcst as cst +import pathlib +import sys +from typing import (Any, Callable, Dict, List, Sequence, Tuple) + + +def partition( + predicate: Callable[[Any], bool], + iterator: Sequence[Any] +) -> Tuple[List[Any], List[Any]]: + """A stable, out-of-place partition.""" + results = ([], []) + + for i in iterator: + results[int(predicate(i))].append(i) + + # Returns trueList, falseList + return results[1], results[0] + + +class websecurityscannerCallTransformer(cst.CSTTransformer): + CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') + METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'create_scan_config': ('parent', 'scan_config', ), + 'delete_scan_config': ('name', ), + 'get_finding': ('name', ), + 'get_scan_config': ('name', ), + 'get_scan_run': ('name', ), + 'list_crawled_urls': ('parent', 'page_token', 'page_size', ), + 'list_findings': ('parent', 'filter', 'page_token', 'page_size', ), + 'list_finding_type_stats': ('parent', ), + 'list_scan_configs': ('parent', 'page_token', 'page_size', ), + 'list_scan_runs': ('parent', 'page_token', 'page_size', ), + 'start_scan_run': ('name', ), + 'stop_scan_run': ('name', ), + 'update_scan_config': ('scan_config', 'update_mask', ), + + } + + def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: + try: + key = original.func.attr.value + kword_params = self.METHOD_TO_PARAMS[key] + except (AttributeError, KeyError): + # Either not a method from the API or too convoluted to be sure. + return updated + + # If the existing code is valid, keyword args come after positional args. + # Therefore, all positional args must map to the first parameters. + args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) + if any(k.keyword.value == "request" for k in kwargs): + # We've already fixed this file, don't fix it again. + return updated + + kwargs, ctrl_kwargs = partition( + lambda a: not a.keyword.value in self.CTRL_PARAMS, + kwargs + ) + + args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] + ctrl_kwargs.extend(cst.Arg(value=a.value, keyword=cst.Name(value=ctrl)) + for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) + + request_arg = cst.Arg( + value=cst.Dict([ + cst.DictElement( + cst.SimpleString("'{}'".format(name)), + cst.Element(value=arg.value) + ) + # Note: the args + kwargs looks silly, but keep in mind that + # the control parameters had to be stripped out, and that + # those could have been passed positionally or by keyword. + for name, arg in zip(kword_params, args + kwargs)]), + keyword=cst.Name("request") + ) + + return updated.with_changes( + args=[request_arg] + ctrl_kwargs + ) + + +def fix_files( + in_dir: pathlib.Path, + out_dir: pathlib.Path, + *, + transformer=websecurityscannerCallTransformer(), +): + """Duplicate the input dir to the output dir, fixing file method calls. + + Preconditions: + * in_dir is a real directory + * out_dir is a real, empty directory + """ + pyfile_gen = ( + pathlib.Path(os.path.join(root, f)) + for root, _, files in os.walk(in_dir) + for f in files if os.path.splitext(f)[1] == ".py" + ) + + for fpath in pyfile_gen: + with open(fpath, 'r') as f: + src = f.read() + + # Parse the code and insert method call fixes. + tree = cst.parse_module(src) + updated = tree.visit(transformer) + + # Create the path and directory structure for the new file. + updated_path = out_dir.joinpath(fpath.relative_to(in_dir)) + updated_path.parent.mkdir(parents=True, exist_ok=True) + + # Generate the updated source file at the corresponding path. + with open(updated_path, 'w') as f: + f.write(updated.code) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="""Fix up source that uses the websecurityscanner client library. + +The existing sources are NOT overwritten but are copied to output_dir with changes made. + +Note: This tool operates at a best-effort level at converting positional + parameters in client method calls to keyword based parameters. + Cases where it WILL FAIL include + A) * or ** expansion in a method call. + B) Calls via function or method alias (includes free function calls) + C) Indirect or dispatched calls (e.g. the method is looked up dynamically) + + These all constitute false negatives. The tool will also detect false + positives when an API method shares a name with another method. +""") + parser.add_argument( + '-d', + '--input-directory', + required=True, + dest='input_dir', + help='the input directory to walk for python files to fix up', + ) + parser.add_argument( + '-o', + '--output-directory', + required=True, + dest='output_dir', + help='the directory to output files fixed via un-flattening', + ) + args = parser.parse_args() + input_dir = pathlib.Path(args.input_dir) + output_dir = pathlib.Path(args.output_dir) + if not input_dir.is_dir(): + print( + f"input directory '{input_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if not output_dir.is_dir(): + print( + f"output directory '{output_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if os.listdir(output_dir): + print( + f"output directory '{output_dir}' is not empty", + file=sys.stderr, + ) + sys.exit(-1) + + fix_files(input_dir, output_dir) diff --git a/synth.metadata b/synth.metadata index 0e215fe..4c53358 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,15 +4,15 @@ "git": { "name": ".", "remote": "git@github.com:googleapis/python-websecurityscanner", - "sha": "c051344a2a83b0e22794984a6502cec59b97fe54" + "sha": "838be24c4e489ce6822f0e6ff6c87d67df8a172b" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "d5c594f49d7ce6c698807c3602551e56b45f0b33", - "internalRef": "365084845" + "sha": "fa29ad90d3b75ebc55a77837c0d3895d057b861d", + "internalRef": "365097355" } }, { @@ -41,6 +41,15 @@ "language": "python", "generator": "bazel" } + }, + { + "client": { + "source": "googleapis", + "apiName": "websecurityscanner", + "apiVersion": "v1", + "language": "python", + "generator": "bazel" + } } ] } \ No newline at end of file diff --git a/synth.py b/synth.py index f11b4c2..f2582ec 100644 --- a/synth.py +++ b/synth.py @@ -23,7 +23,7 @@ # ---------------------------------------------------------------------------- # Generate websecurityscanner GAPIC layer # ---------------------------------------------------------------------------- -versions = ["v1alpha", "v1beta"] +versions = ["v1alpha", "v1beta", "v1"] for version in versions: library = gapic.py_library( diff --git a/tests/unit/gapic/websecurityscanner_v1/__init__.py b/tests/unit/gapic/websecurityscanner_v1/__init__.py new file mode 100644 index 0000000..42ffdf2 --- /dev/null +++ b/tests/unit/gapic/websecurityscanner_v1/__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_v1/test_web_security_scanner.py b/tests/unit/gapic/websecurityscanner_v1/test_web_security_scanner.py new file mode 100644 index 0000000..7d5d1a7 --- /dev/null +++ b/tests/unit/gapic/websecurityscanner_v1/test_web_security_scanner.py @@ -0,0 +1,3857 @@ +# -*- 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. +# + +import os +import mock + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + +from google import auth +from google.api_core import client_options +from google.api_core import exceptions +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.auth import credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.websecurityscanner_v1.services.web_security_scanner import ( + WebSecurityScannerAsyncClient, +) +from google.cloud.websecurityscanner_v1.services.web_security_scanner import ( + WebSecurityScannerClient, +) +from google.cloud.websecurityscanner_v1.services.web_security_scanner import pagers +from google.cloud.websecurityscanner_v1.services.web_security_scanner import transports +from google.cloud.websecurityscanner_v1.types import crawled_url +from google.cloud.websecurityscanner_v1.types import finding +from google.cloud.websecurityscanner_v1.types import finding_addon +from google.cloud.websecurityscanner_v1.types import finding_type_stats +from google.cloud.websecurityscanner_v1.types import scan_config +from google.cloud.websecurityscanner_v1.types import scan_run +from google.cloud.websecurityscanner_v1.types import scan_run_error_trace +from google.cloud.websecurityscanner_v1.types import scan_run_warning_trace +from google.cloud.websecurityscanner_v1.types import web_security_scanner +from google.oauth2 import service_account +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + + +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" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert WebSecurityScannerClient._get_default_mtls_endpoint(None) is None + assert ( + WebSecurityScannerClient._get_default_mtls_endpoint(api_endpoint) + == api_mtls_endpoint + ) + assert ( + WebSecurityScannerClient._get_default_mtls_endpoint(api_mtls_endpoint) + == api_mtls_endpoint + ) + assert ( + WebSecurityScannerClient._get_default_mtls_endpoint(sandbox_endpoint) + == sandbox_mtls_endpoint + ) + assert ( + WebSecurityScannerClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) + == sandbox_mtls_endpoint + ) + assert ( + WebSecurityScannerClient._get_default_mtls_endpoint(non_googleapi) + == non_googleapi + ) + + +@pytest.mark.parametrize( + "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() + with mock.patch.object( + service_account.Credentials, "from_service_account_file" + ) as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + 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 isinstance(client, client_class) + + assert client.transport._host == "websecurityscanner.googleapis.com:443" + + +def test_web_security_scanner_client_get_transport_class(): + transport = WebSecurityScannerClient.get_transport_class() + available_transports = [ + transports.WebSecurityScannerGrpcTransport, + ] + assert transport in available_transports + + transport = WebSecurityScannerClient.get_transport_class("grpc") + assert transport == transports.WebSecurityScannerGrpcTransport + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (WebSecurityScannerClient, transports.WebSecurityScannerGrpcTransport, "grpc"), + ( + WebSecurityScannerAsyncClient, + transports.WebSecurityScannerGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +@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 +): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(WebSecurityScannerClient, "get_transport_class") as gtc: + transport = transport_class(credentials=credentials.AnonymousCredentials()) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(WebSecurityScannerClient, "get_transport_class") as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + 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="squid.clam.whelk", + scopes=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_ENDPOINT is + # "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() + 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=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # 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_ENDPOINT": "always"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=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_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=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 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, + ): + 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", + return_value=False, + ): + patched.return_value = None + client = client_class() + 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=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (WebSecurityScannerClient, transports.WebSecurityScannerGrpcTransport, "grpc"), + ( + WebSecurityScannerAsyncClient, + transports.WebSecurityScannerGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +def test_web_security_scanner_client_client_options_scopes( + client_class, transport_class, transport_name +): + # Check the case scopes are provided. + options = client_options.ClientOptions(scopes=["1", "2"],) + 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=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (WebSecurityScannerClient, transports.WebSecurityScannerGrpcTransport, "grpc"), + ( + WebSecurityScannerAsyncClient, + transports.WebSecurityScannerGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +def test_web_security_scanner_client_client_options_credentials_file( + client_class, transport_class, transport_name +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + 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="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +def test_web_security_scanner_client_client_options_from_dict(): + with mock.patch( + "google.cloud.websecurityscanner_v1.services.web_security_scanner.transports.WebSecurityScannerGrpcTransport.__init__" + ) as grpc_transport: + grpc_transport.return_value = None + client = WebSecurityScannerClient( + client_options={"api_endpoint": "squid.clam.whelk"} + ) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=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", 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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = scan_config.ScanConfig( + name="name_value", + display_name="display_name_value", + max_qps=761, + starting_urls=["starting_urls_value"], + user_agent=scan_config.ScanConfig.UserAgent.CHROME_LINUX, + blacklist_patterns=["blacklist_patterns_value"], + export_to_security_command_center=scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED, + risk_level=scan_config.ScanConfig.RiskLevel.NORMAL, + managed_scan=True, + static_ip_scan=True, + ) + + response = client.create_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.CreateScanConfigRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, scan_config.ScanConfig) + + assert response.name == "name_value" + + assert response.display_name == "display_name_value" + + assert response.max_qps == 761 + + assert response.starting_urls == ["starting_urls_value"] + + assert response.user_agent == scan_config.ScanConfig.UserAgent.CHROME_LINUX + + assert response.blacklist_patterns == ["blacklist_patterns_value"] + + assert ( + response.export_to_security_command_center + == scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED + ) + + assert response.risk_level == scan_config.ScanConfig.RiskLevel.NORMAL + + assert response.managed_scan is True + + assert response.static_ip_scan is True + + +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", + 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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_config.ScanConfig( + name="name_value", + display_name="display_name_value", + max_qps=761, + starting_urls=["starting_urls_value"], + user_agent=scan_config.ScanConfig.UserAgent.CHROME_LINUX, + blacklist_patterns=["blacklist_patterns_value"], + export_to_security_command_center=scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED, + risk_level=scan_config.ScanConfig.RiskLevel.NORMAL, + managed_scan=True, + static_ip_scan=True, + ) + ) + + response = await client.create_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.CreateScanConfigRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, scan_config.ScanConfig) + + assert response.name == "name_value" + + assert response.display_name == "display_name_value" + + assert response.max_qps == 761 + + assert response.starting_urls == ["starting_urls_value"] + + assert response.user_agent == scan_config.ScanConfig.UserAgent.CHROME_LINUX + + assert response.blacklist_patterns == ["blacklist_patterns_value"] + + assert ( + response.export_to_security_command_center + == scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED + ) + + assert response.risk_level == scan_config.ScanConfig.RiskLevel.NORMAL + + assert response.managed_scan is True + + assert response.static_ip_scan is True + + +@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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.CreateScanConfigRequest() + request.parent = "parent/value" + + # 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: + call.return_value = scan_config.ScanConfig() + + client.create_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_create_scan_config_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.CreateScanConfigRequest() + request.parent = "parent/value" + + # 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_config.ScanConfig() + ) + + await client.create_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.delete_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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", + 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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + + response = await client.delete_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.DeleteScanConfigRequest() + request.name = "name/value" + + # 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: + call.return_value = None + + client.delete_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_scan_config_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.DeleteScanConfigRequest() + request.name = "name/value" + + # 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + + await client.delete_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +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 = 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: + # Designate an appropriate return value for the call. + call.return_value = scan_config.ScanConfig( + name="name_value", + display_name="display_name_value", + max_qps=761, + starting_urls=["starting_urls_value"], + user_agent=scan_config.ScanConfig.UserAgent.CHROME_LINUX, + blacklist_patterns=["blacklist_patterns_value"], + export_to_security_command_center=scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED, + risk_level=scan_config.ScanConfig.RiskLevel.NORMAL, + managed_scan=True, + static_ip_scan=True, + ) + + response = client.get_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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" + + assert response.display_name == "display_name_value" + + assert response.max_qps == 761 + + assert response.starting_urls == ["starting_urls_value"] + + assert response.user_agent == scan_config.ScanConfig.UserAgent.CHROME_LINUX + + assert response.blacklist_patterns == ["blacklist_patterns_value"] + + assert ( + response.export_to_security_command_center + == scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED + ) + + assert response.risk_level == scan_config.ScanConfig.RiskLevel.NORMAL + + assert response.managed_scan is True + + assert response.static_ip_scan is True + + +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", + 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 = 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: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_config.ScanConfig( + name="name_value", + display_name="display_name_value", + max_qps=761, + starting_urls=["starting_urls_value"], + user_agent=scan_config.ScanConfig.UserAgent.CHROME_LINUX, + blacklist_patterns=["blacklist_patterns_value"], + export_to_security_command_center=scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED, + risk_level=scan_config.ScanConfig.RiskLevel.NORMAL, + managed_scan=True, + static_ip_scan=True, + ) + ) + + response = await client.get_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + 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" + + assert response.display_name == "display_name_value" + + assert response.max_qps == 761 + + assert response.starting_urls == ["starting_urls_value"] + + assert response.user_agent == scan_config.ScanConfig.UserAgent.CHROME_LINUX + + assert response.blacklist_patterns == ["blacklist_patterns_value"] + + assert ( + response.export_to_security_command_center + == scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED + ) + + assert response.risk_level == scan_config.ScanConfig.RiskLevel.NORMAL + + assert response.managed_scan is True + + assert response.static_ip_scan is True + + +@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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.GetScanConfigRequest() + 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: + call.return_value = scan_config.ScanConfig() + + client.get_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_scan_config_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.GetScanConfigRequest() + 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_config.ScanConfig() + ) + + await client.get_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = web_security_scanner.ListScanConfigsResponse( + next_page_token="next_page_token_value", + ) + + response = client.list_scan_configs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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", + 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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListScanConfigsResponse( + next_page_token="next_page_token_value", + ) + ) + + response = await client.list_scan_configs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListScanConfigsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListScanConfigsAsyncPager) + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListScanConfigsRequest() + 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_configs), "__call__" + ) as call: + call.return_value = web_security_scanner.ListScanConfigsResponse() + + client.list_scan_configs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_scan_configs_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListScanConfigsRequest() + 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_configs), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListScanConfigsResponse() + ) + + await client.list_scan_configs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_list_scan_configs_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_configs), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListScanConfigsResponse( + scan_configs=[ + scan_config.ScanConfig(), + scan_config.ScanConfig(), + scan_config.ScanConfig(), + ], + next_page_token="abc", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[], next_page_token="def", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[scan_config.ScanConfig(),], next_page_token="ghi", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[scan_config.ScanConfig(), scan_config.ScanConfig(),], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_scan_configs(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, scan_config.ScanConfig) for i in results) + + +def test_list_scan_configs_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_configs), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListScanConfigsResponse( + scan_configs=[ + scan_config.ScanConfig(), + scan_config.ScanConfig(), + scan_config.ScanConfig(), + ], + next_page_token="abc", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[], next_page_token="def", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[scan_config.ScanConfig(),], next_page_token="ghi", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[scan_config.ScanConfig(), scan_config.ScanConfig(),], + ), + 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 + + +@pytest.mark.asyncio +async def test_list_scan_configs_async_pager(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_scan_configs), + "__call__", + new_callable=mock.AsyncMock, + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListScanConfigsResponse( + scan_configs=[ + scan_config.ScanConfig(), + scan_config.ScanConfig(), + scan_config.ScanConfig(), + ], + next_page_token="abc", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[], next_page_token="def", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[scan_config.ScanConfig(),], next_page_token="ghi", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[scan_config.ScanConfig(), scan_config.ScanConfig(),], + ), + RuntimeError, + ) + async_pager = await client.list_scan_configs(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, scan_config.ScanConfig) for i in responses) + + +@pytest.mark.asyncio +async def test_list_scan_configs_async_pages(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_scan_configs), + "__call__", + new_callable=mock.AsyncMock, + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListScanConfigsResponse( + scan_configs=[ + scan_config.ScanConfig(), + scan_config.ScanConfig(), + scan_config.ScanConfig(), + ], + next_page_token="abc", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[], next_page_token="def", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[scan_config.ScanConfig(),], next_page_token="ghi", + ), + web_security_scanner.ListScanConfigsResponse( + scan_configs=[scan_config.ScanConfig(), scan_config.ScanConfig(),], + ), + 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 + + +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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = scan_config.ScanConfig( + name="name_value", + display_name="display_name_value", + max_qps=761, + starting_urls=["starting_urls_value"], + user_agent=scan_config.ScanConfig.UserAgent.CHROME_LINUX, + blacklist_patterns=["blacklist_patterns_value"], + export_to_security_command_center=scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED, + risk_level=scan_config.ScanConfig.RiskLevel.NORMAL, + managed_scan=True, + static_ip_scan=True, + ) + + response = client.update_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.UpdateScanConfigRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, scan_config.ScanConfig) + + assert response.name == "name_value" + + assert response.display_name == "display_name_value" + + assert response.max_qps == 761 + + assert response.starting_urls == ["starting_urls_value"] + + assert response.user_agent == scan_config.ScanConfig.UserAgent.CHROME_LINUX + + assert response.blacklist_patterns == ["blacklist_patterns_value"] + + assert ( + response.export_to_security_command_center + == scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED + ) + + assert response.risk_level == scan_config.ScanConfig.RiskLevel.NORMAL + + assert response.managed_scan is True + + assert response.static_ip_scan is True + + +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", + 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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_config.ScanConfig( + name="name_value", + display_name="display_name_value", + max_qps=761, + starting_urls=["starting_urls_value"], + user_agent=scan_config.ScanConfig.UserAgent.CHROME_LINUX, + blacklist_patterns=["blacklist_patterns_value"], + export_to_security_command_center=scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED, + risk_level=scan_config.ScanConfig.RiskLevel.NORMAL, + managed_scan=True, + static_ip_scan=True, + ) + ) + + response = await client.update_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.UpdateScanConfigRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, scan_config.ScanConfig) + + assert response.name == "name_value" + + assert response.display_name == "display_name_value" + + assert response.max_qps == 761 + + assert response.starting_urls == ["starting_urls_value"] + + assert response.user_agent == scan_config.ScanConfig.UserAgent.CHROME_LINUX + + assert response.blacklist_patterns == ["blacklist_patterns_value"] + + assert ( + response.export_to_security_command_center + == scan_config.ScanConfig.ExportToSecurityCommandCenter.ENABLED + ) + + assert response.risk_level == scan_config.ScanConfig.RiskLevel.NORMAL + + assert response.managed_scan is True + + assert response.static_ip_scan is True + + +@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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.UpdateScanConfigRequest() + request.scan_config.name = "scan_config.name/value" + + # 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: + call.return_value = scan_config.ScanConfig() + + client.update_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "scan_config.name=scan_config.name/value",) in kw[ + "metadata" + ] + + +@pytest.mark.asyncio +async def test_update_scan_config_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.UpdateScanConfigRequest() + request.scan_config.name = "scan_config.name/value" + + # 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_config.ScanConfig() + ) + + await client.update_scan_config(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "scan_config.name=scan_config.name/value",) in kw[ + "metadata" + ] + + +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 = 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: + # Designate an appropriate return value for the call. + call.return_value = scan_run.ScanRun( + name="name_value", + execution_state=scan_run.ScanRun.ExecutionState.QUEUED, + result_state=scan_run.ScanRun.ResultState.SUCCESS, + urls_crawled_count=1935, + urls_tested_count=1846, + has_vulnerabilities=True, + progress_percent=1733, + ) + + response = client.start_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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" + + assert response.execution_state == scan_run.ScanRun.ExecutionState.QUEUED + + assert response.result_state == scan_run.ScanRun.ResultState.SUCCESS + + assert response.urls_crawled_count == 1935 + + assert response.urls_tested_count == 1846 + + assert response.has_vulnerabilities is True + + 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", + 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 = 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: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_run.ScanRun( + name="name_value", + execution_state=scan_run.ScanRun.ExecutionState.QUEUED, + result_state=scan_run.ScanRun.ResultState.SUCCESS, + urls_crawled_count=1935, + urls_tested_count=1846, + has_vulnerabilities=True, + progress_percent=1733, + ) + ) + + response = await client.start_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + 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" + + assert response.execution_state == scan_run.ScanRun.ExecutionState.QUEUED + + assert response.result_state == scan_run.ScanRun.ResultState.SUCCESS + + assert response.urls_crawled_count == 1935 + + assert response.urls_tested_count == 1846 + + assert response.has_vulnerabilities is True + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.StartScanRunRequest() + 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: + call.return_value = scan_run.ScanRun() + + client.start_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_start_scan_run_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.StartScanRunRequest() + 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) + + await client.start_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +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 = 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: + # Designate an appropriate return value for the call. + call.return_value = scan_run.ScanRun( + name="name_value", + execution_state=scan_run.ScanRun.ExecutionState.QUEUED, + result_state=scan_run.ScanRun.ResultState.SUCCESS, + urls_crawled_count=1935, + urls_tested_count=1846, + has_vulnerabilities=True, + progress_percent=1733, + ) + + response = client.get_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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" + + assert response.execution_state == scan_run.ScanRun.ExecutionState.QUEUED + + assert response.result_state == scan_run.ScanRun.ResultState.SUCCESS + + assert response.urls_crawled_count == 1935 + + assert response.urls_tested_count == 1846 + + assert response.has_vulnerabilities is True + + 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", 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 = 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: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_run.ScanRun( + name="name_value", + execution_state=scan_run.ScanRun.ExecutionState.QUEUED, + result_state=scan_run.ScanRun.ResultState.SUCCESS, + urls_crawled_count=1935, + urls_tested_count=1846, + has_vulnerabilities=True, + progress_percent=1733, + ) + ) + + response = await client.get_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + 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" + + assert response.execution_state == scan_run.ScanRun.ExecutionState.QUEUED + + assert response.result_state == scan_run.ScanRun.ResultState.SUCCESS + + assert response.urls_crawled_count == 1935 + + assert response.urls_tested_count == 1846 + + assert response.has_vulnerabilities is True + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.GetScanRunRequest() + 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: + call.return_value = scan_run.ScanRun() + + client.get_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_scan_run_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.GetScanRunRequest() + 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) + + await client.get_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +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 = 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: + # Designate an appropriate return value for the call. + call.return_value = web_security_scanner.ListScanRunsResponse( + next_page_token="next_page_token_value", + ) + + response = client.list_scan_runs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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", + 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 = 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: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListScanRunsResponse( + next_page_token="next_page_token_value", + ) + ) + + response = await client.list_scan_runs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListScanRunsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListScanRunsAsyncPager) + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListScanRunsRequest() + 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: + call.return_value = web_security_scanner.ListScanRunsResponse() + + client.list_scan_runs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_scan_runs_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListScanRunsRequest() + 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListScanRunsResponse() + ) + + await client.list_scan_runs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +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: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(), scan_run.ScanRun(), scan_run.ScanRun(),], + next_page_token="abc", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[], next_page_token="def", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(),], next_page_token="ghi", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(), scan_run.ScanRun(),], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_scan_runs(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, scan_run.ScanRun) for i in results) + + +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: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(), scan_run.ScanRun(), scan_run.ScanRun(),], + next_page_token="abc", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[], next_page_token="def", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(),], next_page_token="ghi", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(), scan_run.ScanRun(),], + ), + 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 + + +@pytest.mark.asyncio +async def test_list_scan_runs_async_pager(): + client = WebSecurityScannerAsyncClient( + 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__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(), scan_run.ScanRun(), scan_run.ScanRun(),], + next_page_token="abc", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[], next_page_token="def", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(),], next_page_token="ghi", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(), scan_run.ScanRun(),], + ), + RuntimeError, + ) + async_pager = await client.list_scan_runs(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, scan_run.ScanRun) for i in responses) + + +@pytest.mark.asyncio +async def test_list_scan_runs_async_pages(): + client = WebSecurityScannerAsyncClient( + 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__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(), scan_run.ScanRun(), scan_run.ScanRun(),], + next_page_token="abc", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[], next_page_token="def", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(),], next_page_token="ghi", + ), + web_security_scanner.ListScanRunsResponse( + scan_runs=[scan_run.ScanRun(), scan_run.ScanRun(),], + ), + 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 + + +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 = 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: + # Designate an appropriate return value for the call. + call.return_value = scan_run.ScanRun( + name="name_value", + execution_state=scan_run.ScanRun.ExecutionState.QUEUED, + result_state=scan_run.ScanRun.ResultState.SUCCESS, + urls_crawled_count=1935, + urls_tested_count=1846, + has_vulnerabilities=True, + progress_percent=1733, + ) + + response = client.stop_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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" + + assert response.execution_state == scan_run.ScanRun.ExecutionState.QUEUED + + assert response.result_state == scan_run.ScanRun.ResultState.SUCCESS + + assert response.urls_crawled_count == 1935 + + assert response.urls_tested_count == 1846 + + assert response.has_vulnerabilities is True + + 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", + 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 = 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: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + scan_run.ScanRun( + name="name_value", + execution_state=scan_run.ScanRun.ExecutionState.QUEUED, + result_state=scan_run.ScanRun.ResultState.SUCCESS, + urls_crawled_count=1935, + urls_tested_count=1846, + has_vulnerabilities=True, + progress_percent=1733, + ) + ) + + response = await client.stop_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + 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" + + assert response.execution_state == scan_run.ScanRun.ExecutionState.QUEUED + + assert response.result_state == scan_run.ScanRun.ResultState.SUCCESS + + assert response.urls_crawled_count == 1935 + + assert response.urls_tested_count == 1846 + + assert response.has_vulnerabilities is True + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.StopScanRunRequest() + 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: + call.return_value = scan_run.ScanRun() + + client.stop_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_stop_scan_run_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.StopScanRunRequest() + 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(scan_run.ScanRun()) + + await client.stop_scan_run(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = web_security_scanner.ListCrawledUrlsResponse( + next_page_token="next_page_token_value", + ) + + response = client.list_crawled_urls(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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", + 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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListCrawledUrlsResponse( + next_page_token="next_page_token_value", + ) + ) + + response = await client.list_crawled_urls(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListCrawledUrlsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListCrawledUrlsAsyncPager) + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListCrawledUrlsRequest() + request.parent = "parent/value" + + # 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: + call.return_value = web_security_scanner.ListCrawledUrlsResponse() + + client.list_crawled_urls(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_crawled_urls_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListCrawledUrlsRequest() + request.parent = "parent/value" + + # 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListCrawledUrlsResponse() + ) + + await client.list_crawled_urls(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_list_crawled_urls_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_crawled_urls), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[ + crawled_url.CrawledUrl(), + crawled_url.CrawledUrl(), + crawled_url.CrawledUrl(), + ], + next_page_token="abc", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[], next_page_token="def", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[crawled_url.CrawledUrl(),], next_page_token="ghi", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[crawled_url.CrawledUrl(), crawled_url.CrawledUrl(),], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_crawled_urls(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, crawled_url.CrawledUrl) for i in results) + + +def test_list_crawled_urls_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_crawled_urls), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[ + crawled_url.CrawledUrl(), + crawled_url.CrawledUrl(), + crawled_url.CrawledUrl(), + ], + next_page_token="abc", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[], next_page_token="def", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[crawled_url.CrawledUrl(),], next_page_token="ghi", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[crawled_url.CrawledUrl(), crawled_url.CrawledUrl(),], + ), + 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 + + +@pytest.mark.asyncio +async def test_list_crawled_urls_async_pager(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_crawled_urls), + "__call__", + new_callable=mock.AsyncMock, + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[ + crawled_url.CrawledUrl(), + crawled_url.CrawledUrl(), + crawled_url.CrawledUrl(), + ], + next_page_token="abc", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[], next_page_token="def", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[crawled_url.CrawledUrl(),], next_page_token="ghi", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[crawled_url.CrawledUrl(), crawled_url.CrawledUrl(),], + ), + RuntimeError, + ) + async_pager = await client.list_crawled_urls(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, crawled_url.CrawledUrl) for i in responses) + + +@pytest.mark.asyncio +async def test_list_crawled_urls_async_pages(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_crawled_urls), + "__call__", + new_callable=mock.AsyncMock, + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[ + crawled_url.CrawledUrl(), + crawled_url.CrawledUrl(), + crawled_url.CrawledUrl(), + ], + next_page_token="abc", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[], next_page_token="def", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[crawled_url.CrawledUrl(),], next_page_token="ghi", + ), + web_security_scanner.ListCrawledUrlsResponse( + crawled_urls=[crawled_url.CrawledUrl(), crawled_url.CrawledUrl(),], + ), + 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 + + +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 = 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: + # Designate an appropriate return value for the call. + call.return_value = finding.Finding( + name="name_value", + finding_type="finding_type_value", + severity=finding.Finding.Severity.CRITICAL, + http_method="http_method_value", + fuzzed_url="fuzzed_url_value", + body="body_value", + description="description_value", + reproduction_url="reproduction_url_value", + frame_url="frame_url_value", + final_url="final_url_value", + tracking_id="tracking_id_value", + ) + + response = client.get_finding(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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" + + assert response.finding_type == "finding_type_value" + + assert response.severity == finding.Finding.Severity.CRITICAL + + assert response.http_method == "http_method_value" + + assert response.fuzzed_url == "fuzzed_url_value" + + assert response.body == "body_value" + + assert response.description == "description_value" + + assert response.reproduction_url == "reproduction_url_value" + + assert response.frame_url == "frame_url_value" + + assert response.final_url == "final_url_value" + + 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", 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 = 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: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + finding.Finding( + name="name_value", + finding_type="finding_type_value", + severity=finding.Finding.Severity.CRITICAL, + http_method="http_method_value", + fuzzed_url="fuzzed_url_value", + body="body_value", + description="description_value", + reproduction_url="reproduction_url_value", + frame_url="frame_url_value", + final_url="final_url_value", + tracking_id="tracking_id_value", + ) + ) + + response = await client.get_finding(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + 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" + + assert response.finding_type == "finding_type_value" + + assert response.severity == finding.Finding.Severity.CRITICAL + + assert response.http_method == "http_method_value" + + assert response.fuzzed_url == "fuzzed_url_value" + + assert response.body == "body_value" + + assert response.description == "description_value" + + assert response.reproduction_url == "reproduction_url_value" + + assert response.frame_url == "frame_url_value" + + assert response.final_url == "final_url_value" + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.GetFindingRequest() + 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: + call.return_value = finding.Finding() + + client.get_finding(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_finding_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.GetFindingRequest() + 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(finding.Finding()) + + await client.get_finding(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +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 = 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: + # Designate an appropriate return value for the call. + call.return_value = web_security_scanner.ListFindingsResponse( + next_page_token="next_page_token_value", + ) + + response = client.list_findings(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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", + 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 = 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: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListFindingsResponse( + next_page_token="next_page_token_value", + ) + ) + + response = await client.list_findings(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == web_security_scanner.ListFindingsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListFindingsAsyncPager) + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListFindingsRequest() + 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: + call.return_value = web_security_scanner.ListFindingsResponse() + + client.list_findings(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_findings_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListFindingsRequest() + 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListFindingsResponse() + ) + + await client.list_findings(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +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: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(), finding.Finding(), finding.Finding(),], + next_page_token="abc", + ), + web_security_scanner.ListFindingsResponse( + findings=[], next_page_token="def", + ), + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(),], next_page_token="ghi", + ), + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(), finding.Finding(),], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_findings(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, finding.Finding) for i in results) + + +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: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(), finding.Finding(), finding.Finding(),], + next_page_token="abc", + ), + web_security_scanner.ListFindingsResponse( + findings=[], next_page_token="def", + ), + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(),], next_page_token="ghi", + ), + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(), finding.Finding(),], + ), + 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 + + +@pytest.mark.asyncio +async def test_list_findings_async_pager(): + client = WebSecurityScannerAsyncClient( + 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__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(), finding.Finding(), finding.Finding(),], + next_page_token="abc", + ), + web_security_scanner.ListFindingsResponse( + findings=[], next_page_token="def", + ), + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(),], next_page_token="ghi", + ), + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(), finding.Finding(),], + ), + RuntimeError, + ) + async_pager = await client.list_findings(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, finding.Finding) for i in responses) + + +@pytest.mark.asyncio +async def test_list_findings_async_pages(): + client = WebSecurityScannerAsyncClient( + 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__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(), finding.Finding(), finding.Finding(),], + next_page_token="abc", + ), + web_security_scanner.ListFindingsResponse( + findings=[], next_page_token="def", + ), + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(),], next_page_token="ghi", + ), + web_security_scanner.ListFindingsResponse( + findings=[finding.Finding(), finding.Finding(),], + ), + 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 + + +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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = web_security_scanner.ListFindingTypeStatsResponse() + + response = client.list_finding_type_stats(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + 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", + 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 = 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__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListFindingTypeStatsResponse() + ) + + response = await client.list_finding_type_stats(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + 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(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListFindingTypeStatsRequest() + request.parent = "parent/value" + + # 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: + call.return_value = web_security_scanner.ListFindingTypeStatsResponse() + + client.list_finding_type_stats(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_finding_type_stats_field_headers_async(): + client = WebSecurityScannerAsyncClient( + credentials=credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = web_security_scanner.ListFindingTypeStatsRequest() + request.parent = "parent/value" + + # 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: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + web_security_scanner.ListFindingTypeStatsResponse() + ) + + await client.list_finding_type_stats(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.WebSecurityScannerGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.WebSecurityScannerGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebSecurityScannerClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.WebSecurityScannerGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebSecurityScannerClient( + client_options={"scopes": ["1", "2"]}, transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.WebSecurityScannerGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + client = WebSecurityScannerClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.WebSecurityScannerGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.WebSecurityScannerGrpcAsyncIOTransport( + credentials=credentials.AnonymousCredentials(), + ) + channel = transport.grpc_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,) + + +def test_web_security_scanner_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(exceptions.DuplicateCredentialArgs): + transport = transports.WebSecurityScannerTransport( + credentials=credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_web_security_scanner_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.websecurityscanner_v1.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. + methods = ( + "create_scan_config", + "delete_scan_config", + "get_scan_config", + "list_scan_configs", + "update_scan_config", + "start_scan_run", + "get_scan_run", + "list_scan_runs", + "stop_scan_run", + "list_crawled_urls", + "get_finding", + "list_findings", + "list_finding_type_stats", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + +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, mock.patch( + "google.cloud.websecurityscanner_v1.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", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +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_v1.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: + adc.return_value = (credentials.AnonymousCredentials(), None) + WebSecurityScannerClient() + adc.assert_called_once_with( + scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id=None, + ) + + +def test_web_security_scanner_transport_auth_adc(): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transports.WebSecurityScannerGrpcTransport( + host="squid.clam.whelk", quota_project_id="octopus" + ) + adc.assert_called_once_with( + scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +@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(), + client_options=client_options.ClientOptions( + api_endpoint="websecurityscanner.googleapis.com" + ), + ) + assert client.transport._host == "websecurityscanner.googleapis.com:443" + + +def test_web_security_scanner_host_with_port(): + client = WebSecurityScannerClient( + credentials=credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="websecurityscanner.googleapis.com:8000" + ), + ) + assert client.transport._host == "websecurityscanner.googleapis.com:8000" + + +def test_web_security_scanner_grpc_transport_channel(): + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.WebSecurityScannerGrpcTransport( + host="squid.clam.whelk", channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_web_security_scanner_grpc_asyncio_transport_channel(): + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.WebSecurityScannerGrpcAsyncIOTransport( + host="squid.clam.whelk", channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + 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( + "transport_class", + [ + transports.WebSecurityScannerGrpcTransport, + transports.WebSecurityScannerGrpcAsyncIOTransport, + ], +) +def test_web_security_scanner_transport_channel_mtls_with_client_cert_source( + transport_class, +): + 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() + 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, + ) + + 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_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_common_billing_account_path(): + billing_account = "winkle" + + 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": "nautilus", + } + 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 = "scallop" + + expected = "folders/{folder}".format(folder=folder,) + actual = WebSecurityScannerClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "abalone", + } + 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 = "squid" + + expected = "organizations/{organization}".format(organization=organization,) + actual = WebSecurityScannerClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "clam", + } + 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 = "whelk" + + expected = "projects/{project}".format(project=project,) + actual = WebSecurityScannerClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "octopus", + } + 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 = "oyster" + location = "nudibranch" + + 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": "cuttlefish", + "location": "mussel", + } + 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)