11# Standard Libraries
22import json
33import re
4- from datetime import datetime
4+ from datetime import datetime , timezone
55
66import pandas as pd
77
@@ -26,6 +26,43 @@ def estimate_days_behind(release_date):
2626 return (datetime .today ().date () - datetime .strptime (release_date , "%Y-%m-%d" ).date ()).days
2727
2828
29+ def check_if_update_allowed (package_name , latest_version , grace_period_days = 5 ):
30+ """
31+ Check if enough time has passed since the latest version was released.
32+ Returns True if grace_period_days have passed, False otherwise.
33+ This implements zero-day protection by waiting before flagging updates.
34+ """
35+ url = f"{ PIP_INDEX_URL } /{ package_name } /json"
36+ response = requests .get (url )
37+
38+ if response .status_code != 200 :
39+ print (f"[{ package_name } ] Package not found on PyPI." )
40+ return False
41+
42+ data = response .json ()
43+ releases = data ["releases" ].get (latest_version )
44+
45+ if not releases :
46+ print (f"[{ package_name } ] No release info found for version { latest_version } ." )
47+ return False
48+
49+ # Get the upload time from the first file in the release
50+ upload_time_str = releases [0 ]["upload_time_iso_8601" ]
51+
52+ # Parse the date and compare with current time
53+ upload_time = datetime .fromisoformat (upload_time_str .replace ("Z" , "+00:00" ))
54+ now = datetime .now (timezone .utc )
55+
56+ age = now - upload_time
57+
58+ if age .days >= grace_period_days :
59+ print (f"[{ package_name } ] Version { latest_version } released { age .days } days ago. UPDATE APPROVED." )
60+ return True
61+ else :
62+ print (f"[{ package_name } ] Version { latest_version } only { age .days } days old. WAITING for zero-day protection." )
63+ return False
64+
65+
2966def get_upstream_version (dependency , last_supported_version ):
3067 """Get the latest version available upstream"""
3168 last_supported_version_release_date = "Not found"
@@ -129,16 +166,23 @@ def get_last_supported_version(tekton_ci_output, dependency):
129166
130167
131168def is_up_to_date (
132- last_supported_version , latest_version , last_supported_version_release_date
169+ package_name , last_supported_version , latest_version , last_supported_version_release_date
133170):
134- """Check if the supported package is up-to-date"""
171+ """Check if the supported package is up-to-date, considering grace period for zero-day protection """
135172 if Version (last_supported_version ) >= Version (latest_version ):
136173 up_to_date = "Yes"
137174 days_behind = 0
138175 else :
139- up_to_date = "No"
140- days_behind = estimate_days_behind (last_supported_version_release_date )
141-
176+ # Check if grace period has passed for the latest version
177+ # This protects against zero-day vulnerabilities by waiting 5 days
178+ if check_if_update_allowed (package_name , latest_version ):
179+ up_to_date = "No"
180+ days_behind = estimate_days_behind (last_supported_version_release_date )
181+ else :
182+ # Grace period not elapsed - treat as up-to-date for now
183+ up_to_date = "Yes (Grace Period)"
184+ days_behind = 0
185+
142186 return up_to_date , days_behind
143187
144188def taskrun_filter (taskrun ):
@@ -264,7 +308,7 @@ def main():
264308 )
265309
266310 up_to_date , days_behind = is_up_to_date (
267- last_supported_version , latest_version , last_supported_version_release_date
311+ package , last_supported_version , latest_version , last_supported_version_release_date
268312 )
269313
270314 item .update (
0 commit comments