package iam import ( "context" "time" "atlas9.dev/c/core" ) // AuditEntry is one record in the audit log: who did what to which // resource, when. Entries are written in the same transaction as the // mutation they describe, so the log never disagrees with the data. // // Entries are scoped by Tenant, by Subject, or both. Tenant-scoped // entries record administrative actions within a tenant. Subject-scoped // entries record identity and account events concerning a user (login, // registration, password reset) that have no tenant. type AuditEntry struct { ID core.ID Tenant core.ID // Subject is the user this entry concerns. Distinct from Actor: on a // password reset performed via emailed token, Subject is the account // owner while Actor is empty (anonymous). Subject core.ID Time time.Time // Actor is the principal subject that performed the action. // Empty for anonymous actions (e.g. an invitee declining by token // before registering). Actor string // Action is the API operation name, e.g. "Tenants_Update". Action string // Resource identifies the affected resource: an ID, slug, or email, // depending on what the action operates on. Resource string // Detail is short human-readable context, e.g. the new name on a rename. Detail string // Request is the HTTP request ID, for correlation with request logs. Request string } var CapAuditRead = NewCap("Audit_Read") type AuditStore interface { // Append writes an entry. ID and Time are filled if empty. Append has // no capability check: an entry is a side effect of an operation that // already passed its own check, and appending is never caller-chosen. Append(ctx context.Context, e *AuditEntry) error List(ctx context.Context, tenant core.ID, page core.PageReq, out *core.Page[AuditEntry]) error // ListByUser returns entries whose Subject is the given user. Allowed // for the user themselves, or with system-scoped Audit.Read. ListByUser(ctx context.Context, userID core.ID, page core.PageReq, out *core.Page[AuditEntry]) error }