fix(history): deny unknown page IDs in access check#57
Conversation
There was a problem hiding this comment.
💡 Codex Review
openbridgeserver/obs/api/v1/history.py
Line 93 in 22acd70
When access is inherited from a protected ancestor, this check validates the token against the requested page id, but session tokens are minted for the node passed to /visu/nodes/{node_id}/auth and validate_session requires an exact node-id match. After this commit started resolving inherited ACLs, protected child pages now hit this branch and valid tokens from the defining protected parent are rejected with 401, breaking legitimate history reads for inherited-protected pages.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| async def _resolve_page_access(db: Database, node_id: str) -> str: | ||
| """Traversiert die parent_id-Kette und gibt das effektive Access-Level zurück.""" | ||
| current_id: str | None = node_id | ||
| while current_id: |
There was a problem hiding this comment.
Guard against cycles in access-chain traversal
Track visited node IDs (or enforce a max depth) in _resolve_page_access, because the current while current_id loop can become non-terminating when visu_nodes.parent_id contains a cycle. Cycles are possible from existing write paths (for example, node moves do not enforce acyclic parent relationships), and with such data a history request using that X-Page-Id will repeatedly query forever, tying up a worker and creating a denial-of-service condition for affected endpoints.
Useful? React with 👍 / 👎.
Upstream Tracking
Motivation
X-Page-Idor a node with inherited/NULL access was treated aspublic, allowing unauthenticated reads of history/aggregate endpoints.public.Description
async def _resolve_page_access(db: Database, node_id: str) -> strwhich walksvisu_nodes.parent_idto determine the effective access level and returns"private"for unknown nodes._check_history_access(request, user, db)to callawait _resolve_page_access(db, page_id)and use the resolved ACL instead of defaulting missing/NULL access topublic.public,readonly, andprotectedpages and kept session-token validation viavalidate_sessionunchanged.obs/api/v1/history.pyto deny unknown page IDs and fail closed for missing/inherited ACLs.Testing
pytest -q tests/integration/test_history.py -k limit_above_1000, but the test run failed in this environment due to a missing test dependency (ModuleNotFoundError: No module named 'pytest_asyncio').Codex Task