88# --- Determine mode ---
99TEST_MODE = os .getenv ("TEST_MODE" , "true" ).lower () == "true"
1010
11- # Only import Flask if not in TEST_MODE
11+ # Import Flask only if not in TEST_MODE
1212if not TEST_MODE :
1313 from flask import Flask , request
1414 app = Flask (__name__ )
@@ -72,6 +72,29 @@ def verify_github_signature(payload_body, signature, secret):
7272 expected_signature = "sha256=" + mac .hexdigest ()
7373 return hmac .compare_digest (expected_signature , signature )
7474
75+ # --- Format GitHub repository event for email ---
76+ def format_repo_event (repo , action ):
77+ repo_name = repo ["full_name" ]
78+ visibility_icon = "π Private" if repo .get ("private" ) else "π Public"
79+ owner = repo ["owner" ]["login" ]
80+ default_branch = repo .get ("default_branch" , "N/A" )
81+ created_at = repo .get ("created_at" , "" ).replace ("T" , " " ).replace ("Z" , "" )
82+ updated_at = repo .get ("updated_at" , "" ).replace ("T" , " " ).replace ("Z" , "" )
83+ url = repo .get ("html_url" , "" )
84+
85+ subject = f"[GitHub Alert] Repository { action } : { repo_name } "
86+ body = (
87+ f"A repository was { action } in your GitHub organization.\n \n "
88+ f"π Repository Name: { repo_name } \n "
89+ f"{ visibility_icon } \n "
90+ f"π€ Owner: { owner } \n "
91+ f"πΏ Default branch: { default_branch } \n "
92+ f"π Created at: { created_at } \n "
93+ f"π Last updated: { updated_at } \n "
94+ f"π URL: { url } \n "
95+ )
96+ return subject , body
97+
7598# --- GitHub Webhook + Health Handlers ---
7699if not TEST_MODE :
77100 @app .route ("/webhook" , methods = ["POST" ])
@@ -80,12 +103,9 @@ def github_webhook():
80103 signature = request .headers .get ("X-Hub-Signature-256" )
81104 secret = os .getenv ("GITHUB_WEBHOOK_SECRET" )
82105
83- # --- Debug logging ---
84106 print ("π₯ Incoming GitHub webhook" )
85- print (f"π₯ Payload size: { len (payload_body )} bytes" )
86- print (f"π₯ GitHub Event: { request .headers .get ('X-GitHub-Event' )} " )
107+ print (f"π₯ Event: { request .headers .get ('X-GitHub-Event' )} " )
87108 print (f"π₯ Signature header: { signature } " )
88- print (f"π₯ Secret length: { len (secret ) if secret else 'None' } " )
89109
90110 if not verify_github_signature (payload_body , signature , secret ):
91111 print (f"β Invalid signature! Webhook rejected." )
@@ -100,41 +120,14 @@ def github_webhook():
100120 event = request .headers .get ("X-GitHub-Event" , "" )
101121
102122 if event == "repository" and data .get ("action" ) in ["created" , "deleted" ]:
103- repo = data ["repository" ]
104- repo_name = repo ["full_name" ]
105- visibility_icon = "π Private" if repo .get ("private" ) else "π Public"
106- owner = repo ["owner" ]["login" ]
107- default_branch = repo .get ("default_branch" , "N/A" )
108- created_at = repo .get ("created_at" )
109- updated_at = repo .get ("updated_at" )
110- url = repo .get ("html_url" , "" )
111-
112- # Remove T and Z from timestamps
113- if created_at :
114- created_at = created_at .replace ("T" , " " ).replace ("Z" , "" )
115- if updated_at :
116- updated_at = updated_at .replace ("T" , " " ).replace ("Z" , "" )
117-
118- subject = f"[GitHub Alert] Repository { data ['action' ]} : { repo_name } "
119- body = (
120- f"A repository was { data ['action' ]} in your GitHub organization.\n \n "
121- f"π Repository Name: { repo_name } \n "
122- f"{ visibility_icon } \n "
123- f"π€ Owner: { owner } \n "
124- f"πΏ Default branch: { default_branch } \n "
125- f"π Created at: { created_at } \n "
126- f"π Last updated: { updated_at } \n "
127- f"π URL: { url } \n "
128- )
129-
123+ subject , body = format_repo_event (data ["repository" ], data ["action" ])
130124 print (f"π© Sending email alert: { subject } " )
131125 send_email_via_graph (subject , body )
132126 else :
133127 print (f"βΉοΈ Ignored event: { event } , action: { data .get ('action' )} " )
134128
135129 return "OK" , 200
136130
137- # Health check endpoint
138131 @app .route ("/health" , methods = ["GET" ])
139132 def health_check ():
140133 return {"status" : "running" }, 200
@@ -143,10 +136,17 @@ def health_check():
143136if __name__ == "__main__" :
144137 if TEST_MODE :
145138 print ("πΉ TEST_MODE: sending test email" )
146- send_email_via_graph (
147- "[Test] Graph Email" ,
148- "π Repository Name: quantori/sadsrepo\n π Visibility: Private\n π€ Owner: quantori\n πΏ Default branch: main\n π Created at: 2025-09-09 13:06:02\n π Last updated: 2025-09-09 13:09:20\n π URL: https://github.com/quantori/sadsrepo"
149- )
139+ test_repo = {
140+ "full_name" : "quantori/sadsrepo" ,
141+ "private" : True ,
142+ "owner" : {"login" : "quantori" },
143+ "default_branch" : "main" ,
144+ "created_at" : "2025-09-09T13:06:02Z" ,
145+ "updated_at" : "2025-09-09T13:09:20Z" ,
146+ "html_url" : "https://github.com/quantori/sadsrepo"
147+ }
148+ subject , body = format_repo_event (test_repo , "created" )
149+ send_email_via_graph (subject , body )
150150 else :
151151 print ("β
Flask is up and listening on /webhook and /health" )
152152 app .run (host = "0.0.0.0" , port = 8000 )
0 commit comments