Example #1
0
def test_db_tool_data_insert_with_versions(config, caplog):
    caplog.set_level(logging.DEBUG)
    test_db = ToolDatabase(config)
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        n_tools = test_db.get_tools()
        assert len(n_tools) == 1
        assert len(n_tools[0].versions) == 2
        n_versions = n_tools[0].versions
        assert n_versions[0].version == FAKE_VERSION_INFO_NO_CHECKER.get(
            "version")
        assert n_versions[0].version_type == FAKE_VERSION_INFO_NO_CHECKER.get(
            "version_type")
        assert n_versions[0].source == FAKE_VERSION_INFO_NO_CHECKER.get(
            "source")
        assert n_versions[0].tags == FAKE_VERSION_INFO_NO_CHECKER.get("tags")
        # DB insert should not update time - should tell information of origin update time
        assert n_versions[0].updated == FAKE_VERSION_INFO_NO_CHECKER.get(
            "updated")
        assert n_versions[0].raw_size() == FAKE_VERSION_INFO_NO_CHECKER.get(
            "size")
        # Duplicate insert, should be handled gracefully
        test_db.insert_tool_info(tool_obj)
        n_tools = test_db.get_tools()
        # Still two versions
        assert len(n_tools[0].versions) == 2
Example #2
0
def test_insert_meta_data(caplog, config):
    """Insert metadata of checker"""
    caplog.set_level(logging.DEBUG)
    test_db = ToolDatabase(config)
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    assert isinstance(ver2.source, UpstreamChecker)

    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        test_db.insert_meta_info(tool_obj.name, tool_obj.location,
                                 FAKE_CHECKER_CONF)
        meta_data = test_db.get_meta_information(
            tool_obj.name, FAKE_CHECKER_CONF.get("provider"))[0]
        assert meta_data.get("uri") == FAKE_CHECKER_CONF.get("uri")
        assert meta_data.get("repository") == FAKE_CHECKER_CONF.get(
            "repository")
        assert meta_data.get("tool") == FAKE_CHECKER_CONF.get("tool")
        assert meta_data.get("provider") == FAKE_CHECKER_CONF.get("provider")
        assert meta_data.get("method") == FAKE_CHECKER_CONF.get("method")
        assert meta_data.get("suite") == FAKE_CHECKER_CONF.get("suite")
        assert meta_data.get("origin") == FAKE_CHECKER_CONF.get("origin")
        assert meta_data.get("docker_origin") == FAKE_CHECKER_CONF.get(
            "docker_origin")
def test_version_info_from_dict():
    obj = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    obj_dict = dict(obj)
    obj = VersionInfo.from_dict(obj_dict)
    assert obj.version == "0.9"
    assert obj.source == "no_checker_case"
    assert obj.tags == set(["latest-stable", "latest"])
    assert obj.updated == datetime(2020, 3, 3, 13, 37)
    assert obj.size == "39.53 MB"

    with pytest.raises(TypeError):
        VersionInfo.from_dict("not_dict")
def test_version_info_eq():
    obj1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    obj2 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    assert obj1 == obj2
    obj1.version = 1.2
    assert obj1 != obj2
    # We can compare for strings.
    assert obj1 == "1.2"
    assert obj1 != "1.3"
    # But not integers
    with pytest.raises(ValueError):
        assert obj1 != 1
def test_getters_version_info_no_checker():
    obj = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)

    assert obj.version == "0.9"
    assert obj.provider == "no_checker_case"
    assert not obj.docker_origin
    assert obj.extra_info == ""
    assert obj.source == "no_checker_case"
    assert not obj.origin
    assert obj.tags == set(["latest", "latest-stable"])
    assert obj.updated == datetime(2020, 3, 3, 13, 37)
    assert obj.size == "39.53 MB"
    assert obj.raw_size() == 39529754
Example #6
0
def test_tool_info_latest_version():
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)

    assert tool_obj.get_latest() == "0.9"
    assert tool_obj.get_latest(in_upstream=True) == "1.1"

    # No versions at all
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    assert tool_obj.get_latest() == VersionInfo("undefined", VersionType.UNDEFINED, "", set(), datetime.min)
Example #7
0
def test_failed_constraints_meta_data(caplog, base_db):
    caplog.set_level(logging.DEBUG)
    # Null tool data
    tmp_conf = deepcopy(FAKE_CHECKER_CONF)
    tmp_conf["tool"] = None
    tmp_checker = {
        "version": "1.9",
        "version_type": VersionType.REMOTE,
        "source": "no_checker_case",
        "tags": {"latest", "latest-stable"},
        "updated": datetime(
            2021,
            3,
            3,
            13,
            37,
        ),
        "size": 89529754,
    }
    with pytest.raises(sqlite3.IntegrityError):
        with base_db.transaction():
            base_db.insert_version_info(ToolInfo(**FAKE_TOOL_INFO),
                                        VersionInfo(**tmp_checker))
            base_db.insert_meta_info(FAKE_TOOL_INFO.get("name"),
                                     FAKE_TOOL_INFO.get("location"), tmp_conf)
        # Rollback should happen, inserted version not found
        version = base_db.get_versions_by_tool(
            FAKE_TOOL_INFO.get("name"),
            provider=tmp_checker.get("source"),
            latest=True)
        assert version.version != "1.9"
        tools = base_db.get_tools()
        assert len(tools[0].versions) == 2
Example #8
0
def test_db_insert_duplicate_version(caplog, config):
    caplog.set_level(logging.DEBUG)
    test_db = ToolDatabase(config)
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    cp_FAKE_VERSION_INFO_NO_CHECKER = deepcopy(FAKE_VERSION_INFO_NO_CHECKER)
    cp_FAKE_VERSION_INFO_NO_CHECKER["version"] = "1.1"
    ver3 = VersionInfo(**cp_FAKE_VERSION_INFO_NO_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)
    tool_obj.versions.append(ver3)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        tools_db = test_db.get_tools()
        assert len(tools_db[0].versions) == 2
Example #9
0
def test_tool_info_from_dict():
    t_info = ToolInfo(**FAKE_TOOL_INFO)
    t_info.versions.append(VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER))
    t_info.versions.append(VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER))
    t_info_dict = dict(t_info)
    t_info_from_dict = ToolInfo.from_dict(t_info_dict)
    assert t_info.name == t_info_from_dict.name
    assert t_info.updated == t_info_from_dict.updated
    assert t_info.location == t_info_from_dict.location
    assert t_info.versions[1].version == t_info_from_dict.versions[1].version
    assert t_info.versions[1].version == "1.1"

    with pytest.raises(TypeError):
        ToolInfo.from_dict("not_dict")

    assert json.dumps(t_info, cls=ToolInfoEncoder)
Example #10
0
def base_db(caplog, config):
    caplog.set_level(logging.DEBUG)
    # Make sample database for other tests
    test_db = ToolDatabase(config)
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        tool_obj2 = ToolInfo(**FAKE_TOOL_INFO2)
        tool_obj2.versions.append(ver1)
        tool_obj2.versions.append(ver2)
        test_db.insert_tool_info(tool_obj2)
    yield test_db
def test_create_version_info_no_checker():
    """
    Test init method and attribute content
    """
    obj = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    assert obj._version == "0.9"
    assert obj._source == "no_checker_case"
    assert obj._tags == {"latest", "latest-stable"}
    assert obj._updated == datetime(2020, 3, 3, 13, 37)
    assert obj._origin is False
    fake_d = FAKE_VERSION_INFO_NO_CHECKER.copy()
    fake_d["updated"] = "invalid_dateformat"
    with pytest.raises(ValueError):
        VersionInfo(**fake_d)
    fake_d["updated"] = FAKE_VERSION_INFO_NO_CHECKER.get("updated")
    with pytest.raises(ValueError):
        v_obj = VersionInfo(**fake_d)
        v_obj.version_type = ""
Example #12
0
def test_get_latest_version_by_provider(base_db):
    tmp_checker = {
        "version": "1.9",
        "version_type": VersionType.REMOTE,
        "source": "no_checker_case",
        "tags": {"latest", "latest-stable"},
        "updated": datetime(
            2021,
            3,
            3,
            13,
            37,
        ),
        "size": 89529754,
    }
    with base_db.transaction():
        base_db.insert_version_info(ToolInfo(**FAKE_TOOL_INFO),
                                    VersionInfo(**tmp_checker))
        version = base_db.get_versions_by_tool(
            FAKE_TOOL_INFO.get("name"),
            provider=tmp_checker.get("source"),
            latest=True)
        assert version.version == "1.9"
        versions = base_db.get_versions_by_tool(
            FAKE_TOOL_INFO.get("name"),
            provider=tmp_checker.get("source"),
            latest=False)
        assert len(versions) == 2
        # Replace existing record with identical data but different date
        tmp_checker["updated"] = datetime(
            2018,
            3,
            3,
            13,
            37,
        )
        base_db.insert_version_info(ToolInfo(**FAKE_TOOL_INFO),
                                    VersionInfo(**tmp_checker))
        version = base_db.get_versions_by_tool(
            FAKE_TOOL_INFO.get("name"),
            provider=tmp_checker.get("source"),
            latest=True)
        assert version.version == "0.9"
Example #13
0
def test_tool_info_iter():
    t_info = ToolInfo(**FAKE_TOOL_INFO)
    t_info.versions.append(VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER))
    t_info.versions.append(VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER))
    t_info_dict = dict(t_info)

    assert t_info_dict.get("name") == "test_tool"
    assert t_info_dict.get("updated") == "2020-03-13T13:37:00"
    assert t_info_dict.get("location") == "test_location"
    assert t_info_dict.get("description") == "test_description"
    assert t_info_dict.get("versions")[0] == {
        "version": "0.9",
        "version_type": VersionType.REMOTE.value,
        "source": "no_checker_case",
        "tags": ["latest", "latest-stable"],
        "updated": format_time(datetime(2020, 3, 3, 13, 37,)),
        "size": "39.53 MB",
        "origin": False,
    }
def test_create_version_info_with_checker():
    """
    Test init and attribute content
    """
    obj = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    obj._source.reset_mock()
    assert isinstance(obj._source, UpstreamChecker)
    assert obj.provider == "test_provider"
    assert obj.docker_origin
    assert obj.extra_info == "Test information"
    assert obj.version == "1.1"
Example #15
0
def test_create_tool_info():
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)

    assert tool_obj.name == "test_tool"
    assert tool_obj.updated == datetime(2020, 3, 13, 13, 37)
    assert tool_obj.location == "test_location"
    assert tool_obj.description == "test_description"

    assert tool_obj.versions[0].version == "0.9"
    assert tool_obj.versions[1].version == "1.1"

    assert len(tool_obj.versions) == 2

    with pytest.raises(ValueError):
        ToolInfo("", datetime.now(), "test-location")

    with pytest.raises(ValueError):
        ToolInfo(1234, datetime.now(), "test-location")
Example #16
0
def test_tool_info_eq():
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj2 = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj2.versions.append(ver2)

    # Same name and version
    assert tool_obj == tool_obj2
    # Different version
    tool_obj.versions[0].version = "NOT_SAME"
    assert tool_obj != tool_obj2

    # Test different names
    tool_obj = ToolInfo(**FAKE_TOOL_INFO2)
    tool_obj.versions.append(ver1)
    assert tool_obj != tool_obj2

    # Invalid type comparison
    with pytest.raises(ValueError):
        assert tool_obj == "Heheehe"
Example #17
0
def test_tool_info_origin_version():
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)

    assert tool_obj.get_origin_version() == VersionInfo(
        "Not implemented", VersionType.UNDEFINED, "", set(), datetime.min
    )
    assert tool_obj.get_docker_origin_version() == VersionInfo(
        "Not implemented", VersionType.UNDEFINED, "", set(), datetime.min
    )

    tool_obj.versions.append(ver2)

    assert tool_obj.get_origin_version() == "1.1"
    # Above fetch updated timestamp when getting 1.2 version with 'get_version' method, because
    # timestamp was older than 1 hour
    # However, this is mock object, and does not update original object as real UpstreamCheck
    # Object would do - therefore we are getting version 1.1 in next fetch, because VersionInfo
    # has timestamp updated
    assert tool_obj.get_docker_origin_version() == "1.1"
    def update_versions_from_manifest_by_tags(
            self, tool_name: str, tag_names: List[str]) -> List[VersionInfo]:
        """
        By given tag name list, fetches corresponding manifests and generates version info
        """
        available_versions: List[VersionInfo] = []
        # Get token only once for one tool because speed
        token = self._get_registry_service_token(tool_name)
        for t in tag_names:
            manifest = self.fetch_manifest(tool_name, t, token)
            if not manifest:
                continue
            container_config = self.fetch_image_config(tool_name,
                                                       manifest.config.digest,
                                                       token)
            if not container_config:
                continue
            size = sum([layer.size for layer in manifest.layers])
            if manifest:
                version = self._get_version_from_image_config(container_config)
                updated = parse_file_time(container_config.created)
                # Get meta data from latest image for upstream checking, skip big files (1MB+). Should be only file
                # on final layer
                if t == self.config.tag and manifest.layers[
                        -1].size < self.config.meta_max_size:
                    meta_blob_resp = self.fetch_blob(
                        tool_name, manifest.layers[-1].digest, token)
                    meta_parsed = self._parse_meta_file(
                        meta_blob_resp, tool_name)
                    if meta_parsed and isinstance(meta_parsed, Dict):
                        self.cache_meta_data.put(
                            (basename(tool_name), self.registry_name,
                             meta_parsed))
                if not version:
                    version = self.VER_UNDEFINED
                match = [v for v in available_versions if version == v.version]
                if match:
                    next(iter(match)).tags.add(t)
                else:
                    ver_info = VersionInfo(version,
                                           VersionType.REMOTE,
                                           self.registry_name, {t},
                                           updated,
                                           size=size)
                    available_versions.append(ver_info)

        return available_versions
def test_version_info_iter():
    obj = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    obj.updated = datetime.now()
    test_dict = {
        "version": "1.1",
        "version_type": "upstream",
        "source": {
            "uri": "https://test.uri",
            "repository": "test_repository",
            "tool": "test_tool",
            "provider": "test_provider",
            "method": "test_release",
            "suite": "test_suite",
            "origin": True,
            "docker_origin": True,
            "version": "1.1",
            "extra_info": "Test information",
        },
        "tags": ["latest", "latest-stable"],
        "updated": format_time(obj.updated),
        "origin": True,
        "size": "3.95 MB",
    }
    assert dict(obj) == test_dict
    obj = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    obj.updated = datetime.now()
    test_dict2 = {
        "version": "0.9",
        "version_type": "remote",
        "source": "no_checker_case",
        "tags": ["latest", "latest-stable"],
        "updated": format_time(obj.updated),
        "origin": False,
        "size": "39.53 MB",
    }
    assert dict(obj) == test_dict2

    assert json.dumps(test_dict)
    assert json.dumps(test_dict2)
def test_version_info_str():
    obj = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    assert str(obj) == "0.9"
def test_version_info_format():
    obj1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    assert f"{obj1}" == "0.9"
def test_setters_version_info_no_checker():
    obj = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    assert obj.source == "no_checker_case"
    obj.source = "new case"
    assert obj.source == "new case"
    assert obj.version == "0.9"
    obj.version = 1.2
    assert obj.version == "1.2"
    with pytest.raises(ValueError):
        obj.version = ""

    obj.updated = datetime(2020, 1, 1, 11, 11)
    obj.updated == datetime(2020, 1, 1, 11, 11)
    # Test invalid time format
    with pytest.raises(ValueError):
        obj.updated = ""

    # size
    with pytest.raises(ValueError):
        obj.size = "16062006"

    obj._size = None
    assert obj.size == "NaN"
    obj.size = 900
    assert obj.size == "900 bytes"
    obj.size = 1001
    assert obj.size == "1.00 KB"
    obj.size = 16062
    assert obj.size == "16.06 KB"
    obj.size = 16062006
    assert obj.size == "16.06 MB"
    obj.size = 1606200600
    assert obj.size == "1.61 GB"

    obj_c = FAKE_VERSION_INFO_NO_CHECKER.copy()
    obj_c["size"] = "This is something"
    obj = VersionInfo(**obj_c)
    assert obj.size == "NaN"
def test_version_info_normalization():
    obj1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    assert obj1.get_normalized_ver() == [0, 9]
    obj1.version = "1.2.3.4.5.6"
    assert obj1.get_normalized_ver() == [1, 2, 3, 4, 5, 6]
    obj1.version = "1_2_3_4"
    assert obj1.get_normalized_ver() == [1, 2, 3, 4]
    obj1.version = "ghidra_9.1.2_PUBLIC_20200212"
    assert obj1.get_normalized_ver() == [9, 1, 2]
    obj1.version = "release-1.2.3"
    assert obj1.get_normalized_ver() == [1, 2, 3]
    # sha1 test - 40 char
    obj1.version = "ee9f16b4b95c28f8f79a39ca6a1840d8a6444c10"
    assert obj1.get_normalized_ver(
    ) == "ee9f16b4b95c28f8f79a39ca6a1840d8a6444c10"
    # sha256 test - 64 char
    obj1.version = "f8b09fba9fda9ffebae86611261cf628bd71022fb4348d876974f7c48ddcc6d5"
    assert (obj1.get_normalized_ver() ==
            "f8b09fba9fda9ffebae86611261cf628bd71022fb4348d876974f7c48ddcc6d5")
    # missing couple characters from sha256 length
    obj1.version = "f809fba9fda9ffebae86611261cf628bd71022fb4348d876974f7c48ddcc65"
    assert obj1.get_normalized_ver() == [809998661126162871022434887697474865]

    obj1.version = "ABCDEFG"
    assert obj1.get_normalized_ver() == "ABCDEFG"