Skip to content

Commit 38961b0

Browse files
authored
feat: error if modified date for existing advisories is ahead of the proposed modified date (#70)
Now that we're starting to generate advisories autonomously, it's possible that local caches could get outdated meaning that regenerating the advisories after doing a change could mistakenly revert advisory updates or skip advisories that have since been published. This introduces a check to help guard against that whereby we error if the `modified` timestamp for the version of the advisory we've just generated is behind the `modified` timestamp for the version of the advisory that exists on disk which should be an indicator that the local advisory cache is out of date. I think this should be robust enough but I wouldn't be surprised if there's an edge case or two that we discover later - I'm not really worried about that though due to the utility of this check and worst case you can just locally hardcode the function to return `False` as a workaround. Also just want to acknowledge we're technically opening the file twice in a row but I found attempting to do this within the context of the single file handler was a lot uglier since we have to account for the advisory not existing ideally without suppressing if the file has invalid JSON - in the scheme of things, the performance hit of doing a double open will likely never be measurable 🤷
1 parent 09830a1 commit 38961b0

1 file changed

Lines changed: 18 additions & 0 deletions

File tree

scripts/generate_osv_advisories.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,18 @@ def fetch_affected_packages(osv_advisory: osv.Vulnerability) -> list[str]:
420420
return [affected['package']['name'] for affected in osv_advisory['affected']]
421421

422422

423+
def is_existing_advisory_ahead(
424+
name: str, sa_id: str, proposed_modified_at: str
425+
) -> bool:
426+
try:
427+
with open(f'advisories/{name}/D{sa_id}.json') as f:
428+
existing_advisory = typing.cast(osv.Vulnerability, json.load(f))
429+
# RFC3339 dates are designed to be comparable as strings, so this is safe
430+
return existing_advisory['modified'] > proposed_modified_at
431+
except FileNotFoundError:
432+
return False
433+
434+
423435
def generate_osv_advisories() -> None:
424436
for file in os.scandir('cache/advisories'):
425437
if not file.is_file() or not file.name.endswith('.json'):
@@ -442,6 +454,12 @@ def generate_osv_advisories() -> None:
442454
for affected_package in affected_packages:
443455
name = affected_package.removeprefix('drupal/')
444456
os.makedirs(f'advisories/{name}', exist_ok=True)
457+
if is_existing_advisory_ahead(name, sa_id, osv_advisory['modified']):
458+
print(
459+
' \\- error: current modified date is ahead of the proposed modified date (is your cache up to date?)'
460+
)
461+
exit(1)
462+
445463
with open(f'advisories/{name}/D{sa_id}.json', 'w') as f:
446464
json.dump(osv_advisory, f, indent=2)
447465
f.write('\n')

0 commit comments

Comments
 (0)