Exemplo n.º 1
0
def test_round_robin():
    db = Database()
    db.bugs.update(EXPECTED_BUGS)
    data = io.StringIO()
    db.save(data)
    data.seek(0)
    db2 = Database()
    db2.load(data)
    assert db2.bugs == EXPECTED_BUGS
Exemplo n.º 2
0
def main() -> int:
    """CLI interface for kuroneko scraper."""
    argp = argparse.ArgumentParser()
    argp.add_argument('-l', '--limit', type=int,
                      help='Limit the results to LIMIT bugs')
    argp.add_argument('-o', '--output', default='-',
                      help='Output JSON file (default: - = stdout)')
    argp.add_argument('-q', '--quiet', action='store_true',
                      help='Disable status output')
    argp.add_argument('-X', '--exclude-file', type=argparse.FileType(),
                      help='File to read list of excluded bugs from')
    args = argp.parse_args()

    if args.output == '-':
        output = sys.stdout
    else:
        output = open(args.output, 'w')
    exclude: typing.List[int] = []
    if args.exclude_file is not None:
        for line in args.exclude_file:
            line = line.strip()
            if line.startswith('#'):
                continue
            exclude.extend(int(x) for x in line.split())
    exclude_set = frozenset(exclude)

    db = Database()
    for i, bug in enumerate(find_security_bugs(limit=args.limit)):
        if bug.id in exclude_set:
            continue
        packages = sorted(split_version_ranges(
            find_package_specs(bug.summary)))
        # skip bugs with no packages
        if not packages:
            continue
        # skip RESO/INVALID bugs
        if bug.resolution == 'INVALID':
            continue
        # skip resolved bugs without specific version ranges
        resolved = bug.resolution != ''
        if resolved and not all(p[0] in '<>~=' for p
                                in itertools.chain.from_iterable(packages)):
            continue
        db.add_bug(bug=bug.id,
                   packages=packages,
                   summary=bug.summary,
                   severity=get_severity(bug.whiteboard),
                   created=bug.creation_time.split('T', 1)[0],
                   resolved=resolved)
    if not args.quiet:
        print(f'Found {i+1} bugs', file=sys.stderr)
    db.save(output)

    return 0
Exemplo n.º 3
0
def test_version_bad(version):
    db = Database()
    with pytest.raises(DatabaseError):
        db.load(io.BytesIO(JSON_DATA.format(version=version).encode()))
Exemplo n.º 4
0
def test_version_good(version):
    db = Database()
    db.load(io.BytesIO(JSON_DATA.format(version=version).encode()))
    assert db.bugs == EXPECTED_BUGS
Exemplo n.º 5
0
def test_no_magic():
    db = Database()
    with pytest.raises(DatabaseError):
        db.load(io.BytesIO(b'{"bugs": []}'))
Exemplo n.º 6
0
def test_load_database():
    db = Database()
    db.load(
        io.StringIO(
            JSON_DATA.format(version='"{}.{}"'.format(*db.SCHEMA_VERSION))))
    assert db.bugs == EXPECTED_BUGS
Exemplo n.º 7
0
def main() -> int:
    """CLI interface for kuroneko scraper."""
    colorama.init()
    argp = argparse.ArgumentParser()
    db_source = argp.add_mutually_exclusive_group()
    db_source.add_argument('-d',
                           '--database',
                           type=argparse.FileType('r'),
                           help='Use bug database from specified json file '
                           '(if not specified, database will be fetched '
                           'from --database-url)')
    db_source.add_argument('--database-url',
                           default=DEFAULT_DB_URL,
                           help=f'Fetch bug database from specified URL '
                           f'(default: {DEFAULT_DB_URL})')
    argp.add_argument('--cache-file',
                      help=f'File used to store a cached copy of bug database '
                      f'(default: {DEFAULT_CACHE_PATH})')
    argp.add_argument('-q',
                      '--quiet',
                      action='store_true',
                      help='Disable progress messages')
    args = argp.parse_args()

    # load the database
    db = Database()
    if args.database is not None:
        if not args.quiet:
            print(f'Using local database {args.database.name}',
                  file=sys.stderr)
    else:
        if not args.quiet:
            print(f'Using remote database {args.database_url}',
                  file=sys.stderr)
        if args.cache_file is None:
            os.makedirs(XDG_CACHE_HOME, exist_ok=True)
            args.cache_file = DEFAULT_CACHE_PATH
        args.database = cached_get(args.database_url, args.cache_file)
        if not args.quiet:
            if isinstance(args.database, io.BytesIO):
                print('Database update fetched', file=sys.stderr)
            else:
                print('Local cache is up-to-date', file=sys.stderr)
    db.load(args.database)
    args.database.close()

    # initialize pkgcore
    config = load_config()
    domain = config.get_default('domain')
    vdb = domain.repos_raw['vdb']

    # do a quick search for vulnerable packages
    restrict = packages_to_restriction(db)
    if not args.quiet:
        print('Searching for vulnerable packages', file=sys.stderr)
    vulnerable = vdb.match(restrict)

    # match vulnerable packages to bugs
    if not args.quiet:
        print(file=sys.stderr)
    first_one = True
    for pkg in vulnerable:
        for bug_pkg, bug in find_applicable_bugs(pkg, db):
            if first_one:
                first_one = False
            else:
                print()
            print_bug(bug, bug_pkg, pkg.cpvstr)

    return 0