use anyhow::Result;
use chrono::{DateTime, Utc};
use clap::{Args, Subcommand};
use ironflow_sdk::IronflowClient;
use ironflow_sdk::client::ListAuditLogsFilter;
use ironflow_sdk::types::EventKind;
use uuid::Uuid;
use crate::commands::parse_enum;
use crate::output;
#[derive(Debug, Args)]
pub struct AuditLogArgs {
#[command(subcommand)]
pub command: AuditLogCommands,
}
#[derive(Debug, Subcommand)]
pub enum AuditLogCommands {
List {
#[arg(long = "run", value_name = "UUID")]
run: Option<Uuid>,
#[arg(long = "type", value_name = "KIND", value_parser = parse_event_kind)]
event_type: Option<EventKind>,
#[arg(long)]
from: Option<DateTime<Utc>>,
#[arg(long)]
to: Option<DateTime<Utc>>,
#[arg(long)]
page: Option<u32>,
#[arg(long)]
per_page: Option<u32>,
},
}
const ALL_EVENT_KINDS: [EventKind; 13] = [
EventKind::RunCreated,
EventKind::RunStatusChanged,
EventKind::RunFailed,
EventKind::RunBudgetExceeded,
EventKind::StepCompleted,
EventKind::StepFailed,
EventKind::ApprovalRequested,
EventKind::ApprovalGranted,
EventKind::ApprovalRejected,
EventKind::LogLine,
EventKind::UserSignedIn,
EventKind::UserSignedUp,
EventKind::UserSignedOut,
];
fn parse_event_kind(raw: &str) -> Result<EventKind, String> {
parse_enum(raw, &ALL_EVENT_KINDS, "event type")
}
pub async fn execute(client: &IronflowClient, args: &AuditLogArgs, json_mode: bool) -> Result<()> {
match &args.command {
AuditLogCommands::List {
run,
event_type,
from,
to,
page,
per_page,
} => {
let event_type = event_type.as_ref().map(ToString::to_string);
let filter = ListAuditLogsFilter {
run_id: *run,
event_type: event_type.as_deref(),
from: *from,
to: *to,
page: *page,
per_page: *per_page,
};
let response = client.list_audit_logs_filtered(&filter).await?;
output::print_output(json_mode, &response, || {
output::audit_logs_table(&response.data)
})?;
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_event_kind_accepts_every_declared_kind() {
for kind in ALL_EVENT_KINDS {
let raw = kind.to_string();
assert_eq!(parse_event_kind(&raw).unwrap(), kind);
}
}
#[test]
fn parse_event_kind_rejects_an_unknown_value_and_lists_the_valid_ones() {
let err = parse_event_kind("run_exploded").unwrap_err();
assert!(err.contains("unknown event type 'run_exploded'"), "{err}");
assert!(err.contains("run_created"), "{err}");
}
}