def wrapper(db, *args, **kwargs): issue_objs = [] for issue in issues: issue_objs.append(db.get_or_create(CVE, id=issue)) max_severity = highest_severity( [issue.severity for issue in issue_objs]) for num in range(1, count + 1): group = CVEGroup() if id: group.id = id if count <= 1 else '{}{}'.format(id, num) group.status = status if status else affected_to_status( Affected.affected, packages[0], fixed) group.severity = severity if severity else max_severity group.affected = affected group.fixed = fixed group.bug_ticket = bug_ticket group.reference = reference group.notes = notes group.created = created group.advisory_qualified = advisory_qualified db.session.add(group) db.session.commit() for issue in issue_objs: db.get_or_create(CVEGroupEntry, group=group, cve=issue) for pkgname in packages: db.get_or_create(CVEGroupPackage, pkgname=pkgname, group=group) db.session.commit() func(db=db, *args, **kwargs)
def recalc_group_severity(): updated = [] entries = (db.session.query( CVEGroup, CVEGroupEntry, CVE).join(CVEGroupEntry).join(CVE).group_by( CVEGroupEntry.group_id).group_by(CVE.id)).all() issues = defaultdict(set) for group, entry, issue in entries: issues[group].add(issue) for group, issues in issues.items(): new_severity = highest_severity([issue.severity for issue in issues]) if group.severity is not new_severity: updated.append(dict(group=group, old_severity=group.severity)) group.severity = new_severity db.session.commit() return updated
def add_group(): form = GroupForm() if not form.validate_on_submit(): return render_template('form/group.html', title='Add AVG', form=form, CVEGroup=CVEGroup) issue_ids = multiline_to_list(form.cve.data) issue_ids = set(filter(lambda s: s.startswith('CVE-'), issue_ids)) existing_issues = CVE.query.filter(CVE.id.in_(issue_ids)).all() existing_issue_ids = [issue.id for issue in existing_issues] pkgnames = multiline_to_list(form.pkgnames.data) # check if a package with a CVE clashes with an existing group if not form.force_creation.data: same_group = (db.session.query(CVEGroup, CVE, CVEGroupPackage).join( CVEGroupEntry, CVEGroup.issues).join(CVE, CVEGroupEntry.cve).join( CVEGroupPackage, CVEGroup.packages).filter( CVEGroupPackage.pkgname.in_(pkgnames))) if issue_ids: same_group = same_group.filter(CVE.id.in_(issue_ids)) same_group = same_group.all() if same_group: for group, cve, package in same_group: flash( ERROR_GROUP_WITH_ISSUE_EXISTS.format( group.id, cve.id, package.pkgname), 'warning') return render_template('form/group.html', title='Add AVG', form=form, CVEGroup=CVEGroup, show_force_creation=True) for cve_id in list( filter(lambda issue: issue not in existing_issue_ids, issue_ids)): cve = db.create(CVE, id=cve_id) existing_issues.append(cve) flash('Added {}'.format(cve.id)) fixed = form.fixed.data affected = Affected.fromstring(form.status.data) status = affected_to_status(affected, pkgnames[0], fixed) severity = highest_severity([issue.severity for issue in existing_issues]) advisory_qualified = form.advisory_qualified.data and status is not Status.not_affected group = db.create(CVEGroup, affected=form.affected.data, status=status, fixed=fixed, bug_ticket=form.bug_ticket.data, reference=form.reference.data, notes=form.notes.data, severity=severity, advisory_qualified=advisory_qualified) for cve in existing_issues: db.create(CVEGroupEntry, group=group, cve=cve) for pkgname in pkgnames: db.get_or_create(CVEGroupPackage, pkgname=pkgname, group=group) flash('Added {}'.format(pkgname)) db.session.commit() flash('Added {}'.format(group.name)) return redirect('/{}'.format(group.name))
def edit_cve(cve): entries = (db.session.query(CVE, CVEGroup, Advisory) .filter(CVE.id == cve) .outerjoin(CVEGroupEntry, CVEGroupEntry.cve_id == CVE.id) .outerjoin(CVEGroup, CVEGroupEntry.group) .outerjoin(CVEGroupPackage, CVEGroup.packages) .outerjoin(Advisory, Advisory.group_package_id == CVEGroupPackage.id)).all() if not entries: return not_found() cve = entries[0][0] groups = set(group for (cve, group, advisory) in entries if group) advisories = set(advisory for (cve, group, advisory) in entries if advisory) if not user_can_edit_issue(advisories): return forbidden() form = CVEForm(edit=True) if not form.is_submitted(): form.cve.data = cve.id form.issue_type.data = cve.issue_type form.description.data = cve.description form.severity.data = cve.severity.name form.remote.data = cve.remote.name form.reference.data = cve.reference form.notes.data = cve.notes if not form.validate_on_submit(): if advisories: flash('WARNING: This is referenced by an already published advisory!', 'warning') return render_template('form/cve.html', title='Edit {}'.format(cve), form=form, CVE=CVE) severity = Severity.fromstring(form.severity.data) severity_changed = cve.severity != severity issue_type_changed = cve.issue_type != form.issue_type.data cve.issue_type = form.issue_type.data cve.description = form.description.data cve.severity = severity cve.remote = Remote.fromstring(form.remote.data) cve.reference = form.reference.data cve.notes = form.notes.data if severity_changed or issue_type_changed: # update cached group severity for all goups containing this issue group_ids = [group.id for group in groups] issues = (db.session.query(CVEGroup, CVE) .join(CVEGroupEntry, CVEGroup.issues) .join(CVE, CVEGroupEntry.cve) .group_by(CVEGroup.id).group_by(CVE.id)) if group_ids: issues = issues.filter(CVEGroup.id.in_(group_ids)) issues = (issues).all() if severity_changed: group_severity = defaultdict(list) for group, issue in issues: group_severity[group].append(issue.severity) for group, severities in group_severity.items(): group.severity = highest_severity(severities) # update scheduled advisories if the issue type changes if advisories and issue_type_changed: group_issue_type = defaultdict(set) for group, issue in issues: group_issue_type[group].add(issue.issue_type) for advisory in advisories: if Publication.published == advisory.publication: continue issue_types = group_issue_type[advisory.group_package.group] issue_type = 'multiple issues' if len(issue_types) > 1 else next(iter(issue_types)) advisory.advisory_type = issue_type if db.session.is_modified(cve): flash('Edited {}'.format(cve.id)) db.session.commit() return redirect('/{}'.format(cve.id))
def edit_group(avg): group_id = avg.replace('AVG-', '') group_data = (db.session.query(CVEGroup, CVE, func.group_concat(CVEGroupPackage.pkgname, ' '), Advisory) .filter(CVEGroup.id == group_id) .join(CVEGroupEntry, CVEGroup.issues) .join(CVE, CVEGroupEntry.cve) .join(CVEGroupPackage, CVEGroup.packages) .outerjoin(Advisory, Advisory.group_package_id == CVEGroupPackage.id) .group_by(CVEGroup.id).group_by(CVE.id).group_by(CVEGroupPackage.pkgname) .order_by(CVE.id)).all() if not group_data: return not_found() group = group_data[0][0] issues = set([cve for (group, cve, pkg, advisory) in group_data]) issue_ids = set([cve.id for cve in issues]) pkgnames = set(chain.from_iterable([pkg.split(' ') for (group, cve, pkg, advisory) in group_data])) advisories = set(advisory for (group, cve, pkg, advisory) in group_data if advisory) if not user_can_edit_group(advisories): return forbidden() form = GroupForm(pkgnames) if not form.is_submitted(): form.affected.data = group.affected form.fixed.data = group.fixed form.pkgnames.data = "\n".join(sorted(pkgnames)) form.status.data = status_to_affected(group.status).name form.reference.data = group.reference form.notes.data = group.notes form.bug_ticket.data = group.bug_ticket form.advisory_qualified.data = group.advisory_qualified and group.status is not Status.not_affected issue_ids = sorted(issue_ids, key=issue_to_numeric) form.cve.data = "\n".join(issue_ids) if not form.validate_on_submit(): if advisories: flash('WARNING: This is referenced by an already published advisory!', 'warning') return render_template('form/group.html', title='Edit {}'.format(avg), form=form, CVEGroup=CVEGroup) pkgnames_edited = multiline_to_list(form.pkgnames.data) group.affected = form.affected.data group.fixed = form.fixed.data group.status = affected_to_status(Affected.fromstring(form.status.data), pkgnames_edited[0], group.fixed) group.bug_ticket = form.bug_ticket.data group.reference = form.reference.data group.notes = form.notes.data group.advisory_qualified = form.advisory_qualified.data and group.status is not Status.not_affected cve_ids = multiline_to_list(form.cve.data) cve_ids = set(filter(lambda s: s.startswith('CVE-'), cve_ids)) issues_removed = set(filter(lambda issue: issue not in cve_ids, issue_ids)) issues_added = set(filter(lambda issue: issue not in issue_ids, cve_ids)) issues_final = set(filter(lambda issue: issue.id not in issues_removed, issues)) issues_changed = any(issues_added) or any(issues_removed) # remove old issues for issue in filter(lambda issue: issue.cve_id in issues_removed, list(group.issues)): group.issues.remove(issue) flash('Removed {}'.format(issue.cve_id)) # add new issues severities = [issue.severity for issue in list(filter(lambda issue: issue.id not in issues_removed, issues))] for cve_id in issues_added: # TODO check if we can avoid this by the latter append call cve = db.get(CVE, id=cve_id) if not cve: cve = CVE.new(id=cve_id) db.get_or_create(CVEGroupEntry, group=group, cve=cve) flash('Added {}'.format(cve.id)) severities.append(cve.severity) issues_final.add(cve) group.severity = highest_severity(severities) pkgnames_removed = set(filter(lambda pkgname: pkgname not in pkgnames_edited, pkgnames)) pkgnames_added = set(filter(lambda pkgname: pkgname not in pkgnames, pkgnames_edited)) pkgnames_changed = any(pkgnames_removed) or any(pkgnames_added) # remove old packages for pkg in filter(lambda pkg: pkg.pkgname in pkgnames_removed, list(group.packages)): group.packages.remove(pkg) flash('Removed {}'.format(pkg.pkgname)) # add new packages for pkgname in pkgnames_added: db.get_or_create(CVEGroupPackage, pkgname=pkgname, group=group) flash('Added {}'.format(pkgname)) # update scheduled advisories for advisory in advisories: if Publication.published == advisory.publication: continue issue_type = 'multiple issues' if len(set([issue.issue_type for issue in issues_final])) > 1 else next(iter(issues_final)).issue_type advisory.advisory_type = issue_type # update changed date on modification if pkgnames_changed or issues_changed or db.session.is_modified(group): group.changed = datetime.utcnow() flash('Edited {}'.format(group.name)) db.session.commit() return redirect('/{}'.format(group.name))
def edit_cve(cve): entries = (db.session.query( CVE, CVEGroup, Advisory).filter(CVE.id == cve).outerjoin( CVEGroupEntry, CVEGroupEntry.cve_id == CVE.id).outerjoin( CVEGroup, CVEGroupEntry.group).outerjoin( CVEGroupPackage, CVEGroup.packages).outerjoin( Advisory, Advisory.group_package_id == CVEGroupPackage.id) ).all() if not entries: return not_found() cve: CVE = entries[0][0] groups = set(group for (cve, group, advisory) in entries if group) advisories = set(advisory for (cve, group, advisory) in entries if advisory) if not user_can_edit_issue(advisories): flash(ERROR_ISSUE_REFERENCED_BY_ADVISORY.format(cve.id), 'error') return forbidden() form = CVEForm(edit=True) if not form.is_submitted(): form.cve.data = cve.id form.issue_type.data = cve.issue_type form.description.data = cve.description form.severity.data = cve.severity.name form.remote.data = cve.remote.name form.reference.data = cve.reference form.notes.data = cve.notes form.changed.data = str(cve.changed) form.changed_latest.data = str(cve.changed) concurrent_modification = str(cve.changed) != form.changed.data if not form.validate_on_submit() or ( concurrent_modification and not (form.force_submit.data and str(cve.changed) == form.changed_latest.data)): if advisories: flash( 'WARNING: This is referenced by an already published advisory!', 'warning') issue = None code = 200 if concurrent_modification: flash('WARNING: The remote data has changed!', 'warning') code = Conflict.code issue = CVE() issue.id = form.cve.data issue.issue_type = form.issue_type.data issue.issue_type_mod = cve.issue_type != issue.issue_type issue.description = form.description.data issue.description_mod = cve.description != issue.description issue.severity = Severity.fromstring(form.severity.data) issue.severity_mod = cve.severity != issue.severity issue.remote = Remote.fromstring(form.remote.data) issue.remote_mod = cve.remote != issue.remote issue.reference = form.reference.data issue.reference_mod = cve.reference != issue.reference issue.notes = form.notes.data issue.notes_mod = cve.notes != issue.notes if form.changed_latest.data != cve.changed: form.force_submit.data = False form.changed_latest.data = str(cve.changed) Transaction = versioning_manager.transaction_cls VersionClassCVE = version_class(CVE) version = (db.session.query( Transaction, VersionClassCVE).outerjoin( VersionClassCVE, Transaction.id == VersionClassCVE.transaction_id).filter( VersionClassCVE.id == cve.id).order_by( Transaction.issued_at.desc())).first()[1] issue.transaction = version.transaction issue.operation_type = version.operation_type issue.previous = cve return render_template( 'form/cve.html', title='Edit {}'.format(cve), form=form, CVE=CVE, issue=issue, concurrent_modification=concurrent_modification, can_watch_user_log=user_can_watch_user_log()), code severity = Severity.fromstring(form.severity.data) severity_changed = cve.severity != severity issue_type_changed = cve.issue_type != form.issue_type.data cve.issue_type = form.issue_type.data cve.description = form.description.data cve.severity = severity cve.remote = Remote.fromstring(form.remote.data) cve.reference = form.reference.data cve.notes = form.notes.data if severity_changed or issue_type_changed: # update cached group severity for all goups containing this issue group_ids = [group.id for group in groups] issues = (db.session.query( CVEGroup, CVE).join(CVEGroupEntry, CVEGroup.issues).join( CVE, CVEGroupEntry.cve).group_by(CVEGroup.id).group_by(CVE.id)) if group_ids: issues = issues.filter(CVEGroup.id.in_(group_ids)) issues = (issues).all() if severity_changed: group_severity = defaultdict(list) for group, issue in issues: group_severity[group].append(issue.severity) for group, severities in group_severity.items(): group.severity = highest_severity(severities) # update scheduled advisories if the issue type changes if advisories and issue_type_changed: group_issue_type = defaultdict(set) for group, issue in issues: group_issue_type[group].add(issue.issue_type) for advisory in advisories: if Publication.published == advisory.publication: continue issue_types = group_issue_type[advisory.group_package.group] issue_type = 'multiple issues' if len( issue_types) > 1 else next(iter(issue_types)) advisory.advisory_type = issue_type if db.session.is_modified(cve) or severity_changed or issue_type_changed: cve.changed = datetime.utcnow() flash('Edited {}'.format(cve.id)) db.session.commit() return redirect('/{}'.format(cve.id))