SharathReddy commited on
Commit
cbe96e4
·
verified ·
1 Parent(s): 096835f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -52
app.py CHANGED
@@ -1,90 +1,139 @@
1
  import os
2
  import hmac
3
  import hashlib
 
 
 
 
 
4
  from fastapi import FastAPI, Request, HTTPException, status
5
  from dotenv import load_dotenv
6
-
7
- # Load environment variables from .env file
8
- load_dotenv()
9
 
10
  # --- Configuration ---
11
- # It's crucial to load the secret from the environment for security
12
  GITHUB_WEBHOOK_SECRET = os.getenv("GITHUB_WEBHOOK_SECRET")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- # --- FastAPI App Initialization ---
 
 
 
 
 
 
 
 
15
  app = FastAPI()
16
 
17
- # --- Helper Functions ---
18
  async def verify_signature(request: Request):
19
- """Verify that the request is from GitHub."""
20
  if not GITHUB_WEBHOOK_SECRET:
21
- # This is a server-side configuration error.
22
- raise HTTPException(
23
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
24
- detail="Webhook secret not configured."
25
- )
26
-
27
- # Get the signature from the headers
28
  signature_header = request.headers.get("X-Hub-Signature-256")
29
  if not signature_header:
30
- raise HTTPException(
31
- status_code=status.HTTP_400_BAD_REQUEST,
32
- detail="X-Hub-Signature-256 header is missing."
33
- )
34
-
35
- # The signature is in the format "sha256=..."
36
  sha_name, signature = signature_header.split("=")
37
  if sha_name != "sha256":
38
- raise HTTPException(
39
- status_code=status.HTTP_501_NOT_IMPLEMENTED,
40
- detail="Only sha256 signatures are supported."
41
- )
42
-
43
- # Get the raw request body
44
  body = await request.body()
45
-
46
- # Create our own signature
47
- mac = hmac.new(
48
- GITHUB_WEBHOOK_SECRET.encode("utf-8"),
49
- msg=body,
50
- digestmod=hashlib.sha256
51
- )
52
-
53
- # Compare the signatures
54
  if not hmac.compare_digest(mac.hexdigest(), signature):
55
- raise HTTPException(
56
- status_code=status.HTTP_400_BAD_REQUEST,
57
- detail="Invalid signature."
58
- )
59
 
60
- # --- API Endpoints ---
61
  @app.get("/")
62
  def read_root():
63
- """A simple root endpoint to confirm the server is running."""
64
  return {"message": "Docu-Pilot server is alive!"}
65
 
66
-
67
  @app.post("/api/github/webhook")
68
  async def github_webhook(request: Request):
69
- """
70
- This endpoint receives webhook events from GitHub.
71
- It first verifies the signature to ensure the request is authentic.
72
- """
73
  await verify_signature(request)
74
 
75
- # You can get the event type from the headers
76
  event_type = request.headers.get("X-GitHub-Event")
77
  payload = await request.json()
78
 
79
- if event_type == "push":
80
- # In future steps, we will process the push event here.
81
- # For now, we'll just log it.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  pusher = payload.get("pusher", {}).get("name")
83
  repo_name = payload.get("repository", {}).get("full_name")
84
  print(f"Received a push event from {pusher} on repo {repo_name}")
85
-
 
86
  elif event_type == "ping":
87
- # GitHub sends a ping event when the webhook is first set up.
88
  print("Received ping event from GitHub!")
89
 
90
  return {"status": "ok"}
 
1
  import os
2
  import hmac
3
  import hashlib
4
+ import time
5
+ import jwt
6
+ import requests
7
+ import tempfile
8
+ import shutil
9
  from fastapi import FastAPI, Request, HTTPException, status
10
  from dotenv import load_dotenv
11
+ from git import Repo
 
 
12
 
13
  # --- Configuration ---
14
+ load_dotenv()
15
  GITHUB_WEBHOOK_SECRET = os.getenv("GITHUB_WEBHOOK_SECRET")
16
+ GITHUB_APP_ID = os.getenv("GITHUB_APP_ID")
17
+ GITHUB_PRIVATE_KEY = os.getenv("GITHUB_PRIVATE_KEY")
18
+
19
+ # In-memory storage for our repository data (for this simple version)
20
+ # In a real app, you might use Redis or a database.
21
+ repo_data_store = {}
22
+
23
+ # --- GitHub App Authentication Logic ---
24
+
25
+ def create_jwt(app_id, private_key):
26
+ """Creates a JSON Web Token to authenticate as a GitHub App."""
27
+ now = int(time.time())
28
+ payload = {
29
+ "iat": now, # Issued at time
30
+ "exp": now + (10 * 60), # Expiration time (10 minutes)
31
+ "iss": app_id, # Issuer (your app's ID)
32
+ }
33
+ return jwt.encode(payload, private_key, algorithm="RS256")
34
+
35
+ def get_installation_access_token(installation_id, app_id, private_key):
36
+ """Gets a temporary access token for a specific installation."""
37
+ app_jwt = create_jwt(app_id, private_key)
38
+ headers = {
39
+ "Authorization": f"Bearer {app_jwt}",
40
+ "Accept": "application/vnd.github.v3+json",
41
+ }
42
+ url = f"https://api.github.com/app/installations/{installation_id}/access_tokens"
43
+ response = requests.post(url, headers=headers)
44
+ response.raise_for_status() # Raise an exception for bad status codes
45
+ return response.json()["token"]
46
+
47
+
48
+ # --- Repository Management Logic ---
49
+
50
+ def process_repository(repo_url, token, repo_full_name):
51
+ """Clones a repo, parses it, and stores the data."""
52
+ # Create a temporary directory to clone the repo into
53
+ temp_dir = tempfile.mkdtemp()
54
+ print(f"Cloning {repo_full_name} into {temp_dir}")
55
+
56
+ try:
57
+ # Clone the repository using the installation token
58
+ # The token is embedded in the URL for authentication
59
+ clone_url = repo_url.replace("https://", f"https://x-access-token:{token}@")
60
+ Repo.clone_from(clone_url, temp_dir)
61
+
62
+ # --- THIS IS WHERE STEP 2.C and 2.D WILL GO ---
63
+ # For now, we'll just simulate processing
64
+ print(f"Parsing repository {repo_full_name}...")
65
+ # In the next step, we will add AST parsing and vectorization here.
66
+
67
+ # Store some placeholder data
68
+ repo_data_store[repo_full_name] = {"status": "processed", "path": temp_dir}
69
+ print(f"Successfully processed and 'stored' data for {repo_full_name}")
70
 
71
+ except Exception as e:
72
+ print(f"Failed to process repository {repo_full_name}: {e}")
73
+ # finally:
74
+ # In a real app, you would clean up the temp directory.
75
+ # For this step, we leave it to inspect if needed.
76
+ # shutil.rmtree(temp_dir)
77
+
78
+
79
+ # --- FastAPI App ---
80
  app = FastAPI()
81
 
 
82
  async def verify_signature(request: Request):
83
+ # (This function remains unchanged from Step 1)
84
  if not GITHUB_WEBHOOK_SECRET:
85
+ raise HTTPException(status_code=500, detail="Webhook secret not configured.")
 
 
 
 
 
 
86
  signature_header = request.headers.get("X-Hub-Signature-256")
87
  if not signature_header:
88
+ raise HTTPException(status_code=400, detail="X-Hub-Signature-256 header is missing.")
 
 
 
 
 
89
  sha_name, signature = signature_header.split("=")
90
  if sha_name != "sha256":
91
+ raise HTTPException(status_code=501, detail="Only sha256 signatures are supported.")
 
 
 
 
 
92
  body = await request.body()
93
+ mac = hmac.new(GITHUB_WEBHOOK_SECRET.encode("utf-8"), msg=body, digestmod=hashlib.sha256)
 
 
 
 
 
 
 
 
94
  if not hmac.compare_digest(mac.hexdigest(), signature):
95
+ raise HTTPException(status_code=400, detail="Invalid signature.")
 
 
 
96
 
 
97
  @app.get("/")
98
  def read_root():
 
99
  return {"message": "Docu-Pilot server is alive!"}
100
 
 
101
  @app.post("/api/github/webhook")
102
  async def github_webhook(request: Request):
103
+ """Handles all incoming webhook events from GitHub."""
 
 
 
104
  await verify_signature(request)
105
 
 
106
  event_type = request.headers.get("X-GitHub-Event")
107
  payload = await request.json()
108
 
109
+ print(f"Received event: {event_type}")
110
+
111
+ # --- NEW: Handle Installation Event ---
112
+ if event_type == "installation" and payload.get("action") == "created":
113
+ installation_id = payload["installation"]["id"]
114
+ print(f"New installation created! ID: {installation_id}")
115
+
116
+ # Get an access token for this installation
117
+ try:
118
+ token = get_installation_access_token(installation_id, GITHUB_APP_ID, GITHUB_PRIVATE_KEY)
119
+
120
+ # Process all repositories this app was installed on
121
+ for repo in payload["repositories"]:
122
+ repo_full_name = repo["full_name"]
123
+ repo_url = repo["html_url"]
124
+ process_repository(repo_url, token, repo_full_name)
125
+
126
+ except Exception as e:
127
+ print(f"Error during installation processing: {e}")
128
+ raise HTTPException(status_code=500, detail="Failed to process installation.")
129
+
130
+ elif event_type == "push":
131
  pusher = payload.get("pusher", {}).get("name")
132
  repo_name = payload.get("repository", {}).get("full_name")
133
  print(f"Received a push event from {pusher} on repo {repo_name}")
134
+ # We will add logic here in Step 4
135
+
136
  elif event_type == "ping":
 
137
  print("Received ping event from GitHub!")
138
 
139
  return {"status": "ok"}