def test_get_layer(self): """ Test for basic retrieval of layers from the security scanner. """ repo_ref = registry_model.lookup_repository(ADMIN_ACCESS_USER, SIMPLE_REPO) repo_tag = registry_model.get_repo_tag(repo_ref, "latest") manifest = registry_model.get_manifest_for_tag(repo_tag) registry_model.populate_legacy_images_for_testing(manifest, storage) with fake_security_scanner() as security_scanner: # Ensure the layer doesn't exist yet. self.assertFalse( security_scanner.has_layer( security_scanner.layer_id(manifest))) self.assertIsNone(self.api.get_layer_data(manifest)) # Add the layer. security_scanner.add_layer(security_scanner.layer_id(manifest)) # Retrieve the results. result = self.api.get_layer_data(manifest, include_vulnerabilities=True) self.assertIsNotNone(result) self.assertEquals(result["Layer"]["Name"], security_scanner.layer_id(manifest))
def test_load_security_information_api_responses(secscan_api_response, initialized_db): repository_ref = registry_model.lookup_repository("devtable", "simple") tag = registry_model.get_repo_tag(repository_ref, "latest") manifest = registry_model.get_manifest_for_tag(tag) registry_model.populate_legacy_images_for_testing(manifest, storage) legacy_image_row = shared.get_legacy_image_for_manifest(manifest._db_id) assert legacy_image_row is not None set_secscan_status(legacy_image_row, True, 3) secscan = V2SecurityScanner(app, instance_keys, storage) secscan._legacy_secscan_api = mock.Mock() secscan._legacy_secscan_api.get_layer_data.return_value = secscan_api_response security_information = secscan.load_security_information( manifest).security_information assert isinstance(security_information, SecurityInformation) assert security_information.Layer.Name == secscan_api_response[ "Layer"].get("Name", "") assert security_information.Layer.ParentName == secscan_api_response[ "Layer"].get("ParentName", "") assert security_information.Layer.IndexedByVersion == secscan_api_response[ "Layer"].get("IndexedByVersion", None) assert len(security_information.Layer.Features) == len( secscan_api_response["Layer"].get("Features", []))
def test_load_security_information_queued(initialized_db): repository_ref = registry_model.lookup_repository("devtable", "simple") tag = registry_model.get_repo_tag(repository_ref, "latest") manifest = registry_model.get_manifest_for_tag(tag) registry_model.populate_legacy_images_for_testing(manifest, storage) secscan = V2SecurityScanner(app, instance_keys, storage) assert secscan.load_security_information( manifest).status == ScanLookupStatus.NOT_YET_INDEXED
def test_load_security_information_unknown_manifest(initialized_db): repository_ref = registry_model.lookup_repository("devtable", "simple") tag = registry_model.get_repo_tag(repository_ref, "latest") manifest = registry_model.get_manifest_for_tag(tag) registry_model.populate_legacy_images_for_testing(manifest, storage) # Delete the manifest. Manifest.get(id=manifest._db_id).delete_instance(recursive=True) secscan = V2SecurityScanner(app, instance_keys, storage) assert (secscan.load_security_information(manifest).status == ScanLookupStatus.UNSUPPORTED_FOR_INDEXING)
def test_load_security_information_failed_to_index(initialized_db): repository_ref = registry_model.lookup_repository("devtable", "simple") tag = registry_model.get_repo_tag(repository_ref, "latest") manifest = registry_model.get_manifest_for_tag(tag) registry_model.populate_legacy_images_for_testing(manifest, storage) # Set the index status. image = shared.get_legacy_image_for_manifest(manifest._db_id) image.security_indexed = False image.security_indexed_engine = 3 image.save() secscan = V2SecurityScanner(app, instance_keys, storage) assert secscan.load_security_information( manifest).status == ScanLookupStatus.FAILED_TO_INDEX
def move_tag(repository, tag, image_ids, expect_gc=True): namespace = repository.namespace_user.username name = repository.name repo_ref = RepositoryReference.for_repo_obj(repository) builder = DockerSchema1ManifestBuilder(namespace, name, tag) # NOTE: Building root to leaf. parent_id = None for image_id in image_ids: config = { "id": image_id, "config": { "Labels": { "foo": "bar", "meh": "grah", } }, } if parent_id: config["parent"] = parent_id # Create a storage row for the layer blob. _, layer_blob_digest = _populate_blob(repository, image_id.encode("ascii")) builder.insert_layer(layer_blob_digest, json.dumps(config)) parent_id = image_id # Store the manifest. manifest = builder.build(docker_v2_signing_key) registry_model.create_manifest_and_retarget_tag(repo_ref, manifest, tag, storage, raise_on_error=True) tag_ref = registry_model.get_repo_tag(repo_ref, tag) manifest_ref = registry_model.get_manifest_for_tag(tag_ref) registry_model.populate_legacy_images_for_testing(manifest_ref, storage) if expect_gc: assert gc_now(repository) == expect_gc
def test_load_security_information(indexed_v2, indexed_v4, expected_status, initialized_db): secscan_model.configure(app, instance_keys, storage) repository_ref = registry_model.lookup_repository("devtable", "simple") tag = registry_model.find_matching_tag(repository_ref, ["latest"]) manifest = registry_model.get_manifest_for_tag(tag) assert manifest registry_model.populate_legacy_images_for_testing(manifest, storage) image = shared.get_legacy_image_for_manifest(manifest._db_id) if indexed_v2: image.security_indexed = False image.security_indexed_engine = 3 image.save() else: ManifestLegacyImage.delete().where( ManifestLegacyImage.manifest == manifest._db_id).execute() if indexed_v4: ManifestSecurityStatus.create( manifest=manifest._db_id, repository=repository_ref._db_id, error_json={}, index_status=IndexStatus.MANIFEST_UNSUPPORTED, indexer_hash="abc", indexer_version=IndexerVersion.V4, metadata_json={}, ) result = secscan_model.load_security_information(manifest, True) assert isinstance(result, SecurityInformationLookupResult) assert result.status == expected_status
def test_images_shared_cas(default_tag_policy, initialized_db): """ A repository, each two tags, pointing to the same image, which has image storage with the same *CAS path*, but *distinct records*. Deleting the first tag should delete the first image, and its storage, but not the file in storage, as it shares its CAS path. """ with assert_gc_integrity(expect_storage_removed=True): repository = create_repository() # Create two image storage records with the same content checksum. content = b"hello world" digest = "sha256:" + hashlib.sha256(content).hexdigest() preferred = storage.preferred_locations[0] storage.put_content({preferred}, storage.blob_path(digest), content) is1 = database.ImageStorage.create(content_checksum=digest) is2 = database.ImageStorage.create(content_checksum=digest) location = database.ImageStorageLocation.get(name=preferred) database.ImageStoragePlacement.create(location=location, storage=is1) database.ImageStoragePlacement.create(location=location, storage=is2) # Temp link so its available. model.blob.store_blob_record_and_temp_link_in_repo( repository, digest, location, len(content), 120) # Ensure the CAS path exists. assert storage.exists({preferred}, storage.blob_path(digest)) repo_ref = RepositoryReference.for_repo_obj(repository) # Store a manifest pointing to that path as `first`. builder = DockerSchema1ManifestBuilder( repository.namespace_user.username, repository.name, "first") builder.insert_layer( digest, json.dumps({ "id": "i1", }), ) manifest = builder.build(docker_v2_signing_key) registry_model.create_manifest_and_retarget_tag(repo_ref, manifest, "first", storage, raise_on_error=True) tag_ref = registry_model.get_repo_tag(repo_ref, "first") manifest_ref = registry_model.get_manifest_for_tag(tag_ref) registry_model.populate_legacy_images_for_testing( manifest_ref, storage) # Store another as `second`. builder = DockerSchema1ManifestBuilder( repository.namespace_user.username, repository.name, "second") builder.insert_layer( digest, json.dumps({ "id": "i2", }), ) manifest = builder.build(docker_v2_signing_key) created, _ = registry_model.create_manifest_and_retarget_tag( repo_ref, manifest, "second", storage, raise_on_error=True) tag_ref = registry_model.get_repo_tag(repo_ref, "second") manifest_ref = registry_model.get_manifest_for_tag(tag_ref) registry_model.populate_legacy_images_for_testing( manifest_ref, storage) # Manually retarget the second manifest's blob to the second row. try: second_blob = ManifestBlob.get(manifest=created._db_id, blob=is1) second_blob.blob = is2 second_blob.save() except ManifestBlob.DoesNotExist: second_blob = ManifestBlob.get(manifest=created._db_id, blob=is2) second_blob.blob = is1 second_blob.save() # Delete the temp reference. _delete_temp_links(repository) # Ensure the legacy images exist. assert_not_deleted(repository, "i1", "i2") # Delete the first tag. delete_tag(repository, "first") assert_deleted(repository, "i1") assert_not_deleted(repository, "i2") # Ensure the CAS path still exists. assert storage.exists({preferred}, storage.blob_path(digest))
def _add_legacy_image(namespace, repo_name, tag_name): repo_ref = registry_model.lookup_repository(namespace, repo_name) tag_ref = registry_model.get_repo_tag(repo_ref, tag_name) manifest_ref = registry_model.get_manifest_for_tag(tag_ref) registry_model.populate_legacy_images_for_testing(manifest_ref, storage)