8ed8750160
CI / push-validation (pull_request) Successful in 23s
CI / helm (pull_request) Successful in 30s
CI / build (pull_request) Successful in 43s
CI / lint (pull_request) Successful in 55s
CI / quality (pull_request) Successful in 54s
CI / typecheck (pull_request) Successful in 57s
CI / security (pull_request) Successful in 1m28s
CI / integration_tests (pull_request) Successful in 3m4s
CI / unit_tests (pull_request) Successful in 7m30s
CI / docker (pull_request) Failing after 14m0s
CI / coverage (pull_request) Failing after 21m7s
CI / status-check (pull_request) Has been cancelled
AuditService.record() was generating its own timestamp internally, discarding the original DomainEvent.timestamp. This means audit entries recorded when an event was audited, not when the domain event actually occurred, breaking forensic accuracy per §Audit Logging (SEC7). Changes: - Add `timestamp: datetime | None = None` keyword parameter to AuditService.record(). When provided, uses it as created_at; falls back to datetime.now(tz=UTC) for backward compatibility. Applied to both the async queue path and the synchronous DB path. - AuditEventSubscriber._handle_event() now passes timestamp=event.timestamp so the original event creation time is preserved in audit entries. - Add 3 Behave BDD scenarios covering: full pipeline timestamp preservation, direct record() with explicit timestamp, and backward compatibility (record() without timestamp auto-generates created_at). - Add preserve_event_timestamp Robot integration test and helper subcommand. - Add static source check in security_audit.robot verifying the timestamp parameter signature exists. ISSUES CLOSED: #719
109 lines
4.7 KiB
Plaintext
109 lines
4.7 KiB
Plaintext
*** Settings ***
|
|
Documentation Integration test for AuditService EventBus wiring
|
|
Resource ${CURDIR}/common.resource
|
|
Suite Setup Setup Test Environment With Database Isolation
|
|
Suite Teardown Cleanup Test Environment
|
|
|
|
*** Variables ***
|
|
${HELPER} ${CURDIR}/helper_audit_wiring.py
|
|
|
|
*** Test Cases ***
|
|
Audit Subscriber Records Events
|
|
[Documentation] Verify AuditEventSubscriber records events from EventBus
|
|
[Tags] observability audit
|
|
${result}= Run Process ${PYTHON} ${HELPER} record_events
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} AUDIT_OK
|
|
|
|
Audit Subscriber Redacts Sensitive Data
|
|
[Documentation] Verify sensitive data is redacted in audit entries
|
|
[Tags] observability audit security
|
|
${result}= Run Process ${PYTHON} ${HELPER} redact_secrets
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} REDACT_OK
|
|
|
|
Audit Subscriber Ignores Non-Security Events
|
|
[Documentation] Verify non-security events are not recorded
|
|
[Tags] observability audit
|
|
${result}= Run Process ${PYTHON} ${HELPER} ignore_non_security
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} FILTER_OK
|
|
|
|
Container Wires Audit Subscriber
|
|
[Documentation] Verify DI container registers AuditEventSubscriber
|
|
[Tags] observability audit di
|
|
${result}= Run Process ${PYTHON} ${HELPER} container_wiring
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} CONTAINER_OK
|
|
|
|
E2E Plan Lifecycle Through Audit Pipeline
|
|
[Documentation] End-to-end: PlanLifecycleService cancel_plan -> EventBus -> AuditEventSubscriber -> AuditService DB
|
|
[Tags] observability audit e2e
|
|
${result}= Run Process ${PYTHON} ${HELPER} e2e_plan_lifecycle
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} E2E_OK
|
|
User Identity Field Propagates Through Audit Pipeline
|
|
[Documentation] DomainEvent.user_identity propagates via AuditEventSubscriber to AuditService DB entry
|
|
[Tags] observability audit identity
|
|
${result}= Run Process ${PYTHON} ${HELPER} user_identity_field
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} IDENTITY_FIELD_OK
|
|
|
|
User Identity Fallback From Details
|
|
[Documentation] Backward compat: user_identity extracted from details when field is None
|
|
[Tags] observability audit identity
|
|
${result}= Run Process ${PYTHON} ${HELPER} user_identity_details_fallback
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} IDENTITY_FALLBACK_OK
|
|
|
|
User Identity Field Precedence Over Details
|
|
[Documentation] DomainEvent.user_identity field takes precedence over details dict
|
|
[Tags] observability audit identity
|
|
${result}= Run Process ${PYTHON} ${HELPER} user_identity_field_precedence
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} IDENTITY_PRECEDENCE_OK
|
|
|
|
Auth Middleware Emits Audit Events
|
|
[Documentation] End-to-end: TokenAuthMiddleware emits AUTH_SUCCESS/AUTH_FAILURE through audit pipeline
|
|
[Tags] observability audit auth
|
|
${result}= Run Process ${PYTHON} ${HELPER} auth_middleware_pipeline
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} AUTH_PIPELINE_OK
|
|
|
|
Audit Subscriber Preserves Event Timestamp
|
|
[Documentation] DomainEvent.timestamp propagates to AuditLogEntry.created_at via AuditEventSubscriber
|
|
[Tags] observability audit
|
|
${result}= Run Process ${PYTHON} ${HELPER} preserve_event_timestamp
|
|
... cwd=${WORKSPACE}
|
|
Log ${result.stdout}
|
|
Log ${result.stderr}
|
|
Should Be Equal As Integers ${result.rc} 0
|
|
Should Contain ${result.stdout} TIMESTAMP_OK
|