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
|
#!/usr/bin/python3
#
# Merge a separate CVE file (such as data/next-point-update.txt) back into
# the main one.
#
# Copyright © 2020-2023 Emilio Pozuelo Monfort <pochu@debian.org>
# Copyright (c) 2021-2022 Neil Williams <codehelp@debian.org>
import os
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(annotations, new_annotation):
"""
Special support for StringAnnotations.
Merges a note into the bug's annotations, taking care not to
add duplicate notes.
new_annotation is a new string annotation for this CVE (bug),
"""
old_descriptions = [ann.description
for ann in annotations
if isinstance(ann, StringAnnotation)]
# prevent adding duplicate notes
if not new_annotation.description in old_descriptions:
annotations.append(new_annotation)
def merge_annotations(annotations, new_annotation):
"""
Adds new_annotation to the annotations list
"""
if not isinstance(new_annotation, PackageAnnotation):
raise NotImplementedError(f"unsupported annotation of type {new_annotation.type} (line {new_annotation.line})")
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
# 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 we found an experimental annotation, it will be followed by a 'sid'
# one, so next_annotation.release will be None in the next case. That
# comparison will break, so we avoid it by continuing. If new_annotation
# was for experimental, we would have already replaced it in the above check.
if annotation.release == 'experimental':
continue
# 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
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 = cvelist(main_list)
extra_data = cvelist(extra_list)
for extra_bug in extra_data:
bug = next(bug for bug in data if bug.header.name == extra_bug.header.name)
for extra_annotation in extra_bug.annotations:
if isinstance(extra_annotation, FlagAnnotation):
continue
if isinstance(extra_annotation, StringAnnotation):
merge_notes(bug.annotations, extra_annotation)
continue
merge_annotations(bug.annotations, extra_annotation)
with open(main_list, 'w') as f:
writecvelist(data, f)
# check for and erase an .xpck file built from the merge
xpck = f"{extra_list}.xpck"
if os.path.exists(xpck):
os.unlink(xpck)
|