Skip to content

Commit 4ca3198

Browse files
authored
Update get_email_webhook.py
1 parent da8dc62 commit 4ca3198

File tree

1 file changed

+30
-18
lines changed

1 file changed

+30
-18
lines changed

get_email_webhook.py

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,27 @@
66
from msal import ConfidentialClientApplication
77
from datetime import datetime, timezone, timedelta
88

9-
# --- Determine mode ---
9+
# --- Environment variables (loaded once) ---
10+
TENANT_ID = os.getenv("TENANT_ID")
11+
CLIENT_ID = os.getenv("CLIENT_ID")
12+
CLIENT_SECRET = os.getenv("CLIENT_SECRET")
13+
FROM_EMAIL = os.getenv("FROM_EMAIL")
14+
TO_EMAIL = os.getenv("TO_EMAIL")
15+
GITHUB_WEBHOOK_SECRET = os.getenv("GITHUB_WEBHOOK_SECRET")
16+
17+
# --- Mode toggle (Test vs Webhook server) ---
1018
TEST_MODE = os.getenv("TEST_MODE", "true").lower() == "true"
1119

12-
# Import Flask only if not in TEST_MODE
1320
if not TEST_MODE:
1421
from flask import Flask, request
1522
app = Flask(__name__)
1623

24+
1725
# --- Microsoft Graph Email Sending Function ---
1826
def send_email_via_graph(subject, body):
19-
TENANT_ID = os.getenv("TENANT_ID")
20-
CLIENT_ID = os.getenv("CLIENT_ID")
21-
CLIENT_SECRET = os.getenv("CLIENT_SECRET")
22-
FROM_EMAIL = os.getenv("FROM_EMAIL")
23-
TO_EMAIL = os.getenv("TO_EMAIL")
24-
27+
"""Send email using Microsoft Graph API via client credentials flow."""
2528
if not all([TENANT_ID, CLIENT_ID, CLIENT_SECRET, FROM_EMAIL, TO_EMAIL]):
26-
print("❌ Missing required environment variables")
29+
print("❌ Missing required environment variables for email sending")
2730
return
2831

2932
try:
@@ -34,6 +37,7 @@ def send_email_via_graph(subject, body):
3437
)
3538
token = app_msal.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
3639
access_token = token.get("access_token")
40+
3741
if not access_token:
3842
print(f"❌ Failed to get access token: {token}")
3943
return
@@ -60,8 +64,10 @@ def send_email_via_graph(subject, body):
6064
except Exception as e:
6165
print(f"❌ Exception occurred while sending email: {e}")
6266

63-
# --- Verify GitHub webhook signature ---
67+
68+
# --- GitHub Webhook Signature Verification ---
6469
def verify_github_signature(payload_body, signature, secret):
70+
"""Verify X-Hub-Signature-256 against webhook secret."""
6571
if not secret:
6672
print("⚠️ No webhook secret set, skipping verification")
6773
return True
@@ -73,8 +79,10 @@ def verify_github_signature(payload_body, signature, secret):
7379
expected_signature = "sha256=" + mac.hexdigest()
7480
return hmac.compare_digest(expected_signature, signature)
7581

82+
7683
# --- Convert UTC timestamp to UTC+4 ---
7784
def convert_to_utc4(timestamp):
85+
"""Convert ISO UTC timestamp string to UTC+4 formatted datetime string."""
7886
if not timestamp:
7987
return "N/A"
8088
try:
@@ -85,8 +93,10 @@ def convert_to_utc4(timestamp):
8593
print(f"⚠️ Failed to convert timestamp {timestamp}: {e}")
8694
return timestamp
8795

96+
8897
# --- Format GitHub repository event for email ---
8998
def format_repo_event(repo, action):
99+
"""Generate subject + body text for repository created/deleted events."""
90100
repo_name = repo["full_name"]
91101
visibility_icon = "🔒 Private" if repo.get("private") else "🌐 Public"
92102
owner = repo["owner"]["login"]
@@ -108,20 +118,20 @@ def format_repo_event(repo, action):
108118
)
109119
return subject, body
110120

111-
# --- GitHub Webhook + Health Handlers ---
121+
122+
# --- Flask Handlers (only if not in TEST_MODE) ---
112123
if not TEST_MODE:
113124
@app.route("/webhook", methods=["POST"])
114125
def github_webhook():
115126
payload_body = request.data
116127
signature = request.headers.get("X-Hub-Signature-256")
117-
secret = os.getenv("GITHUB_WEBHOOK_SECRET")
118128

119129
print("📥 Incoming GitHub webhook")
120130
print(f"📥 Event: {request.headers.get('X-GitHub-Event')}")
121131
print(f"📥 Signature header: {signature}")
122132

123-
if not verify_github_signature(payload_body, signature, secret):
124-
print(f"❌ Invalid signature! Webhook rejected.")
133+
if not verify_github_signature(payload_body, signature, GITHUB_WEBHOOK_SECRET):
134+
print("❌ Invalid signature! Webhook rejected.")
125135
return "❌ Invalid signature", 401
126136

127137
try:
@@ -131,24 +141,26 @@ def github_webhook():
131141
return "❌ Bad payload", 400
132142

133143
event = request.headers.get("X-GitHub-Event", "")
144+
action = data.get("action", "")
134145

135-
if event == "repository" and data.get("action") in ["created", "deleted"]:
136-
subject, body = format_repo_event(data["repository"], data["action"])
146+
if event == "repository" and action in ["created", "deleted"]:
147+
subject, body = format_repo_event(data["repository"], action)
137148
print(f"📩 Sending email alert: {subject}")
138149
send_email_via_graph(subject, body)
139150
else:
140-
print(f"ℹ️ Ignored event: {event}, action: {data.get('action')}")
151+
print(f"ℹ️ Ignored event: {event}, action: {action}")
141152

142153
return "OK", 200
143154

144155
@app.route("/health", methods=["GET"])
145156
def health_check():
146157
return {"status": "running"}, 200
147158

159+
148160
# --- Main Entry Point ---
149161
if __name__ == "__main__":
150162
if TEST_MODE:
151-
print("🔹 TEST_MODE: sending test email")
163+
print("🔹 TEST_MODE enabled: sending test email...")
152164
test_repo = {
153165
"full_name": "quantori/sadsrepo",
154166
"private": True,

0 commit comments

Comments
 (0)