Merge ~litios/ubuntu-cve-tracker:ppas-tag-migration into ubuntu-cve-tracker:master
- Git
- lp:~litios/ubuntu-cve-tracker
- ppas-tag-migration
- Merge into master
Proposed by
David Fernandez Gonzalez
Status: | Merged |
---|---|
Merge reported by: | David Fernandez Gonzalez |
Merged at revision: | 8d5aa3898e261c0861d302c17b9d8220970388a8 |
Proposed branch: | ~litios/ubuntu-cve-tracker:ppas-tag-migration |
Merge into: | ubuntu-cve-tracker:master |
Diff against target: |
435 lines (+114/-73) 3 files modified
scripts/cve_lib.py (+78/-45) scripts/generate_pkg_cache.py (+35/-27) scripts/test_source_map.py (+1/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Eduardo Barretto | Approve | ||
Emilia Torino | Approve | ||
Review via email: mp+453042@code.launchpad.net |
Commit message
Description of the change
Due to https:/
To post a comment you must log in.
Revision history for this message
Eduardo Barretto (ebarretto) wrote : | # |
As we've spoken, the current changes break generate_
It would also be great to handle the pockets correctly in that same script, otherwise everything will show up as "Release" pocket.
Thanks for making these changes
review:
Needs Fixing
- be2fc23... by David Fernandez Gonzalez
-
Add pockets to subprojects
Signed-off-by: David Fernandez Gonzalez <email address hidden>
- 8d5aa38... by David Fernandez Gonzalez
-
cve_lib: remove /ubuntu from subproject ppa names
Signed-off-by: David Fernandez Gonzalez <email address hidden>
Revision history for this message
Eduardo Barretto (ebarretto) wrote : | # |
lgtm, thanks
CI failures are not related to this PR
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/scripts/cve_lib.py b/scripts/cve_lib.py |
2 | index fb9a744..7299ac0 100755 |
3 | --- a/scripts/cve_lib.py |
4 | +++ b/scripts/cve_lib.py |
5 | @@ -106,7 +106,7 @@ subprojects = { |
6 | "name": "Ubuntu 12.04 ESM", |
7 | "codename": "Precise Pangolin", |
8 | "alias": "precise/esm", |
9 | - "ppa": "ubuntu-esm/esm", |
10 | + "ppas": [{ "ppa": "ubuntu-esm/esm", "pocket": "security"}], |
11 | "parent": "ubuntu/precise", |
12 | "description": "Available with UA Infra or UA Desktop: https://ubuntu.com/advantage", |
13 | "stamp": 1493521200, |
14 | @@ -118,7 +118,10 @@ subprojects = { |
15 | "name": "Ubuntu 14.04 ESM", |
16 | "codename": "Trusty Tahr", |
17 | "alias": "trusty/esm", |
18 | - "ppa": "ubuntu-esm/esm-infra-security", |
19 | + "ppas": [ |
20 | + {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"}, |
21 | + {"ppa": "ubuntu-esm/esm-infra-updates", "pocket": "updates"} |
22 | + ], |
23 | "parent": "ubuntu/trusty", |
24 | "description": "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro", |
25 | "stamp": 1556593200, |
26 | @@ -130,7 +133,10 @@ subprojects = { |
27 | "packages": ["esm-infra-xenial-supported.txt"], |
28 | "name": "Ubuntu 16.04 ESM", |
29 | "codename": "Xenial Xerus", |
30 | - "ppa": "ubuntu-esm/esm-infra-security", |
31 | + "ppas": [ |
32 | + {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"}, |
33 | + {"ppa": "ubuntu-esm/esm-infra-updates", "pocket": "updates"} |
34 | + ], |
35 | "parent": "ubuntu/xenial", |
36 | "description": "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro", |
37 | "stamp": 1618963200, |
38 | @@ -142,7 +148,10 @@ subprojects = { |
39 | "packages": ["esm-infra-bionic-supported.txt"], |
40 | "name": "Ubuntu 18.04 ESM", |
41 | "codename": "Bionic Beaver", |
42 | - "ppa": "ubuntu-esm/esm-infra-security", |
43 | + "ppas": [ |
44 | + {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"}, |
45 | + {"ppa": "ubuntu-esm/esm-infra-updates", "pocket": "updates"} |
46 | + ], |
47 | "parent": "ubuntu/bionic", |
48 | "description": "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro", |
49 | "stamp": 1685539024, |
50 | @@ -154,7 +163,10 @@ subprojects = { |
51 | "packages": ["esm-apps-xenial-supported.txt"], |
52 | "name": "Ubuntu 16.04 ESM", |
53 | "codename": "Xenial Xerus", |
54 | - "ppa": "ubuntu-esm/esm-apps-security", |
55 | + "ppas": [ |
56 | + {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"}, |
57 | + {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"} |
58 | + ], |
59 | "parent": "esm-infra/xenial", |
60 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
61 | "stamp": 1618963200, |
62 | @@ -166,7 +178,10 @@ subprojects = { |
63 | "packages": ["esm-apps-bionic-supported.txt"], |
64 | "name": "Ubuntu 18.04 ESM", |
65 | "codename": "Bionic Beaver", |
66 | - "ppa": "ubuntu-esm/esm-apps-security", |
67 | + "ppas": [ |
68 | + {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"}, |
69 | + {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"} |
70 | + ], |
71 | "parent": "esm-infra/bionic", |
72 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
73 | "stamp": 1524870000, |
74 | @@ -178,7 +193,10 @@ subprojects = { |
75 | "packages": ["esm-apps-focal-supported.txt"], |
76 | "name": "Ubuntu 20.04 ESM", |
77 | "codename": "Focal Fossa", |
78 | - "ppa": "ubuntu-esm/esm-apps-security", |
79 | + "ppas": [ |
80 | + {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"}, |
81 | + {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"} |
82 | + ], |
83 | "parent": "ubuntu/focal", |
84 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
85 | "stamp": 1587567600, |
86 | @@ -190,7 +208,10 @@ subprojects = { |
87 | "packages": ["esm-apps-jammy-supported.txt"], |
88 | "name": "Ubuntu 22.04 ESM", |
89 | "codename": "Jammy Jellyfish", |
90 | - "ppa": "ubuntu-esm/esm-apps-security", |
91 | + "ppas": [ |
92 | + {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"}, |
93 | + {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"} |
94 | + ], |
95 | "parent": "ubuntu/jammy", |
96 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
97 | "stamp": 1650693600, |
98 | @@ -201,7 +222,7 @@ subprojects = { |
99 | "packages": ["fips-xenial-supported.txt"], |
100 | "name": "Ubuntu 16.04 FIPS Certified", |
101 | "codename": "Xenial Xerus", |
102 | - "ppa": "ubuntu-advantage/fips", |
103 | + "ppas": [{"ppa" : "ubuntu-advantage/fips", "pocket": "security"}], |
104 | "parent": "ubuntu/xenial", |
105 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
106 | }, |
107 | @@ -211,7 +232,7 @@ subprojects = { |
108 | "packages": ["fips-bionic-supported.txt"], |
109 | "name": "Ubuntu 18.04 FIPS Certified", |
110 | "codename": "Bionic Beaver", |
111 | - "ppa": "ubuntu-advantage/fips", |
112 | + "ppas": [{"ppa" : "ubuntu-advantage/fips", "pocket": "security"}], |
113 | "parent": "ubuntu/bionic", |
114 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
115 | }, |
116 | @@ -221,7 +242,7 @@ subprojects = { |
117 | "packages": ["fips-focal-supported.txt"], |
118 | "name": "Ubuntu 20.04 FIPS Certified", |
119 | "codename": "Focal Fossa", |
120 | - "ppa": "ubuntu-advantage/fips", |
121 | + "ppas": [{"ppa" : "ubuntu-advantage/fips", "pocket": "security"}], |
122 | "parent": "ubuntu/bionic", |
123 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
124 | }, |
125 | @@ -231,7 +252,7 @@ subprojects = { |
126 | "packages": ["fips-updates-xenial-supported.txt"], |
127 | "name": "Ubuntu 16.04 FIPS Compliant", |
128 | "codename": "Xenial Xerus", |
129 | - "ppa": "ubuntu-advantage/fips-updates", |
130 | + "ppas": [{"ppa" : "ubuntu-advantage/fips-updates", "pocket": "updates"}], |
131 | "parent": "ubuntu/xenial", |
132 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
133 | }, |
134 | @@ -241,7 +262,7 @@ subprojects = { |
135 | "packages": ["fips-updates-bionic-supported.txt"], |
136 | "name": "Ubuntu 18.04 FIPS Compliant", |
137 | "codename": "Bionic Beaver", |
138 | - "ppa": "ubuntu-advantage/fips-updates", |
139 | + "ppas": [{"ppa" : "ubuntu-advantage/fips-updates", "pocket": "updates"}], |
140 | "parent": "ubuntu/bionic", |
141 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
142 | }, |
143 | @@ -251,7 +272,7 @@ subprojects = { |
144 | "packages": ["fips-updates-focal-supported.txt"], |
145 | "name": "Ubuntu 20.04 FIPS Compliant", |
146 | "codename": "Focal Fossa", |
147 | - "ppa": "ubuntu-advantage/fips-updates", |
148 | + "ppas": [{"ppa" : "ubuntu-advantage/fips-updates", "pocket": "updates"}], |
149 | "parent": "ubuntu/bionic", |
150 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
151 | }, |
152 | @@ -262,7 +283,7 @@ subprojects = { |
153 | "name": "Ubuntu 16.04 ROS ESM", |
154 | "codename": "Xenial Xerus", |
155 | "alias": "ros-esm/xenial", |
156 | - "ppa": "ubuntu-robotics-packagers/ros-security", |
157 | + "ppas": [{"ppa": "ubuntu-robotics-packagers/ros-security", "pocket": "security"}], |
158 | "parent": "ubuntu/xenial", |
159 | "description": "Available with Ubuntu Advantage: https://ubuntu.com/advantage", |
160 | }, |
161 | @@ -273,7 +294,7 @@ subprojects = { |
162 | "name": "Ubuntu 18.04 ROS ESM", |
163 | "codename": "Bionic Beaver", |
164 | "alias": "ros-esm/bionic", |
165 | - "ppa": "ubuntu-robotics-packagers/ros-security", |
166 | + "ppas": [{"ppa": "ubuntu-robotics-packagers/ros-security", "pocket": "security"}], |
167 | "parent": "ubuntu/bionic", |
168 | "description": "Available with Ubuntu Advantage: https://ubuntu.com/advantage", |
169 | }, |
170 | @@ -755,17 +776,30 @@ def get_subproject_details_by_ppa_url_and_series(url, series): |
171 | prod, ser = product_series(rel) |
172 | if ser == series: |
173 | try: |
174 | - if subprojects[rel]["ppa"] in url: |
175 | - product = prod |
176 | - canon = product + "/" + series |
177 | - details = subprojects[rel] |
178 | - break |
179 | + for ppa_pocket in subprojects[rel]["ppas"]: |
180 | + if ppa_pocket['ppa'] in url: |
181 | + product = prod |
182 | + canon = product + "/" + series |
183 | + details = subprojects[rel] |
184 | + break |
185 | except KeyError: |
186 | pass |
187 | if details is not None: |
188 | break |
189 | return canon, product, series, details |
190 | |
191 | +def release_ppa_pocket(rel, ppa): |
192 | + _, _, _, details = get_subproject_details(rel) |
193 | + pocket = None |
194 | + try: |
195 | + for ppa_pocket in details["ppas"]: |
196 | + if ppa_pocket["ppa"] == ppa: |
197 | + pocket = ppa_pocket["pocket"] |
198 | + break |
199 | + except (KeyError, TypeError): |
200 | + pass |
201 | + return pocket |
202 | + |
203 | def release_name(rel): |
204 | name = None |
205 | _, _, _, details = get_subproject_details(rel) |
206 | @@ -832,16 +866,16 @@ def release_version(rel): |
207 | if details: |
208 | version = details["version"] |
209 | return version |
210 | - |
211 | -def release_ppa(rel): |
212 | - """Return the ppa for a given subproject.""" |
213 | - ppa = None |
214 | + |
215 | +def release_ppas(rel): |
216 | + """Return the ppas for a given subproject.""" |
217 | + ppas = None |
218 | _, _, _, details = get_subproject_details(rel) |
219 | try: |
220 | - ppa = details["ppa"] |
221 | + ppas = details["ppas"] |
222 | except (KeyError, TypeError): |
223 | pass |
224 | - return ppa |
225 | + return ppas |
226 | |
227 | def needs_oval(rel): |
228 | """Return if OVAL should be generated for a given subproject""" |
229 | @@ -931,7 +965,7 @@ def find_external_subproject_cves(cve): |
230 | # should follow the same as any other subproject |
231 | # except for the extra 'product' and 'release' keys. |
232 | MANDATORY_EXTERNAL_SUBPROJECT_KEYS = ['cve_triage', 'cve_patching', 'cve_notification', 'security_updates_notification', 'binary_copies_only', 'seg_support', 'owners'] |
233 | -MANDATORY_EXTERNAL_SUBPROJECT_PPA_KEYS = ['ppa', 'oval', 'product', 'release', 'supported_packages'] |
234 | +MANDATORY_EXTERNAL_SUBPROJECT_PPA_KEYS = ['ppas', 'oval', 'product', 'release', 'supported_packages'] |
235 | OPTIONAL_EXTERNAL_SUBPROJECT_PPA_KEYS = ['parent', 'name', 'codename', 'description', 'aliases', 'archs'] |
236 | |
237 | def load_external_subprojects(strict=False): |
238 | @@ -976,8 +1010,8 @@ def load_external_subprojects(strict=False): |
239 | else: |
240 | support_metadata[key] = main_config[key] |
241 | |
242 | - for ppa in main_config['ppas']: |
243 | - config = main_config['ppas'][ppa] |
244 | + for subproject in main_config['subprojects']: |
245 | + config = main_config['subprojects'][subproject] |
246 | if 'product' not in config or 'release' not in config: |
247 | if strict: |
248 | raise ValueError(error_msg) |
249 | @@ -985,39 +1019,38 @@ def load_external_subprojects(strict=False): |
250 | print(error_msg, file=sys.stderr) |
251 | error_msg = '%s: missing "product" or "release".' % (subproject_path) |
252 | |
253 | - subproject_name = ppa |
254 | - external_releases.append(subproject_name) |
255 | - subprojects.setdefault(subproject_name, {"packages": [], |
256 | + external_releases.append(subproject) |
257 | + subprojects.setdefault(subproject, {"packages": [], |
258 | "eol": False}) |
259 | # an external subproject can append to an internal one |
260 | - subprojects[subproject_name]["packages"].append(\ |
261 | + subprojects[subproject]["packages"].append(\ |
262 | os.path.join(subproject_path, config['supported_packages'])) |
263 | |
264 | # check if aliases for packages exist |
265 | if 'aliases' in config: |
266 | - subprojects[subproject_name].setdefault("aliases", \ |
267 | + subprojects[subproject].setdefault("aliases", \ |
268 | os.path.join(subproject_path, config['aliases'])) |
269 | |
270 | for key in MANDATORY_EXTERNAL_SUBPROJECT_PPA_KEYS + OPTIONAL_EXTERNAL_SUBPROJECT_PPA_KEYS: |
271 | if key in config: |
272 | - subprojects[subproject_name].setdefault(key, config[key]) |
273 | + subprojects[subproject].setdefault(key, config[key]) |
274 | elif key in OPTIONAL_EXTERNAL_SUBPROJECT_PPA_KEYS: |
275 | - _, _, _, original_release_details = get_subproject_details(subprojects[subproject_name]['release']) |
276 | + _, _, _, original_release_details = get_subproject_details(subprojects[subproject]['release']) |
277 | if original_release_details and key in original_release_details: |
278 | - subprojects[subproject_name].setdefault(key, original_release_details[key]) |
279 | + subprojects[subproject].setdefault(key, original_release_details[key]) |
280 | else: |
281 | error_msg = '%s missing "%s" field.' % (subproject_path, key) |
282 | - del subprojects[subproject_name] |
283 | - external_releases.remove(subproject_name) |
284 | + del subprojects[subproject] |
285 | + external_releases.remove(subproject) |
286 | if strict: |
287 | raise ValueError(error_msg) |
288 | else: |
289 | print(error_msg, file=sys.stderr) |
290 | |
291 | - subprojects[subproject_name].setdefault("support_metadata", support_metadata) |
292 | - project = read_external_subproject_details(subproject_name) |
293 | + subprojects[subproject].setdefault("support_metadata", support_metadata) |
294 | + project = read_external_subproject_details(subproject) |
295 | if project: |
296 | - subprojects[subproject_name].setdefault("customer", project) |
297 | + subprojects[subproject].setdefault("customer", project) |
298 | |
299 | load_external_subprojects() |
300 | |
301 | @@ -1068,8 +1101,8 @@ def release_is_older_than(release_a, release_b): |
302 | flavor_releases = [ |
303 | 'lucid', 'precise', 'trusty', 'utopic', 'vivid', 'wily', 'xenial', |
304 | 'yakkety', 'zesty', 'artful', 'bionic', 'cosmic', 'disco', 'eoan', |
305 | - 'focal', 'groovy', 'hirsute', 'impish', 'jammy', 'kinetic', "lunar", |
306 | - 'mantic', 'noble', |
307 | + 'focal', 'groovy', 'hirsute', 'impish', 'jammy', 'kinetic', 'lunar', |
308 | + 'mantic','noble', |
309 | ] |
310 | |
311 | all_releases = release_sort(all_releases) |
312 | diff --git a/scripts/generate_pkg_cache.py b/scripts/generate_pkg_cache.py |
313 | index 27404f7..672e614 100644 |
314 | --- a/scripts/generate_pkg_cache.py |
315 | +++ b/scripts/generate_pkg_cache.py |
316 | @@ -11,7 +11,7 @@ |
317 | # for details. |
318 | # |
319 | |
320 | -from cve_lib import (all_releases, devel_release, eol_releases, needs_oval, product_series, release_parent, release_ppa) |
321 | +from cve_lib import (all_releases, devel_release, eol_releases, needs_oval, product_series, release_parent, release_ppas, release_ppa_pocket) |
322 | |
323 | import argparse |
324 | import datetime |
325 | @@ -55,31 +55,11 @@ def write_to_cache(cache_dir, release, cache): |
326 | except Exception: |
327 | error(f"Could not write to JSON file: {filename}") |
328 | |
329 | - |
330 | -def update_cache(release, cache, ppa=None, latest_date_created=None): |
331 | - lp = lpl_common.connect(version='devel') |
332 | - ubuntu = lp.distributions['ubuntu'] |
333 | - series = ubuntu.getSeries(name_or_version=product_series(release)[1]) |
334 | - |
335 | - real_threshold = None |
336 | - if latest_date_created: |
337 | - # Allow a grace period to cope with publications arriving out of |
338 | - # order during long transactions. |
339 | - real_threshold = latest_date_created - datetime.timedelta(hours=1) |
340 | - |
341 | - if ppa: |
342 | - archive, group, ppa_full_name = lpl_common.get_archive( |
343 | - ppa, |
344 | - lp, |
345 | - False, |
346 | - distribution=ubuntu |
347 | - ) |
348 | - else: |
349 | - archive = ubuntu.main_archive |
350 | - |
351 | +def get_binaries_rel(release, archive, real_threshold, series, cache, latest_date_created, ppa=None): |
352 | debug(f"Retrieving Launchpad publications since {real_threshold}") |
353 | sources = archive.getPublishedSources(order_by_date=True, created_since_date=real_threshold, distro_series=series) |
354 | for s in sources: |
355 | + override_pocket = None |
356 | if s.pocket not in pockets: |
357 | continue |
358 | |
359 | @@ -90,15 +70,16 @@ def update_cache(release, cache, ppa=None, latest_date_created=None): |
360 | src = s.source_package_name |
361 | src_ver = s.source_package_version |
362 | src_component = None |
363 | - if not ppa: |
364 | + if ppa: |
365 | src_component = s.component_name |
366 | + override_pocket = release_ppa_pocket(release, ppa) |
367 | |
368 | binaries = s.getPublishedBinaries(active_binaries_only=False) |
369 | for b in binaries: |
370 | bin_name = b.binary_package_name |
371 | bin_version = b.binary_package_version |
372 | bin_component = b.component_name |
373 | - pocket = b.pocket |
374 | + pocket = b.pocket if not ppa else override_pocket |
375 | bin_arch = b.display_name.split(' ')[-1] |
376 | |
377 | if src not in cache: |
378 | @@ -120,6 +101,33 @@ def update_cache(release, cache, ppa=None, latest_date_created=None): |
379 | |
380 | return latest_date_created |
381 | |
382 | +def update_cache(release, cache, ppas=None, latest_date_created=None): |
383 | + lp = lpl_common.connect(version='devel') |
384 | + ubuntu = lp.distributions['ubuntu'] |
385 | + series = ubuntu.getSeries(name_or_version=product_series(release)[1]) |
386 | + |
387 | + real_threshold = None |
388 | + if latest_date_created: |
389 | + # Allow a grace period to cope with publications arriving out of |
390 | + # order during long transactions. |
391 | + real_threshold = latest_date_created - datetime.timedelta(hours=1) |
392 | + |
393 | + if ppas: |
394 | + for ppa_pocket in ppas: |
395 | + ppa = ppa_pocket['ppa'] |
396 | + archive, _, _ = lpl_common.get_archive( |
397 | + ppa.split('/ubuntu')[0], |
398 | + lp, |
399 | + False, |
400 | + distribution=ubuntu |
401 | + ) |
402 | + |
403 | + latest_date_created = get_binaries_rel(release, archive, real_threshold, series, cache, latest_date_created, ppa) |
404 | + else: |
405 | + latest_date_created = get_binaries_rel(release, ubuntu.main_archive, real_threshold, series, cache, latest_date_created) |
406 | + |
407 | + return latest_date_created |
408 | + |
409 | |
410 | def warn(message): |
411 | """ print a warning message """ |
412 | @@ -186,8 +194,8 @@ def main(): |
413 | |
414 | debug('UPDATING CACHE') |
415 | |
416 | - ppa = release_ppa(release) |
417 | - latest_date_created = update_cache(release, cache, ppa, latest_date_created) |
418 | + ppas = release_ppas(release) |
419 | + latest_date_created = update_cache(release, cache, ppas, latest_date_created) |
420 | |
421 | if latest_date_created is not None: |
422 | epoch = datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc) |
423 | diff --git a/scripts/test_source_map.py b/scripts/test_source_map.py |
424 | index 8e99825..e05117c 100755 |
425 | --- a/scripts/test_source_map.py |
426 | +++ b/scripts/test_source_map.py |
427 | @@ -13,7 +13,7 @@ mock_subprojects = { |
428 | "packages": ["test/esm-fake-supported.txt"], |
429 | "name": "Ubuntu 01.01 ESM", |
430 | "codename": "Fabulous Fake", |
431 | - "ppa": "ubuntu-esm/esm-bar-security/ubuntu", |
432 | + "ppas": [{"ppa": "ubuntu-esm/esm-bar-security/ubuntu", "pocket": "main"}], |
433 | "parent": "ubuntu/bar", |
434 | "description": "Available with Ubuntu Pro: https://ubuntu.com/pro", |
435 | "stamp": 1618963200, |
LGTM, thanks!