Merge ubuntu-cve-tracker:usn-summary into ubuntu-cve-tracker:master

Proposed by Mark Morlino
Status: Merged
Merged at revision: 4f1bb640b406155b9e9cf3c6aa7cc12f96d70629
Proposed branch: ubuntu-cve-tracker:usn-summary
Merge into: ubuntu-cve-tracker:master
Diff against target: 198 lines (+88/-64)
1 file modified
scripts/publish-usn-to-website-api.py (+88/-64)
Reviewer Review Type Date Requested Status
Steve Beattie Approve
Alex Murray Approve
Review via email: mp+387383@code.launchpad.net

Description of the change

* print the USN ID with the response
* Some changes required to allow for importing older USNs (present in database-all.json but not in database.json).
* Send the value of the isummary field from our database.json as the value of the summary field on the json data payload posted top the api
* Sort the USNs and Add an argument to start with a specific USN ID. This allows large batches to be restarted more easily without re-uploading stuff

To post a comment you must log in.
Revision history for this message
Alex Murray (alexmurray) wrote :

LGTM!

review: Approve
Revision history for this message
Steve Beattie (sbeattie) wrote :

Approved additional commits.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/scripts/publish-usn-to-website-api.py b/scripts/publish-usn-to-website-api.py
2index 7ebf2bf..b67819b 100755
3--- a/scripts/publish-usn-to-website-api.py
4+++ b/scripts/publish-usn-to-website-api.py
5@@ -100,6 +100,10 @@ parser.add_argument(
6 "--no-upsert", action="store_true",
7 help="No update after non-200 status on add, No add after non-200 status on update",
8 )
9+parser.add_argument(
10+ "--startwith", action="store", type=str,
11+ help='USN ID (without USN- prefix) to start with. Useful for resuming an interupted batch operation.',
12+ )
13
14 args = parser.parse_args()
15
16@@ -109,6 +113,8 @@ if (args.action == 'add' or args.action == 'update') and not args.json:
17 sys.exit(f"Error: --action {args.action} requires --json")
18 if args.action == 'remove' and not args.json and not args.usns:
19 sys.exit("Error: --action remove requires --json or --usns")
20+if args.startwith and not re.match("\d{1,5}-\d{1,2}", args.startwith):
21+ sys.exit("Error: --startwith must match '\d{1,5}-\d{1,2}'")
22
23 client = httpbakery.Client(cookies=MozillaCookieJar(".login"))
24
25@@ -128,91 +134,109 @@ if args.action == 'remove' and args.usns:
26 sys.exit(0)
27
28 # read in the json
29-with open(args.json) as usn_json:
30- payload = json.load(usn_json).items()
31+with open(args.json, 'r') as fh:
32+ usn_json = json.load(fh)
33+
34+# split usn ids into tuples for sorting
35+def usn_key(usn):
36+ if not usn:
37+ return ()
38+ return tuple([int(n) for n in usn[0].split('-')])
39+
40+payload = sorted(usn_json.items(), key=usn_key)
41
42- for notice_id, notice in payload:
43- # format release_packages
44- release_packages = {}
45+for notice_id, notice in payload:
46
47- for codename, packages in notice["releases"].items():
48- release_packages[codename] = []
49+ if args.startwith and usn_key([notice_id]) < usn_key([args.startwith]):
50+ continue
51+
52+ # format release_packages
53+ release_packages = {}
54+
55+ for codename, packages in notice["releases"].items():
56+ release_packages[codename] = []
57+ if "sources" in packages:
58 for name, info in packages["sources"].items():
59 release_packages[codename].append(
60 {
61 "name": name,
62 "version": info["version"],
63- "description": info["description"],
64+ "description": info.get("description", ""),
65 "is_source": "true"
66 }
67 )
68
69- for name, info in packages["binaries"].items():
70+ for name, info in packages["binaries"].items():
71+ if "sources" in packages:
72 source_link, version_link = guess_binary_links(
73 name, info["version"], packages["sources"]
74 )
75- release_packages[codename].append(
76- {
77- "name": name,
78- "version": info["version"],
79- "is_source": "false",
80- "source_link": source_link,
81- "version_link": version_link,
82- }
83- )
84- # format CVEs and references
85- cves = []
86- references = []
87+ else:
88+ source_link = ""
89+ version_link = ""
90+ release_packages[codename].append(
91+ {
92+ "name": name,
93+ "version": info["version"],
94+ "is_source": "false",
95+ "source_link": source_link,
96+ "version_link": version_link,
97+ }
98+ )
99+ # format CVEs and references
100+ cves = []
101+ references = []
102+ if "cves" in notice:
103 for reference in notice["cves"]:
104- if reference.startswith("CVE-"):
105+ if re.match("CVE-\d{4}-\d+", reference) and not reference in cves:
106 cves.append(reference)
107 else:
108 references.append(reference)
109
110- # Build json payload
111- json_data = {
112- "id": notice["id"],
113- "description": notice["description"],
114- "references": references,
115- "cves": cves,
116- "release_packages": release_packages,
117- "title": notice["title"],
118- "published": datetime.utcfromtimestamp(
119- notice["timestamp"]
120- ).isoformat(),
121- "summary": notice["summary"],
122- "instructions": notice.get("action"),
123- }
124-
125- # Build endpoint
126+ # Build json payload
127+ json_data = {
128+ "id": notice["id"],
129+ "description": notice["description"],
130+ "references": references,
131+ "cves": cves,
132+ "release_packages": release_packages,
133+ "title": notice["title"],
134+ "published": datetime.utcfromtimestamp(
135+ notice["timestamp"]
136+ ).isoformat(),
137+ "summary": notice.get("isummary", notice["title"]),
138+ "instructions": notice.get("action", "In general, a standard system update will make all the necessary changes."),
139+ }
140+
141+ # Build endpoint
142+ if args.action == 'add':
143+ upsert = not args.no_upsert
144+ http_method = 'POST'
145+ endpoint = args.endpoint
146+ elif args.action == 'update':
147+ upsert = not args.no_upsert
148+ http_method = 'PUT'
149+ endpoint = f"{args.endpoint}/{notice['id']}"
150+ elif args.action == 'remove':
151+ upsert = False
152+ http_method = 'DELETE'
153+ endpoint = f"{args.endpoint}/{notice['id']}"
154+ json_data = None
155+
156+ response = client.request( http_method, url=endpoint, json=json_data)
157+ print(notice['id'], response, response.text[0:60])
158+
159+ if upsert and not re.match(r'^<Response \[2..\]>$',str(response)):
160 if args.action == 'add':
161- upsert = not args.no_upsert
162- http_method = 'POST'
163- endpoint = args.endpoint
164- elif args.action == 'update':
165- upsert = not args.no_upsert
166+ #print(f"{notice['id']} add failed, trying update")
167 http_method = 'PUT'
168 endpoint = f"{args.endpoint}/{notice['id']}"
169- elif args.action == 'remove':
170- upsert = False
171- http_method = 'DELETE'
172- endpoint = f"{args.endpoint}/{notice['id']}"
173- json_data = None
174-
175+ elif args.action == 'update':
176+ #print(f"{notice['id']} update failed, trying add")
177+ http_method = 'POST'
178+ endpoint = args.endpoint
179 response = client.request( http_method, url=endpoint, json=json_data)
180- print(response, response.text[0:60])
181+ print(notice['id'], response, response.text[0:60])
182
183- if upsert and not re.match(r'^<Response \[2..\]>$',str(response)):
184- if args.action == 'add':
185- print("add failed, trying update")
186- http_method = 'PUT'
187- endpoint = f"{args.endpoint}/{notice['id']}"
188- elif args.action == 'update':
189- print("update failed, trying add")
190- http_method = 'POST'
191- endpoint = args.endpoint
192- response = client.request( http_method, url=endpoint, json=json_data)
193- print(response, response.text[0:60])
194-
195- if args.stop and not re.match(r'^<Response \[2..\]>$',str(response)):
196- sys.exit(1)
197+ if args.stop and not re.match(r'^<Response \[2..\]>$',str(response)):
198+ sys.exit(1)

Subscribers

People subscribed via source and target branches