Files
cleveragents-core/features/audit_session_race.feature
HAL9000 e6878c2c30
CI / coverage (push) Blocked by required conditions
CI / docker (push) Blocked by required conditions
CI / push-validation (push) Waiting to run
CI / status-check (push) Blocked by required conditions
CI / benchmark-publish (push) Waiting to run
CI / lint (push) Successful in 45s
CI / typecheck (push) Successful in 1m11s
CI / unit_tests (push) Has started running
CI / integration_tests (push) Has started running
CI / quality (push) Successful in 1m5s
CI / security (push) Successful in 1m12s
CI / e2e_tests (push) Has started running
CI / build (push) Has started running
CI / helm (push) Has started running
fix(audit): protect AuditService._ensure_session() with threading.Lock
2026-05-02 21:54:17 +00:00

30 lines
1.5 KiB
Gherkin

# This test captures bug #991 - AuditService._ensure_session() TOCTOU race.
#
# Originally tagged @tdd_expected_fail while the bug was unfixed (see TDD
# issue #1095). The @tdd_expected_fail tag was removed when the fix for
# #991 was merged.
#
# See: https://git.cleverthis.com/cleveragents/cleveragents-core/issues/991
@tdd_issue @tdd_issue_991
Feature: TDD Bug #991 - AuditService._ensure_session() TOCTOU race
AuditService._ensure_session() used to check if self._session is None,
then create an engine, run create_all, build a sessionmaker, and assign
self._session - all without a threading.Lock. If two threads called
_ensure_session() concurrently, both saw self._session as None, both
created separate engines and sessions, and the second assignment won,
leaking the first engine/session.
The fix adds a threading.Lock with double-checked locking so that only
the first thread to acquire the lock performs the initialisation.
This test proves the fix works by launching multiple threads that call
_ensure_session() simultaneously via a threading.Barrier and verifying
that create_engine is called exactly once.
Scenario: Concurrent _ensure_session() calls must create only one engine
Given an AuditService with no pre-injected session and a temp database
When 10 threads call _ensure_session concurrently through a barrier
Then create_engine should have been called exactly once
And all 10 threads should have received a valid session