Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a8da034

Browse files
beenuarBeenu Arora
andauthored
fix(security): resolve remaining 2 CodeQL alerts (#440, #441) (#136)
Address the two CodeQL alerts that persisted after PR #133 because the fixes there were not recognised by CodeQL's static analysis: - #441 py/log-injection in services/api/app/api/v1/endpoints/waitlist.py: the `_log_safe` helper was not detected as a sanitiser when the value came from a database row. Inline the `.replace("\\r","").replace("\\n"," ")` chain with a 32-char cap at the `logger.info` call site so the taint tracker sees the cleansing directly. The now-unused `_log_safe` helper has been removed. - #440 py/import-and-import-from in services/connectors/tests/connectors/test_confluence_audit.py: the previous module alias still tripped the rule. Drop the alias entirely and switch the `_PAGE_SIZE` override to `pytest.MonkeyPatch.setattr`, giving a single import style and automatic restoration at teardown. Both values in waitlist are also Pydantic-validated against ALLOWED_WAITLIST_STATUSES, so this is defence in depth, not a behaviour change. Co-authored-by: Beenu Arora <[email protected]>
1 parent 424a095 commit a8da034

2 files changed

Lines changed: 19 additions & 29 deletions

File tree

services/api/app/api/v1/endpoints/waitlist.py

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -200,22 +200,6 @@ def _validate_status(cls, value: str) -> str:
200200
# ---------------------------------------------------------------------------
201201

202202

203-
def _log_safe(value: str | None) -> str | None:
204-
"""Strip CR/LF from a user-supplied string before it enters a log record.
205-
206-
The waitlist status fields are validated upstream (Pydantic
207-
``field_validator`` against ``ALLOWED_WAITLIST_STATUSES``) and cannot in
208-
practice contain newlines, but static analysis (CodeQL
209-
``py/log-injection``) does not recognise the validator as a sanitiser.
210-
This helper makes the cleansing explicit so the taint tracker treats the
211-
value as safe, while remaining a no-op for any well-formed input.
212-
"""
213-
214-
if value is None:
215-
return None
216-
return value.replace("\r", "").replace("\n", " ")
217-
218-
219203
def _client_ip(request: Request) -> str:
220204
"""Resolve the source IP, trusting the proxy chain in front of us.
221205
@@ -436,12 +420,19 @@ async def patch_entry(
436420
detail="Could not update waitlist entry.",
437421
) from exc
438422

423+
# CodeQL py/log-injection: sanitise inline so the taint tracker
424+
# sees the .replace() chain directly at the call site. Both values
425+
# are also Pydantic-validated against ``ALLOWED_WAITLIST_STATUSES``
426+
# so they can only ever be short safe identifiers, but the inline
427+
# sanitisation makes the property explicit for static analysis.
428+
safe_previous = (previous or "").replace("\r", "").replace("\n", " ")[:32]
429+
safe_next = (payload.status or "").replace("\r", "").replace("\n", " ")[:32]
439430
logger.info(
440431
"waitlist_status_transition",
441432
extra={
442433
"entry_id": str(entry_id),
443-
"previous": _log_safe(previous),
444-
"next": _log_safe(payload.status),
434+
"previous": safe_previous,
435+
"next": safe_next,
445436
"actor": str(user.user_id),
446437
},
447438
)

services/connectors/tests/connectors/test_confluence_audit.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import json
66
from pathlib import Path
77

8-
import app.connectors.confluence_audit as confluence_audit_module
98
import httpx
109
import pytest
1110
import respx
@@ -78,7 +77,10 @@ def test_normalize_creation_date_ms_to_iso(fixture):
7877

7978
@pytest.mark.asyncio
8079
@respx.mock
81-
async def test_fetch_alerts_uses_pagination(fixture):
80+
async def test_fetch_alerts_uses_pagination(
81+
fixture: dict,
82+
monkeypatch: pytest.MonkeyPatch,
83+
) -> None:
8284
calls = 0
8385

8486
def handler(request: httpx.Request) -> httpx.Response:
@@ -94,15 +96,12 @@ def handler(request: httpx.Request) -> httpx.Response:
9496
respx.get(f"{_SITE}/wiki/rest/api/audit").mock(side_effect=handler)
9597

9698
connector = ConfluenceAuditConnector(_SITE, _EMAIL, _TOKEN)
97-
# Lower the page size to match the fixture. We reuse the module-level
98-
# ``confluence_audit_module`` alias rather than re-importing inline so
99-
# CodeQL (``py/import-and-import-from``) sees a single import style.
100-
monkey_orig = confluence_audit_module._PAGE_SIZE # noqa: SLF001
101-
try:
102-
confluence_audit_module._PAGE_SIZE = 4 # type: ignore[assignment]
103-
events = await connector.fetch_alerts(since_seconds=10**9)
104-
finally:
105-
confluence_audit_module._PAGE_SIZE = monkey_orig # type: ignore[assignment]
99+
# Lower the page size to match the fixture. ``monkeypatch`` rewrites the
100+
# module attribute and restores it automatically at teardown, so we keep
101+
# a single import style for the connector module (CodeQL
102+
# ``py/import-and-import-from``).
103+
monkeypatch.setattr("app.connectors.confluence_audit._PAGE_SIZE", 4)
104+
events = await connector.fetch_alerts(since_seconds=10**9)
106105

107106
# First page returned 4 items, second page returned []; pagination
108107
# terminated cleanly.

0 commit comments

Comments
 (0)