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
30 lines
1.5 KiB
Gherkin
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
|