Пример #1
0
def merge_results(results, scan_id=None):
    for result in results:
        logger.info('{} merge results'.format(result))

    # with db.session_scope() as session:
    #     scan = get_scan(scan_id, session)

    # After the merge we remove the folder with the scan source
    scan_dir = os.path.join(SHARED_VOLUME_PATH, scan_id)
    try:
        shutil.rmtree(scan_dir)
    except IOError as e:
        logger.error("Error while removing tmp dir: {} - {}".format(
            scan_dir, e))

    with db.session_scope() as session:
        scan = get_scan(scan_id, session)
        project = scan.project

        scan = update_scan_state(scan, ScanState.DONE, session)
        session.commit()

        if project.hook_type != ProjectHookType.NONE.name:
            # launch notify task
            logger.debug('{} launch notify task for project.hook_type'.format(
                scan.id))
            notify_results.delay(scan.id)
Пример #2
0
def add_scan_for_project_with_repo(repo_url: str, branch: str=None):
    """
    If a project with repo_url exists in the database, adds a scan to it

    :param repo_url: (str) repo url for the project to launch the scan
    :param branch: (str, Optional) branch for the project to launch the scan
    :return:
    """
    assert type(repo_url) is str

    with db.session_scope() as session:

        project = get_project_by_repo(repo_url, session)

        allowed_scan = True
        if ALLOWED_SCANS_PER_PERIOD > 0:
            previous_scans = get_num_scans_in_last_minutes(project.id, ALLOWED_SCANS_CHECK_PERIOD, session)
            allowed_scan = previous_scans < ALLOWED_SCANS_PER_PERIOD

        if allowed_scan:
            scan = add_scan(project.id, session, branch=branch)
            session.commit()

            celery = Celery('deeptracy', broker=BROKER_URI)
            celery.send_task('prepare_scan', [scan.id])
        else:
            raise APIError('cant create more scans', status_code=503)
Пример #3
0
def notify_patton_deltas(vulnerabilities):
    scan_dep_by_project_id = {}
    with db.session_scope() as session:
        for cpe in vulnerabilities:
            scan_deps_ids = []
            cves = vulnerabilities[cpe]
            for vuln_db in get_vulns_for_cpe(cpe, session):
                for scan_vuln in vuln_db.scan_vulns:
                    scan_dep = scan_vuln.scan_dep
                    scan_deps_ids.append(scan_dep.id)
                    raw_dep = scan_dep.raw_dep
                    scan = scan_dep.scan
                    project = scan.project
                    if project.id in scan_dep_by_project_id:
                        scan_dep_by_project_id[project.id]['dependencies'].append(raw_dep)
                    else:
                        scan_dep_by_project_id[project.id] = {'project': project, 'dependencies': [raw_dep]}
            for scan_dep_id in set(scan_deps_ids):
                add_vulns_in_scan_dep(cpe=cpe, cves=cves, scan_dep_id=scan_dep_id, session=session)

        for project_id in scan_dep_by_project_id:
            elem = scan_dep_by_project_id[project_id]
            dependencies = set(elem['dependencies'])
            notify_deltas(elem['project'], dependencies)
    logger.debug('notify vulnerabilities')
Пример #4
0
def get_projects():
    """List Projects

    Retrieves a list of all projects on database.

    Example:

    :return codes:  200 on success
                    404 on errors
    """
    filter = request.args.get('filter')

    with db.session_scope() as session:
        try:
            if filter:
                if filter == 'count':
                    return jsonify(project_manager.get_projects_count(session)), 200
                else:
                    return api_error_response('Filter not exists'), 400
            else:
                term = request.args.get('term')

                if term:
                    projects = project_manager.get_projects_by_name_term(term, 20, session)
                else:
                    projects = project_manager.get_projects(session)

                project_arr = [project.to_dict() for project in projects]

                return jsonify(project_arr), 200
        except Exception as exc:
            return api_error_response(exc.args[0]), 400
Пример #5
0
def post_delta():
    """Add new vulnerabilities on the database

    Add new vulnerabilities on existing project

    Example:
        Body
        {
          "project_id": "00001",
          "lang": "javascript",
          "branch": "develop" //Optional
        }

    :return codes:  201 on success
                    400 on errors
    """
    with db.session_scope() as session:
        data = request.get_json()

        if not data:
            return api_error_response('invalid payload'), 400

        celery = Celery('deeptracy', broker=BROKER_URI)
        celery.send_task('notify_patton_deltas', [data])
        return "Se ha procesado correctamente", 201
Пример #6
0
def update_project(project_id):
    """Updates a project on the database

    Update repo url on existing project

    Example:
        Body
        {"repo": "http://google.com"}

    :return codes:  201 on success
                    400 on errors
    """

    data = request.get_json()
    if not data:
        return api_error_response('invalid payload'), 400

    repo = data.get('repo', None)
    if repo is not None or repo == '':
        return api_error_response('can not update repo'), 400

    with db.session_scope() as session:
        try:
            project = project_manager.update_project(project_id, session,
                                                     **data)
            session.commit()
        except Exception as exc:
            session.rollback()
            return api_error_response(exc.args[0]), 400

        return jsonify(project.to_dict()), 201
Пример #7
0
def update_project(project_id):
    """Updates a project on the database

    Update repo url on existing project

    Example:
        Body
        {"repo": "http://google.com"}

    :return codes:  201 on success
                    400 on errors
    """

    data = request.get_json()
    if not data:
        return api_error_response('invalid payload'), 400

    repo = data.get('repo', None)
    if repo is not None or repo == '':
        return api_error_response('can not update repo'), 400

    with db.session_scope() as session:
        try:
            project = project_manager.update_project(project_id, session, **data)
            session.commit()
        except Exception as exc:
            session.rollback()
            return api_error_response(exc.args[0]), 400

        return jsonify(project.to_dict()), 201
Пример #8
0
def get_projects():
    """List Projects

    Retrieves a list of all projects on database.

    Example:

    :return codes:  200 on success
                    404 on errors
    """
    filter = request.args.get('filter')

    with db.session_scope() as session:
        try:
            if filter:
                if filter == 'count':
                    return jsonify(
                        project_manager.get_projects_count(session)), 200
                else:
                    return api_error_response('Filter not exists'), 400
            else:
                term = request.args.get('term')

                if term:
                    projects = project_manager.get_projects_by_name_term(
                        term, 20, session)
                else:
                    projects = project_manager.get_projects(session)

                project_arr = [project.to_dict() for project in projects]

                return jsonify(project_arr), 200
        except Exception as exc:
            return api_error_response(exc.args[0]), 400
Пример #9
0
def get_vulnerabilities(scan_id):
    """Get scan vulnerabilities"""
    with db.session_scope() as session:
        try:
            scan_vulnerabilities = [
                scan_vulnerability.to_dict()
                for scan_vulnerability in get_scan_vulnerabilities(
                    scan_id, session)
            ]
            response = []

            def fillResponse(scan_vulnerability):
                vulns = get_vulns_for_cpe(scan_vulnerability['cpe'], session)
                scan_dep = get_scan_dep_by_id(
                    scan_vulnerability['scan_dep_id'], session)
                return [
                    response.append({
                        'library': scan_dep.library,
                        'version': scan_dep.version,
                        'cpe': vuln.cpe,
                        'cve': vuln.cve
                    }) for vuln in vulns
                ]

            [
                fillResponse(scan_vulnerability)
                for scan_vulnerability in scan_vulnerabilities
            ]
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(response)
Пример #10
0
def scan_deps(scan_id: str):
    with db.session_scope() as session:
        logger.debug('{} extract dependencies'.format(scan_id))

        scan = get_scan(scan_id, session)

        dependencies = get_dependencies(scan.lang, scan.source_path)
        logger.debug('found dependencies {}'.format(dependencies))

        # save all dependencies in the database
        add_scan_deps(scan.id, dependencies, datetime.now(), session)
        scan.total_packages = len(dependencies)
        session.commit()
        logger.debug('saved {} dependencies'.format(len(dependencies)))

        # compare the dependencies in this scan with the last scan for this project
        previous_scan = get_previous_scan_for_project(scan.project_id, scan.id,
                                                      session)

        if previous_scan is None:
            logger.debug('no previous scan found for {}'.format(scan_id))
            deps_equals = False
        else:
            logger.debug('previous scan to {} is {}'.format(
                scan_id, previous_scan.id))
            deps_equals = compare_scan_deps(scan.id, previous_scan.id, session)

            if deps_equals:
                update_scan_state(scan, ScanState.SAME_DEPS_AS_PREVIOUS,
                                  session)
                logger.debug('{} scan has same deps as {}'.format(
                    scan_id, previous_scan.id))

    if not deps_equals:
        get_vulnerabilities.delay(scan_id)
Пример #11
0
def post_delta():
    """Add new vulnerabilities on the database

    Add new vulnerabilities on existing project

    Example:
        Body
        {
          "project_id": "00001",
          "lang": "javascript",
          "branch": "develop" //Optional
        }

    :return codes:  201 on success
                    400 on errors
    """
    with db.session_scope() as session:
        data = request.get_json()

        if not data:
            return api_error_response('invalid payload'), 400

        celery = Celery('deeptracy', broker=BROKER_URI)
        celery.send_task('notify_patton_deltas', [data])
        return "Se ha procesado correctamente", 201
Пример #12
0
def get_vulnerabilities(scan_id):
    """Get scan vulnerabilities"""
    with db.session_scope() as session:
        try:
            scan_vulnerabilities = [scan_vulnerability.to_dict() for scan_vulnerability in get_scan_vulnerabilities(scan_id, session)]
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(scan_vulnerabilities)
Пример #13
0
def post_project():
    """Adds a project to the database

    It receive a Project in the body as a json object and tries to create the project in the database

    Example:
        Body
        {"repo": "http://google.com"}

    :return codes:  201 on success
                    400 on errors
                    409 on a duplicate repo
    """

    data = request.get_json()
    if not data:
        return api_error_response('invalid payload'), 400

    repo = data.get('repo', None)
    if repo is None or repo == '':
        return api_error_response('missing repo'), 400
    else:
        data.pop('repo')  # repo should not be present in data

    name = data.get('name', None)
    if name is None or name == '':
        name = repo.split('/')[-1]
    if data.get('name'):
        data.pop('name')  # name should not be present in data

    email = data.get('email', None)
    if email is not None:
        hook_type = ProjectHookType.EMAIL.name
        hook_data = {"email": email}
    else:
        hook_type = ProjectHookType.NONE.name
        hook_data = {}

    with db.session_scope() as session:
        try:
            project = project_manager.add_project(repo,
                                                  name,
                                                  session,
                                                  hook_type=hook_type,
                                                  hook_data=hook_data,
                                                  **data)
            session.commit()
        except Exception as exc:
            session.rollback()
            if 'unique constraint "project_repo_key"' in exc.args[0]:
                return api_error_response(
                    'unique constraint project repo {}'.format(repo)), 409
            else:
                return api_error_response(exc.args[0]), 400

        return jsonify(project.to_dict()), 201
Пример #14
0
def get_vulnerabilities(scan_id: str):
    with db.session_scope() as session:
        logger.debug('{} extract dependencies'.format(scan_id))

        scan_deps = get_scan_deps(scan_id, session)
        scan = get_scan(scan_id, session)
        project = scan.project

        url = '{}/api/v1/check-dependencies?cpeDetailed=1'.format(PATTON_URI)
        req_body = {
            'method':
            'auto',
            'source':
            'auto',
            'libraries': [{
                'library': scan_dep.library,
                'version': scan_dep.version
            } for scan_dep in scan_deps]
        }
        response = requests.post(url, json=req_body).json()

        total_vulnerabilities = 0
        if response:
            for key in response:
                if response[key]:
                    [library, version] = key.split(':')
                    scan_dep = get_scan_dep_by_scan_id_and_raw_dep(
                        scan_id, '{}:{}'.format(library, version), session)
                    cpes = response[key]
                    for cpe_dict in cpes['cpes']:
                        cpe = cpe_dict['cpe']
                        cves = cpe_dict['cves']
                        total_vulnerabilities += len(cves)
                        # save all dependencies in the database
                        add_scan_vuln(scan_dep.id, scan.id, scan.lang, cpe,
                                      cves, session)
                        logger.info('saved {cves} cves for cpe {cpe}'.format(
                            cves=len(cves), cpe=cpe))

        scan.total_vulnerabilities = total_vulnerabilities
        update_scan_state(scan, ScanState.DONE, session)
        session.commit()

        # After the merge we remove the folder with the scan source
        scan_dir = os.path.join(SHARED_VOLUME_PATH, scan_id)
        try:
            shutil.rmtree(scan_dir)
        except IOError as e:
            logger.error("Error while removing tmp dir: {} - {}".format(
                scan_dir, e))
        if project.hook_type != ProjectHookType.NONE.name:
            # launch notify task
            logger.debug('{} launch notify task for project.hook_type'.format(
                scan.id))

            notify_results.delay(scan.id)
Пример #15
0
def notify_results(scan_id):
    with db.session_scope() as session:
        scan = get_scan(scan_id, session)
        scan_vulns = set([
            scan_vuln.scan_dep.raw_dep
            for scan_vuln in get_scan_vulnerabilities(scan_id, session)
        ])
        project = scan.project

        logger.debug('notify project data {}'.format(project.hook_data))
        notify_scan_results(project, scan_vulns)
Пример #16
0
def notify_results(scan_id):
    with db.session_scope() as session:
        scan = get_scan(scan_id, session)
        scan_vulns = [
            '{}:{}'.format(scan_vuln.library, scan_vuln.version)
            for scan_vuln in get_scan_vulnerabilities(scan_id, session)
        ]
        project = scan.project

        logger.debug('notify project data {}'.format(project.hook_data))
        notify_scan_results(project, scan_vulns)
Пример #17
0
def notify_results(scan_id):
    with db.session_scope() as session:
        scan = get_scan(scan_id, session)
        project = scan.project

        logger.debug('notify project data {}'.format(project.hook_data))

        notif_text = 'project at {} has vulnerabilities'.format(project.repo)

        if project.hook_type == ProjectHookType.SLACK.name:
            hook_data_dict = json.loads(project.hook_data)
            slack.notify(hook_data_dict.get('webhook_url'), notif_text)
Пример #18
0
def post_scan():
    """Add a scan on the database

    Add a scan language on existing project

    Example:
        Body
        {
          "project_id": "00001",
          "lang": "javascript",
          "branch": "develop" //Optional
        }

    :return codes:  201 on success
                    400 on errors
    """
    with db.session_scope() as session:
        data = request.get_json()
        if not data:
            return api_error_response('invalid payload'), 400

        project_id = get_required_field(data, 'project_id')
        lang = data.get('lang', None)

        branch = data.get('branch', None)
        if branch is None or branch == '':
            branch = 'master'
        else:
            project = get_project(project_id, session)
            command = 'git ls-remote --ref {}'.format(project.repo)

        # if defined, limit the number of scans that can be created by a given period for the same project
        logger.debug(' allowed scans per period {}/{}'.format(
            ALLOWED_SCANS_PER_PERIOD, ALLOWED_SCANS_CHECK_PERIOD))
        allowed_scan = True
        if ALLOWED_SCANS_PER_PERIOD > 0:
            previous_scans = get_num_scans_in_last_minutes(
                project_id, ALLOWED_SCANS_CHECK_PERIOD, session)
            allowed_scan = previous_scans < ALLOWED_SCANS_PER_PERIOD

        if allowed_scan:
            scan = add_scan(project_id, session, lang=lang, branch=branch)
            session.commit()

            # when the scan is added to the database, a celery task is inserted for that scan to start the process
            celery = Celery('deeptracy', broker=BROKER_URI)
            celery.send_task('prepare_scan', [scan.id])

            return jsonify(scan.to_dict()), 201
        else:
            return api_error_response('cant create more scans'), 403
Пример #19
0
def prepare_scan(scan_id: str):
    with db.session_scope() as session:
        logger.info('{} START SCAN'.format(scan_id))
        scan = get_scan(scan_id, session)
        project = scan.project

        logger.debug('{} for project({})'.format(scan_id, project.id))

        try:
            # clone the repository in a shared volume
            cloned_dir = clone_project(config.SHARED_VOLUME_PATH, scan_id,
                                       project.repo, project.repo_auth_type,
                                       scan.branch)
            scan.source_path = cloned_dir
            session.add(scan)
            logger.debug('{} cloned dir {}'.format(scan_id, cloned_dir))
        except Exception as e:
            update_scan_state(scan, ScanState.INVALID_BRANCH, session)
            session.commit()

            logger.error(str(e))
            raise e

        # if a .deeptracy.yml is found, parse it to a dictionary
        try:
            deeptracy_yml = parse_deeptracy_yml(cloned_dir)
            logger.debug('{} .deeptracy.yml {}'.format(
                scan_id, 'TRUE' if deeptracy_yml else 'FALSE'))
        except Exception as e:
            update_scan_state(scan, ScanState.INVALID_YML_ON_PROJECT, session)
            session.commit()
            logger.error('{} unable to parse .deeptracy.yml'.format(scan_id))
            raise e

        # the language for a scan can be specified on the scan of in the deeptracy file in the sources
        if scan.lang is None:
            if deeptracy_yml is None:
                update_scan_state(scan, ScanState.CANT_GET_LANGUAGE, session)
                session.commit()
                logger.debug(
                    '{} unable to retrieve language for scan'.format(scan_id))
                raise TaskException('unable to retrieve language for scan')
            else:
                lang = deeptracy_yml.get(
                    'lang')  # the parse ensures us a valid lang in the dict
                scan.lang = lang  # update the san object to store the language
                session.add(scan)

    # once the scan is ready continue with the dependency extraction

    scan_deps.delay(scan_id)
def get_vulnerabilities(scan_id: str):
    with db.session_scope() as session:
        logger.debug('{} extract dependencies'.format(scan_id))

        scan_deps = get_scan_deps(scan_id, session)
        scan_deps_len = len(scan_deps)

        scan = get_scan(scan_id, session)
        project = scan.project

        total_vulnerabilities = []

        def get_response(i, scan_dep):
            [package, version] = scan_dep.raw_dep.split(':')
            url = '{}/batch'.format(PATTON_URI)

            response = requests.post(url, json=[[package, version]]).json()
            print(response)
            logger.info("Procesado {} de {}".format(i, scan_deps_len))

            if response:
                for key in response:
                    if response[key]:
                        total_vulnerabilities.append([package, version])
                        # save all dependencies in the database
                        add_scan_vul(scan.id, package, version, response[key], session)
                        session.commit()
                        logger.info('saved {vulnerabilities} vulnerabilities for package {package}:{version}'.format(
                            vulnerabilities=len(response), package=package, version=version))

        [get_response(i, scan_dep) for i, scan_dep in enumerate(scan_deps)]

        scan.total_vulnerabilities = len(total_vulnerabilities)
        update_scan_state(scan, ScanState.DONE, session)
        session.commit()

        # After the merge we remove the folder with the scan source
        scan_dir = os.path.join(SHARED_VOLUME_PATH, scan_id)
        try:
            shutil.rmtree(scan_dir)
        except IOError as e:
            logger.error("Error while removing tmp dir: {} - {}".format(
                scan_dir,
                e
            ))
        if project.hook_type != ProjectHookType.NONE.name:
            # launch notify task
            logger.debug('{} launch notify task for project.hook_type'.format(scan.id))

            notify_results.delay(scan.id)
Пример #21
0
def post_project():
    """Adds a project to the database

    It receive a Project in the body as a json object and tries to create the project in the database

    Example:
        Body
        {"repo": "http://google.com"}

    :return codes:  201 on success
                    400 on errors
                    409 on a duplicate repo
    """

    data = request.get_json()
    if not data:
        return api_error_response('invalid payload'), 400

    repo = data.get('repo', None)
    if repo is None or repo == '':
        return api_error_response('missing repo'), 400
    else:
        data.pop('repo')  # repo should not be present in data

    name = data.get('name', None)
    if name is None or name == '':
        name = repo.split('/')[-1]
    if data.get('name'):
        data.pop('name')  # name should not be present in data

    email = data.get('email', None)
    if email is not None:
        hook_type = ProjectHookType.EMAIL.name
        hook_data = {"email": email}
    else:
        hook_type = ProjectHookType.NONE.name
        hook_data = {}

    with db.session_scope() as session:
        try:
            project = project_manager.add_project(repo, name, session, hook_type=hook_type, hook_data=hook_data, **data)
            session.commit()
        except Exception as exc:
            session.rollback()
            if 'unique constraint "project_repo_key"' in exc.args[0]:
                return api_error_response('unique constraint project repo {}'.format(repo)), 409
            else:
                return api_error_response(exc.args[0]), 400

        return jsonify(project.to_dict()), 201
Пример #22
0
def post_scan():
    """Add a scan on the database

    Add a scan language on existing project

    Example:
        Body
        {
          "project_id": "00001",
          "lang": "javascript",
          "branch": "develop" //Optional
        }

    :return codes:  201 on success
                    400 on errors
    """
    with db.session_scope() as session:
        data = request.get_json()
        if not data:
            return api_error_response('invalid payload'), 400

        project_id = get_required_field(data, 'project_id')
        lang = data.get('lang', None)

        branch = data.get('branch', None)
        if branch is None or branch == '':
            branch = 'master'
        else:
            project = get_project(project_id, session)
            command = 'git ls-remote --ref {}'.format(project.repo)

        # if defined, limit the number of scans that can be created by a given period for the same project
        logger.debug(' allowed scans per period {}/{}'.format(ALLOWED_SCANS_PER_PERIOD, ALLOWED_SCANS_CHECK_PERIOD))
        allowed_scan = True
        if ALLOWED_SCANS_PER_PERIOD > 0:
            previous_scans = get_num_scans_in_last_minutes(project_id, ALLOWED_SCANS_CHECK_PERIOD, session)
            allowed_scan = previous_scans < ALLOWED_SCANS_PER_PERIOD

        if allowed_scan:
            scan = add_scan(project_id, session, lang=lang, branch=branch)
            session.commit()

            # when the scan is added to the database, a celery task is inserted for that scan to start the process
            celery = Celery('deeptracy', broker=BROKER_URI)
            celery.send_task('prepare_scan', [scan.id])

            return jsonify(scan.to_dict()), 201
        else:
            return api_error_response('cant create more scans'), 403
Пример #23
0
def get_project(project_id):
    """Show Requested Project

    Queries and returns a project with a passed ID

    Example:

    :return codes:  200 on success
                    404 on errors
    """
    with db.session_scope() as session:
        try:
            project = project_manager.get_project(project_id, session)
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(project.to_dict()), 200
Пример #24
0
def get_project(project_id):
    """Show Requested Project

    Queries and returns a project with a passed ID

    Example:

    :return codes:  200 on success
                    404 on errors
    """
    with db.session_scope() as session:
        try:
            project = project_manager.get_project(project_id, session)
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(project.to_dict()), 200
Пример #25
0
def delete_projects():
    """Remove a project on the database

    Tries to delete the project that you specified in the endpoint on the database

    :return codes:  204 on success (no content)
                    400 on errors
    """
    with db.session_scope() as session:
        try:
            project_manager.delete_projects(session)
            session.commit()
        except Exception as exc:
            session.rollback()
            return api_error_response(exc.args[0]), 400

        return '', 204
Пример #26
0
def get_scans_by_project_id(project_id):
    """Show Requested Scans by Project

    Queries and returns all scans in a project with a passed ID

    Example:

    :return codes:  200 on success
                    404 on errors
    """
    with db.session_scope() as session:
        try:
            scans = [scan.to_dict() for scan in project_manager.get_project(project_id, session).scans]
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(scans), 200
Пример #27
0
def delete_projects():
    """Remove a project on the database

    Tries to delete the project that you specified in the endpoint on the database

    :return codes:  204 on success (no content)
                    400 on errors
    """
    with db.session_scope() as session:
        try:
            project_manager.delete_projects(session)
            session.commit()
        except Exception as exc:
            session.rollback()
            return api_error_response(exc.args[0]), 400

        return '', 204
Пример #28
0
def notify_patton_deltas(dependencies):
    scan_dep_by_project_id = {}
    with db.session_scope() as session:
        for raw_dep in dependencies:
            scan_deps = get_scan_by_raw_dep(raw_dep, session)
            for scan_dep in scan_deps:
                project = scan_dep.scan.project
                if project.id in scan_dep_by_project_id:
                    scan_dep_by_project_id[project.id]['dependencies'].append(
                        raw_dep)
                else:
                    scan_dep_by_project_id[project.id] = {
                        'project': project,
                        'dependencies': [raw_dep]
                    }
        for project_id in scan_dep_by_project_id:
            elem = scan_dep_by_project_id[project_id]
            notify_deltas(elem['project'], elem['dependencies'])
    logger.debug('notify vulnerabilities')
Пример #29
0
def start_scan(scan_id: str):
    with db.session_scope() as session:
        logger.info('{} START SCAN'.format(scan_id))
        scan = get_scan(scan_id, session)
        project = scan.project

        logger.debug('{} for project({})'.format(scan_id, project.id))

        # for the lang, get the plugins that can be run
        available_plugins_for_lang = get_plugins_for_lang(scan.lang, session)
        analysis_count = len(available_plugins_for_lang)

        if analysis_count < 1:
            update_scan_state(scan, ScanState.NO_PLUGINS_FOR_LANGUAGE, session)
            logger.debug('{} no plugins found for language {}'.format(
                scan_id, scan.lang))
            raise TaskException('no plugins found for language {}'.format(
                scan.lang))

        # when we have the lang, the number of analysis to run and the source code dir, update the scan
        scan.analysis_count = analysis_count
        scan.analysis_done = 0
        scan.state = ScanState.RUNNING.name
        session.add(scan)
        session.commit()  # save at this point as we need the ID for this scan

        # save each analysis to be ran for this scan in the database and collect its ids
        scan_analysis_ids = []
        for plugin in available_plugins_for_lang:
            scan_analysis = add_scan_analysis(scan.id, plugin.id, session)
            session.commit(
            )  # Commit the session to persist the scan_analysis and get and id
            scan_analysis_ids.append(scan_analysis.id)

    # create a task for each analysis to run
    analyzers = [
        run_analyzer.s(scan_analysis_id)
        for scan_analysis_id in scan_analysis_ids
    ]

    # launch all jobs
    chord(analyzers)(merge_results.s(scan_id=scan_id))
Пример #30
0
def get_scans_by_project_id(project_id):
    """Show Requested Scans by Project

    Queries and returns all scans in a project with a passed ID

    Example:

    :return codes:  200 on success
                    404 on errors
    """
    with db.session_scope() as session:
        try:
            scans = [
                scan.to_dict() for scan in project_manager.get_project(
                    project_id, session).scans
            ]
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(scans), 200
Пример #31
0
def patch_project_email(project_id):
    """Update the user email for the Project

    Update the email for the project with project_id

    Example:

    :return codes:  200 on success
                    404 on errors
    """
    with db.session_scope() as session:
        data = request.get_json()
        if not data:
            return api_error_response('invalid payload'), 400

        email = data.get('email', None)
        if email is None or email == '':
            return api_error_response('missing remail'), 400

        try:
            project = project_manager.get_project(project_id, session)
            hook_type = project.hook_type
            if project.hook_data:
                hook_data_dict = json.loads(project.hook_data)
            else:
                hook_data_dict = {}

            if hook_type == ProjectHookType.NONE.name:
                hook_type = ProjectHookType.EMAIL.name
            elif hook_type == ProjectHookType.SLACK.name:
                hook_type = ProjectHookType.SLACK_EMAIL.name

            hook_data_dict['email'] = email
            project_manager.update_project(project_id,
                                           session,
                                           hook_type=hook_type,
                                           hook_data=hook_data_dict)
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(project.to_dict()), 200
Пример #32
0
def run_analyzer(scan_analysis_id: str) -> List[str]:
    with db.session_scope() as session:
        scan_analysis = get_scan_analysis(scan_analysis_id, session)

        logger.debug('{} run analyzer'.format(scan_analysis.id))

        scan = scan_analysis.scan

        # a plugin is a function
        plugin = plugin_store.get_plugin(scan_analysis.plugin_id)
        logger.debug('{} run analyzer for plugin {}'.format(scan_analysis.id, scan_analysis.plugin_id))
        results = plugin(scan.source_path)
        add_scan_vulnerabilities_results(scan_analysis_id, results, session)

        # TODO: this should be a function that calls the celery state instead of cherrypicking a counter that can lose
        # integrity if something wrong happen
        scan.analysis_done += 1
        session.add(scan)

        serialized_results = [result.to_dict() for result in results]
        return serialized_results
Пример #33
0
def patch_project_email(project_id):
    """Update the user email for the Project

    Update the email for the project with project_id

    Example:

    :return codes:  200 on success
                    404 on errors
    """
    with db.session_scope() as session:
        data = request.get_json()
        if not data:
            return api_error_response('invalid payload'), 400

        email = data.get('email', None)
        if email is None or email == '':
            return api_error_response('missing remail'), 400

        try:
            project = project_manager.get_project(project_id, session)
            hook_type = project.hook_type
            if project.hook_data:
                hook_data_dict = json.loads(project.hook_data)
            else:
                hook_data_dict = {}

            if hook_type == ProjectHookType.NONE.name:
                hook_type = ProjectHookType.EMAIL.name
            elif hook_type == ProjectHookType.SLACK.name:
                hook_type = ProjectHookType.SLACK_EMAIL.name

            hook_data_dict['email'] = email
            project_manager.update_project(project_id, session, hook_type=hook_type, hook_data=hook_data_dict)
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(project.to_dict()), 200
Пример #34
0
def get_vulnerabilities(scan_id):
    """Get scan vulnerabilities"""
    with db.session_scope() as session:
        try:
            scan_vulnerabilities = [scan_vulnerability.to_dict() for scan_vulnerability in get_scan_vulnerabilities(scan_id, session)]
            response = []

            def fillResponse(scan_vulnerability):
                vulns = get_vulns_for_cpe(scan_vulnerability['cpe'], session)
                scan_dep = get_scan_dep_by_id(scan_vulnerability['scan_dep_id'], session)
                return [response.append(
                    {
                        'library': scan_dep.library,
                        'version': scan_dep.version,
                        'cpe': vuln.cpe,
                        'cve': vuln.cve
                    }) for vuln in vulns]

            [ fillResponse(scan_vulnerability) for scan_vulnerability in scan_vulnerabilities]
        except Exception as exc:
            return api_error_response(exc.args[0]), 404

        return jsonify(response)
Пример #35
0
def delete_project(project_id):
    """Remove a project on the database

    Tries to delete the project that you specified in the endpoint on the database

    :return codes:  204 on success (no content)
                    404 on errors (not found)
    """
    with db.session_scope() as session:
        project = session.query(Project).get(project_id)

        try:
            if project:
                project_manager.delete_project(project_id, session)
                session.commit()
            else:
                return api_error_response('project not found'), 404

        except Exception as exc:
            session.rollback()
            return api_error_response(exc.args[0]), 404

        return '', 204
Пример #36
0
def delete_project(project_id):
    """Remove a project on the database

    Tries to delete the project that you specified in the endpoint on the database

    :return codes:  204 on success (no content)
                    404 on errors (not found)
    """
    with db.session_scope() as session:
        project = session.query(Project).get(project_id)

        try:
            if project:
                project_manager.delete_project(project_id, session)
                session.commit()
            else:
                return api_error_response('project not found'), 404

        except Exception as exc:
            session.rollback()
            return api_error_response(exc.args[0]), 404

        return '', 204