#!/usr/bin/env nu # Workspace Audit Query Commands # Query and analyze workspace operation audit logs def get_audit_dir [] { let home = ($env.HOME | path expand) $home + "/.local/share/provisioning/audit" } def read_audit_logs [filter_fn: closure] { let audit_dir = (get_audit_dir) if not ($audit_dir | path exists) { return (error make { msg: $"Audit directory not found: {$audit_dir}" }) } glob $"($audit_dir)/*.jsonl" | each { |file| cat $file | lines | each { |line| if ($line | is-empty) { return null } try { let event = ($line | from json) (do $filter_fn $event) | if $in { $event } else { null } } } } | compact } export def "audit workspace operations" [workspace: string] { let workspace_ops = ["WorkspaceCreate", "WorkspaceDelete", "WorkspaceUpdate", "WorkspaceSwitch", "WorkspaceList", "WorkspaceSync"] let events = (read_audit_logs { |event| (($event.action.workspace == $workspace) and ($workspace_ops | any { |op| $event.action.action_type == $op })) }) $events | sort-by timestamp -r | each { |e| { timestamp: $e.timestamp, action: $e.action.action_type, user: $e.user.name, resource: $e.action.resource, status: $e.result.status, duration_ms: $e.result.duration_ms, } } } export def "audit workspace summary" [days?: int] { let days = if ($days == null) { 30 } else { $days } let cutoff_time = ((now) - ($days * 24 * 60 * 60 | into duration)) let workspace_ops = ["WorkspaceCreate", "WorkspaceDelete", "WorkspaceUpdate", "WorkspaceSwitch", "WorkspaceList", "WorkspaceSync"] let events = (read_audit_logs { |event| let event_time = ($event.timestamp | into datetime) (($event_time > $cutoff_time) and ($workspace_ops | any { |op| $event.action.action_type == $op })) }) # Simple summary: just list unique workspaces and total ops count let unique_workspaces = ($events | map { |e| $e.action.workspace } | unique) $unique_workspaces | each { |ws| let ws_events = ($events | where { |e| $e.action.workspace == $ws }) { workspace: $ws, total_operations: ($ws_events | length), operations: ( $ws_events | map { |e| $e.action.action_type } | unique | each { |op| { action: $op, count: ($ws_events | where { |e| $e.action.action_type == $op } | length) } } ), } } | sort-by workspace } export def "audit workspace failures" [workspace: string] { let events = (read_audit_logs { |event| (($event.action.workspace == $workspace) and ($event.result.status != "Success")) }) $events | sort-by timestamp -r | each { |e| { timestamp: $e.timestamp, action: $e.action.action_type, resource: $e.action.resource, status: $e.result.status, error: $e.result.error, duration_ms: $e.result.duration_ms, } } } export def "audit workspace switches" [user_id: string] { let events = (read_audit_logs { |event| (($event.user.id == $user_id) and ($event.action.action_type == "WorkspaceSwitch")) }) $events | sort-by timestamp -r | each { |e| { timestamp: $e.timestamp, user: $e.user.name, to_workspace: $e.action.workspace, status: $e.result.status, duration_ms: $e.result.duration_ms, } } } export def "audit workspace user-actions" [user_id: string] { let events = (read_audit_logs { |event| $event.user.id == $user_id }) $events | sort-by timestamp -r | each { |e| { timestamp: $e.timestamp, action: $e.action.action_type, workspace: $e.action.workspace, resource: $e.action.resource, status: $e.result.status, } } }