Merge pull request #39 from Molecule-AI/fix/n1-python-auth-headers

fix(security): N1 — Python callers missing auth headers for /workspaces/* routes
This commit is contained in:
Hongming Wang 2026-04-14 02:25:36 -07:00 committed by GitHub
commit 264d490e06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 23 additions and 6 deletions

View File

@ -10,6 +10,8 @@ import uuid
import httpx
from platform_auth import auth_headers
logger = logging.getLogger(__name__)
WORKSPACE_ID = os.environ.get("WORKSPACE_ID", "")
@ -94,7 +96,10 @@ async def get_workspace_info() -> dict:
"""Get this workspace's info from the platform."""
async with httpx.AsyncClient(timeout=10.0) as client:
try:
resp = await client.get(f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}")
resp = await client.get(
f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}",
headers=auth_headers(),
)
if resp.status_code == 200:
return resp.json()
return {"error": "not found"}

View File

@ -14,6 +14,8 @@ import os
import httpx
from platform_auth import auth_headers
logger = logging.getLogger(__name__)
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
@ -53,6 +55,7 @@ class ConsolidationLoop:
resp = await client.get(
f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/memories",
params={"scope": "LOCAL"},
headers=auth_headers(),
)
if resp.status_code != 200:
return
@ -95,12 +98,14 @@ class ConsolidationLoop:
resp = await client.post(
f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/memories",
json={"content": f"[Consolidated] {summary}", "scope": "TEAM"},
headers=auth_headers(),
)
if resp.status_code in (200, 201):
# Safe to delete originals — consolidated version is saved
for m in memories:
await client.delete(
f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/memories/{m['id']}"
f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/memories/{m['id']}",
headers=auth_headers(),
)
logger.info("Consolidated %d memories into team knowledge", len(memories))
else:
@ -118,6 +123,7 @@ class ConsolidationLoop:
await client.post(
f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/memories",
json={"content": f"[Consolidated] {combined}", "scope": "TEAM"},
headers=auth_headers(),
)
logger.info("Consolidated %d memories via concatenation fallback", len(memories))

View File

@ -17,6 +17,8 @@ from pathlib import Path
import httpx
from platform_auth import auth_headers
logger = logging.getLogger(__name__)
HEARTBEAT_INTERVAL = 30 # seconds
@ -83,7 +85,6 @@ class HeartbeatLoop:
while True:
# 1. Send heartbeat (Phase 30.1: include auth header if token known)
try:
from platform_auth import auth_headers
await client.post(
f"{self.platform_url}/registry/heartbeat",
json={
@ -135,7 +136,8 @@ class HeartbeatLoop:
"""Check for completed delegations and store results for the agent."""
try:
resp = await client.get(
f"{self.platform_url}/workspaces/{self.workspace_id}/delegations"
f"{self.platform_url}/workspaces/{self.workspace_id}/delegations",
headers=auth_headers(),
)
if resp.status_code != 200:
return
@ -208,13 +210,15 @@ class HeartbeatLoop:
if self._parent_name is None:
try:
parent_resp = await client.get(
f"{self.platform_url}/workspaces/{self.workspace_id}"
f"{self.platform_url}/workspaces/{self.workspace_id}",
headers=auth_headers(),
)
if parent_resp.status_code == 200:
parent_id = parent_resp.json().get("parent_id", "")
if parent_id:
parent_info = await client.get(
f"{self.platform_url}/workspaces/{parent_id}"
f"{self.platform_url}/workspaces/{parent_id}",
headers=auth_headers(),
)
if parent_info.status_code == 200:
self._parent_name = parent_info.json().get("name", "")
@ -262,6 +266,7 @@ class HeartbeatLoop:
},
},
},
headers=auth_headers(),
timeout=120.0,
)
logger.info("Heartbeat: self-message sent to process delegation results")
@ -277,6 +282,7 @@ class HeartbeatLoop:
await client.post(
f"{self.platform_url}/workspaces/{self.workspace_id}/notify",
json={"message": msg, "type": "delegation_result"},
headers=auth_headers(),
)
except Exception:
pass