@@ -42,6 +42,36 @@ def get_secret_manager_client() -> boto3.client:
4242 secret_manager = session .client ("secretsmanager" , secret_reigon )
4343 return secret_manager
4444
45+ def get_last_modified (client : boto3 .client , file_names : list [str ]) -> dict :
46+ """
47+ This function retrieves and returns the `LastModified` value for the specified set of files
48+ in a given S3 bucket.
49+
50+ Args:
51+ client (boto3.client): An initialized boto3 S3 client.
52+ file_names: A list of string values.
53+
54+ Returns:
55+ dict: A dictionary containing formatted datetime values of the last modification date for each file.
56+ The keys are the base file names (without extension) and the values are the formatted datetime strings.
57+
58+ Raises:
59+ Exception: Propagates any exceptions not caught by the individual file processing.
60+ """
61+
62+ last_modified_timestamps = {}
63+
64+ for file in file_names :
65+ try :
66+ response = client .head_object (Bucket = bucket_name , Key = file )
67+ last_modified = response ["LastModified" ]
68+ file_key = file .split ("." )[0 ]
69+ last_modified_timestamps [file_key ] = last_modified .strftime ('%Y-%m-%d %H:%M:%S' )
70+ except Exception as e :
71+ # Handle the error for a specific file here.
72+ print (f"Error processing file { file } : { e } " )
73+
74+ return last_modified_timestamps
4575
4676@st .cache_data
4777def load_repositories (_s3 , load_date : datetime .date ) -> pd .DataFrame | str :
@@ -216,6 +246,9 @@ def load_file(filename: str) -> dict:
216246
217247s3 = get_s3_client ()
218248
249+ file_names = ["repositories.json" , "secret_scanning.json" , "dependabot.json" ]
250+ last_modified_values = get_last_modified (s3 , file_names )
251+
219252df_repositories = load_repositories (s3 , loading_date )
220253total_secret_alerts , oldest_secret_alert , df_secret_scanning = load_secret_scanning (s3 , loading_date )
221254df_total_dependabot_alerts , oldest_dependabot_alert , worst_severity_dependabot , df_dependabot = load_dependabot (s3 , loading_date )
@@ -258,7 +291,15 @@ def load_file(filename: str) -> dict:
258291# Repository Analysis Section
259292
260293with repository_tab :
261- st .header (":blue-background[Repository Analysis]" )
294+ rep_last_modified = last_modified_values ["repositories" ]
295+ col1 , col2 = st .columns ([3 ,1 ])
296+
297+ with col1 :
298+ st .header (":blue-background[Repository Analysis]" )
299+
300+ with col2 :
301+ st .write (f"#### Last Updated: { rep_last_modified } " )
302+
262303
263304 # Gets the rules from the repository DataFrame
264305 rules = df_repositories .columns .to_list ()[4 :]
@@ -546,7 +587,15 @@ def load_file(filename: str) -> dict:
546587# Secret Scanning Analysis Section
547588
548589with secret_tab :
549- st .header (":blue-background[Secret Scanning Analysis]" )
590+ col1 , col2 = st .columns ([3 ,1 ])
591+ secrets_tab = last_modified_values ["secret_scanning" ]
592+
593+ with col1 :
594+ st .header (":blue-background[Secret Scanning Analysis]" )
595+
596+ with col2 :
597+ st .write (f"#### Last Updated: { secrets_tab } " )
598+
550599 st .write ("Alerts open for more than 5 days." )
551600
552601 col1 , col2 , col3 , col4 = st .columns (4 )
@@ -584,7 +633,15 @@ def load_file(filename: str) -> dict:
584633# Dependabot Analysis Section
585634
586635with dependabot_tab :
587- st .header (":blue-background[Dependabot Analysis]" )
636+ col1 , col2 = st .columns ([3 ,1 ])
637+ dependabot = last_modified_values ["dependabot" ]
638+
639+ with col1 :
640+ st .header (":blue-background[Dependabot Analysis]" )
641+
642+ with col2 :
643+ st .write (f"#### Last Updated: { dependabot } " )
644+
588645 st .write ("Alerts open for more than 5 days (Critical), 15 days (High), 60 days (Medium), 90 days (Low)." )
589646
590647 # Data filters
0 commit comments