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

Skip to content

chore(security): resolve all open CodeQL python alerts#133

Merged
beenuar merged 1 commit into
mainfrom
fix/codeql-scanning-alerts
May 14, 2026
Merged

chore(security): resolve all open CodeQL python alerts#133
beenuar merged 1 commit into
mainfrom
fix/codeql-scanning-alerts

Conversation

@beenuar
Copy link
Copy Markdown
Owner

@beenuar beenuar commented May 14, 2026

Summary

Sweeps the full backlog of open CodeQL python alerts on main — 26 alerts
across 11 distinct rules. Every change is behaviour-preserving; they help
the static analyzer recognise existing invariants (validated inputs, terminated
control flow, runtime-resolved names) rather than altering runtime semantics.

Closes the following alerts:

Rule Alert IDs Count
py/log-injection 396, 401, 402, 412, 413 5
py/uninitialized-local-variable 414, 415 2
py/mixed-returns 438 1
py/side-effect-in-assert 435 1
py/incomplete-url-substring-sanitization 411 1
py/ineffectual-statement 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434 17
py/unnecessary-lambda 439 1
py/unused-global-variable 408, 416, 417 3
py/import-and-import-from 437 1
py/unused-import 436 1

Changes by category

py/log-injection — sanitise CR/LF before logging

User-controlled strings that flow into logger.* calls now pass through a
small _log_safe(value) helper that strips \r and replaces \n with a
space. Pydantic validators already prevent newlines for most fields, but
CodeQL's taint tracker doesn't model the validator as a sanitiser, so the
helper makes the cleansing explicit and is a no-op for valid input.

  • services/api/app/api/v1/endpoints/alerts.py — apply existing _log_safe
    to idempotency_key and payload.connector_type.
  • services/api/app/api/v1/endpoints/waitlist.py — introduce _log_safe,
    apply to previous and payload.status on waitlist_status_transition.
  • services/api/app/services/effective_permissions/service.py — scrub
    provider into safe_provider before the no-loader warning.

py/uninitialized-local-variable + py/mixed-returns — explicit control flow

  • services/agents/tests/test_graph_freshness.pypytest.skip() raises
    Skipped, but CodeQL doesn't model it as NoReturn. Added explicit
    return / return None after every skip so every branch terminates.

py/side-effect-in-assert

  • services/agents/tests/test_fidelity_harness.py — hoist file open +
    line count out of the assert expression. Under python -O the side
    effect would otherwise disappear silently.

py/incomplete-url-substring-sanitization

  • services/teams-bot/tests/test_cards.py — replace
    startswith("http://adaptivecards.io/") with an exact equality check
    against the full canonical $schema URL.

py/ineffectual-statement (17 alerts)

Two patterns:

  • Protocol method bodies with ... — replaced the ellipsis with an
    explicit docstring so CodeQL doesn't flag the placeholder as a no-op.
    Affects aisoc_clients.py, callbacks.py, approval_audit.py,
    attack_chain.py, email_approval.py.
  • Bare await task — bound to _ so the awaited value is consumed
    semantically. Affects approval_timeout.py (1 prod, 5 tests).

py/unnecessary-lambda

  • services/slack-bot/app/services/approval_audit.py — use
    default_factory=time.time directly instead of lambda: time.time().

py/unused-global-variable

  • services/agents/app/context/bundle.py — rename _LLM_SAFE_KEYS
    LLM_SAFE_KEYS (the test already imports it, so the leading underscore
    was misleading); update the importer in test_context_bundle.py.
  • services/api/app/scripts/seed_demo.py — drop unused _quick_rng;
    deterministic seeding still flows through _rng_for_tenant.
  • services/connectors/app/connectors/datadog.py — drop unused
    _EVENTS_PER_PAGE; the Datadog Events v1 API windows on
    start/end epoch seconds, not a page-size knob.

py/import-and-import-from

  • services/connectors/tests/connectors/test_confluence_audit.py — collapse
    inline import app.connectors.confluence_audit as mod into a single
    module-level alias and reuse it for the _PAGE_SIZE monkey-patch.

py/unused-import

  • services/api/app/services/tenant_provision/provisioner.py — unquote
    Any in DemoSeederCallable = Callable[[AsyncSession, Tenant], Any]. The
    module already has from __future__ import annotations, so the string
    form was unnecessary and hid the only runtime reference to typing.Any.

Verification

  • python3 -m py_compile clean on all 19 modified files
  • ruff format is a no-op (files already match repo style)
  • ruff check passes with no new findings
  • ✅ Diff is surgical: +113 / −46 across 19 files, all targeted at
    specific CodeQL rule patterns

Test plan

  • CI: Python — Lint & Type-check green
  • CI: Python — Tests green
  • CI: Verify docs/openapi.yaml is up to date green (no schema changes,
    so this should be a no-op)
  • CodeQL re-scan on main after merge shows all 26 alerts dismissed
  • Smoke: /v1/alerts/ingest still logs idempotency_key (now sanitised)
  • Smoke: PATCH /v1/waitlist/{id} still logs waitlist_status_transition
  • Smoke: Slack/Teams approval timeout tasks still cancel cleanly

Notes

  • No public API change, no schema change, no docs/openapi.yaml change.
  • No competitor names or other forbidden strings touched.
  • No secrets or credentials in the diff.

Made with Cursor

Sweeps the full backlog of CodeQL `python` alerts on `main` (alerts 396, 401,
402, 408, 411-439). All fixes are surgical and behaviour-preserving — they
make CodeQL's taint and dataflow tracker recognise existing invariants rather
than changing runtime semantics.

py/log-injection (4 alerts)
- `services/api/app/api/v1/endpoints/alerts.py` (#396, #401, #402):
  apply existing `_log_safe` helper to `idempotency_key` and
  `payload.connector_type` before they hit `logger.info` / `logger.exception`.
- `services/api/app/api/v1/endpoints/waitlist.py` (#413): introduce a local
  `_log_safe` and sanitise `previous` + `payload.status` on the
  `waitlist_status_transition` log line. Pydantic already gates these against
  `ALLOWED_WAITLIST_STATUSES`, so this is a no-op for valid input.
- `services/api/app/services/effective_permissions/service.py` (#412):
  scrub CR/LF out of `provider` before the
  "no production snapshot loader wired" warning.

py/uninitialized-local-variable (2 alerts)
- `services/agents/tests/test_graph_freshness.py` (#414, #415):
  add `return` after `pytest.skip()` in two `except ImportError` blocks so
  CodeQL sees every branch terminating.

py/mixed-returns (1 alert)
- `services/agents/tests/test_graph_freshness.py` (#438):
  add explicit `return None` after `pytest.skip()` in `_import_or_skip` so
  every control-flow path ends in an explicit return.

py/side-effect-in-assert (1 alert)
- `services/agents/tests/test_fidelity_harness.py` (#435):
  hoist file open + line count out of the `assert` expression so the
  side-effect doesn't disappear under `python -O`.

py/incomplete-url-substring-sanitization (1 alert)
- `services/teams-bot/tests/test_cards.py` (#411):
  replace `startswith("http://adaptivecards.io/")` with an exact equality
  check against the full canonical `$schema` URL.

py/ineffectual-statement (12 alerts)
- Replace `...` placeholders inside `Protocol` method bodies with explicit
  docstrings so CodeQL doesn't flag the ellipsis as a no-op statement:
  - `services/teams-bot/app/services/aisoc_clients.py` (#418, #419, #420, #421)
  - `services/teams-bot/app/callbacks.py` (#426, #427, #428)
  - `services/slack-bot/app/services/approval_audit.py` (#422)
  - `services/api/app/services/attack_chain.py` (#424, #425)
  - `services/api/app/services/email_approval.py` (#429)
- Bind bare `await task` results to `_` so the value is consumed
  semantically, not discarded:
  - `services/slack-bot/app/services/approval_timeout.py` (#423)
  - `services/slack-bot/tests/test_approval_timeout.py` (#430-#434)

py/unnecessary-lambda (1 alert)
- `services/slack-bot/app/services/approval_audit.py` (#439):
  use `default_factory=time.time` directly instead of wrapping it in a
  lambda.

py/unused-global-variable (3 alerts)
- `services/agents/app/context/bundle.py` (#408) +
  `services/agents/tests/test_context_bundle.py`:
  rename `_LLM_SAFE_KEYS` -> `LLM_SAFE_KEYS` (already used by tests, so the
  leading underscore was misleading) and update the importer.
- `services/api/app/scripts/seed_demo.py` (#417): drop the unused
  `_quick_rng` module-level RNG; deterministic seeding still flows through
  `_rng_for_tenant`. Replaced with a comment explaining the removal so
  future work doesn't accidentally re-add an unused source of randomness.
- `services/connectors/app/connectors/datadog.py` (#416): remove the unused
  `_EVENTS_PER_PAGE` constant; the Datadog Events v1 API is windowed by
  `start`/`end` epoch seconds, not by a page-size knob, so the constant was
  dead. Added a comment so anyone wiring pagination in later does it inside
  `_fetch_events` instead of reintroducing the global.

py/import-and-import-from (1 alert)
- `services/connectors/tests/connectors/test_confluence_audit.py` (#437):
  collapse the inline `import app.connectors.confluence_audit as mod` into
  a single module-level `import ... as confluence_audit_module` alias and
  reuse it for the `_PAGE_SIZE` monkey-patch.

py/unused-import (1 alert)
- `services/api/app/services/tenant_provision/provisioner.py` (#436):
  unquote `Any` in `DemoSeederCallable = Callable[[AsyncSession, Tenant], Any]`
  so the existing `from typing import Any` is recognised as used. The
  module already has `from __future__ import annotations`, so the string
  form was unnecessary — and it was hiding the only runtime reference.

Verification
- `python3 -m py_compile` clean on all 19 files.
- `ruff format` is a no-op (files already match style).
- `ruff check` passes with no new lint findings.

No behaviour change, no public API change. All edits are sanitisation,
docstring, or static-analysis hint changes.
import json
from pathlib import Path

import app.connectors.confluence_audit as confluence_audit_module
@beenuar beenuar merged commit 424a095 into main May 14, 2026
25 checks passed
@beenuar beenuar deleted the fix/codeql-scanning-alerts branch May 14, 2026 16:07
beenuar added a commit that referenced this pull request May 14, 2026
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]>
beenuar added a commit that referenced this pull request May 14, 2026
Brings every cross-cutting doc surface in line with the 21 PRs that
landed on `main` on 2026-05-14, anchored by the v8.0 architectural
foundation (PR #125) and the security + correctness wave that
followed it.

- `CHANGELOG.md` — new `[Unreleased]` block covering the v8.0
  architectural foundation (graph at ingest, four-agent rebrand,
  `/hunt`, sixteen connectors, automation maturity, public
  scoreboard), the eight-PR security hardening wave (PRs #116-#128),
  the three-PR CodeQL alert sweep to zero (#133, #136, #137), the
  UEBA env-var alignment (PR #135, first community contribution,
  closes #134), the security-smoke + UX cleanup pair (PR #132,
  closes #131 + #130), and the playbook engine correctness pass
  (PR #129).
- `README.md` — new `v8.0 wave-1 (on main, not yet tagged)` entry
  in the version-history section; `Next` block rewritten as
  `v8.0 wave-2` with the still-`[~]` items from
  `AISOC_V8_PROGRESS.md`. Version badge intentionally not bumped
  (still 7.3.1) because wave-1 is on `main` but not tagged.
- `AGENTS.md` — new `v8.0 wave-1` block under "Learned Workspace
  Facts" documenting the four-agent topology, `/hunt` surface,
  connector inventory, automation maturity ladder, security wave
  outcomes, CodeQL hygiene patterns (inline `replace`-chain
  sanitisation for `py/log-injection`, single import style for
  `py/import-and-import-from`), and the UEBA env-var dual-alias
  convention.
- `AISOC_V8_PROGRESS.md` — `Status` block refreshed to record that
  PR #125 shipped at `b854010e` on 2026-05-14, list the 12
  post-merge PRs that landed on `main` after it, and clarify that
  wave-2 is the still-tracked `[~]` work.
- `apps/docs/docs/deployment/env-vars.md` — UEBA section rewritten
  around the dual-alias rule (unprefixed wins over `UEBA_`-prefixed,
  matches every other Python service and the `docker-compose.yml`
  exports); table now lists canonical + legacy names side by side.
- `apps/docs/docs/operations/security.md` — new `Static analysis
  (CodeQL)` section: zero alerts on `main` as a CI gate, plus the
  two patterns that came up repeatedly during the sweep
  (inline-at-call-site sanitisation for `py/log-injection`, single
  import style for `py/import-and-import-from`).

No code changes; pure documentation sync.

Co-authored-by: Beenu Arora <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants