def _get_latest_package_version(package): """ Get the latest package version available on pypi for a package. It is retried multiple times in case there are transient failures in executing the command. :param package: str Name of the package whose latest version must be retrieved :return: tuple(command_success: bool, latest_version_value: str) """ pypi_package_info = requests.get(f"https://pypi.org/pypi/{package}/json") data = json.loads(pypi_package_info.text) versions = data["releases"].keys() return str(max(Version(v) for v in versions))
def test_safety(image): """ Runs safety check on a container with the capability to ignore safety issues that cannot be fixed, and only raise error if an issue is fixable. """ from dlc.safety_check import SafetyCheck safety_check = SafetyCheck() repo_name, image_tag = image.split('/')[-1].split(':') ignore_ids_list = _get_safety_ignore_list(image) sep = " -i " ignore_str = "" if not ignore_ids_list else f"{sep}{sep.join(ignore_ids_list)}" container_name = f"{repo_name}-{image_tag}-safety" docker_exec_cmd = f"docker exec -i {container_name}" test_file_path = os.path.join(CONTAINER_TESTS_PREFIX, "testSafety") # Add null entrypoint to ensure command exits immediately run( f"docker run -id " f"--name {container_name} " f"--mount type=bind,src=$(pwd)/container_tests,target=/test " f"--entrypoint='/bin/bash' " f"{image}", hide=True) try: run(f"{docker_exec_cmd} pip install safety yolk3k ", hide=True) json_str_safety_result = safety_check.run_safety_check_on_container( docker_exec_cmd) safety_result = json.loads(json_str_safety_result) for package, affected_versions, curr_version, _, vulnerability_id in safety_result: # Get the latest version of the package with vulnerability command_success, latest_version = _get_latest_package_version( docker_exec_cmd, package) if not command_success: continue # If the latest version of the package is also affected, ignore this vulnerability if Version(latest_version) in SpecifierSet(affected_versions): # Version(x) gives an object that can be easily compared with another version, or with a SpecifierSet. # Comparing two versions as a string has some edge cases which require us to write more code. # SpecifierSet(x) takes a version constraint, such as "<=4.5.6", ">1.2.3", or ">=1.2,<3.4.5", and # gives an object that can be easily compared against a Version object. # https://packaging.pypa.io/en/latest/specifiers/ ignore_str += f" -i {vulnerability_id}" assert (safety_check.run_safety_check_with_ignore_list(docker_exec_cmd, ignore_str) == 0), \ f"Safety test failed for {image}" finally: run(f"docker rm -f {container_name}", hide=True)
def test_safety(image): """ Runs safety check on a container with the capability to ignore safety issues that cannot be fixed, and only raise error if an issue is fixable. """ repo_name, image_tag = image.split('/')[-1].split(':') ignore_ids_list = _get_safety_ignore_list(image) ignore_str = "" if not ignore_ids_list else " ".join(ignore_ids_list) container_name = f"{repo_name}-{image_tag}-safety" docker_exec_cmd = f"docker exec -i {container_name}" test_file_path = os.path.join(CONTAINER_TESTS_PREFIX, "testSafety") # Add null entrypoint to ensure command exits immediately run(f"docker run -id " f"--name {container_name} " f"--mount type=bind,src=$(pwd)/container_tests,target=/test " f"--entrypoint='/bin/bash' " f"{image}", hide=True) try: run(f"{docker_exec_cmd} pip install safety yolk3k ", hide=True) run_out = run(f"{docker_exec_cmd} safety check --json ", warn=True, hide=True) json_str_safety_result = run_out.stdout safety_result = json.loads(json_str_safety_result) for package, affected_versions, curr_version, _, vulnerability_id in safety_result: run_out = run(f"{docker_exec_cmd} yolk -M {package} -f version ", warn=True, hide=True) if run_out.return_code != 0: continue latest_version = run_out.stdout if Version(latest_version) in SpecifierSet(affected_versions): # Version(x) gives an object that can be easily compared with another version, or with a SpecifierSet. # Comparing two versions as a string has some edge cases which require us to write more code. # SpecifierSet(x) takes a version constraint, such as "<=4.5.6", ">1.2.3", or ">=1.2,<3.4.5", and # gives an object that can be easily compared against a Version object. # https://packaging.pypa.io/en/latest/specifiers/ ignore_str += f" {vulnerability_id}" run(f"{docker_exec_cmd} chmod +x {test_file_path}", hide=True) output = run(f"{docker_exec_cmd} {test_file_path} {ignore_str} ", warn=True) LOGGER.info(f"{test_file_path} log for {image}\n{output.stdout}") assert output.return_code == 0, f"Safety test failed for {image}\n{output.stdout}" finally: run(f"docker rm -f {container_name}", hide=True)