Skip to content

Commit c769652

Browse files
minor improvements
1 parent b2b649c commit c769652

File tree

1 file changed

+21
-9
lines changed

1 file changed

+21
-9
lines changed

src/launchpad/sentry_client.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
import json
88
import logging
99
import os
10+
import re
11+
import secrets
1012

13+
from pathlib import Path
1114
from typing import Any, Dict
1215

1316
import requests
@@ -18,10 +21,9 @@
1821
class SentryClient:
1922
"""Client for authenticated API calls to the Sentry monolith."""
2023

21-
def __init__(self, base_url: str = "http://localhost:8000", shared_secret: str | None = None) -> None:
24+
def __init__(self, base_url: str) -> None:
2225
self.base_url = base_url.rstrip("/")
23-
self.shared_secret = shared_secret or os.getenv("LAUNCHPAD_RPC_SHARED_SECRET")
24-
26+
self.shared_secret = os.getenv("LAUNCHPAD_RPC_SHARED_SECRET")
2527
if not self.shared_secret:
2628
raise RuntimeError("LAUNCHPAD_RPC_SHARED_SECRET must be provided or set as environment variable")
2729

@@ -47,7 +49,7 @@ def _make_request(
4749
"Authorization": f"rpcsignature {self._generate_signature(body)}",
4850
}
4951

50-
logger.debug(f"{method} {url}")
52+
logger.debug(f"{method} {endpoint}")
5153
response = requests.request(
5254
method=method,
5355
url=url,
@@ -58,7 +60,7 @@ def _make_request(
5860
)
5961

6062
if response.status_code != 200:
61-
logger.warning(f"{method} {url} -> {response.status_code}")
63+
logger.warning(f"{method} {endpoint} -> {response.status_code}")
6264

6365
return response
6466

@@ -69,7 +71,6 @@ def _handle_response(self, response: requests.Response) -> Dict[str, Any]:
6971
else:
7072
return {
7173
"error": f"HTTP {response.status_code}",
72-
"message": response.text,
7374
"status_code": response.status_code,
7475
}
7576

@@ -82,6 +83,13 @@ def assemble_size_analysis(
8283
chunks: list[str],
8384
) -> Dict[str, Any]:
8485
"""Call the assemble size analysis endpoint."""
86+
# Validate hex strings
87+
if not re.match(r"^[a-fA-F0-9]+$", checksum):
88+
raise ValueError("Invalid checksum format")
89+
for chunk in chunks:
90+
if not re.match(r"^[a-fA-F0-9]+$", chunk):
91+
raise ValueError("Invalid chunk format")
92+
8593
data = {
8694
"checksum": checksum,
8795
"chunks": chunks,
@@ -136,10 +144,14 @@ def upload_size_analysis_file(
136144
max_retries: int = 3,
137145
) -> Dict[str, Any]:
138146
"""Upload size analysis file with chunking following Rust sentry-cli pattern."""
139-
if not os.path.exists(file_path):
147+
# Basic path validation
148+
path = Path(file_path).resolve()
149+
if not path.exists():
140150
raise FileNotFoundError(f"File not found: {file_path}")
151+
if ".." in str(path):
152+
raise ValueError("Invalid file path")
141153

142-
with open(file_path, "rb") as f:
154+
with open(path, "rb") as f:
143155
content = f.read()
144156

145157
logger.info(f"Uploading {file_path} ({len(content)} bytes, {len(content) / 1024 / 1024:.2f} MB)")
@@ -250,7 +262,7 @@ def _upload_chunks(self, org: str, chunks: list[Dict[str, Any]], target_checksum
250262
def _upload_chunk(self, org: str, chunk: Dict[str, Any]) -> bool:
251263
"""Upload single chunk."""
252264
endpoint = f"/api/0/organizations/{org}/chunk-upload/"
253-
boundary = f"----FormBoundary{chunk['checksum'][:16]}"
265+
boundary = f"----FormBoundary{secrets.token_hex(16)}"
254266

255267
# Create multipart body
256268
body = self._create_multipart_body(boundary, chunk["checksum"], chunk["data"])

0 commit comments

Comments
 (0)