Skip to content

Audit capture is a process-global; writes made in Celery tasks are never audited #498

Closed

Description

@antosubash

Tier 1: correctness

Problem

framework/db/simple_module_db/listeners.py:57,97-98 stores the DatabaseState in a module-level global (global _db_state; _db_state = db_state). The audit hooks read it at lines 214 and 239. Only install_listeners sets it, and only the create_app path calls that.

Celery workers never run create_app. background_tasks/sync_db.py:120-123 calls only attach_session_listeners(WorkerSession), so in a worker _db_state is None and every write a task makes skips audit capture with no signal. The audit_log module installs audit_callback on app.state.sm.db, which a worker doesn't have.

Second problem: the last app built in a process wins the global. That leaks between apps in tests and in any multi-app process.

Smaller layering leak: listeners.py:219 imports simple_module_hosting.logging from the db package, behind a try/except.

Fix

  • Attach the audit policy per engine or session, the same way tenancy already does with bind_engine_policy, instead of using a module global.
  • Wire the audit callback into the worker bootstrap.
  • Add a test: a Celery task (run eagerly) that writes an audited model produces an audit row.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions