44import hashlib
55import requests
66from msal import ConfidentialClientApplication
7+ from datetime import datetime
78
89# --- Determine mode ---
910TEST_MODE = os .getenv ("TEST_MODE" , "true" ).lower () == "true"
1011
1112# Only import Flask if not in TEST_MODE
1213if not TEST_MODE :
13- from flask import Flask , request , jsonify
14+ from flask import Flask , request
1415 app = Flask (__name__ )
1516
1617# --- Microsoft Graph Email Sending Function ---
@@ -23,7 +24,7 @@ def send_email_via_graph(subject, body):
2324
2425 if not all ([TENANT_ID , CLIENT_ID , CLIENT_SECRET , FROM_EMAIL , TO_EMAIL ]):
2526 print ("❌ Missing required environment variables" )
26- return False
27+ return
2728
2829 try :
2930 app_msal = ConfidentialClientApplication (
@@ -35,7 +36,7 @@ def send_email_via_graph(subject, body):
3536 access_token = token .get ("access_token" )
3637 if not access_token :
3738 print (f"❌ Failed to get access token: { token } " )
38- return False
39+ return
3940
4041 email_msg = {
4142 "message" : {
@@ -53,14 +54,22 @@ def send_email_via_graph(subject, body):
5354
5455 if response .status_code == 202 :
5556 print (f"✅ Email sent to { TO_EMAIL } " )
56- return True
5757 else :
5858 print (f"❌ Failed to send email: { response .status_code } { response .text } " )
59- return False
6059
6160 except Exception as e :
6261 print (f"❌ Exception occurred while sending email: { e } " )
63- return False
62+
63+ # --- Format GitHub timestamp ---
64+ def format_timestamp (ts ):
65+ """Convert GitHub timestamp to 'YYYY-MM-DD HH:MM:SS' format."""
66+ if not ts :
67+ return None
68+ try :
69+ dt = datetime .strptime (ts , "%Y-%m-%dT%H:%M:%SZ" )
70+ return dt .strftime ("%Y-%m-%d %H:%M:%S" )
71+ except Exception :
72+ return ts # fallback
6473
6574# --- Verify GitHub webhook signature ---
6675def verify_github_signature (payload_body , signature , secret ):
@@ -75,13 +84,13 @@ def verify_github_signature(payload_body, signature, secret):
7584 expected_signature = "sha256=" + mac .hexdigest ()
7685 return hmac .compare_digest (expected_signature , signature )
7786
78- # --- GitHub Webhook Handler ---
87+ # --- GitHub Webhook + Health Handlers ---
7988if not TEST_MODE :
8089 @app .route ("/webhook" , methods = ["POST" ])
8190 def github_webhook ():
8291 payload_body = request .data
8392 signature = request .headers .get ("X-Hub-Signature-256" )
84- secret = os .getenv ("GITHUB_WEBHOOK_SECRET" ) # ✅ Correct usage
93+ secret = os .getenv ("GITHUB_WEBHOOK_SECRET" )
8594
8695 # Debug logging
8796 print ("📥 Incoming GitHub webhook" )
@@ -102,19 +111,35 @@ def github_webhook():
102111
103112 event = request .headers .get ("X-GitHub-Event" , "" )
104113
105- # Handle repository create/delete events
106114 if event == "repository" and data .get ("action" ) in ["created" , "deleted" ]:
107- repo_name = data [ "repository" ][ "full_name" ]
115+ repo = data . get ( "repository" , {})
108116 action = data ["action" ]
109117
110- subject = f"[GitHub Alert] Repository { action } : { repo_name } "
111- body = (
112- f"A repository was { action } in your GitHub organization.\n \n "
113- f"Details:\n { json .dumps (data , indent = 2 )} "
114- )
118+ repo_name = repo .get ("name" )
119+ full_name = repo .get ("full_name" )
120+ org = repo .get ("owner" , {}).get ("login" )
121+ owner_id = repo .get ("owner" , {}).get ("id" )
122+ default_branch = repo .get ("default_branch" )
123+ created_at = format_timestamp (repo .get ("created_at" ))
124+ updated_at = format_timestamp (repo .get ("updated_at" ))
125+ html_url = repo .get ("html_url" )
126+
127+ subject = f"[GitHub Alert] Repository { action } : { full_name } "
128+ body = f"""
129+ A repository was { action } in your GitHub organization.
130+
131+ Repository: { repo_name }
132+ Full name: { full_name }
133+ Organization: { org }
134+ Owner ID: { owner_id }
135+ Default branch: { default_branch }
136+ Created at: { created_at }
137+ Last updated: { updated_at }
138+ URL: { html_url }
139+ """
115140
116141 print (f"📩 Sending email alert: { subject } " )
117- send_email_via_graph (subject , body )
142+ send_email_via_graph (subject , body . strip () )
118143 else :
119144 print (f"ℹ️ Ignored event: { event } , action: { data .get ('action' )} " )
120145
@@ -123,18 +148,16 @@ def github_webhook():
123148 # Health check endpoint
124149 @app .route ("/health" , methods = ["GET" ])
125150 def health_check ():
126- return jsonify ( {"status" : "running" }) , 200
151+ return {"status" : "running" }, 200
127152
128153# --- Main Entry Point ---
129154if __name__ == "__main__" :
130155 if TEST_MODE :
131156 print ("🔹 TEST_MODE: sending test email" )
132157 send_email_via_graph (
133158 "[Test] Graph Email" ,
134- "This is a test email sent via Microsoft Graph with application permissions. "
159+ "The information of Quantori's GitHub repositories has been updated "
135160 )
136161 else :
137162 print ("✅ Flask is up and listening on /webhook and /health" )
138- # Azure expects port 8000 by default for containerized apps
139- port = int (os .getenv ("PORT" , 8000 ))
140- app .run (host = "0.0.0.0" , port = port )
163+ app .run (host = "0.0.0.0" , port = int (os .getenv ("PORT" , 8000 )))
0 commit comments