Beispiel #1
0
def test_load_security_information_api_request_failure(initialized_db,
                                                       set_secscan_config):
    repository_ref = registry_model.lookup_repository("devtable", "simple")
    tag = registry_model.get_repo_tag(repository_ref,
                                      "latest",
                                      include_legacy_image=True)
    manifest = registry_model.get_manifest_for_tag(tag,
                                                   backfill_if_necessary=True)

    mss = ManifestSecurityStatus.create(
        manifest=manifest._db_id,
        repository=repository_ref._db_id,
        error_json={},
        index_status=IndexStatus.COMPLETED,
        indexer_hash="abc",
        indexer_version=IndexerVersion.V4,
        metadata_json={},
    )

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.vulnerability_report.side_effect = APIRequestFailure()

    assert secscan.load_security_information(
        manifest).status == ScanLookupStatus.COULD_NOT_LOAD
    assert not ManifestSecurityStatus.select().where(
        ManifestSecurityStatus.id == mss.id).exists()
Beispiel #2
0
def test_load_security_information_api_returns_none(initialized_db,
                                                    set_secscan_config):
    repository_ref = registry_model.lookup_repository("devtable", "simple")
    tag = registry_model.get_repo_tag(repository_ref,
                                      "latest",
                                      include_legacy_image=True)
    manifest = registry_model.get_manifest_for_tag(tag,
                                                   backfill_if_necessary=True)

    ManifestSecurityStatus.create(
        manifest=manifest._db_id,
        repository=repository_ref._db_id,
        error_json={},
        index_status=IndexStatus.COMPLETED,
        indexer_hash="abc",
        indexer_version=IndexerVersion.V4,
        metadata_json={},
    )

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.vulnerability_report.return_value = None

    assert secscan.load_security_information(
        manifest).status == ScanLookupStatus.NOT_YET_INDEXED
Beispiel #3
0
def test_process_notification_page(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)

    results = list(
        secscan.process_notification_page([
            {
                "reason": "removed",
            },
            {
                "reason": "added",
                "manifest": "sha256:abcd",
                "vulnerability": {
                    "normalized_severity": "s",
                    "description": "d",
                    "package": {
                        "id": "42",
                        "name": "p",
                        "version": "v0.0.1",
                    },
                    "name": "n",
                    "fixed_in_version": "f",
                    "links": "l",
                },
            },
        ]))

    assert len(results) == 1
    assert results[0].manifest_digest == "sha256:abcd"
    assert results[0].vulnerability.Severity == "s"
    assert results[0].vulnerability.Description == "d"
    assert results[0].vulnerability.NamespaceName == "p"
    assert results[0].vulnerability.Name == "n"
    assert results[0].vulnerability.FixedBy == "f"
    assert results[0].vulnerability.Link == "l"
Beispiel #4
0
def test_perform_indexing_failed_within_reindex_threshold(
        initialized_db, set_secscan_config):
    app.config["SECURITY_SCANNER_V4_REINDEX_THRESHOLD"] = 300
    expected_manifests = (Manifest.select().join(Repository).join(User).where(
        User.username == "devtable"))

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "abc"}
    secscan._secscan_api.index.return_value = (
        {
            "err": None,
            "state": IndexReportState.Index_Finished
        },
        "abc",
    )

    for manifest in expected_manifests:
        ManifestSecurityStatus.create(
            manifest=manifest,
            repository=manifest.repository,
            error_json={},
            index_status=IndexStatus.FAILED,
            indexer_hash="abc",
            indexer_version=IndexerVersion.V4,
            metadata_json={},
        )

    secscan.perform_indexing()

    assert ManifestSecurityStatus.select().count() == expected_manifests.count(
    )
    for mss in ManifestSecurityStatus.select():
        assert mss.index_status == IndexStatus.FAILED
Beispiel #5
0
def test_perform_indexing_api_request_failure_index(initialized_db,
                                                    set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "abc"}
    secscan._secscan_api.index.side_effect = APIRequestFailure()

    next_token = secscan.perform_indexing()

    assert next_token is None
    assert ManifestSecurityStatus.select().count() == 0

    # Set security scanner to return good results and attempt indexing again
    secscan._secscan_api.index.side_effect = None
    secscan._secscan_api.index.return_value = (
        {
            "err": None,
            "state": IndexReportState.Index_Finished
        },
        "abc",
    )

    next_token = secscan.perform_indexing()

    assert next_token.min_id == Manifest.select(fn.Max(
        Manifest.id)).scalar() + 1
    assert ManifestSecurityStatus.select().count() == Manifest.select(
        fn.Max(Manifest.id)).count()
Beispiel #6
0
def test_perform_indexing_failed(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "abc"}
    secscan._secscan_api.index.return_value = (
        {
            "err": None,
            "state": IndexReportState.Index_Finished
        },
        "abc",
    )

    for manifest in Manifest.select():
        ManifestSecurityStatus.create(
            manifest=manifest,
            repository=manifest.repository,
            error_json={},
            index_status=IndexStatus.FAILED,
            indexer_hash="abc",
            indexer_version=IndexerVersion.V4,
            last_indexed=datetime.utcnow() - timedelta(
                seconds=app.config["SECURITY_SCANNER_V4_REINDEX_THRESHOLD"] +
                60),
            metadata_json={},
        )

    secscan.perform_indexing()

    assert ManifestSecurityStatus.select().count() == Manifest.select().count()
    for mss in ManifestSecurityStatus.select():
        assert mss.index_status == IndexStatus.COMPLETED
Beispiel #7
0
def test_perform_indexing_whitelist(initialized_db, set_secscan_config):
    app.config["SECURITY_SCANNER_V4_NAMESPACE_WHITELIST"] = ["devtable"]
    expected_manifests = (Manifest.select().join(Repository).join(User).where(
        User.username == "devtable"))

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "abc"}
    secscan._secscan_api.index.return_value = (
        {
            "err": None,
            "state": IndexReportState.Index_Finished
        },
        "abc",
    )

    next_token = secscan.perform_indexing()

    assert secscan._secscan_api.index.call_count == expected_manifests.count()
    for mss in ManifestSecurityStatus.select():
        assert mss.repository.namespace_user.username == "devtable"
    assert ManifestSecurityStatus.select().count() == expected_manifests.count(
    )
    assert (
        Manifest.get_by_id(next_token.min_id -
                           1).repository.namespace_user.username == "devtable")
Beispiel #8
0
def test_perform_indexing_api_request_failure_index(initialized_db):
    app.config["SECURITY_SCANNER_V4_NAMESPACE_WHITELIST"] = ["devtable"]
    expected_manifests = (
        Manifest.select(fn.Max(Manifest.id))
        .join(Repository)
        .join(User)
        .where(User.username == "devtable")
    )

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = "abc"
    secscan._secscan_api.index.side_effect = APIRequestFailure()

    next_token = secscan.perform_indexing()

    assert next_token is None
    assert ManifestSecurityStatus.select().count() == 0

    # Set security scanner to return good results and attempt indexing again
    secscan._secscan_api.index.side_effect = None
    secscan._secscan_api.index.return_value = (
        {"err": None, "state": IndexReportState.Index_Finished},
        "abc",
    )

    next_token = secscan.perform_indexing()

    assert next_token.min_id == expected_manifests.scalar() + 1
    assert ManifestSecurityStatus.select().count() == expected_manifests.count()
Beispiel #9
0
def test_perform_indexing_needs_reindexing_skip_unsupported(
        initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "new hash"}
    secscan._secscan_api.index.return_value = (
        {
            "err": None,
            "state": IndexReportState.Index_Finished
        },
        "new hash",
    )

    for manifest in Manifest.select():
        ManifestSecurityStatus.create(
            manifest=manifest,
            repository=manifest.repository,
            error_json={},
            index_status=IndexStatus.MANIFEST_UNSUPPORTED,
            indexer_hash="old hash",
            indexer_version=IndexerVersion.V4,
            last_indexed=datetime.utcnow() - timedelta(
                seconds=app.config["SECURITY_SCANNER_V4_REINDEX_THRESHOLD"] +
                60),
            metadata_json={},
        )

    secscan.perform_indexing()

    # Since this manifest should not be scanned, the old hash should remain
    assert ManifestSecurityStatus.select().count() == Manifest.select().count()
    for mss in ManifestSecurityStatus.select():
        assert mss.indexer_hash == "old hash"
Beispiel #10
0
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", include_legacy_image=True)
    manifest = registry_model.get_manifest_for_tag(tag, backfill_if_necessary=True)

    secscan = V4SecurityScanner(app, instance_keys, storage)
    assert secscan.load_security_information(manifest).status == ScanLookupStatus.NOT_YET_INDEXED
Beispiel #11
0
def test_manifest_iterator(initialized_db, set_secscan_config, index_status,
                           indexer_state, seconds, expect_zero):
    secscan = V4SecurityScanner(app, instance_keys, storage)

    for manifest in Manifest.select():
        with db_transaction():
            ManifestSecurityStatus.delete().where(
                ManifestSecurityStatus.manifest == manifest,
                ManifestSecurityStatus.repository == manifest.repository,
            ).execute()
            ManifestSecurityStatus.create(
                manifest=manifest,
                repository=manifest.repository,
                error_json={},
                index_status=index_status,
                indexer_hash="old hash",
                indexer_version=IndexerVersion.V4,
                last_indexed=datetime.utcnow() - timedelta(seconds=seconds),
                metadata_json={},
            )

    iterator = secscan._get_manifest_iterator(
        indexer_state,
        Manifest.select(fn.Min(Manifest.id)).scalar(),
        Manifest.select(fn.Max(Manifest.id)).scalar(),
    )

    count = 0
    for candidate, abt, num_remaining in iterator:
        count = count + 1

    if expect_zero:
        assert count == 0
    else:
        assert count != 0
Beispiel #12
0
def test_perform_indexing_needs_reindexing(initialized_db):
    app.config["SECURITY_SCANNER_V4_NAMESPACE_WHITELIST"] = ["devtable"]
    expected_manifests = (
        Manifest.select().join(Repository).join(User).where(User.username == "devtable")
    )

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = "xyz"
    secscan._secscan_api.index.return_value = (
        {"err": None, "state": IndexReportState.Index_Finished},
        "xyz",
    )

    for manifest in expected_manifests:
        ManifestSecurityStatus.create(
            manifest=manifest,
            repository=manifest.repository,
            error_json={},
            index_status=IndexStatus.COMPLETED,
            indexer_hash="abc",
            indexer_version=IndexerVersion.V4,
            metadata_json={},
        )

    secscan.perform_indexing()

    assert ManifestSecurityStatus.select().count() == expected_manifests.count()
    for mss in ManifestSecurityStatus.select():
        assert mss.indexer_hash == "xyz"
Beispiel #13
0
def test_perform_indexing_needs_reindexing_within_reindex_threshold(
        initialized_db, set_secscan_config):
    app.config["SECURITY_SCANNER_V4_REINDEX_THRESHOLD"] = 300

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "xyz"}
    secscan._secscan_api.index.return_value = (
        {
            "err": None,
            "state": IndexReportState.Index_Finished
        },
        "xyz",
    )

    for manifest in Manifest.select():
        ManifestSecurityStatus.create(
            manifest=manifest,
            repository=manifest.repository,
            error_json={},
            index_status=IndexStatus.COMPLETED,
            indexer_hash="abc",
            indexer_version=IndexerVersion.V4,
            metadata_json={},
        )

    secscan.perform_indexing()

    assert ManifestSecurityStatus.select().count() == Manifest.select().count()
    for mss in ManifestSecurityStatus.select():
        assert mss.indexer_hash == "abc"
Beispiel #14
0
def test_load_security_information_queued(initialized_db, set_secscan_config):
    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)

    secscan = V4SecurityScanner(app, instance_keys, storage)
    assert secscan.load_security_information(manifest).status == ScanLookupStatus.NOT_YET_INDEXED
Beispiel #15
0
def test_load_security_information_success(initialized_db, set_secscan_config):
    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)

    ManifestSecurityStatus.create(
        manifest=manifest._db_id,
        repository=repository_ref._db_id,
        error_json={},
        index_status=IndexStatus.COMPLETED,
        indexer_hash="abc",
        indexer_version=IndexerVersion.V4,
        metadata_json={},
    )

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.vulnerability_report.return_value = {
        "manifest_hash": manifest.digest,
        "state": "IndexFinished",
        "packages": {},
        "distributions": {},
        "repository": {},
        "environments": {},
        "package_vulnerabilities": {},
        "success": True,
        "err": "",
    }

    result = secscan.load_security_information(manifest)

    assert result.status == ScanLookupStatus.SUCCESS
    assert result.security_information == SecurityInformation(
        Layer(manifest.digest, "", "", 4, []))
Beispiel #16
0
def test_lookup_notification_page_invalid(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.retrieve_notification_page.return_value = None

    result = secscan.lookup_notification_page("someinvalidid")

    assert result.status == PaginatedNotificationStatus.FATAL_ERROR
Beispiel #17
0
def test_perform_indexing_api_request_failure_state(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.side_effect = APIRequestFailure()

    next_token = secscan.perform_indexing()

    assert next_token is None
    assert ManifestSecurityStatus.select().count() == 0
def test_perform_indexing_whitelist(initialized_db):
    app.config["SECURITY_SCANNER_V4_NAMESPACE_WHITELIST"] = ["devtable"]
    secscan = V4SecurityScanner(app, instance_keys, storage)

    next_token = secscan.perform_indexing()

    assert (
        Manifest.get_by_id(next_token.min_id -
                           1).repository.namespace_user.username == "devtable")
Beispiel #19
0
def test_perform_indexing_api_request_failure_state(initialized_db):
    app.config["SECURITY_SCANNER_V4_NAMESPACE_WHITELIST"] = ["devtable"]

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.side_effect = APIRequestFailure()

    next_token = secscan.perform_indexing()

    assert next_token is None
    assert ManifestSecurityStatus.select().count() == 0
Beispiel #20
0
def test_perform_indexing_invalid_manifest(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()

    # Delete all ManifestBlob rows to cause the manifests to be invalid.
    ManifestBlob.delete().execute()

    secscan.perform_indexing()

    assert ManifestSecurityStatus.select().count() == Manifest.select().count()
    for mss in ManifestSecurityStatus.select():
        assert mss.index_status == IndexStatus.MANIFEST_UNSUPPORTED
Beispiel #21
0
def test_perform_indexing_api_request_non_finished_state(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "xyz"}
    secscan._secscan_api.index.return_value = (
        {"err": "something", "state": "ScanLayers"},
        "xyz",
    )

    next_token = secscan.perform_indexing()
    assert next_token and next_token.min_id == Manifest.select(fn.Max(Manifest.id)).scalar() + 1
    assert ManifestSecurityStatus.select().count() == 0
Beispiel #22
0
def test_perform_indexing_api_request_index_error_response(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "xyz"}
    secscan._secscan_api.index.return_value = (
        {"err": "something", "state": IndexReportState.Index_Error},
        "xyz",
    )

    next_token = secscan.perform_indexing()
    assert next_token.min_id == Manifest.select(fn.Max(Manifest.id)).scalar() + 1
    assert ManifestSecurityStatus.select().count() == Manifest.select(fn.Max(Manifest.id)).count()
    for mss in ManifestSecurityStatus.select():
        assert mss.index_status == IndexStatus.FAILED
Beispiel #23
0
    def configure(self, app, instance_keys, storage):
        # TODO(alecmerdler): Just use `V4SecurityScanner` once Clair V2 is removed.
        self._model = V2SecurityScanner(app, instance_keys, storage)
        self._v4_model = V4SecurityScanner(app, instance_keys, storage)
        self._v4_namespace_whitelist = app.config.get(
            "SECURITY_SCANNER_V4_NAMESPACE_WHITELIST", [])

        logger.info("===============================")
        logger.info(
            "Using split secscan model: v4 whitelist `%s`",
            self._v4_namespace_whitelist,
        )
        logger.info("===============================")

        return self
Beispiel #24
0
def test_perform_indexing_manifest_list(initialized_db, set_secscan_config):
    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)
    Manifest.update(media_type=MediaType.get(
        name=DOCKER_SCHEMA2_MANIFESTLIST_CONTENT_TYPE)).execute()

    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()

    secscan.perform_indexing()

    assert ManifestSecurityStatus.select().count() == Manifest.select().count()
    for mss in ManifestSecurityStatus.select():
        assert mss.index_status == IndexStatus.MANIFEST_UNSUPPORTED
Beispiel #25
0
def test_perform_indexing_empty_whitelist(initialized_db):
    app.config["SECURITY_SCANNER_V4_NAMESPACE_WHITELIST"] = []
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = "abc"
    secscan._secscan_api.index.return_value = (
        {"err": None, "state": IndexReportState.Index_Finished},
        "abc",
    )

    next_token = secscan.perform_indexing()

    assert secscan._secscan_api.index.call_count == 0
    assert ManifestSecurityStatus.select().count() == 0
    assert next_token.min_id == Manifest.select(fn.Max(Manifest.id)).scalar() + 1
Beispiel #26
0
    def configure(self, app, instance_keys, storage):
        try:
            self._model = V4SecurityScanner(app, instance_keys, storage)
        except InvalidConfigurationException:
            self._model = NoopV4SecurityScanner()

        try:
            self._legacy_model = V2SecurityScanner(app, instance_keys, storage)
        except InvalidConfigurationException:
            self._legacy_model = NoopV2SecurityScanner()

        logger.info("===============================")
        logger.info("Using split secscan model: `%s`", [self._legacy_model, self._model])
        logger.info("===============================")

        return self
Beispiel #27
0
def test_perform_indexing_whitelist(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.state.return_value = {"state": "abc"}
    secscan._secscan_api.index.return_value = (
        {"err": None, "state": IndexReportState.Index_Finished},
        "abc",
    )

    next_token = secscan.perform_indexing()

    assert next_token.min_id == Manifest.select(fn.Max(Manifest.id)).scalar() + 1

    assert secscan._secscan_api.index.call_count == Manifest.select().count()
    assert ManifestSecurityStatus.select().count() == Manifest.select().count()
    for mss in ManifestSecurityStatus.select():
        assert mss.index_status == IndexStatus.COMPLETED
Beispiel #28
0
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", include_legacy_image=True)
    manifest = registry_model.get_manifest_for_tag(tag, backfill_if_necessary=True)

    ManifestSecurityStatus.create(
        manifest=manifest._db_id,
        repository=repository_ref._db_id,
        error_json='failed to fetch layers: encountered error while fetching a layer: fetcher: unknown content-type "binary/octet-stream"',
        index_status=IndexStatus.FAILED,
        indexer_hash="",
        indexer_version=IndexerVersion.V4,
        metadata_json={},
    )

    secscan = V4SecurityScanner(app, instance_keys, storage)
    assert secscan.load_security_information(manifest).status == ScanLookupStatus.FAILED_TO_INDEX
Beispiel #29
0
def test_lookup_notification_page_valid(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.retrieve_notification_page.return_value = {
        "notifications": [{
            "id": "5e4b387e-88d3-4364-86fd-063447a6fad2",
            "manifest":
            "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
            "reason": "added",
            "vulnerability": {},
        }],
        "page": {},
    }

    result = secscan.lookup_notification_page(
        "5e4b387e-88d3-4364-86fd-063447a6fad2")

    assert result.status == PaginatedNotificationStatus.SUCCESS
    assert result.next_page_index is None
    assert (
        result.data[0]["manifest"] ==
        "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a"
    )
Beispiel #30
0
def test_mark_notification_handled(initialized_db, set_secscan_config):
    secscan = V4SecurityScanner(app, instance_keys, storage)
    secscan._secscan_api = mock.Mock()
    secscan._secscan_api.delete_notification.return_value = True

    assert secscan.mark_notification_handled("somevalidid") == True