From 789d021800383b34537e3d42f83fa824cd8e44cc Mon Sep 17 00:00:00 2001 From: "ci.datadog-api-spec" Date: Mon, 9 Nov 2026 16:39:29 +0000 Subject: [PATCH] Regenerate client from commit e7cc003 of spec repo --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/client.rs | 26 +-- src/generated/mod.rs | 5 + src/generated/security/historical_jobs.rs | 208 +++++++++++++++++++++ src/generated/security/histsignals.rs | 213 ++++++++++++++++++++++ src/generated/security/mod.rs | 29 +++ src/generated/surface.txt | 11 ++ src/generated/writes.rs | 3 + 9 files changed, 472 insertions(+), 27 deletions(-) create mode 100644 src/generated/security/historical_jobs.rs create mode 100644 src/generated/security/histsignals.rs create mode 100644 src/generated/security/mod.rs diff --git a/Cargo.lock b/Cargo.lock index c07302dd..0d7d5a95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1100,7 +1100,7 @@ checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] name = "datadog-api-client" version = "0.38.0" -source = "git+https://github.com/DataDog/datadog-api-client-rust?rev=a0148e35b714615060937e8ebde2711fe9906aae#a0148e35b714615060937e8ebde2711fe9906aae" +source = "git+https://github.com/DataDog/datadog-api-client-rust?rev=53de0d8e0e38c302a88e09e78ae4b81c8cf885e1#53de0d8e0e38c302a88e09e78ae4b81c8cf885e1" dependencies = [ "async-stream", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 7f508d68..faff1da4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -136,7 +136,7 @@ zip = { version = "9", default-features = false, features = ["deflate"], optiona # Datadog API client — pinned to a git rev # Use default-features = false; feature sets are activated per-target via features above -datadog-api-client = { git = "https://github.com/DataDog/datadog-api-client-rust", rev = "a0148e35b714615060937e8ebde2711fe9906aae", optional = true, default-features = false } +datadog-api-client = { git = "https://github.com/DataDog/datadog-api-client-rust", rev = "53de0d8e0e38c302a88e09e78ae4b81c8cf885e1", optional = true, default-features = false } # HTTP middleware (version-matched to DD client; compiles on all targets) reqwest-middleware = "0.5" diff --git a/src/client.rs b/src/client.rs index bded7a55..63459392 100644 --- a/src/client.rs +++ b/src/client.rs @@ -418,30 +418,6 @@ static UNSTABLE_OPS: &[&str] = &[ "v2.star_model_lab_project", "v2.unpin_model_lab_run", "v2.unstar_model_lab_project", - // Databricks Integration (5) - "v2.create_databricks_integration_account", - "v2.delete_databricks_integration_account", - "v2.get_databricks_integration_account", - "v2.list_databricks_integration_accounts", - "v2.update_databricks_integration_account", - // Elastic Cloud Integration (5) - "v2.create_elastic_cloud_integration_account", - "v2.delete_elastic_cloud_integration_account", - "v2.get_elastic_cloud_integration_account", - "v2.list_elastic_cloud_integration_accounts", - "v2.update_elastic_cloud_integration_account", - // Snowflake Integration (5) - "v2.create_snowflake_integration_account", - "v2.delete_snowflake_integration_account", - "v2.get_snowflake_integration_account", - "v2.list_snowflake_integration_accounts", - "v2.update_snowflake_integration_account", - // Twilio Integration (5) - "v2.create_twilio_integration_account", - "v2.delete_twilio_integration_account", - "v2.get_twilio_integration_account", - "v2.list_twilio_integration_accounts", - "v2.update_twilio_integration_account", ]; #[cfg(test)] @@ -563,7 +539,7 @@ mod tests { #[test] fn test_unstable_ops_count() { - assert_eq!(UNSTABLE_OPS.len(), 207); + assert_eq!(UNSTABLE_OPS.len(), 187); } #[test] diff --git a/src/generated/mod.rs b/src/generated/mod.rs index ba771ea5..7dca2847 100644 --- a/src/generated/mod.rs +++ b/src/generated/mod.rs @@ -1,8 +1,13 @@ // Code generated by openapi-transformer. DO NOT EDIT. +// pup CI denies clippy warnings, and the spec's size, not the generator, drives these two: +// operations with many params make long handler signatures and large command variants. +#![allow(clippy::too_many_arguments, clippy::large_enum_variant)] + pub mod authn_mappings; pub mod domain_allowlist; pub mod downtime; +pub mod security; pub mod writes; use anyhow::Result; diff --git a/src/generated/security/historical_jobs.rs b/src/generated/security/historical_jobs.rs new file mode 100644 index 00000000..a072142f --- /dev/null +++ b/src/generated/security/historical_jobs.rs @@ -0,0 +1,208 @@ +// Code generated by openapi-transformer. DO NOT EDIT. + +use anyhow::Result; +use datadog_api_client::datadogV2::api_security_monitoring::{ + ListHistoricalJobsOptionalParams, SecurityMonitoringAPI, +}; +use datadog_api_client::datadogV2::model::ConvertJobResultsToSignalsRequest; + +use crate::config::Config; +use crate::formatter; +use crate::util; + +#[derive(clap::Subcommand)] +pub enum Command { + /// Cancel a historical job + /// + /// Cancel a historical job. + Cancel { + /// The ID of the job. + job_id: String, + }, + /// Convert a job result to a signal + /// + /// Convert a job result to a signal. + Convert { + #[arg(long = "file")] + file: String, + }, + /// Delete an existing job + /// + /// Delete an existing job. + Delete { + /// The ID of the job. + job_id: String, + }, + /// Get a job's details + /// + /// Get a job's details. + Get { + /// The ID of the job. + job_id: String, + }, + /// List historical jobs + /// + /// List historical jobs. + List { + /// Number of items to return per page. The maximum allowed value is 100. + #[arg(long = "page-size")] + page_size: Option, + /// Specific page number to return. + #[arg(long = "page-number")] + page_number: Option, + /// The order of the jobs in results. + #[arg(long = "sort")] + sort: Option, + /// Query used to filter items from the fetched list. + #[arg(long = "filter-query")] + filter_query: Option, + }, +} + +pub async fn run(cfg: &Config, command: Command) -> Result<()> { + match command { + Command::Cancel { job_id } => cancel(cfg, job_id).await, + Command::Convert { file } => convert(cfg, &file).await, + Command::Delete { job_id } => delete(cfg, job_id).await, + Command::Get { job_id } => get(cfg, job_id).await, + Command::List { + page_size, + page_number, + sort, + filter_query, + } => list(cfg, page_size, page_number, sort, filter_query).await, + } +} + +/// Cancel a historical job +/// +/// Cancel a historical job. +pub async fn cancel(cfg: &Config, job_id: String) -> Result<()> { + let resource_label = job_id.to_string(); + let api = crate::make_api!(SecurityMonitoringAPI, cfg); + api.cancel_historical_job(job_id) + .await + .map_err(|e| anyhow::anyhow!("failed to cancel_historical_job: {:?}", e))?; + formatter::output_no_content( + cfg, + "security historical-jobs cancel", + Some(&resource_label), + ) +} + +/// Convert a job result to a signal +/// +/// Convert a job result to a signal. +pub async fn convert(cfg: &Config, file: &str) -> Result<()> { + let body: ConvertJobResultsToSignalsRequest = util::read_json_file(file)?; + let api = crate::make_api!(SecurityMonitoringAPI, cfg); + api.convert_job_result_to_signal(body) + .await + .map_err(|e| anyhow::anyhow!("failed to convert_job_result_to_signal: {:?}", e))?; + formatter::output_no_content(cfg, "security historical-jobs convert", None) +} + +/// Delete an existing job +/// +/// Delete an existing job. +pub async fn delete(cfg: &Config, job_id: String) -> Result<()> { + let resource_label = job_id.to_string(); + let api = crate::make_api!(SecurityMonitoringAPI, cfg); + api.delete_historical_job(job_id) + .await + .map_err(|e| anyhow::anyhow!("failed to delete_historical_job: {:?}", e))?; + formatter::output_no_content( + cfg, + "security historical-jobs delete", + Some(&resource_label), + ) +} + +/// Get a job's details +/// +/// Get a job's details. +pub async fn get(cfg: &Config, job_id: String) -> Result<()> { + let api = crate::make_api!(SecurityMonitoringAPI, cfg); + let resp = api + .get_historical_job(job_id) + .await + .map_err(|e| anyhow::anyhow!("failed to get_historical_job: {:?}", e))?; + formatter::output(cfg, &resp) +} + +/// List historical jobs +/// +/// List historical jobs. +pub async fn list( + cfg: &Config, + page_size: Option, + page_number: Option, + sort: Option, + filter_query: Option, +) -> Result<()> { + let api = crate::make_api!(SecurityMonitoringAPI, cfg); + let mut params = ListHistoricalJobsOptionalParams::default(); + if let Some(v) = page_size { + params = params.page_size(v); + } + if let Some(v) = page_number { + params = params.page_number(v); + } + if let Some(v) = sort { + params = params.sort(v); + } + if let Some(v) = filter_query { + params = params.filter_query(v); + } + let resp = api + .list_historical_jobs(params) + .await + .map_err(|e| anyhow::anyhow!("failed to list_historical_jobs: {:?}", e))?; + let count = resp.data.as_ref().map_or(0, |d| d.len()); + let truncated = page_size.is_some_and(|l| count >= l as usize); + let next_action = if truncated { + page_size.map(|l| { + format!( + "Results may be truncated at {l}. Use --page-size={} or narrow the filters", + l + 1 + ) + }) + } else { + None + }; + let meta = formatter::Metadata { + count: Some(count), + truncated, + command: Some("security historical-jobs list".to_string()), + next_action, + ..Default::default() + }; + formatter::output_with_meta(cfg, &resp, &meta) +} + +#[cfg(test)] +mod tests { + use crate::test_support::*; + + #[tokio::test] + async fn test_get_ok() { + let _lock = lock_env().await; + let mut server = mockito::Server::new_async().await; + let cfg = test_config(&server.url()); + let _mock = mock_any(&mut server, "GET", r##"{"data": {"attributes": {"createdAt": "2024-01-01T00:00:00+00:00", "createdByHandle": "example-handle", "createdByName": "Example Name", "jobName": "Example Job", "jobStatus": "COMPLETED", "modifiedAt": "2024-01-01T00:00:00+00:00", "signalOutput": false}, "id": "abc-123", "type": "historicalDetectionsJob"}}"##).await; + let result = super::get(&cfg, "test".to_string()).await; + assert!(result.is_ok(), "get failed: {:?}", result.err()); + cleanup_env(); + } + + #[tokio::test] + async fn test_list_ok() { + let _lock = lock_env().await; + let mut server = mockito::Server::new_async().await; + let cfg = test_config(&server.url()); + let _mock = mock_any(&mut server, "GET", r##"{"data": [{"attributes": {"createdAt": "2024-01-01T00:00:00+00:00", "createdByHandle": "example-handle", "createdByName": "Example Name", "jobName": "Example Job", "jobStatus": "COMPLETED"}, "id": "abc-123", "type": "historicalDetectionsJob"}], "meta": {"totalCount": 1}}"##).await; + let result = super::list(&cfg, None, None, None, None).await; + assert!(result.is_ok(), "list failed: {:?}", result.err()); + cleanup_env(); + } +} diff --git a/src/generated/security/histsignals.rs b/src/generated/security/histsignals.rs new file mode 100644 index 00000000..19034ceb --- /dev/null +++ b/src/generated/security/histsignals.rs @@ -0,0 +1,213 @@ +// Code generated by openapi-transformer. DO NOT EDIT. + +use anyhow::Result; +use datadog_api_client::datadogV2::api_security_monitoring::{ + ListSecurityMonitoringHistsignalsOptionalParams, + SearchSecurityMonitoringHistsignalsOptionalParams, SecurityMonitoringAPI, +}; +use datadog_api_client::datadogV2::model::{ + SecurityMonitoringSignalListRequest, SecurityMonitoringSignalsSort, +}; + +use crate::config::Config; +use crate::formatter; +use crate::util; + +#[derive(clap::Subcommand)] +pub enum Command { + /// Get a hist signal's details + /// + /// Get a hist signal's details. + Get { + /// The ID of the historical signal. + histsignal_id: String, + }, + /// List hist signals + /// + /// List hist signals. + List { + /// The search query for security signals. + #[arg(long = "filter-query")] + filter_query: Option, + /// The minimum timestamp for requested security signals. + /// Accepts now, a time ago (1h, 30m, 7d, now-15m), YYYY-MM, YYYY-MM-DD, RFC3339, or a Unix timestamp (seconds or ms). + #[arg(long = "filter-from", value_parser = crate::util_ext::parse_time_to_datetime)] + filter_from: Option>, + /// The maximum timestamp for requested security signals. + /// Accepts now, a time ago (1h, 30m, 7d, now-15m), YYYY-MM, YYYY-MM-DD, RFC3339, or a Unix timestamp (seconds or ms). + #[arg(long = "filter-to", value_parser = crate::util_ext::parse_time_to_datetime)] + filter_to: Option>, + /// The order of the security signals in results. + #[arg(long = "sort")] + sort: Option, + /// A list of results using the cursor provided in the previous query. + #[arg(long = "page-cursor")] + page_cursor: Option, + /// The maximum number of security signals in the response. + #[arg(long = "page-limit")] + page_limit: Option, + }, + /// Search hist signals + /// + /// Search hist signals. + Search { + #[arg(long = "file")] + file: Option, + }, +} + +pub async fn run(cfg: &Config, command: Command) -> Result<()> { + match command { + Command::Get { histsignal_id } => get(cfg, histsignal_id).await, + Command::List { + filter_query, + filter_from, + filter_to, + sort, + page_cursor, + page_limit, + } => { + list( + cfg, + filter_query, + filter_from, + filter_to, + sort, + page_cursor, + page_limit, + ) + .await + } + Command::Search { file } => search(cfg, file).await, + } +} + +/// Get a hist signal's details +/// +/// Get a hist signal's details. +pub async fn get(cfg: &Config, histsignal_id: String) -> Result<()> { + let api = crate::make_api!(SecurityMonitoringAPI, cfg); + let resp = api + .get_security_monitoring_histsignal(histsignal_id) + .await + .map_err(|e| anyhow::anyhow!("failed to get_security_monitoring_histsignal: {:?}", e))?; + formatter::output(cfg, &resp) +} + +/// List hist signals +/// +/// List hist signals. +pub async fn list( + cfg: &Config, + filter_query: Option, + filter_from: Option>, + filter_to: Option>, + sort: Option, + page_cursor: Option, + page_limit: Option, +) -> Result<()> { + let api = crate::make_api!(SecurityMonitoringAPI, cfg); + let mut params = ListSecurityMonitoringHistsignalsOptionalParams::default(); + if let Some(v) = filter_query { + params = params.filter_query(v); + } + if let Some(v) = filter_from { + params = params.filter_from(v); + } + if let Some(v) = filter_to { + params = params.filter_to(v); + } + if let Some(v) = sort { + params = params.sort(parse_security_monitoring_signals_sort(&v)?); + } + if let Some(v) = page_cursor { + params = params.page_cursor(v); + } + if let Some(v) = page_limit { + params = params.page_limit(v); + } + let resp = api + .list_security_monitoring_histsignals(params) + .await + .map_err(|e| anyhow::anyhow!("failed to list_security_monitoring_histsignals: {:?}", e))?; + let count = resp.data.as_ref().map_or(0, |d| d.len()); + let truncated = page_limit.is_some_and(|l| count >= l as usize); + let next_action = if truncated { + page_limit.map(|l| { + format!( + "Results may be truncated at {l}. Use --page-limit={} or narrow the filters", + l + 1 + ) + }) + } else { + None + }; + let meta = formatter::Metadata { + count: Some(count), + truncated, + command: Some("security histsignals list".to_string()), + next_action, + ..Default::default() + }; + formatter::output_with_meta(cfg, &resp, &meta) +} + +/// Search hist signals +/// +/// Search hist signals. +pub async fn search(cfg: &Config, file: Option) -> Result<()> { + let api = crate::make_api!(SecurityMonitoringAPI, cfg); + let mut params = SearchSecurityMonitoringHistsignalsOptionalParams::default(); + if let Some(file) = file { + let body: SecurityMonitoringSignalListRequest = util::read_json_file(&file)?; + params = params.body(body); + } + let resp = api + .search_security_monitoring_histsignals(params) + .await + .map_err(|e| { + anyhow::anyhow!("failed to search_security_monitoring_histsignals: {:?}", e) + })?; + let count = resp.data.as_ref().map_or(0, |d| d.len()); + let meta = formatter::Metadata { + count: Some(count), + command: Some("security histsignals search".to_string()), + ..Default::default() + }; + formatter::output_with_meta(cfg, &resp, &meta) +} + +fn parse_security_monitoring_signals_sort(s: &str) -> Result { + Ok(match s { + "timestamp" => SecurityMonitoringSignalsSort::TIMESTAMP_ASCENDING, + "-timestamp" => SecurityMonitoringSignalsSort::TIMESTAMP_DESCENDING, + _ => anyhow::bail!("invalid value {s:?}, valid values: timestamp, -timestamp"), + }) +} + +#[cfg(test)] +mod tests { + use crate::test_support::*; + + #[tokio::test] + async fn test_get_ok() { + let _lock = lock_env().await; + let mut server = mockito::Server::new_async().await; + let cfg = test_config(&server.url()); + let _mock = mock_any(&mut server, "GET", r##"{"data": {"attributes": {"message": "A large number of failed login attempts.", "tags": ["source:production"], "timestamp": "2024-01-01T00:00:00+00:00"}, "id": "abc-123", "type": "signal"}}"##).await; + let result = super::get(&cfg, "test".to_string()).await; + assert!(result.is_ok(), "get failed: {:?}", result.err()); + cleanup_env(); + } + + #[tokio::test] + async fn test_list_ok() { + let _lock = lock_env().await; + let mut server = mockito::Server::new_async().await; + let cfg = test_config(&server.url()); + let _mock = mock_any(&mut server, "GET", r##"{"data": [{"attributes": {"message": "A large number of failed login attempts.", "tags": ["source:production"], "timestamp": "2024-01-01T00:00:00+00:00"}, "id": "abc-123", "type": "signal"}]}"##).await; + let result = super::list(&cfg, None, None, None, None, None, None).await; + assert!(result.is_ok(), "list failed: {:?}", result.err()); + cleanup_env(); + } +} diff --git a/src/generated/security/mod.rs b/src/generated/security/mod.rs new file mode 100644 index 00000000..6daf09ae --- /dev/null +++ b/src/generated/security/mod.rs @@ -0,0 +1,29 @@ +// Code generated by openapi-transformer. DO NOT EDIT. + +pub mod historical_jobs; +pub mod histsignals; + +use anyhow::Result; + +use crate::config::Config; + +#[derive(clap::Subcommand)] +pub enum Command { + /// historical_jobs commands + HistoricalJobs { + #[command(subcommand)] + action: historical_jobs::Command, + }, + /// histsignals commands + Histsignals { + #[command(subcommand)] + action: histsignals::Command, + }, +} + +pub async fn run(cfg: &Config, command: Command) -> Result<()> { + match command { + Command::HistoricalJobs { action } => historical_jobs::run(cfg, action).await, + Command::Histsignals { action } => histsignals::run(cfg, action).await, + } +} diff --git a/src/generated/surface.txt b/src/generated/surface.txt index 7a296027..29e0018b 100644 --- a/src/generated/surface.txt +++ b/src/generated/surface.txt @@ -11,3 +11,14 @@ downtime.cancel downtime.create downtime.get downtime.list +security +security.historical-jobs.cancel +security.historical-jobs.convert +security.historical-jobs.delete +security.historical-jobs.get +security.historical-jobs.list +security.histsignals.get +security.histsignals.list +security.histsignals.search +security/historical-jobs +security/histsignals diff --git a/src/generated/writes.rs b/src/generated/writes.rs index 73d3f182..ab8779f6 100644 --- a/src/generated/writes.rs +++ b/src/generated/writes.rs @@ -7,4 +7,7 @@ pub const WRITE_COMMANDS: &[&str] = &[ "authn-mappings update", "downtime cancel", "downtime create", + "security historical-jobs cancel", + "security historical-jobs convert", + "security historical-jobs delete", ];