UAT: plan_applied, plan_cancelled, config_changed, and session_created audit events missing user_identity — spec requires user identity in audit trail #3970

Open
opened 2026-04-06 08:03:10 +00:00 by freemo · 0 comments
Owner

Metadata

  • Branch: fix/audit-events-missing-user-identity
  • Commit Message: fix(audit): propagate user_identity to plan_applied, plan_cancelled, config_changed, and session_created events
  • Milestone: None (Backlog)
  • Parent Epic: #397

Summary

Four security-relevant audit events do not include user_identity in the emitted DomainEvent, despite the specification explicitly requiring it. This means the user_identity column in the audit_log table will always be NULL for these event types in local mode, making the audit trail incomplete for compliance purposes.

Expected Behavior (from spec)

Per docs/specification.md §Audit Logging (line ~46129):

Event Type Details Captured
plan_applied Plan ID, project names, files changed, lines added/removed, resources modified, apply duration, user identity
plan_cancelled Plan ID, reason, project names, cancelled phase, cancelled processing state, last completed step, subplan count, sandbox refs, changeset ID, resources pending cleanup
config_changed Key, old value (masked if secret), new value (masked if secret), user identity
session_created Session ID, actor name, user identity

Actual Behavior

plan_appliedPlanLifecycleService.complete_apply()

src/cleveragents/application/services/plan_lifecycle_service.py, line ~1813:

self.event_bus.emit(
    DomainEvent(
        event_type=EventType.PLAN_APPLIED,
        plan_id=plan_id,
        actor_name=plan.created_by,
        project_name=project_names[0] if project_names else None,
        # ❌ user_identity NOT passed — will be NULL in audit_log
        details={...},
    )
)

The complete_apply() method signature also has no user_identity parameter.

plan_cancelledPlanLifecycleService.cancel_plan()

src/cleveragents/application/services/plan_lifecycle_service.py, line ~2065:

self.event_bus.emit(
    DomainEvent(
        event_type=EventType.PLAN_CANCELLED,
        plan_id=plan_id,
        actor_name=plan.created_by,
        project_name=project_names[0] if project_names else None,
        # ❌ user_identity NOT passed — will be NULL in audit_log
        details=event_details,
    )
)

config_changedConfigService.set()

src/cleveragents/application/services/config_service.py, line ~1340:

self._event_bus.emit(
    DomainEvent(
        event_type=EventType.CONFIG_CHANGED,
        # ❌ user_identity NOT passed — will be NULL in audit_log
        details={"key": key, "old_value": old_value, "new_value": value, "scope": ...},
    )
)

session_createdSessionService.create()

src/cleveragents/application/services/session_service.py, line ~86:

self._event_bus.emit(
    DomainEvent(
        event_type=EventType.SESSION_CREATED,
        session_id=session.session_id,
        actor_name=actor_name,
        # ❌ user_identity NOT passed — will be NULL in audit_log
        details={"session_id": ..., "actor_name": ...},
    )
)

Impact

  • The user_identity column in audit_log is always NULL for these four event types
  • Compliance auditors cannot determine which user performed plan applies, cancellations, config changes, or session creations
  • The spec's audit trail requirement for user identity is not met

Root Cause

The service methods (complete_apply, cancel_plan, ConfigService.set, SessionService.create) do not accept a user_identity parameter and do not pass it to the emitted DomainEvent. The DomainEvent model has a user_identity field (added in issue #715) but it is not being populated by the callers.

Code Locations

  • src/cleveragents/application/services/plan_lifecycle_service.pycomplete_apply() (line ~1752), cancel_plan() (line ~2009)
  • src/cleveragents/application/services/config_service.pyset() (line ~1338)
  • src/cleveragents/application/services/session_service.pycreate() (line ~86)

Subtasks

  • Add user_identity: str | None = None parameter to PlanLifecycleService.complete_apply()
  • Pass user_identity to the PLAN_APPLIED DomainEvent
  • Add user_identity: str | None = None parameter to PlanLifecycleService.cancel_plan()
  • Pass user_identity to the PLAN_CANCELLED DomainEvent
  • Add user_identity: str | None = None parameter to ConfigService.set()
  • Pass user_identity to the CONFIG_CHANGED DomainEvent
  • Add user_identity: str | None = None parameter to SessionService.create()
  • Pass user_identity to the SESSION_CREATED DomainEvent
  • Update CLI callers to pass user identity where available
  • Add BDD scenarios verifying user_identity is captured in audit entries
  • Verify coverage ≥ 97%

Definition of Done

  • All four event types include user_identity in the emitted DomainEvent
  • audit_log.user_identity column is populated for these events when a user identity is available
  • BDD tests verify the behavior
  • PR merged
  • All nox stages pass
  • Coverage ≥ 97%

Backlog note: This issue was discovered during UAT testing of the
Audit and Compliance Features area. It does not block milestone completion
and has been placed in the backlog for human review and future milestone
assignment.


Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-uat-tester

## Metadata - **Branch**: `fix/audit-events-missing-user-identity` - **Commit Message**: `fix(audit): propagate user_identity to plan_applied, plan_cancelled, config_changed, and session_created events` - **Milestone**: None (Backlog) - **Parent Epic**: #397 ## Summary Four security-relevant audit events do not include `user_identity` in the emitted `DomainEvent`, despite the specification explicitly requiring it. This means the `user_identity` column in the `audit_log` table will always be `NULL` for these event types in local mode, making the audit trail incomplete for compliance purposes. ## Expected Behavior (from spec) Per `docs/specification.md` §Audit Logging (line ~46129): | Event Type | Details Captured | |---|---| | `plan_applied` | Plan ID, project names, files changed, lines added/removed, resources modified, apply duration, **user identity** | | `plan_cancelled` | Plan ID, reason, project names, cancelled phase, cancelled processing state, last completed step, subplan count, sandbox refs, changeset ID, resources pending cleanup | | `config_changed` | Key, old value (masked if secret), new value (masked if secret), **user identity** | | `session_created` | Session ID, actor name, **user identity** | ## Actual Behavior ### `plan_applied` — `PlanLifecycleService.complete_apply()` `src/cleveragents/application/services/plan_lifecycle_service.py`, line ~1813: ```python self.event_bus.emit( DomainEvent( event_type=EventType.PLAN_APPLIED, plan_id=plan_id, actor_name=plan.created_by, project_name=project_names[0] if project_names else None, # ❌ user_identity NOT passed — will be NULL in audit_log details={...}, ) ) ``` The `complete_apply()` method signature also has no `user_identity` parameter. ### `plan_cancelled` — `PlanLifecycleService.cancel_plan()` `src/cleveragents/application/services/plan_lifecycle_service.py`, line ~2065: ```python self.event_bus.emit( DomainEvent( event_type=EventType.PLAN_CANCELLED, plan_id=plan_id, actor_name=plan.created_by, project_name=project_names[0] if project_names else None, # ❌ user_identity NOT passed — will be NULL in audit_log details=event_details, ) ) ``` ### `config_changed` — `ConfigService.set()` `src/cleveragents/application/services/config_service.py`, line ~1340: ```python self._event_bus.emit( DomainEvent( event_type=EventType.CONFIG_CHANGED, # ❌ user_identity NOT passed — will be NULL in audit_log details={"key": key, "old_value": old_value, "new_value": value, "scope": ...}, ) ) ``` ### `session_created` — `SessionService.create()` `src/cleveragents/application/services/session_service.py`, line ~86: ```python self._event_bus.emit( DomainEvent( event_type=EventType.SESSION_CREATED, session_id=session.session_id, actor_name=actor_name, # ❌ user_identity NOT passed — will be NULL in audit_log details={"session_id": ..., "actor_name": ...}, ) ) ``` ## Impact - The `user_identity` column in `audit_log` is always `NULL` for these four event types - Compliance auditors cannot determine which user performed plan applies, cancellations, config changes, or session creations - The spec's audit trail requirement for user identity is not met ## Root Cause The service methods (`complete_apply`, `cancel_plan`, `ConfigService.set`, `SessionService.create`) do not accept a `user_identity` parameter and do not pass it to the emitted `DomainEvent`. The `DomainEvent` model has a `user_identity` field (added in issue #715) but it is not being populated by the callers. ## Code Locations - `src/cleveragents/application/services/plan_lifecycle_service.py` — `complete_apply()` (line ~1752), `cancel_plan()` (line ~2009) - `src/cleveragents/application/services/config_service.py` — `set()` (line ~1338) - `src/cleveragents/application/services/session_service.py` — `create()` (line ~86) ## Subtasks - [ ] Add `user_identity: str | None = None` parameter to `PlanLifecycleService.complete_apply()` - [ ] Pass `user_identity` to the `PLAN_APPLIED` `DomainEvent` - [ ] Add `user_identity: str | None = None` parameter to `PlanLifecycleService.cancel_plan()` - [ ] Pass `user_identity` to the `PLAN_CANCELLED` `DomainEvent` - [ ] Add `user_identity: str | None = None` parameter to `ConfigService.set()` - [ ] Pass `user_identity` to the `CONFIG_CHANGED` `DomainEvent` - [ ] Add `user_identity: str | None = None` parameter to `SessionService.create()` - [ ] Pass `user_identity` to the `SESSION_CREATED` `DomainEvent` - [ ] Update CLI callers to pass user identity where available - [ ] Add BDD scenarios verifying `user_identity` is captured in audit entries - [ ] Verify coverage ≥ 97% ## Definition of Done - [ ] All four event types include `user_identity` in the emitted `DomainEvent` - [ ] `audit_log.user_identity` column is populated for these events when a user identity is available - [ ] BDD tests verify the behavior - [ ] PR merged - [ ] All nox stages pass - [ ] Coverage ≥ 97% > **Backlog note:** This issue was discovered during UAT testing of the > Audit and Compliance Features area. It does not block milestone completion > and has been placed in the backlog for human review and future milestone > assignment. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
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.

Blocks
#397 Epic: Server & Autonomy Infrastructure
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#3970
No description provided.