Skip to content

Commit 2dd2ab5

Browse files
committed
fix: require workspace context for route aliases
1 parent 1d6c94b commit 2dd2ab5

2 files changed

Lines changed: 36 additions & 2 deletions

File tree

tests/unit/test_role_acl.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,34 @@ async def api_key_conflict_route( # pyright: ignore[reportUnusedFunction] - rou
230230
authenticate_api_key.assert_not_awaited()
231231

232232

233+
def test_role_acl_auto_workspace_requires_workspace_context(
234+
role_acl_app: FastAPI,
235+
monkeypatch: pytest.MonkeyPatch,
236+
) -> None:
237+
authenticate_api_key = AsyncMock()
238+
monkeypatch.setattr(credentials, "_authenticate_api_key", authenticate_api_key)
239+
240+
@role_acl_app.get("/api-key-missing-workspace")
241+
async def api_key_missing_workspace_route( # pyright: ignore[reportUnusedFunction] - route handler
242+
role: Role = RoleACL(
243+
allow_user=False,
244+
allow_api_key=True,
245+
require_workspace="yes",
246+
workspace_id_in_path="auto",
247+
),
248+
) -> dict[str, str]:
249+
return {"role_type": role.type}
250+
251+
response = TestClient(role_acl_app).get(
252+
"/api-key-missing-workspace",
253+
headers={"Authorization": "Bearer tc_ws_sk_managed-api-key_secret"},
254+
)
255+
256+
assert response.status_code == 422
257+
assert response.json()["detail"] == "workspace_id is required"
258+
authenticate_api_key.assert_not_awaited()
259+
260+
233261
def test_role_acl_combined_service_and_api_key_route_uses_service_key_fallback(
234262
role_acl_app: FastAPI,
235263
monkeypatch: pytest.MonkeyPatch,

tracecat/auth/credentials.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ async def _role_dependency(
896896
def _resolve_workspace_id_from_path_or_query(
897897
request: Request,
898898
workspace_id_query: uuid.UUID | None,
899-
) -> uuid.UUID | None:
899+
) -> uuid.UUID:
900900
path_value = request.path_params.get("workspace_id")
901901
path_workspace_id: uuid.UUID | None = None
902902
if path_value is not None:
@@ -921,7 +921,13 @@ def _resolve_workspace_id_from_path_or_query(
921921
status_code=status.HTTP_400_BAD_REQUEST,
922922
detail="Path and query workspace_id values must match",
923923
)
924-
return path_workspace_id or workspace_id_query
924+
workspace_id = path_workspace_id or workspace_id_query
925+
if workspace_id is None:
926+
raise HTTPException(
927+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
928+
detail="workspace_id is required",
929+
)
930+
return workspace_id
925931

926932

927933
def RoleACL(

0 commit comments

Comments
 (0)