forked from wrenn/wrenn
v0.1.3 (#36)
## What's new Compliance, audit, and account lifecycle improvements — admin actions are now fully auditable, user data is properly anonymized on deletion, and OAuth signup flow gives users control over their profile. ### Audit - Added audit logging for all admin actions (user activate/deactivate, team BYOC toggle, team delete, template delete, build create/cancel) - Added admin audit page with infinite scroll and hierarchical filters - Fixed audit log team assignment — admin/host actions now correctly land under PlatformTeamID - Anonymize audit logs on user hard-delete (actor name, IDs, emails stripped) - Deduplicated audit logger internals (665 → 374 lines, no behavior change) ### Authentication - Separated GitHub OAuth login/signup flows — login no longer auto-creates accounts - Added name confirmation dialog for new GitHub signups ### Account Lifecycle - Email notification sent when account is permanently deleted after grace period - Audit log anonymization tied to user purge (per-user transactional) ### UX - Removed accent gradient bars from admin host dialogs (border + shadow only) - Frontend renders deleted users as styled badge in audit log view ### Others - Version bump - Bug fixes Reviewed-on: wrenn/wrenn#36
This commit is contained in:
@ -11,6 +11,21 @@ import (
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const anonymizeAuditLogsByUserID = `-- name: AnonymizeAuditLogsByUserID :exec
|
||||
UPDATE audit_logs
|
||||
SET actor_name = CASE WHEN actor_id = $1 THEN 'deleted-user' ELSE actor_name END,
|
||||
actor_id = CASE WHEN actor_id = $1 THEN NULL ELSE actor_id END,
|
||||
resource_id = CASE WHEN resource_type = 'member' AND resource_id = $1 THEN NULL ELSE resource_id END,
|
||||
metadata = CASE WHEN resource_type = 'member' AND resource_id = $1 AND metadata ? 'email' THEN metadata - 'email' ELSE metadata END
|
||||
WHERE actor_id = $1
|
||||
OR (resource_type = 'member' AND resource_id = $1)
|
||||
`
|
||||
|
||||
func (q *Queries) AnonymizeAuditLogsByUserID(ctx context.Context, actorID pgtype.Text) error {
|
||||
_, err := q.db.Exec(ctx, anonymizeAuditLogsByUserID, actorID)
|
||||
return err
|
||||
}
|
||||
|
||||
const insertAuditLog = `-- name: InsertAuditLog :exec
|
||||
INSERT INTO audit_logs (id, team_id, actor_type, actor_id, actor_name, resource_type, resource_id, action, scope, status, metadata)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
|
||||
@ -183,15 +183,6 @@ func (q *Queries) GetUserByID(ctx context.Context, id pgtype.UUID) (User, error)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const hardDeleteExpiredUsers = `-- name: HardDeleteExpiredUsers :exec
|
||||
DELETE FROM users WHERE deleted_at IS NOT NULL AND deleted_at < NOW() - INTERVAL '15 days'
|
||||
`
|
||||
|
||||
func (q *Queries) HardDeleteExpiredUsers(ctx context.Context) error {
|
||||
_, err := q.db.Exec(ctx, hardDeleteExpiredUsers)
|
||||
return err
|
||||
}
|
||||
|
||||
const hardDeleteUser = `-- name: HardDeleteUser :exec
|
||||
DELETE FROM users WHERE id = $1
|
||||
`
|
||||
@ -334,6 +325,35 @@ func (q *Queries) InsertUserOAuth(ctx context.Context, arg InsertUserOAuthParams
|
||||
return i, err
|
||||
}
|
||||
|
||||
const listExpiredSoftDeletedUsers = `-- name: ListExpiredSoftDeletedUsers :many
|
||||
SELECT id, email FROM users WHERE deleted_at IS NOT NULL AND deleted_at < NOW() - INTERVAL '15 days'
|
||||
`
|
||||
|
||||
type ListExpiredSoftDeletedUsersRow struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListExpiredSoftDeletedUsers(ctx context.Context) ([]ListExpiredSoftDeletedUsersRow, error) {
|
||||
rows, err := q.db.Query(ctx, listExpiredSoftDeletedUsers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListExpiredSoftDeletedUsersRow
|
||||
for rows.Next() {
|
||||
var i ListExpiredSoftDeletedUsersRow
|
||||
if err := rows.Scan(&i.ID, &i.Email); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listUsersAdmin = `-- name: ListUsersAdmin :many
|
||||
SELECT
|
||||
u.id,
|
||||
|
||||
Reference in New Issue
Block a user