def check(key, db, full_report, stdin, files, cache): if files and stdin: click.secho( "Can't read from --stdin and --file at the same time, exiting", fg="red") sys.exit(-1) if files: packages = itertools.chain.from_iterable( read_requirements(f, resolve=True) for f in files) elif stdin: packages = read_requirements(sys.stdin) else: packages = pip.get_installed_distributions() try: vulns = safety.check(packages=packages, key=key, db_mirror=db, cached=cache) click.secho(report(vulns=vulns, full=full_report)) sys.exit(-1 if vulns else 0) except InvalidKeyError: click.secho("Your API Key is invalid", fg="red") sys.exit(-1) except DatabaseFileNotFoundError: click.secho( "Unable to load vulnerability database from {db}".format(db=db), fg="red") sys.exit(-1) except DatabaseFetchError: click.secho("Unable to load vulnerability database", fg="red") sys.exit(-1)
def test_check_live_cached(self): from safety.constants import CACHE_FILE # lets clear the cache first try: with open(CACHE_FILE, 'w') as f: f.write(json.dumps({})) except Exception: pass reqs = StringIO("insecure-package==0.1") packages = util.read_requirements(reqs) vulns, _ = safety.check(packages=packages, key=None, db_mirror=False, cached=60 * 60, ignore_vulns={}, ignore_severity_rules=None, proxy={}, telemetry=False) self.assertEqual(len(vulns), 1) reqs = StringIO("insecure-package==0.1") packages = util.read_requirements(reqs) # make a second call to use the cache vulns, _ = safety.check(packages=packages, key=None, db_mirror=False, cached=60 * 60, ignore_vulns={}, ignore_severity_rules=None, proxy={}, telemetry=False) self.assertEqual(len(vulns), 1)
def test_check_live_cached(self): reqs = StringIO("insecure-package==0.1") packages = util.read_requirements(reqs) vulns = safety.check( packages=packages, db_mirror=False, cached=True, key=False, ignore_ids=[], proxy={}, ) self.assertEqual(len(vulns), 1) reqs = StringIO("insecure-package==0.1") packages = util.read_requirements(reqs) # make a second call to use the cache vulns = safety.check( packages=packages, db_mirror=False, cached=True, key=False, ignore_ids=[], proxy={}, ) self.assertEqual(len(vulns), 1)
def test_check_live_down_cached(self): reqs = StringIO("insecure-package==0.1") packages = util.read_requirements(reqs) vulns = safety.check( packages=packages, db_mirror=False, cached=True, key=False, ignore_ids=[], proxy={} ) self.assertEqual(len(vulns), 1) reqs = StringIO("insecure-package==0.1") packages = util.read_requirements(reqs) # make a second call, where server responds with 400 error, so use # the cache vulns = safety.check( packages=packages, db_mirror="http://pyup.io/", cached=False, key=False, ignore_ids=[], proxy={} ) self.assertEqual(len(vulns), 1)
def check(key, db, json, full_report, bare, stdin, files, pipfile, cache, ignore, output, proxyprotocol, proxyhost, proxyport): if (files or pipfile) and stdin: click.secho("Can't read from --stdin and --file at the same time, exiting", fg="red", file=sys.stderr) sys.exit(-1) if files: packages = list(itertools.chain.from_iterable(read_requirements(f, resolve=True) for f in files)) elif pipfile: packages = list(read_pipfile(pipfile)) elif stdin: packages = list(read_requirements(sys.stdin)) else: import pkg_resources packages = [ d for d in pkg_resources.working_set if d.key not in {"python", "wsgiref", "argparse"} ] proxy_dictionary = {} if proxyhost is not None: if proxyprotocol in ["http", "https"]: proxy_dictionary = {proxyprotocol: "{0}://{1}:{2}".format(proxyprotocol, proxyhost, str(proxyport))} else: click.secho("Proxy Protocol should be http or https only.", fg="red") sys.exit(-1) try: vulns = safety.check(packages=packages, key=key, db_mirror=db, cached=cache, ignore_ids=ignore, proxy=proxy_dictionary) output_report = report(vulns=vulns, full=full_report, json_report=json, bare_report=bare, checked_packages=len(packages), db=db, key=key) if output: with open(output, 'w+') as output_file: output_file.write(output_report) else: click.secho(output_report, nl=False if bare and not vulns else True) sys.exit(-1 if vulns else 0) except InvalidKeyError: click.secho("Your API Key '{key}' is invalid. See {link}".format( key=key, link='https://goo.gl/O7Y1rS'), fg="red", file=sys.stderr) sys.exit(-1) except DatabaseFileNotFoundError: click.secho("Unable to load vulnerability database from {db}".format(db=db), fg="red", file=sys.stderr) sys.exit(-1) except DatabaseFetchError: click.secho("Unable to load vulnerability database", fg="red", file=sys.stderr) sys.exit(-1)
def license(key, db, cache, files, proxyprotocol, proxyhost, proxyport): if files: packages = list(itertools.chain.from_iterable(read_requirements(f, resolve=True) for f in files)) else: import pkg_resources packages = [ d for d in pkg_resources.working_set if d.key not in {"python", "wsgiref", "argparse"} ] proxy_dictionary = get_proxy_dict(proxyprotocol, proxyhost, proxyport) try: licenses_db = safety.get_licenses(key, db, cache, proxy_dictionary) except InvalidKeyError: click.secho("Your API Key '{key}' is invalid. See {link}".format( key=key, link='https://goo.gl/O7Y1rS'), fg="red", file=sys.stderr) sys.exit(-1) except DatabaseFileNotFoundError: click.secho("Unable to load licenses database from {db}".format(db=db), fg="red", file=sys.stderr) sys.exit(-1) except TooManyRequestsError: click.secho("Unable to load licenses database (Too many requests, please wait before another request)", fg="red", file=sys.stderr ) sys.exit(-1) except DatabaseFetchError: click.secho("Unable to load licenses database", fg="red", file=sys.stderr) sys.exit(-1) filtered_packages_licenses = get_packages_licenses(packages, licenses_db) output_report = license_report(packages=packages, licenses=filtered_packages_licenses) click.secho(output_report, nl=True)
def test_get_packages_licenses(self): reqs = StringIO("Django==1.8.1\n\rinvalid==1.0.0") packages = util.read_requirements(reqs) licenses_db = safety.get_licenses( db_mirror=os.path.join( os.path.dirname(os.path.realpath(__file__)), "test_db" ), cached=False, key="foobarqux", proxy={}, ) self.assertIn("licenses", licenses_db) self.assertIn("packages", licenses_db) self.assertIn("BSD-3-Clause", licenses_db['licenses']) self.assertIn("django", licenses_db['packages']) pkg_licenses = util.get_packages_licenses(packages, licenses_db) self.assertIsInstance(pkg_licenses, list) for pkg_license in pkg_licenses: license = pkg_license['license'] version = pkg_license['version'] if pkg_license['package'] == 'django': self.assertEqual(license, 'BSD-3-Clause') self.assertEqual(version, '1.8.1') elif pkg_license['package'] == 'invalid': self.assertEqual(license, 'N/A') self.assertEqual(version, '1.0.0') else: raise AssertionError( "unexpected package '" + pkg_license['package'] + "' was found" )
def test_report_licenses_bare(self): from safety.formatter import license_report reqs = StringIO("Django==1.8.1\n\rinexistent==1.0.0") packages = util.read_requirements(reqs) # Using DB: test.test_db.licenses.json licenses_db = safety.get_licenses( db_mirror=os.path.join( os.path.dirname(os.path.realpath(__file__)), "test_db" ), cached=False, key=None, proxy={}, ) pkgs_licenses = util.get_packages_licenses(packages, licenses_db) output_report = license_report( packages=packages, licenses=pkgs_licenses, json_report=False, bare_report=True ) self.assertEqual(output_report, "BSD-3-Clause")
def test_unpinned_vcs_requirement(self): """ https://github.com/pyupio/safety/issues/72 """ # this shouldn't raise an error content = StringIO("-e git+https://github.com/jdunck/python-unicodecsv#egg=unicodecsv") result = list(read_requirements(content)) self.assertEqual(len(result), 0)
def check(key, db, json, full_report, bare, stdin, files, cache, ignore): if files and stdin: click.secho( "Can't read from --stdin and --file at the same time, exiting", fg="red") sys.exit(-1) if files: packages = list( itertools.chain.from_iterable( read_requirements(f, resolve=True) for f in files)) elif stdin: packages = list(read_requirements(sys.stdin)) else: packages = get_installed_distributions() try: vulns = safety.check(packages=packages, key=key, db_mirror=db, cached=cache, ignore_ids=ignore) click.secho( report(vulns=vulns, full=full_report, json_report=json, bare_report=bare, checked_packages=len(packages), db=db, key=key)) sys.exit(-1 if vulns else 0) except InvalidKeyError: click.secho("Your API Key '{key}' is invalid. See {link}".format( key=key, link='https://goo.gl/O7Y1rS'), fg="red") sys.exit(-1) except DatabaseFileNotFoundError: click.secho( "Unable to load vulnerability database from {db}".format(db=db), fg="red") sys.exit(-1) except DatabaseFetchError: click.secho("Unable to load vulnerability database", fg="red") sys.exit(-1)
def test_check_live(self): reqs = StringIO("insecure-package==0.1") packages = util.read_requirements(reqs) vulns = safety.check(packages=packages, db_mirror=False, cached=False, key=False) self.assertEqual(len(vulns), 1)
def test_recursive_requirement(self): """ https://github.com/pyupio/safety/issues/132 """ # this should find 2 bad packages dirname = os.path.dirname(__file__) test_filename = os.path.join(dirname, "reqs_1.txt") with open(test_filename) as fh: result = list(read_requirements(fh, resolve=True)) self.assertEqual(len(result), 2)
def test_check_from_file(self): reqs = StringIO("Django==1.8.1") packages = util.read_requirements(reqs) vulns = safety.check(packages=packages, db_mirror=os.path.join( os.path.dirname(os.path.realpath(__file__)), "test_db"), cached=False, key=False) self.assertEqual(len(vulns), 2)
def test_multiple_versions(self): reqs = StringIO("Django==1.8.1\n\rDjango==1.7.0") packages = util.read_requirements(reqs) vulns = safety.check(packages=packages, db_mirror=os.path.join( os.path.dirname(os.path.realpath(__file__)), "test_db"), cached=False, key=False, ignore_ids=[]) self.assertEqual(len(vulns), 4)
def safety(): # noqa: WPS430 packages = list(read_requirements(StringIO(requirements))) vulns = safety_check(packages=packages, ignore_ids="", key="", db_mirror="", cached=False, proxy={}) output_report = report(vulns=vulns, full=True, checked_packages=len(packages)) if vulns: print(output_report)
def test_check_live(self): reqs = StringIO("insecure-package==0.1") packages = util.read_requirements(reqs) vulns, _ = safety.check(packages=packages, key=None, db_mirror=False, cached=0, ignore_vulns={}, ignore_severity_rules=None, proxy={}, telemetry=False) self.assertEqual(len(vulns), 1)
def check_vulns(): packages = list(read_requirements(StringIO(requirements))) vulns = safety.check(packages=packages, ignore_ids="41002", key="", db_mirror="", cached=False, proxy={}) output_report = report(vulns=vulns, full=True, checked_packages=len(packages)) print(vulns) if vulns: print(output_report)
def check(key, db, json, full_report, bare, stdin, files, cache, ignore): if files and stdin: click.secho("Can't read from --stdin and --file at the same time, exiting", fg="red") sys.exit(-1) if files: packages = list(itertools.chain.from_iterable(read_requirements(f, resolve=True) for f in files)) elif stdin: packages = list(read_requirements(sys.stdin)) else: packages = get_installed_distributions() try: vulns = safety.check(packages=packages, key=key, db_mirror=db, cached=cache, ignore_ids=ignore) click.secho(report( vulns=vulns, full=full_report, json_report=json, bare_report=bare, checked_packages=len(packages), db=db, key=key ) ) sys.exit(-1 if vulns else 0) except InvalidKeyError: click.secho("Your API Key '{key}' is invalid. See {link}".format( key=key, link='https://goo.gl/O7Y1rS'), fg="red") sys.exit(-1) except DatabaseFileNotFoundError: click.secho("Unable to load vulnerability database from {db}".format(db=db), fg="red") sys.exit(-1) except DatabaseFetchError: click.secho("Unable to load vulnerability database", fg="red") sys.exit(-1)
def test_report_licenses_json(self, get_report_brief_info): get_report_brief_info.return_value = { 'scan_target': 'environment', 'scanned': ['/usr/local/lib/python3.9/site-packages'], 'api_key': True, 'packages_found': 2, 'timestamp': '2022-03-03 16:31:30', 'safety_version': '2.0.0.dev6' } reqs = StringIO("Django==1.8.1\n\rinexistent==1.0.0") packages = util.read_requirements(reqs) # Using DB: test.test_db.licenses.json licenses_db = safety.get_licenses(db_mirror=os.path.join( os.path.dirname(os.path.realpath(__file__)), "test_db"), cached=0, key=None, proxy={}, telemetry=False) pkgs_licenses = util.get_packages_licenses(packages, licenses_db) output_report = SafetyFormatter(output='json').render_licenses( [], pkgs_licenses) expected_result = json.dumps( { "report_meta": { "scan_target": "environment", "scanned": ["/usr/local/lib/python3.9/site-packages"], "api_key": True, "packages_found": 2, "timestamp": "2022-03-03 16:31:30", "safety_version": "2.0.0.dev6" }, "announcements": [], "licenses": [{ "package": "django", "version": "1.8.1", "license": "BSD-3-Clause" }, { "package": "inexistent", "version": "1.0.0", "license": "unknown", }] }, indent=4) # Packages without license are reported as "N/A" self.assertEqual(output_report.rstrip(), expected_result)
def test_check_from_file(self): reqs = StringIO("Django==1.8.1") packages = util.read_requirements(reqs) vulns, _ = safety.check( packages=packages, key=None, db_mirror=os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_db"), cached=0, ignore_vulns={}, ignore_severity_rules=None, proxy={}, telemetry=False) self.assertEqual(len(vulns), 2)
def parse(file_name): reqs = [] try: with open(file_name) as fh: for item in read_requirements(fh): if isinstance(item, SafetyPackage): reqs.append(item) elif isinstance(item, SafetyRequirementFile): for other_file in parse(item.path): yield other_file if reqs: yield RequirementFile(project=self, requirements=reqs, path=file_name) except: pass
def test_multiple_versions(self): # Probably used for external tools using safety.check directly reqs = StringIO("Django==1.8.1\n\rDjango==1.7.0") packages = util.read_requirements(reqs) vulns, _ = safety.check( packages=packages, key=None, db_mirror=os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_db"), cached=0, ignore_vulns={}, ignore_severity_rules=None, proxy={}, telemetry=False) self.assertEqual(len(vulns), 4)
def test_check_from_file_with_hash_pins(self): reqs = StringIO(( "Django==1.8.1 " "--hash=sha256:c6c7e7a961e2847d050d214ca96dc3167bb5f2b25cd5c6cb2eea96e1717f4ade" )) packages = util.read_requirements(reqs) vulns = safety.check(packages=packages, db_mirror=os.path.join( os.path.dirname(os.path.realpath(__file__)), "test_db"), cached=False, key=False, ignore_ids=[], proxy={}) self.assertEqual(len(vulns), 2)
def test_report_licenses_bare(self): reqs = StringIO("Django==1.8.1\n\rinexistent==1.0.0") packages = util.read_requirements(reqs) # Using DB: test.test_db.licenses.json licenses_db = safety.get_licenses(db_mirror=os.path.join( os.path.dirname(os.path.realpath(__file__)), "test_db"), cached=0, key=None, proxy={}, telemetry=False) pkgs_licenses = util.get_packages_licenses(packages, licenses_db) output_report = SafetyFormatter(output='bare').render_licenses( [], pkgs_licenses) self.assertEqual(output_report, "BSD-3-Clause unknown")
def test_report_licenses_json(self): from safety.formatter import license_report reqs = StringIO("Django==1.8.1\n\rinexistent==1.0.0") packages = util.read_requirements(reqs) # Using DB: test.test_db.licenses.json licenses_db = safety.get_licenses( db_mirror=os.path.join( os.path.dirname(os.path.realpath(__file__)), "test_db" ), cached=False, key=None, proxy={}, ) pkgs_licenses = util.get_packages_licenses(packages, licenses_db) output_report = license_report( packages=packages, licenses=pkgs_licenses, json_report=True, bare_report=False ) expected_result = json.dumps( [{ "license": "BSD-3-Clause", "package": "django", "version": "1.8.1" }, { "license": "N/A", "package": "inexistent", "version": "1.0.0" }], indent=4, sort_keys=True ) # Packages without license are reported as "N/A" self.assertEqual(output_report.rstrip(), expected_result)