datadog_api_client/datadogV1/api/
api_security_monitoring.rs

1// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
2// This product includes software developed at Datadog (https://www.datadoghq.com/).
3// Copyright 2019-Present Datadog, Inc.
4use crate::datadog;
5use flate2::{
6    write::{GzEncoder, ZlibEncoder},
7    Compression,
8};
9use reqwest::header::{HeaderMap, HeaderValue};
10use serde::{Deserialize, Serialize};
11use std::io::Write;
12
13/// AddSecurityMonitoringSignalToIncidentError is a struct for typed errors of method [`SecurityMonitoringAPI::add_security_monitoring_signal_to_incident`]
14#[derive(Debug, Clone, Serialize, Deserialize)]
15#[serde(untagged)]
16pub enum AddSecurityMonitoringSignalToIncidentError {
17    APIErrorResponse(crate::datadogV1::model::APIErrorResponse),
18    UnknownValue(serde_json::Value),
19}
20
21/// EditSecurityMonitoringSignalAssigneeError is a struct for typed errors of method [`SecurityMonitoringAPI::edit_security_monitoring_signal_assignee`]
22#[derive(Debug, Clone, Serialize, Deserialize)]
23#[serde(untagged)]
24pub enum EditSecurityMonitoringSignalAssigneeError {
25    APIErrorResponse(crate::datadogV1::model::APIErrorResponse),
26    UnknownValue(serde_json::Value),
27}
28
29/// EditSecurityMonitoringSignalStateError is a struct for typed errors of method [`SecurityMonitoringAPI::edit_security_monitoring_signal_state`]
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(untagged)]
32pub enum EditSecurityMonitoringSignalStateError {
33    APIErrorResponse(crate::datadogV1::model::APIErrorResponse),
34    UnknownValue(serde_json::Value),
35}
36
37/// Create and manage your security rules, signals, filters, and more. See the [Datadog Security page](<https://docs.datadoghq.com/security/>) for more information.
38#[derive(Debug, Clone)]
39pub struct SecurityMonitoringAPI {
40    config: datadog::Configuration,
41    client: reqwest_middleware::ClientWithMiddleware,
42}
43
44impl Default for SecurityMonitoringAPI {
45    fn default() -> Self {
46        Self::with_config(datadog::Configuration::default())
47    }
48}
49
50impl SecurityMonitoringAPI {
51    pub fn new() -> Self {
52        Self::default()
53    }
54    pub fn with_config(config: datadog::Configuration) -> Self {
55        let mut reqwest_client_builder = reqwest::Client::builder();
56
57        if let Some(proxy_url) = &config.proxy_url {
58            let proxy = reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL");
59            reqwest_client_builder = reqwest_client_builder.proxy(proxy);
60        }
61
62        let mut middleware_client_builder =
63            reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap());
64
65        if config.enable_retry {
66            struct RetryableStatus;
67            impl reqwest_retry::RetryableStrategy for RetryableStatus {
68                fn handle(
69                    &self,
70                    res: &Result<reqwest::Response, reqwest_middleware::Error>,
71                ) -> Option<reqwest_retry::Retryable> {
72                    match res {
73                        Ok(success) => reqwest_retry::default_on_request_success(success),
74                        Err(_) => None,
75                    }
76                }
77            }
78            let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder()
79                .build_with_max_retries(config.max_retries);
80
81            let retry_middleware =
82                reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy(
83                    backoff_policy,
84                    RetryableStatus,
85                );
86
87            middleware_client_builder = middleware_client_builder.with(retry_middleware);
88        }
89
90        let client = middleware_client_builder.build();
91
92        Self { config, client }
93    }
94
95    pub fn with_client_and_config(
96        config: datadog::Configuration,
97        client: reqwest_middleware::ClientWithMiddleware,
98    ) -> Self {
99        Self { config, client }
100    }
101
102    /// Add a security signal to an incident. This makes it possible to search for signals by incident within the signal explorer and to view the signals on the incident timeline.
103    pub async fn add_security_monitoring_signal_to_incident(
104        &self,
105        signal_id: String,
106        body: crate::datadogV1::model::AddSignalToIncidentRequest,
107    ) -> Result<
108        crate::datadogV1::model::SuccessfulSignalUpdateResponse,
109        datadog::Error<AddSecurityMonitoringSignalToIncidentError>,
110    > {
111        match self
112            .add_security_monitoring_signal_to_incident_with_http_info(signal_id, body)
113            .await
114        {
115            Ok(response_content) => {
116                if let Some(e) = response_content.entity {
117                    Ok(e)
118                } else {
119                    Err(datadog::Error::Serde(serde::de::Error::custom(
120                        "response content was None",
121                    )))
122                }
123            }
124            Err(err) => Err(err),
125        }
126    }
127
128    /// Add a security signal to an incident. This makes it possible to search for signals by incident within the signal explorer and to view the signals on the incident timeline.
129    pub async fn add_security_monitoring_signal_to_incident_with_http_info(
130        &self,
131        signal_id: String,
132        body: crate::datadogV1::model::AddSignalToIncidentRequest,
133    ) -> Result<
134        datadog::ResponseContent<crate::datadogV1::model::SuccessfulSignalUpdateResponse>,
135        datadog::Error<AddSecurityMonitoringSignalToIncidentError>,
136    > {
137        let local_configuration = &self.config;
138        let operation_id = "v1.add_security_monitoring_signal_to_incident";
139
140        let local_client = &self.client;
141
142        let local_uri_str = format!(
143            "{}/api/v1/security_analytics/signals/{signal_id}/add_to_incident",
144            local_configuration.get_operation_host(operation_id),
145            signal_id = datadog::urlencode(signal_id)
146        );
147        let mut local_req_builder =
148            local_client.request(reqwest::Method::PATCH, local_uri_str.as_str());
149
150        // build headers
151        let mut headers = HeaderMap::new();
152        headers.insert("Content-Type", HeaderValue::from_static("application/json"));
153        headers.insert("Accept", HeaderValue::from_static("application/json"));
154
155        // build user agent
156        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
157            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
158            Err(e) => {
159                log::warn!("Failed to parse user agent header: {e}, falling back to default");
160                headers.insert(
161                    reqwest::header::USER_AGENT,
162                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
163                )
164            }
165        };
166
167        // build auth
168        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
169            headers.insert(
170                "DD-API-KEY",
171                HeaderValue::from_str(local_key.key.as_str())
172                    .expect("failed to parse DD-API-KEY header"),
173            );
174        };
175        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
176            headers.insert(
177                "DD-APPLICATION-KEY",
178                HeaderValue::from_str(local_key.key.as_str())
179                    .expect("failed to parse DD-APPLICATION-KEY header"),
180            );
181        };
182
183        // build body parameters
184        let output = Vec::new();
185        let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
186        if body.serialize(&mut ser).is_ok() {
187            if let Some(content_encoding) = headers.get("Content-Encoding") {
188                match content_encoding.to_str().unwrap_or_default() {
189                    "gzip" => {
190                        let mut enc = GzEncoder::new(Vec::new(), Compression::default());
191                        let _ = enc.write_all(ser.into_inner().as_slice());
192                        match enc.finish() {
193                            Ok(buf) => {
194                                local_req_builder = local_req_builder.body(buf);
195                            }
196                            Err(e) => return Err(datadog::Error::Io(e)),
197                        }
198                    }
199                    "deflate" => {
200                        let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
201                        let _ = enc.write_all(ser.into_inner().as_slice());
202                        match enc.finish() {
203                            Ok(buf) => {
204                                local_req_builder = local_req_builder.body(buf);
205                            }
206                            Err(e) => return Err(datadog::Error::Io(e)),
207                        }
208                    }
209                    "zstd1" => {
210                        let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
211                        let _ = enc.write_all(ser.into_inner().as_slice());
212                        match enc.finish() {
213                            Ok(buf) => {
214                                local_req_builder = local_req_builder.body(buf);
215                            }
216                            Err(e) => return Err(datadog::Error::Io(e)),
217                        }
218                    }
219                    _ => {
220                        local_req_builder = local_req_builder.body(ser.into_inner());
221                    }
222                }
223            } else {
224                local_req_builder = local_req_builder.body(ser.into_inner());
225            }
226        }
227
228        local_req_builder = local_req_builder.headers(headers);
229        let local_req = local_req_builder.build()?;
230        log::debug!("request content: {:?}", local_req.body());
231        let local_resp = local_client.execute(local_req).await?;
232
233        let local_status = local_resp.status();
234        let local_content = local_resp.text().await?;
235        log::debug!("response content: {}", local_content);
236
237        if !local_status.is_client_error() && !local_status.is_server_error() {
238            match serde_json::from_str::<crate::datadogV1::model::SuccessfulSignalUpdateResponse>(
239                &local_content,
240            ) {
241                Ok(e) => {
242                    return Ok(datadog::ResponseContent {
243                        status: local_status,
244                        content: local_content,
245                        entity: Some(e),
246                    })
247                }
248                Err(e) => return Err(datadog::Error::Serde(e)),
249            };
250        } else {
251            let local_entity: Option<AddSecurityMonitoringSignalToIncidentError> =
252                serde_json::from_str(&local_content).ok();
253            let local_error = datadog::ResponseContent {
254                status: local_status,
255                content: local_content,
256                entity: local_entity,
257            };
258            Err(datadog::Error::ResponseError(local_error))
259        }
260    }
261
262    /// Modify the triage assignee of a security signal.
263    pub async fn edit_security_monitoring_signal_assignee(
264        &self,
265        signal_id: String,
266        body: crate::datadogV1::model::SignalAssigneeUpdateRequest,
267    ) -> Result<
268        crate::datadogV1::model::SuccessfulSignalUpdateResponse,
269        datadog::Error<EditSecurityMonitoringSignalAssigneeError>,
270    > {
271        match self
272            .edit_security_monitoring_signal_assignee_with_http_info(signal_id, body)
273            .await
274        {
275            Ok(response_content) => {
276                if let Some(e) = response_content.entity {
277                    Ok(e)
278                } else {
279                    Err(datadog::Error::Serde(serde::de::Error::custom(
280                        "response content was None",
281                    )))
282                }
283            }
284            Err(err) => Err(err),
285        }
286    }
287
288    /// Modify the triage assignee of a security signal.
289    pub async fn edit_security_monitoring_signal_assignee_with_http_info(
290        &self,
291        signal_id: String,
292        body: crate::datadogV1::model::SignalAssigneeUpdateRequest,
293    ) -> Result<
294        datadog::ResponseContent<crate::datadogV1::model::SuccessfulSignalUpdateResponse>,
295        datadog::Error<EditSecurityMonitoringSignalAssigneeError>,
296    > {
297        let local_configuration = &self.config;
298        let operation_id = "v1.edit_security_monitoring_signal_assignee";
299
300        let local_client = &self.client;
301
302        let local_uri_str = format!(
303            "{}/api/v1/security_analytics/signals/{signal_id}/assignee",
304            local_configuration.get_operation_host(operation_id),
305            signal_id = datadog::urlencode(signal_id)
306        );
307        let mut local_req_builder =
308            local_client.request(reqwest::Method::PATCH, local_uri_str.as_str());
309
310        // build headers
311        let mut headers = HeaderMap::new();
312        headers.insert("Content-Type", HeaderValue::from_static("application/json"));
313        headers.insert("Accept", HeaderValue::from_static("application/json"));
314
315        // build user agent
316        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
317            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
318            Err(e) => {
319                log::warn!("Failed to parse user agent header: {e}, falling back to default");
320                headers.insert(
321                    reqwest::header::USER_AGENT,
322                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
323                )
324            }
325        };
326
327        // build auth
328        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
329            headers.insert(
330                "DD-API-KEY",
331                HeaderValue::from_str(local_key.key.as_str())
332                    .expect("failed to parse DD-API-KEY header"),
333            );
334        };
335        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
336            headers.insert(
337                "DD-APPLICATION-KEY",
338                HeaderValue::from_str(local_key.key.as_str())
339                    .expect("failed to parse DD-APPLICATION-KEY header"),
340            );
341        };
342
343        // build body parameters
344        let output = Vec::new();
345        let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
346        if body.serialize(&mut ser).is_ok() {
347            if let Some(content_encoding) = headers.get("Content-Encoding") {
348                match content_encoding.to_str().unwrap_or_default() {
349                    "gzip" => {
350                        let mut enc = GzEncoder::new(Vec::new(), Compression::default());
351                        let _ = enc.write_all(ser.into_inner().as_slice());
352                        match enc.finish() {
353                            Ok(buf) => {
354                                local_req_builder = local_req_builder.body(buf);
355                            }
356                            Err(e) => return Err(datadog::Error::Io(e)),
357                        }
358                    }
359                    "deflate" => {
360                        let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
361                        let _ = enc.write_all(ser.into_inner().as_slice());
362                        match enc.finish() {
363                            Ok(buf) => {
364                                local_req_builder = local_req_builder.body(buf);
365                            }
366                            Err(e) => return Err(datadog::Error::Io(e)),
367                        }
368                    }
369                    "zstd1" => {
370                        let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
371                        let _ = enc.write_all(ser.into_inner().as_slice());
372                        match enc.finish() {
373                            Ok(buf) => {
374                                local_req_builder = local_req_builder.body(buf);
375                            }
376                            Err(e) => return Err(datadog::Error::Io(e)),
377                        }
378                    }
379                    _ => {
380                        local_req_builder = local_req_builder.body(ser.into_inner());
381                    }
382                }
383            } else {
384                local_req_builder = local_req_builder.body(ser.into_inner());
385            }
386        }
387
388        local_req_builder = local_req_builder.headers(headers);
389        let local_req = local_req_builder.build()?;
390        log::debug!("request content: {:?}", local_req.body());
391        let local_resp = local_client.execute(local_req).await?;
392
393        let local_status = local_resp.status();
394        let local_content = local_resp.text().await?;
395        log::debug!("response content: {}", local_content);
396
397        if !local_status.is_client_error() && !local_status.is_server_error() {
398            match serde_json::from_str::<crate::datadogV1::model::SuccessfulSignalUpdateResponse>(
399                &local_content,
400            ) {
401                Ok(e) => {
402                    return Ok(datadog::ResponseContent {
403                        status: local_status,
404                        content: local_content,
405                        entity: Some(e),
406                    })
407                }
408                Err(e) => return Err(datadog::Error::Serde(e)),
409            };
410        } else {
411            let local_entity: Option<EditSecurityMonitoringSignalAssigneeError> =
412                serde_json::from_str(&local_content).ok();
413            let local_error = datadog::ResponseContent {
414                status: local_status,
415                content: local_content,
416                entity: local_entity,
417            };
418            Err(datadog::Error::ResponseError(local_error))
419        }
420    }
421
422    /// Change the triage state of a security signal.
423    pub async fn edit_security_monitoring_signal_state(
424        &self,
425        signal_id: String,
426        body: crate::datadogV1::model::SignalStateUpdateRequest,
427    ) -> Result<
428        crate::datadogV1::model::SuccessfulSignalUpdateResponse,
429        datadog::Error<EditSecurityMonitoringSignalStateError>,
430    > {
431        match self
432            .edit_security_monitoring_signal_state_with_http_info(signal_id, body)
433            .await
434        {
435            Ok(response_content) => {
436                if let Some(e) = response_content.entity {
437                    Ok(e)
438                } else {
439                    Err(datadog::Error::Serde(serde::de::Error::custom(
440                        "response content was None",
441                    )))
442                }
443            }
444            Err(err) => Err(err),
445        }
446    }
447
448    /// Change the triage state of a security signal.
449    pub async fn edit_security_monitoring_signal_state_with_http_info(
450        &self,
451        signal_id: String,
452        body: crate::datadogV1::model::SignalStateUpdateRequest,
453    ) -> Result<
454        datadog::ResponseContent<crate::datadogV1::model::SuccessfulSignalUpdateResponse>,
455        datadog::Error<EditSecurityMonitoringSignalStateError>,
456    > {
457        let local_configuration = &self.config;
458        let operation_id = "v1.edit_security_monitoring_signal_state";
459
460        let local_client = &self.client;
461
462        let local_uri_str = format!(
463            "{}/api/v1/security_analytics/signals/{signal_id}/state",
464            local_configuration.get_operation_host(operation_id),
465            signal_id = datadog::urlencode(signal_id)
466        );
467        let mut local_req_builder =
468            local_client.request(reqwest::Method::PATCH, local_uri_str.as_str());
469
470        // build headers
471        let mut headers = HeaderMap::new();
472        headers.insert("Content-Type", HeaderValue::from_static("application/json"));
473        headers.insert("Accept", HeaderValue::from_static("application/json"));
474
475        // build user agent
476        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
477            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
478            Err(e) => {
479                log::warn!("Failed to parse user agent header: {e}, falling back to default");
480                headers.insert(
481                    reqwest::header::USER_AGENT,
482                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
483                )
484            }
485        };
486
487        // build auth
488        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
489            headers.insert(
490                "DD-API-KEY",
491                HeaderValue::from_str(local_key.key.as_str())
492                    .expect("failed to parse DD-API-KEY header"),
493            );
494        };
495        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
496            headers.insert(
497                "DD-APPLICATION-KEY",
498                HeaderValue::from_str(local_key.key.as_str())
499                    .expect("failed to parse DD-APPLICATION-KEY header"),
500            );
501        };
502
503        // build body parameters
504        let output = Vec::new();
505        let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
506        if body.serialize(&mut ser).is_ok() {
507            if let Some(content_encoding) = headers.get("Content-Encoding") {
508                match content_encoding.to_str().unwrap_or_default() {
509                    "gzip" => {
510                        let mut enc = GzEncoder::new(Vec::new(), Compression::default());
511                        let _ = enc.write_all(ser.into_inner().as_slice());
512                        match enc.finish() {
513                            Ok(buf) => {
514                                local_req_builder = local_req_builder.body(buf);
515                            }
516                            Err(e) => return Err(datadog::Error::Io(e)),
517                        }
518                    }
519                    "deflate" => {
520                        let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
521                        let _ = enc.write_all(ser.into_inner().as_slice());
522                        match enc.finish() {
523                            Ok(buf) => {
524                                local_req_builder = local_req_builder.body(buf);
525                            }
526                            Err(e) => return Err(datadog::Error::Io(e)),
527                        }
528                    }
529                    "zstd1" => {
530                        let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
531                        let _ = enc.write_all(ser.into_inner().as_slice());
532                        match enc.finish() {
533                            Ok(buf) => {
534                                local_req_builder = local_req_builder.body(buf);
535                            }
536                            Err(e) => return Err(datadog::Error::Io(e)),
537                        }
538                    }
539                    _ => {
540                        local_req_builder = local_req_builder.body(ser.into_inner());
541                    }
542                }
543            } else {
544                local_req_builder = local_req_builder.body(ser.into_inner());
545            }
546        }
547
548        local_req_builder = local_req_builder.headers(headers);
549        let local_req = local_req_builder.build()?;
550        log::debug!("request content: {:?}", local_req.body());
551        let local_resp = local_client.execute(local_req).await?;
552
553        let local_status = local_resp.status();
554        let local_content = local_resp.text().await?;
555        log::debug!("response content: {}", local_content);
556
557        if !local_status.is_client_error() && !local_status.is_server_error() {
558            match serde_json::from_str::<crate::datadogV1::model::SuccessfulSignalUpdateResponse>(
559                &local_content,
560            ) {
561                Ok(e) => {
562                    return Ok(datadog::ResponseContent {
563                        status: local_status,
564                        content: local_content,
565                        entity: Some(e),
566                    })
567                }
568                Err(e) => return Err(datadog::Error::Serde(e)),
569            };
570        } else {
571            let local_entity: Option<EditSecurityMonitoringSignalStateError> =
572                serde_json::from_str(&local_content).ok();
573            let local_error = datadog::ResponseContent {
574                status: local_status,
575                content: local_content,
576                entity: local_entity,
577            };
578            Err(datadog::Error::ResponseError(local_error))
579        }
580    }
581}