Part of #777. After 3.0.
Builds on tenant/resource classification (#778), stable identity and actor/owner context (#774), and membership/administrative actions (#779). Later sharing (#780) and service accounts (#783) add event types and actors; they must not require inventing a second audit identity model.
In plain terms
When several people share one CAO, "who did that?" stops being a rhetorical question. Who removed that member? Who shared that workflow with the whole organisation? Who deleted that session?
CAO does have an audit log today, and it's a careful piece of work — append-only, permission-checked, protected against log injection. But it was built for one purpose and doesn't stretch to this one.
Why today's audit log isn't enough
Three specific problems, none of which are criticisms of what it does well:
It covers the memory/learning subsystem, not the whole application. It lives at logs/memory/YYYY-MM-DD.md; alongside memory events, successful instruction promotion calls the audit writer with a profile-change event (services/promotion_service.py:177-205, :243-255), subject to that writer's feature gate and best-effort behavior. Sign-in, membership administration and session deletion do not thereby acquire a general audit trail.
It switches itself off. If memory.enabled is false, the whole thing short-circuits at the top. The code describes this honestly as a "documented forensic gap". That's a reasonable trade for a local tool. It isn't for a shared one, where the audit trail shouldn't depend on an unrelated feature being turned on.
It has no tenant-scoped access model. Events for all users share the daily files, so those files cannot simply be exposed to an administrator who should see only their own tenant. If stored on a pod's temporary volume, they are lost when that pod is removed.
What this delivers
A tenant-scoped audit trail covering delivered security-relevant operations — sign-in and failure, role changes, member add and remove, deletions, and administrative intervention in another person's work. Sharing and service-account features must emit through the same audit interface when they land; the audit foundation does not wait for those later features to exist.
Attribution must describe who acted, not merely who owns the affected resource. Preserve the stable acting principal, delegated execution context where relevant, target resource/owner, operation and actual outcome. A tenant administrator stopping another person's agent is not an action performed by that owner; later service-account actions are not automatically actions by their human creator.
Some failures have no authenticated actor or established tenant. Record known facts and explicitly unknown identity where appropriate. Use trusted server context for an established tenant; do not turn a claimed tenant, email address or invalid token into authoritative attribution. Unattributed/platform events remain operator-scoped and are not exposed through every tenant's audit reader.
Readable by a tenant's administrator, for their own tenant only. The audit trail is itself tenant-isolated data.
Store the new audit trail in the central database on durable storage, with tenant-scoped reads. Durability comes from the storage and retention policy, not from choosing SQL over files: a SQLite database on a disposable volume is lost too, and a file on a persistent volume can survive pod replacement.
Preserve the memory audit log's purpose and format. This sits alongside it rather than replacing it, but does not exempt those files from #774/#778's ownership and access rules. "Unchanged" must not mean exposing an installation-wide file to a tenant or member who may read only their own data.
Define retention, bounded event fields and append-failure behavior explicitly. Exclude secrets and raw authentication material; distinguish an attempted operation from a committed outcome, and make recording failures observable rather than treating a best-effort write as a durable audit guarantee.
A note on sources
AWS's detective-controls page says there are no security practices unique to SaaS. That does not mean AWS offers no relevant guidance: its tenant-aware operations guidance calls for insight into individual tenants' activity. Use that alongside the OWASP Logging Cheat Sheet, which distinguishes known identity, affected objects and outcomes and warns against logging secrets.
Acceptance criteria
Evidence
| Claim |
Where |
| Audit log serves memory/learning and is file-based |
services/audit_log.py:1-30; promotion calls the writer at services/promotion_service.py:205, :243-255 |
| Disabling memory disables auditing |
services/audit_log.py — "documented forensic gap" |
| Tenant-aware operations and application audit guidance |
AWS SaaS Lens tenant-aware operations; OWASP Logging Cheat Sheet |
Part of #777. After 3.0.
Builds on tenant/resource classification (#778), stable identity and actor/owner context (#774), and membership/administrative actions (#779). Later sharing (#780) and service accounts (#783) add event types and actors; they must not require inventing a second audit identity model.
In plain terms
When several people share one CAO, "who did that?" stops being a rhetorical question. Who removed that member? Who shared that workflow with the whole organisation? Who deleted that session?
CAO does have an audit log today, and it's a careful piece of work — append-only, permission-checked, protected against log injection. But it was built for one purpose and doesn't stretch to this one.
Why today's audit log isn't enough
Three specific problems, none of which are criticisms of what it does well:
It covers the memory/learning subsystem, not the whole application. It lives at
logs/memory/YYYY-MM-DD.md; alongside memory events, successful instruction promotion calls the audit writer with a profile-change event (services/promotion_service.py:177-205,:243-255), subject to that writer's feature gate and best-effort behavior. Sign-in, membership administration and session deletion do not thereby acquire a general audit trail.It switches itself off. If
memory.enabledis false, the whole thing short-circuits at the top. The code describes this honestly as a "documented forensic gap". That's a reasonable trade for a local tool. It isn't for a shared one, where the audit trail shouldn't depend on an unrelated feature being turned on.It has no tenant-scoped access model. Events for all users share the daily files, so those files cannot simply be exposed to an administrator who should see only their own tenant. If stored on a pod's temporary volume, they are lost when that pod is removed.
What this delivers
A tenant-scoped audit trail covering delivered security-relevant operations — sign-in and failure, role changes, member add and remove, deletions, and administrative intervention in another person's work. Sharing and service-account features must emit through the same audit interface when they land; the audit foundation does not wait for those later features to exist.
Attribution must describe who acted, not merely who owns the affected resource. Preserve the stable acting principal, delegated execution context where relevant, target resource/owner, operation and actual outcome. A tenant administrator stopping another person's agent is not an action performed by that owner; later service-account actions are not automatically actions by their human creator.
Some failures have no authenticated actor or established tenant. Record known facts and explicitly unknown identity where appropriate. Use trusted server context for an established tenant; do not turn a claimed tenant, email address or invalid token into authoritative attribution. Unattributed/platform events remain operator-scoped and are not exposed through every tenant's audit reader.
Readable by a tenant's administrator, for their own tenant only. The audit trail is itself tenant-isolated data.
Store the new audit trail in the central database on durable storage, with tenant-scoped reads. Durability comes from the storage and retention policy, not from choosing SQL over files: a SQLite database on a disposable volume is lost too, and a file on a persistent volume can survive pod replacement.
Preserve the memory audit log's purpose and format. This sits alongside it rather than replacing it, but does not exempt those files from #774/#778's ownership and access rules. "Unchanged" must not mean exposing an installation-wide file to a tenant or member who may read only their own data.
Define retention, bounded event fields and append-failure behavior explicitly. Exclude secrets and raw authentication material; distinguish an attempted operation from a committed outcome, and make recording failures observable rather than treating a best-effort write as a durable audit guarantee.
A note on sources
AWS's detective-controls page says there are no security practices unique to SaaS. That does not mean AWS offers no relevant guidance: its tenant-aware operations guidance calls for insight into individual tenants' activity. Use that alongside the OWASP Logging Cheat Sheet, which distinguishes known identity, affected objects and outcomes and warns against logging secrets.
Acceptance criteria
Evidence
services/audit_log.py:1-30; promotion calls the writer atservices/promotion_service.py:205,:243-255services/audit_log.py— "documented forensic gap"