use std::collections::HashMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum FindingCategory {
CodeBug,
Security,
Performance,
Todo,
Enhancement,
ConfigIssue,
TestIssue,
Documentation,
RuntimeIssue,
AlreadyFixed,
ExpectedBehavior,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum FindingSeverity {
Critical,
High,
Medium,
Low,
Info,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum FindingStatus {
Detected,
InProgress,
NeedsInput,
Resolved,
WontFix,
Deferred,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum FindingActionType {
AutoFix,
NeedsUserInput,
Manual,
Informational,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct FindingCodeContext {
#[serde(default, skip_serializing_if = "Option::is_none", alias = "file")]
pub file: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "line")]
pub line: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "column")]
pub column: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "snippet")]
pub snippet: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct FindingUserInput {
#[serde(alias = "question")]
pub question: String,
#[serde(default = "default_input_type", alias = "input_type")]
pub input_type: String,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "options")]
pub options: Option<Vec<String>>,
}
fn default_input_type() -> String {
"text".to_string()
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct FindingCreate {
#[serde(alias = "task_run_id")]
pub task_run_id: String,
#[serde(alias = "session_num")]
pub session_num: i64,
#[serde(alias = "category")]
pub category: FindingCategory,
#[serde(alias = "severity")]
pub severity: FindingSeverity,
#[serde(alias = "title")]
pub title: String,
#[serde(alias = "description")]
pub description: String,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "code_context"
)]
pub code_context: Option<FindingCodeContext>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "signature_hash"
)]
pub signature_hash: Option<String>,
#[serde(alias = "action_type")]
pub action_type: FindingActionType,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "user_input")]
pub user_input: Option<FindingUserInput>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct FindingBatchCreate {
#[serde(alias = "findings")]
pub findings: Vec<FindingCreate>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct FindingUpdate {
#[serde(default, skip_serializing_if = "Option::is_none", alias = "status")]
pub status: Option<FindingStatus>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "resolution")]
pub resolution: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "resolved_in_session"
)]
pub resolved_in_session: Option<i64>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "user_response"
)]
pub user_response: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct FindingDetail {
#[serde(alias = "id")]
pub id: String,
#[serde(alias = "task_run_id")]
pub task_run_id: String,
#[serde(alias = "session_num")]
pub session_num: i64,
#[serde(alias = "category")]
pub category: FindingCategory,
#[serde(alias = "severity")]
pub severity: FindingSeverity,
#[serde(alias = "status")]
pub status: FindingStatus,
#[serde(alias = "title")]
pub title: String,
#[serde(alias = "description")]
pub description: String,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "resolution")]
pub resolution: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "code_context"
)]
pub code_context: Option<FindingCodeContext>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "signature_hash"
)]
pub signature_hash: Option<String>,
#[serde(alias = "action_type")]
pub action_type: FindingActionType,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "user_input")]
pub user_input: Option<FindingUserInput>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "user_response"
)]
pub user_response: Option<String>,
#[serde(alias = "detected_at")]
pub detected_at: String,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "resolved_at"
)]
pub resolved_at: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "resolved_in_session"
)]
pub resolved_in_session: Option<i64>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct FindingListResponse {
#[serde(default, alias = "findings")]
pub findings: Vec<FindingDetail>,
#[serde(alias = "total")]
pub total: i64,
#[serde(alias = "limit")]
pub limit: i64,
#[serde(alias = "offset")]
pub offset: i64,
#[serde(alias = "has_more")]
pub has_more: bool,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct FindingSummary {
#[serde(alias = "task_run_id")]
pub task_run_id: String,
#[serde(default, alias = "total")]
pub total: i64,
#[serde(
default,
skip_serializing_if = "HashMap::is_empty",
alias = "by_category"
)]
pub by_category: HashMap<String, i64>,
#[serde(
default,
skip_serializing_if = "HashMap::is_empty",
alias = "by_severity"
)]
pub by_severity: HashMap<String, i64>,
#[serde(
default,
skip_serializing_if = "HashMap::is_empty",
alias = "by_status"
)]
pub by_status: HashMap<String, i64>,
#[serde(default, alias = "needs_input_count")]
pub needs_input_count: i64,
#[serde(default, alias = "resolved_count")]
pub resolved_count: i64,
#[serde(default, alias = "outstanding_count")]
pub outstanding_count: i64,
}