def test_poll_discovery_occurrence(self): # create discovery occurrence note_id = 'discovery-note-{}'.format(uuid.uuid4()) client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() note = {'discovery': {'analysis_kind': NoteKind.DISCOVERY}} grafeas_client.\ create_note(parent=f"projects/{PROJECT_ID}", note_id=note_id, note=note) occurrence = { 'note_name': f"projects/{PROJECT_ID}/notes/{note_id}", 'resource_uri': self.image_url, 'discovery': { 'analysis_status': DiscoveryOccurrence.AnalysisStatus.FINISHED_SUCCESS } } created = grafeas_client.\ create_occurrence(parent=f"projects/{PROJECT_ID}", occurrence=occurrence) disc = samples.poll_discovery_finished(self.image_url, 10, PROJECT_ID) status = disc.discovery.analysis_status assert disc is not None assert status == DiscoveryOccurrence.AnalysisStatus.FINISHED_SUCCESS # clean up samples.delete_occurrence(basename(created.name), PROJECT_ID) samples.delete_note(note_id, PROJECT_ID)
def create_occurrence(resource_url, note_id, occurrence_project, note_project): """ Creates and returns a new occurrence of a previously created vulnerability note.""" # resource_url = 'https://gcr.io/my-project/my-image@sha256:123' # note_id = 'my-note' # occurrence_project = 'my-gcp-project' # note_project = 'my-gcp-project' from grafeas.grafeas_v1.gapic.enums import Version from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() formatted_note = grafeas_client.note_path(note_project, note_id) formatted_project = grafeas_client.project_path(occurrence_project) occurrence = { 'note_name': formatted_note, 'resource_uri': resource_url, 'vulnerability': { 'package_issue': [{ 'affected_cpe_uri': 'your-uri-here', 'affected_package': 'your-package-here', 'min_affected_version': { 'kind': Version.VersionKind.MINIMUM }, 'fixed_version': { 'kind': Version.VersionKind.MAXIMUM } }] } } return grafeas_client.create_occurrence(formatted_project, occurrence)
def create_note(note_id, project_id): """Creates and returns a new vulnerability note.""" # note_id = 'my-note' # project_id = 'my-gcp-project' from grafeas.grafeas_v1.gapic.enums import Version from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() project_name = grafeas_client.project_path(project_id) note = { 'vulnerability': { 'details': [{ 'affected_cpe_uri': 'your-uri-here', 'affected_package': 'your-package-here', 'min_affected_version': { 'kind': Version.VersionKind.MINIMUM }, 'fixed_version': { 'kind': Version.VersionKind.MAXIMUM } }] } } response = grafeas_client.create_note(project_name, note_id, note) return response
def test_set_iam_policy(self): # Setup Expected Response version = 351608024 etag = b"21" expected_response = {"version": version, "etag": etag} expected_response = policy_pb2.Policy(**expected_response) # Mock the API response channel = ChannelStub(responses=[expected_response]) patch = mock.patch("google.api_core.grpc_helpers.create_channel") with patch as create_channel: create_channel.return_value = channel client = containeranalysis_v1.ContainerAnalysisClient() # Setup Request resource = client.note_path("[PROJECT]", "[NOTE]") policy = {} response = client.set_iam_policy(resource, policy) assert expected_response == response assert len(channel.requests) == 1 expected_request = iam_policy_pb2.SetIamPolicyRequest( resource=resource, policy=policy ) actual_request = channel.requests[0][1] assert expected_request == actual_request
def test_test_iam_permissions(self): # Setup Expected Response expected_response = {} expected_response = iam_policy_pb2.TestIamPermissionsResponse( **expected_response ) # Mock the API response channel = ChannelStub(responses=[expected_response]) patch = mock.patch("google.api_core.grpc_helpers.create_channel") with patch as create_channel: create_channel.return_value = channel client = containeranalysis_v1.ContainerAnalysisClient() # Setup Request resource = client.note_path("[PROJECT]", "[NOTE]") permissions = [] response = client.test_iam_permissions(resource, permissions) assert expected_response == response assert len(channel.requests) == 1 expected_request = iam_policy_pb2.TestIamPermissionsRequest( resource=resource, permissions=permissions ) actual_request = channel.requests[0][1] assert expected_request == actual_request
def test_find_high_severity_vulnerabilities(self): occ_list = samples.find_high_severity_vulnerabilities_for_image( self.image_url, PROJECT_ID) assert len(occ_list) == 0 # create new high severity vulnerability note_id = 'discovery-note-{}'.format(int(time())) client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() note = { 'vulnerability': { 'severity': Severity.CRITICAL, 'details': [{ 'affected_cpe_uri': 'your-uri-here', 'affected_package': 'your-package-here', 'min_affected_version': { 'kind': Version.VersionKind.MINIMUM }, 'fixed_version': { 'kind': Version.VersionKind.MAXIMUM } }] } } grafeas_client.\ create_note(grafeas_client.project_path(PROJECT_ID), note_id, note) occurrence = { 'note_name': client.note_path(PROJECT_ID, note_id), 'resource_uri': self.image_url, 'vulnerability': { 'package_issue': [{ 'affected_cpe_uri': 'your-uri-here', 'affected_package': 'your-package-here', 'min_affected_version': { 'kind': Version.VersionKind.MINIMUM }, 'fixed_version': { 'kind': Version.VersionKind.MAXIMUM } }] } } created = grafeas_client.\ create_occurrence(grafeas_client.project_path(PROJECT_ID), occurrence) # query again tries = 0 count = 0 while count != 1 and tries < TRY_LIMIT: tries += 1 occ_list = samples.find_vulnerabilities_for_image( self.image_url, PROJECT_ID) count = len(occ_list) sleep(SLEEP_TIME) assert len(occ_list) == 1 # clean up samples.delete_occurrence(basename(created.name), PROJECT_ID) samples.delete_note(note_id, PROJECT_ID)
def get_occurrence(occurrence_id, project_id): """retrieves and prints a specified occurrence from the server.""" # occurrence_id = basename(occurrence.name) # project_id = 'my-gcp-project' from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() parent = grafeas_client.occurrence_path(project_id, occurrence_id) return grafeas_client.get_occurrence(parent)
def delete_occurrence(occurrence_id, project_id): """Removes an existing occurrence from the server.""" # occurrence_id = basename(occurrence.name) # project_id = 'my-gcp-project' from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() parent = grafeas_client.occurrence_path(project_id, occurrence_id) grafeas_client.delete_occurrence(parent)
def get_note(note_id, project_id): """Retrieves and prints a specified note from the server.""" # note_id = 'my-note' # project_id = 'my-gcp-project' from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() note_name = grafeas_client.note_path(project_id, note_id) response = grafeas_client.get_note(note_name) return response
def delete_note(note_id, project_id): """Removes an existing note from the server.""" # note_id = 'my-note' # project_id = 'my-gcp-project' from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() note_name = grafeas_client.note_path(project_id, note_id) grafeas_client.delete_note(note_name)
def test_get_iam_policy_exception(self): # Mock the API response channel = ChannelStub(responses=[CustomException()]) patch = mock.patch("google.api_core.grpc_helpers.create_channel") with patch as create_channel: create_channel.return_value = channel client = containeranalysis_v1.ContainerAnalysisClient() # Setup request resource = client.note_path("[PROJECT]", "[NOTE]") with pytest.raises(CustomException): client.get_iam_policy(resource)
def test_set_iam_policy_exception(self): # Mock the API response channel = ChannelStub(responses=[CustomException()]) patch = mock.patch("google.api_core.grpc_helpers.create_channel") with patch as create_channel: create_channel.return_value = channel client = containeranalysis_v1.ContainerAnalysisClient() # Setup request resource = "resource-341064690" policy = {} with pytest.raises(CustomException): client.set_iam_policy(resource, policy)
def find_vulnerabilities_for_image(resource_url, project_id): """"Retrieves all vulnerability occurrences associated with a resource.""" # resource_url = 'https://gcr.io/my-project/my-image@sha256:123' # project_id = 'my-gcp-project' from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() project_name = grafeas_client.project_path(project_id) filter_str = 'kind="VULNERABILITY" AND resourceUrl="{}"'\ .format(resource_url) return list(grafeas_client.list_occurrences(project_name, filter_str))
def image_vuln_pubsub_handler(event, context): #get the Pub/Sub message containing the vulnerability occurrence id data = json.loads(base64.b64decode(event['data']).decode('utf-8')) #load in environment variables for GCS bucket. bucket_name = os.environ.get("BUCKET_NAME", "Bucket name not set") #get the occurrence via the grafeas client occurrence_name = (data['name']) client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() o = grafeas_client.get_occurrence(name=occurrence_name) #write to storage write_vuln_to_bucket(bucket_name, str(o), str(o.name))
def poll_discovery_finished(resource_url, timeout_seconds, project_id): """Returns the discovery occurrence for a resource once it reaches a terminal state.""" # resource_url = 'https://gcr.io/my-project/my-image@sha256:123' # timeout_seconds = 20 # project_id = 'my-gcp-project' import time from grafeas.grafeas_v1 import DiscoveryOccurrence from google.cloud.devtools import containeranalysis_v1 deadline = time.time() + timeout_seconds client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() project_name = f"projects/{project_id}" discovery_occurrence = None while discovery_occurrence is None: time.sleep(1) filter_str = 'resourceUrl="{}" \ AND noteProjectId="goog-analysis" \ AND noteId="PACKAGE_VULNERABILITY"'.format(resource_url) # [END containeranalysis_poll_discovery_occurrence_finished] # The above filter isn't testable, since it looks for occurrences in a # locked down project fall back to a more permissive filter for testing filter_str = 'kind="DISCOVERY" AND resourceUrl="{}"'\ .format(resource_url) # [START containeranalysis_poll_discovery_occurrence_finished] result = grafeas_client.list_occurrences(parent=project_name, filter=filter_str) # only one occurrence should ever be returned by ListOccurrences # and the given filter for item in result: discovery_occurrence = item if time.time() > deadline: raise RuntimeError('timeout while retrieving discovery occurrence') status = DiscoveryOccurrence.AnalysisStatus.PENDING while status != DiscoveryOccurrence.AnalysisStatus.FINISHED_UNSUPPORTED \ and status != DiscoveryOccurrence.AnalysisStatus.FINISHED_FAILED \ and status != DiscoveryOccurrence.AnalysisStatus.FINISHED_SUCCESS: time.sleep(1) updated = grafeas_client.get_occurrence(name=discovery_occurrence.name) status = updated.discovery.analysis_status if time.time() > deadline: raise RuntimeError('timeout while waiting for terminal state') return discovery_occurrence
def get_discovery_info(resource_url, project_id): """Retrieves and prints the discovery occurrence created for a specified image. The discovery occurrence contains information about the initial scan on the image.""" # resource_url = 'https://gcr.io/my-project/my-image@sha256:123' # project_id = 'my-gcp-project' from google.cloud.devtools import containeranalysis_v1 filter_str = 'kind="DISCOVERY" AND resourceUrl="{}"'.format(resource_url) client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() project_name = grafeas_client.project_path(project_id) response = grafeas_client.list_occurrences(project_name, filter_=filter_str) for occ in response: print(occ)
def poll_discovery_finished(resource_url, timeout_seconds, project_id): """Returns the discovery occurrence for a resource once it reaches a terminal state.""" # resource_url = 'https://gcr.io/my-project/my-image@sha256:123' # timeout_seconds = 20 # project_id = 'my-gcp-project' import time from google.cloud.devtools import containeranalysis_v1 deadline = time.time() + timeout_seconds client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() project_name = grafeas_client.project_path(project_id) discovery_occurrence = None while discovery_occurrence is None: time.sleep(1) sys.stdout.write(".") resource_url = get_resource_url(resource_url) filter_str = 'resourceUrl="{}" \ AND noteProjectId="goog-analysis" \ AND noteId="PACKAGE_VULNERABILITY"'.format(resource_url) result = grafeas_client.list_occurrences(project_name, filter_str) # only one occurrence should ever be returned by ListOccurrences # and the given filter for item in result: discovery_occurrence = item if time.time() > deadline: raise RuntimeError('timeout while retrieving discovery occurrence') status = DiscoveryOccurrence.AnalysisStatus.PENDING while status != DiscoveryOccurrence.AnalysisStatus.FINISHED_UNSUPPORTED \ and status != DiscoveryOccurrence.AnalysisStatus.FINISHED_FAILED \ and status != DiscoveryOccurrence.AnalysisStatus.FINISHED_SUCCESS: time.sleep(1) sys.stdout.write(".") updated = grafeas_client.get_occurrence(discovery_occurrence.name) status = updated.discovery.analysis_status if time.time() > deadline: raise RuntimeError('timeout while waiting for terminal state') print("") return discovery_occurrence
def get_occurrences_for_note(note_id, project_id): """Retrieves all the occurrences associated with a specified Note. Here, all occurrences are printed and counted.""" # note_id = 'my-note' # project_id = 'my-gcp-project' from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() note_name = grafeas_client.note_path(project_id, note_id) response = grafeas_client.list_note_occurrences(note_name) count = 0 for o in response: # do something with the retrieved occurrence # in this sample, we will simply count each one count += 1 return count
def test_poll_discovery_occurrence(self): # try with no discovery occurrence try: samples.poll_discovery_finished(self.image_url, 5, PROJECT_ID) except RuntimeError: pass else: # we expect timeout error assert False # create discovery occurrence note_id = 'discovery-note-{}'.format(uuid.uuid4()) client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() note = { 'discovery': { 'analysis_kind': NoteKind.DISCOVERY } } grafeas_client.\ create_note(grafeas_client.project_path(PROJECT_ID), note_id, note) occurrence = { 'note_name': grafeas_client.note_path(PROJECT_ID, note_id), 'resource_uri': self.image_url, 'discovery': { 'analysis_status': DiscoveryOccurrence.AnalysisStatus .FINISHED_SUCCESS } } created = grafeas_client.\ create_occurrence(grafeas_client.project_path(PROJECT_ID), occurrence) # poll again disc = samples.poll_discovery_finished(self.image_url, 10, PROJECT_ID) status = disc.discovery.analysis_status assert disc is not None assert status == DiscoveryOccurrence.AnalysisStatus.FINISHED_SUCCESS # clean up samples.delete_occurrence(basename(created.name), PROJECT_ID) samples.delete_note(note_id, PROJECT_ID)
def get_occurrences_for_image(resource_url, project_id): """Retrieves all the occurrences associated with a specified image. Here, all occurrences are simply printed and counted.""" # resource_url = 'https://gcr.io/my-project/my-image@sha256:123' # project_id = 'my-gcp-project' from google.cloud.devtools import containeranalysis_v1 filter_str = 'resourceUrl="{}"'.format(resource_url) client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() project_name = grafeas_client.project_path(project_id) response = grafeas_client.list_occurrences(project_name, filter_=filter_str) count = 0 for o in response: # do something with the retrieved occurrence # in this sample, we will simply count each one count += 1 return count
def find_high_severity_vulnerabilities_for_image(resource_url, project_id): """Retrieves a list of only high vulnerability occurrences associated with a resource.""" # resource_url = 'https://gcr.io/my-project/my-image@sha256:123' # project_id = 'my-gcp-project' from grafeas.grafeas_v1.gapic.enums import Severity from google.cloud.devtools import containeranalysis_v1 client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() project_name = grafeas_client.project_path(project_id) filter_str = 'kind="VULNERABILITY" AND resourceUrl="{}"'\ .format(resource_url) vulnerabilities = grafeas_client.list_occurrences(project_name, filter_str) filtered_list = [] for v in vulnerabilities: if v.severity == Severity.HIGH or v.severity == Severity.CRITICAL: filtered_list.append(v) return filtered_list
def cve_trigger(event, context): """Triggered from a message on a Cloud Pub/Sub topic. Args: event (dict): Event payload. context (google.cloud.functions.Context): Metadata for the event. """ pubsub_message = json.loads(base64.b64decode(event['data']).decode('utf-8')) print(pubsub_message) if "VULNERABILITY" in pubsub_message['kind']: occurrence_id = os.path.basename(pubsub_message['name']) client = containeranalysis_v1.ContainerAnalysisClient() grafeas_client = client.get_grafeas_client() parent = grafeas_client.occurrence_path(project_id, occurrence_id) occurrence = grafeas_client.get_occurrence(parent) if registry in occurrence.resource_uri: for i in occurrence.vulnerability.package_issue: if i.fixed_package is not None: print("Fix found. Triggering build.") buildsomething = cloudbuild_v1.CloudBuildClient() buildsomething.run_build_trigger(project_id, trigger_id, {})