BUG-HUNT: [architecture] project.py _store_project_extras() bypasses DI container and creates independent SQLAlchemy engine #7776

Open
opened 2026-04-12 03:31:50 +00:00 by HAL9000 · 3 comments
Owner

Bug Report: [Architecture] project.py _store_project_extras() Creates Independent SQLAlchemy Engine Bypassing the DI Container

Severity Assessment

  • Impact: When persisting invariants and invariant_actor for a project, a fresh SQLAlchemy engine and session are created outside the DI container's connection pool and transaction management. This can lead to: (1) uncommitted concurrent changes being lost in race conditions between this session and the container's UoW, (2) connection pool exhaustion since no pool is shared, (3) bypassing any audit hooks wired by the container. This function is called during agents project create with --invariant or --invariant-actor flags.
  • Likelihood: Triggered on every agents project create --invariant or --invariant-actor invocation
  • Priority: Medium

Location

  • File: src/cleveragents/cli/commands/project.py
  • Function: _store_project_extras
  • Lines: 95–132

Description

Instead of using the DI container's unit_of_work or a repository, _store_project_extras() constructs a raw SQLAlchemy engine and session, executes a raw SQL UPDATE, and commits it independently:

# project.py lines 107-132
from cleveragents.application.container import get_database_url
db_url = get_database_url()
engine = create_engine(db_url, echo=False)   # NEW engine -- bypasses container pool
session = sessionmaker(bind=engine, expire_on_commit=False)()
try:
    ...
    sql = text(
        f"UPDATE ns_projects SET {', '.join(updates)} "
        f"WHERE namespaced_name = :ns_name"
    )
    session.execute(sql, params)
    session.commit()  # independent commit outside container's UoW
finally:
    session.close()  # engine itself is never closed/disposed

Problems:

  1. Bypasses DI container: The container manages connection pooling, audit logging, and transaction isolation. This raw session bypasses all of that.
  2. Engine not disposed: The created engine is never engine.dispose()d, leaking connection pool resources.
  3. Race condition: The container may have an open transaction; this independent session commits over it.
  4. Inconsistency: Every other CLI command uses get_container() for DB access.

Evidence

# project.py _store_project_extras()
db_url = get_database_url()
engine = create_engine(db_url, echo=False)  # independent engine
session = sessionmaker(bind=engine, expire_on_commit=False)()
# ... raw SQL execute + commit
finally:
    session.close()  # engine.dispose() never called!

Expected Behavior

Persistence of project extras should go through the DI container's repository or unit-of-work:

def _store_project_extras(namespaced_name, ...):
    from cleveragents.application.container import get_container
    container = get_container()
    repo = container.namespaced_project_repo()
    repo.update_extras(namespaced_name, invariants=invariant_texts, inv_actor=inv_actor)

Or at minimum, the repository API should be extended to expose these fields instead of bypassing it with raw SQL.

Actual Behavior

A fresh SQLAlchemy engine is created per call, bypassing the container's connection pool, and the engine is never disposed.

Category

architecture

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD.


Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: bug-hunter

## Bug Report: [Architecture] `project.py` `_store_project_extras()` Creates Independent SQLAlchemy Engine Bypassing the DI Container ### Severity Assessment - **Impact**: When persisting invariants and invariant_actor for a project, a fresh SQLAlchemy engine and session are created outside the DI container's connection pool and transaction management. This can lead to: (1) uncommitted concurrent changes being lost in race conditions between this session and the container's UoW, (2) connection pool exhaustion since no pool is shared, (3) bypassing any audit hooks wired by the container. This function is called during `agents project create` with `--invariant` or `--invariant-actor` flags. - **Likelihood**: Triggered on every `agents project create --invariant` or `--invariant-actor` invocation - **Priority**: Medium ### Location - **File**: `src/cleveragents/cli/commands/project.py` - **Function**: `_store_project_extras` - **Lines**: 95–132 ### Description Instead of using the DI container's `unit_of_work` or a repository, `_store_project_extras()` constructs a raw SQLAlchemy engine and session, executes a raw SQL UPDATE, and commits it independently: ```python # project.py lines 107-132 from cleveragents.application.container import get_database_url db_url = get_database_url() engine = create_engine(db_url, echo=False) # NEW engine -- bypasses container pool session = sessionmaker(bind=engine, expire_on_commit=False)() try: ... sql = text( f"UPDATE ns_projects SET {', '.join(updates)} " f"WHERE namespaced_name = :ns_name" ) session.execute(sql, params) session.commit() # independent commit outside container's UoW finally: session.close() # engine itself is never closed/disposed ``` Problems: 1. **Bypasses DI container**: The container manages connection pooling, audit logging, and transaction isolation. This raw session bypasses all of that. 2. **Engine not disposed**: The created engine is never `engine.dispose()`d, leaking connection pool resources. 3. **Race condition**: The container may have an open transaction; this independent session commits over it. 4. **Inconsistency**: Every other CLI command uses `get_container()` for DB access. ### Evidence ```python # project.py _store_project_extras() db_url = get_database_url() engine = create_engine(db_url, echo=False) # independent engine session = sessionmaker(bind=engine, expire_on_commit=False)() # ... raw SQL execute + commit finally: session.close() # engine.dispose() never called! ``` ### Expected Behavior Persistence of project extras should go through the DI container's repository or unit-of-work: ```python def _store_project_extras(namespaced_name, ...): from cleveragents.application.container import get_container container = get_container() repo = container.namespaced_project_repo() repo.update_extras(namespaced_name, invariants=invariant_texts, inv_actor=inv_actor) ``` Or at minimum, the repository API should be extended to expose these fields instead of bypassing it with raw SQL. ### Actual Behavior A fresh SQLAlchemy engine is created per call, bypassing the container's connection pool, and the engine is never disposed. ### Category architecture ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: bug-hunter
HAL9000 added this to the v3.2.0 milestone 2026-04-12 03:43:19 +00:00
Author
Owner

Verified — Architecture bug: _store_project_extras() bypasses DI container, creating independent SQLAlchemy engine. MoSCoW: Must-have. Priority: High — architecture violation.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

✅ **Verified** — Architecture bug: _store_project_extras() bypasses DI container, creating independent SQLAlchemy engine. MoSCoW: Must-have. Priority: High — architecture violation. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — Architecture bug: _store_project_extras() bypasses DI container, creating independent SQLAlchemy engine. MoSCoW: Must-have. Priority: High — architecture violation.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

✅ **Verified** — Architecture bug: _store_project_extras() bypasses DI container, creating independent SQLAlchemy engine. MoSCoW: Must-have. Priority: High — architecture violation. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — Architecture bug: _store_project_extras() bypasses DI container, creating independent SQLAlchemy engine. MoSCoW: Must-have. Priority: High — architecture violation.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

✅ **Verified** — Architecture bug: _store_project_extras() bypasses DI container, creating independent SQLAlchemy engine. MoSCoW: Must-have. Priority: High — architecture violation. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#7776
No description provided.