bbkdevops commited on
Commit
bf9f684
·
verified ·
1 Parent(s): 4faddf2

Upload webhook_automation_manager.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. webhook_automation_manager.py +90 -0
webhook_automation_manager.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Hugging Face Webhooks Automation Substrate
3
+ Automates real-time event listening and CI/CD triggers on repository changes.
4
+ Supports `create_webhook`, payload signature validation, and event handling.
5
+ """
6
+
7
+ from huggingface_hub import HfApi, get_token
8
+ import os
9
+ import json
10
+ import hmac
11
+ import hashlib
12
+
13
+ class WebhookAutomationManager:
14
+ def __init__(self, token: str = None):
15
+ self.token = token or get_token()
16
+ self.api = HfApi(token=self.token)
17
+
18
+ def register_repo_webhook(
19
+ self,
20
+ watched_repos: list[dict],
21
+ job_id: str = None,
22
+ url: str = None,
23
+ secret: str = None,
24
+ domains: list[str] = None
25
+ ) -> dict:
26
+ """
27
+ Create a webhook on Hugging Face to monitor repository or discussion changes.
28
+ watched: list of dicts e.g. [{"type": "user", "name": "bbkdevops"}]
29
+ domains: ["repo", "discussion"]
30
+ """
31
+ domains = domains or ["repo", "discussion"]
32
+ secret = secret or os.environ.get("HF_WEBHOOK_SECRET", "fiber-moe-webhook-secret-2026")
33
+
34
+ try:
35
+ # Check if create_webhook exists in HfApi
36
+ if hasattr(self.api, "create_webhook"):
37
+ webhook = self.api.create_webhook(
38
+ watched=watched_repos,
39
+ domains=domains,
40
+ secret=secret,
41
+ url=url,
42
+ job_id=job_id
43
+ )
44
+ return {"status": "created", "webhook": str(webhook)}
45
+ else:
46
+ return {
47
+ "status": "simulated",
48
+ "watched": watched_repos,
49
+ "domains": domains,
50
+ "secret": "***"
51
+ }
52
+ except Exception as e:
53
+ return {"status": "error", "error": str(e)}
54
+
55
+ @staticmethod
56
+ def verify_webhook_signature(payload_bytes: bytes, signature_header: str, secret: str) -> bool:
57
+ """Verify the HMAC SHA-256 webhook payload signature."""
58
+ if not signature_header or not secret:
59
+ return False
60
+ expected = hmac.new(secret.encode("utf-8"), payload_bytes, hashlib.sha256).hexdigest()
61
+ return hmac.compare_digest(signature_header, expected)
62
+
63
+ @staticmethod
64
+ def parse_event_payload(payload_json: str | dict) -> dict:
65
+ """Parse incoming webhook event metadata."""
66
+ if isinstance(payload_json, str):
67
+ data = json.loads(payload_json)
68
+ else:
69
+ data = payload_json
70
+
71
+ event = data.get("event", {})
72
+ repo = data.get("repo", {})
73
+ return {
74
+ "action": event.get("action"),
75
+ "scope": event.get("scope"),
76
+ "repo_id": f"{repo.get('owner')}/{repo.get('name')}" if repo else None,
77
+ "repo_type": repo.get("type"),
78
+ "head_sha": repo.get("headSha")
79
+ }
80
+
81
+ if __name__ == "__main__":
82
+ manager = WebhookAutomationManager()
83
+ print("Testing WebhookAutomationManager...")
84
+ sample_payload = {
85
+ "event": {"action": "update", "scope": "repo.content"},
86
+ "repo": {"owner": "bbkdevops", "name": "Fiber-MoE-Symplectic-Gating-Research", "type": "model", "headSha": "a1b2c3d4"}
87
+ }
88
+ parsed = manager.parse_event_payload(sample_payload)
89
+ print("Parsed Event:", json.dumps(parsed, indent=2))
90
+ print("Webhook manager ready!")