Skip to content

Commit 4403b3a

Browse files
committed
fix(audit): resolve critical config API keys, Dockerfile engine copy, secrets.compare_digest, async embedding thread offload, and formulas path traversal
1 parent 312bf78 commit 4403b3a

5 files changed

Lines changed: 14 additions & 2 deletions

File tree

config.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ class Config:
4545
LLAMAPARSE_API_KEY: str = os.getenv("LLAMAPARSE_API_KEY", "").strip()
4646
UNSTRUCTURED_API_KEY: str = os.getenv("UNSTRUCTURED_API_KEY", "").strip()
4747
UNSTRUCTURED_SERVER_URL: str = os.getenv("UNSTRUCTURED_SERVER_URL", "https://api.unstructured.io/general/v0/general").strip()
48+
49+
# Cloud LLM API Keys
50+
GEMINI_API_KEY: str = os.getenv("GEMINI_API_KEY", "").strip()
51+
OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "").strip()
52+
GROQ_API_KEY: str = os.getenv("GROQ_API_KEY", "").strip()
53+
4854
# Security & API Auth
4955
API_KEY: str = os.getenv("API_KEY", "").strip()
5056

@@ -69,5 +75,7 @@ def validate_keys(cls) -> dict:
6975
"LlamaParse": "READY" if cls.LLAMAPARSE_API_KEY else "NOT SET",
7076
"Unstructured": "READY" if cls.UNSTRUCTURED_API_KEY else "NOT SET",
7177
"Gemini": "READY" if cls.GEMINI_API_KEY else "NOT SET",
78+
"OpenAI": "READY" if cls.OPENAI_API_KEY else "NOT SET",
79+
"Groq": "READY" if cls.GROQ_API_KEY else "NOT SET",
7280
"Local Fallback": "pypdf (Always Available)"
7381
}

docker/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ ENV PYTHONDONTWRITEBYTECODE=1
3434
# Copy application source code
3535
COPY config.py server.py cli.py ./
3636
COPY json_ld_extractor/ ./json_ld_extractor/
37+
COPY corpusld_engine/ ./corpusld_engine/
3738
COPY services/ ./services/
3839
COPY routes/ ./routes/
3940
COPY frontend/ ./frontend/

routes/chat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ async def chat_rag(req: ChatRequest):
6262
]
6363
)
6464

65-
query_vector = embedder.encode(req.query).tolist()
65+
query_vector = (await asyncio.to_thread(embedder.encode, req.query)).tolist()
6666
search_results = qdrant.query_points(
6767
collection_name=Config.QDRANT_COLLECTION_NAME,
6868
query=query_vector,

routes/exports.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ async def get_document_terms(file_name: str):
138138

139139
@router.get("/api/documents/{file_name}/formulas")
140140
async def get_document_formulas(file_name: str):
141+
validate_safe_filename(file_name)
141142
stored = get_persisted_document(file_name)
142143
if stored:
143144
data = stored["schema_json_ld"] if "schema_json_ld" in stored else stored

server.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ async def lifespan(app: FastAPI):
117117
)
118118

119119

120+
import secrets
121+
120122
# ---------------------------------------------------------
121123
# OPTIONAL API KEY AUTHENTICATION MIDDLEWARE
122124
# ---------------------------------------------------------
@@ -130,7 +132,7 @@ async def api_key_auth_middleware(request: Request, call_next):
130132
if auth_header.startswith("Bearer "):
131133
client_key = auth_header[7:].strip()
132134

133-
if not client_key or client_key != Config.API_KEY:
135+
if not client_key or not secrets.compare_digest(client_key, Config.API_KEY):
134136
return JSONResponse(
135137
status_code=401,
136138
content={"success": False, "error": True, "message": "Unauthorized: Invalid or missing X-API-Key header.", "status_code": 401}

0 commit comments

Comments
 (0)