SharathReddy commited on
Commit
174d5ef
·
verified ·
1 Parent(s): c710fcc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -52
app.py CHANGED
@@ -17,23 +17,20 @@ 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}",
@@ -41,55 +38,40 @@ def get_installation_access_token(installation_id, app_id, private_key):
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.")
@@ -100,44 +82,46 @@ def read_root():
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
  try:
117
  token = get_installation_access_token(installation_id, GITHUB_APP_ID, GITHUB_PRIVATE_KEY)
118
-
119
- # The key in the payload is "repositories_added" for this event
120
- for repo in payload.get("repositories_added", []):
121
  repo_full_name = repo["full_name"]
122
- # The correct key for the git URL is 'clone_url'
123
- repo_url = repo.get("clone_url") # <--- THIS IS THE FIX
124
-
125
- if repo_url:
126
- process_repository(repo_url, token, repo_full_name)
127
- else:
128
- print(f"Could not find 'clone_url' for repo {repo_full_name}")
129
-
130
  except Exception as e:
131
- print(f"Error during installation processing: {e}")
132
- raise HTTPException(status_code=500, detail=f"Failed to process installation: {e}")
133
-
 
134
  elif event_type == "push":
135
- pusher = payload.get("pusher", {}).get("name")
136
  repo_name = payload.get("repository", {}).get("full_name")
137
- print(f"Received a push event from {pusher} on repo {repo_name}")
138
- # We will add logic here in Step 4
139
-
140
- elif event_type == "ping":
141
- print("Received ping event from GitHub!")
142
 
143
  return {"status": "ok"}
 
17
  GITHUB_PRIVATE_KEY = os.getenv("GITHUB_PRIVATE_KEY")
18
 
19
  # In-memory storage for our repository data (for this simple version)
 
20
  repo_data_store = {}
21
 
22
+ # --- GitHub App Authentication Logic (Unchanged) ---
23
 
24
  def create_jwt(app_id, private_key):
 
25
  now = int(time.time())
26
  payload = {
27
+ "iat": now,
28
+ "exp": now + (10 * 60),
29
+ "iss": app_id,
30
  }
31
  return jwt.encode(payload, private_key, algorithm="RS256")
32
 
33
  def get_installation_access_token(installation_id, app_id, private_key):
 
34
  app_jwt = create_jwt(app_id, private_key)
35
  headers = {
36
  "Authorization": f"Bearer {app_jwt}",
 
38
  }
39
  url = f"https://api.github.com/app/installations/{installation_id}/access_tokens"
40
  response = requests.post(url, headers=headers)
41
+ response.raise_for_status()
42
  return response.json()["token"]
43
 
44
+ # --- Repository Management Logic (Unchanged) ---
 
45
 
46
  def process_repository(repo_url, token, repo_full_name):
 
 
47
  temp_dir = tempfile.mkdtemp()
48
  print(f"Cloning {repo_full_name} into {temp_dir}")
49
 
50
  try:
 
 
51
  clone_url = repo_url.replace("https://", f"https://x-access-token:{token}@")
52
  Repo.clone_from(clone_url, temp_dir)
53
+
 
 
54
  print(f"Parsing repository {repo_full_name}...")
55
  # In the next step, we will add AST parsing and vectorization here.
56
 
 
57
  repo_data_store[repo_full_name] = {"status": "processed", "path": temp_dir}
58
  print(f"Successfully processed and 'stored' data for {repo_full_name}")
59
 
60
  except Exception as e:
61
  print(f"Failed to process repository {repo_full_name}: {e}")
 
 
 
 
 
62
 
63
  # --- FastAPI App ---
64
  app = FastAPI()
65
 
66
  async def verify_signature(request: Request):
67
+ # (This function remains unchanged)
68
  if not GITHUB_WEBHOOK_SECRET:
69
  raise HTTPException(status_code=500, detail="Webhook secret not configured.")
70
  signature_header = request.headers.get("X-Hub-Signature-256")
71
  if not signature_header:
72
  raise HTTPException(status_code=400, detail="X-Hub-Signature-256 header is missing.")
 
 
 
73
  body = await request.body()
74
+ sha_name, signature = signature_header.split("=")
75
  mac = hmac.new(GITHUB_WEBHOOK_SECRET.encode("utf-8"), msg=body, digestmod=hashlib.sha256)
76
  if not hmac.compare_digest(mac.hexdigest(), signature):
77
  raise HTTPException(status_code=400, detail="Invalid signature.")
 
82
 
83
  @app.post("/api/github/webhook")
84
  async def github_webhook(request: Request):
 
85
  await verify_signature(request)
86
 
87
  event_type = request.headers.get("X-GitHub-Event")
88
  payload = await request.json()
89
 
90
+ print(f"Received event: {event_type} with action: {payload.get('action')}")
91
+
92
+ installation_id = payload.get("installation", {}).get("id")
93
+ if not installation_id:
94
+ return {"status": "ok", "message": "Event does not pertain to an installation."}
95
 
96
+ # --- REVISED LOGIC ---
97
+ repos_to_process = []
98
+
99
  if event_type == "installation" and payload.get("action") == "created":
100
+ # This handles the very first time the app is installed on an account.
101
+ repos_to_process = payload.get("repositories", [])
102
+ print(f"Processing 'installation.created' event for repos: {[repo['full_name'] for repo in repos_to_process]}")
103
 
104
+ elif event_type == "installation_repositories" and payload.get("action") == "added":
105
+ # This handles when a user adds one or more repos to an existing installation.
106
+ repos_to_process = payload.get("repositories_added", [])
107
+ print(f"Processing 'installation_repositories.added' event for repos: {[repo['full_name'] for repo in repos_to_process]}")
108
+
109
+ if repos_to_process:
110
  try:
111
  token = get_installation_access_token(installation_id, GITHUB_APP_ID, GITHUB_PRIVATE_KEY)
112
+ for repo in repos_to_process:
 
 
113
  repo_full_name = repo["full_name"]
114
+ # The 'html_url' key is not present in the 'installation_repositories' event,
115
+ # so we construct it manually.
116
+ repo_url = f"https://github.com/{repo_full_name}"
117
+ process_repository(repo_url, token, repo_full_name)
 
 
 
 
118
  except Exception as e:
119
+ print(f"Error during repository processing: {e}")
120
+ # Don't raise HTTPException here to prevent GitHub from disabling the webhook
121
+
122
+ # Handle push events (will be used in Step 4)
123
  elif event_type == "push":
 
124
  repo_name = payload.get("repository", {}).get("full_name")
125
+ print(f"Received a push event on repo {repo_name}")
 
 
 
 
126
 
127
  return {"status": "ok"}