1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
#!/usr/bin/python3
#
# Merge a separate CVE file (such as data/next-point-update.txt) back into
# the main one.
#
# Copyright © 2020 Emilio Pozuelo Monfort <pochu@debian.org>
# Copyright (c) 2021-2022 Neil Williams <codehelp@debian.org>
import os.path
import sys
import setup_paths # noqa
from debian_support import internRelease
from sectracker.parsers import (
Bug,
cvelist,
writecvelist,
PackageAnnotation,
FlagAnnotation,
StringAnnotation,
XrefAnnotation
)
def merge_notes(bug, notes):
"""
Special support for StringAnnotations.
notes is a dict containing a list of string annotations for
each CVE in the file being merged. Pick out the string annotations
for this bug, ignore if already exist, append if new.
"""
new_notes = []
cve = bug.header.name
merge_list = notes.get(cve) # list of notes to merge
if not merge_list:
# nothing to merge
return bug
tagged_notes = [note.description for note in merge_list]
bug_notes = [ann.description for ann in bug.annotations if isinstance(ann, StringAnnotation)]
# get the list items in tagged_notes which are not in bug_notes
new_strings = list(set(tagged_notes) - set(bug_notes))
if not new_strings:
return bug
for new_ann in merge_list:
if new_ann.description in new_strings:
new_notes.append(new_ann)
bug_list = list(bug.annotations)
bug_list.extend(new_notes)
mod_bug = Bug(
bug.file, bug.header, tuple(bug_list)
)
return mod_bug
def merge_annotations(annotations, new_annotation):
if not isinstance(new_annotation, PackageAnnotation):
raise NotImplementedError(f"unsupported annotation of type {new_annotation.type} (line {new_annotation.line})")
annotations = list(annotations)
annotations_for_pkg = [ann for ann in annotations \
if isinstance(ann, PackageAnnotation) \
and ann.package == new_annotation.package]
if not annotations_for_pkg:
if new_annotation.release:
raise ValueError(f"new annotation for {new_annotation.package}/{new_annotation.release} "
"but there is no annotation for sid")
# new package, add it at the top
for idx, annotation in enumerate(annotations):
if isinstance(annotation, FlagAnnotation) \
or isinstance(annotation, XrefAnnotation):
continue
annotations.insert(idx, new_annotation)
return annotations
# append/substitute the new one at the right place
for idx, annotation in enumerate(annotations):
if not isinstance(annotation, PackageAnnotation) \
or annotation.package != new_annotation.package:
continue
# if the annotation is for the same package/release, replace it
if annotation.package == new_annotation.package \
and annotation.release == new_annotation.release:
annotations[idx] = new_annotation
break
# if the next annotation's release is the same, we continue to replace
# it in the next iteration. otherwise if we found the right place, we
# insert the new annotation
next_annotation = annotations[idx + 1] if len(annotations) > (idx + 1) else None
if next_annotation and isinstance(next_annotation, PackageAnnotation) \
and next_annotation.package == new_annotation.package \
and internRelease(new_annotation.release) <= internRelease(next_annotation.release):
continue
annotations.insert(idx + 1, new_annotation)
break
return annotations
def parse_list(path):
data, messages = cvelist(path)
for m in messages:
sys.stderr.write(str(m) + "\n")
return data
if len(sys.argv) not in (2, 3):
print(f"Usage: {os.path.basename(sys.argv[0])} (CVE/list) extra-cve-list")
sys.exit(1)
if len(sys.argv) == 3:
main_list = sys.argv[1]
else:
main_list = os.path.dirname(__file__) + '/../data/CVE/list'
extra_list = sys.argv[-1]
data = parse_list(main_list)
extra_data = parse_list(extra_list)
for extra_bug in extra_data:
bug = next(bug for bug in data if bug.header.name == extra_bug.header.name)
notes = {}
new_annotations = bug.annotations
for extra_annotation in extra_bug.annotations:
if isinstance(extra_annotation, StringAnnotation):
cve = f"{extra_bug.header.name}"
note_tag = notes.setdefault(cve, [])
note_tag.append(extra_annotation)
continue
new_annotations = merge_annotations(new_annotations, extra_annotation)
bug = bug._replace(annotations=new_annotations)
bug = merge_notes(bug, notes)
data = [bug if bug.header.name == old_bug.header.name else old_bug for old_bug in data]
with open(main_list, 'w') as f:
writecvelist(data, f)
|