datadog_api_client/datadogV2/api/
api_static_analysis.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 log::warn;
10use reqwest::header::{HeaderMap, HeaderValue};
11use serde::{Deserialize, Serialize};
12use std::io::Write;
13
14/// CreateSCAResolveVulnerableSymbolsError is a struct for typed errors of method [`StaticAnalysisAPI::create_sca_resolve_vulnerable_symbols`]
15#[derive(Debug, Clone, Serialize, Deserialize)]
16#[serde(untagged)]
17pub enum CreateSCAResolveVulnerableSymbolsError {
18    APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
19    UnknownValue(serde_json::Value),
20}
21
22/// CreateSCAResultError is a struct for typed errors of method [`StaticAnalysisAPI::create_sca_result`]
23#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(untagged)]
25pub enum CreateSCAResultError {
26    APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
27    UnknownValue(serde_json::Value),
28}
29
30/// API for static analysis
31#[derive(Debug, Clone)]
32pub struct StaticAnalysisAPI {
33    config: datadog::Configuration,
34    client: reqwest_middleware::ClientWithMiddleware,
35}
36
37impl Default for StaticAnalysisAPI {
38    fn default() -> Self {
39        Self::with_config(datadog::Configuration::default())
40    }
41}
42
43impl StaticAnalysisAPI {
44    pub fn new() -> Self {
45        Self::default()
46    }
47    pub fn with_config(config: datadog::Configuration) -> Self {
48        let mut reqwest_client_builder = reqwest::Client::builder();
49
50        if let Some(proxy_url) = &config.proxy_url {
51            let proxy = reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL");
52            reqwest_client_builder = reqwest_client_builder.proxy(proxy);
53        }
54
55        let mut middleware_client_builder =
56            reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap());
57
58        if config.enable_retry {
59            struct RetryableStatus;
60            impl reqwest_retry::RetryableStrategy for RetryableStatus {
61                fn handle(
62                    &self,
63                    res: &Result<reqwest::Response, reqwest_middleware::Error>,
64                ) -> Option<reqwest_retry::Retryable> {
65                    match res {
66                        Ok(success) => reqwest_retry::default_on_request_success(success),
67                        Err(_) => None,
68                    }
69                }
70            }
71            let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder()
72                .build_with_max_retries(config.max_retries);
73
74            let retry_middleware =
75                reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy(
76                    backoff_policy,
77                    RetryableStatus,
78                );
79
80            middleware_client_builder = middleware_client_builder.with(retry_middleware);
81        }
82
83        let client = middleware_client_builder.build();
84
85        Self { config, client }
86    }
87
88    pub fn with_client_and_config(
89        config: datadog::Configuration,
90        client: reqwest_middleware::ClientWithMiddleware,
91    ) -> Self {
92        Self { config, client }
93    }
94
95    pub async fn create_sca_resolve_vulnerable_symbols(
96        &self,
97        body: crate::datadogV2::model::ResolveVulnerableSymbolsRequest,
98    ) -> Result<
99        crate::datadogV2::model::ResolveVulnerableSymbolsResponse,
100        datadog::Error<CreateSCAResolveVulnerableSymbolsError>,
101    > {
102        match self
103            .create_sca_resolve_vulnerable_symbols_with_http_info(body)
104            .await
105        {
106            Ok(response_content) => {
107                if let Some(e) = response_content.entity {
108                    Ok(e)
109                } else {
110                    Err(datadog::Error::Serde(serde::de::Error::custom(
111                        "response content was None",
112                    )))
113                }
114            }
115            Err(err) => Err(err),
116        }
117    }
118
119    pub async fn create_sca_resolve_vulnerable_symbols_with_http_info(
120        &self,
121        body: crate::datadogV2::model::ResolveVulnerableSymbolsRequest,
122    ) -> Result<
123        datadog::ResponseContent<crate::datadogV2::model::ResolveVulnerableSymbolsResponse>,
124        datadog::Error<CreateSCAResolveVulnerableSymbolsError>,
125    > {
126        let local_configuration = &self.config;
127        let operation_id = "v2.create_sca_resolve_vulnerable_symbols";
128        if local_configuration.is_unstable_operation_enabled(operation_id) {
129            warn!("Using unstable operation {operation_id}");
130        } else {
131            let local_error = datadog::UnstableOperationDisabledError {
132                msg: "Operation 'v2.create_sca_resolve_vulnerable_symbols' is not enabled"
133                    .to_string(),
134            };
135            return Err(datadog::Error::UnstableOperationDisabledError(local_error));
136        }
137
138        let local_client = &self.client;
139
140        let local_uri_str = format!(
141            "{}/api/v2/static-analysis-sca/vulnerabilities/resolve-vulnerable-symbols",
142            local_configuration.get_operation_host(operation_id)
143        );
144        let mut local_req_builder =
145            local_client.request(reqwest::Method::POST, local_uri_str.as_str());
146
147        // build headers
148        let mut headers = HeaderMap::new();
149        headers.insert("Content-Type", HeaderValue::from_static("application/json"));
150        headers.insert("Accept", HeaderValue::from_static("application/json"));
151
152        // build user agent
153        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
154            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
155            Err(e) => {
156                log::warn!("Failed to parse user agent header: {e}, falling back to default");
157                headers.insert(
158                    reqwest::header::USER_AGENT,
159                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
160                )
161            }
162        };
163
164        // build auth
165        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
166            headers.insert(
167                "DD-API-KEY",
168                HeaderValue::from_str(local_key.key.as_str())
169                    .expect("failed to parse DD-API-KEY header"),
170            );
171        };
172        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
173            headers.insert(
174                "DD-APPLICATION-KEY",
175                HeaderValue::from_str(local_key.key.as_str())
176                    .expect("failed to parse DD-APPLICATION-KEY header"),
177            );
178        };
179
180        // build body parameters
181        let output = Vec::new();
182        let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
183        if body.serialize(&mut ser).is_ok() {
184            if let Some(content_encoding) = headers.get("Content-Encoding") {
185                match content_encoding.to_str().unwrap_or_default() {
186                    "gzip" => {
187                        let mut enc = GzEncoder::new(Vec::new(), Compression::default());
188                        let _ = enc.write_all(ser.into_inner().as_slice());
189                        match enc.finish() {
190                            Ok(buf) => {
191                                local_req_builder = local_req_builder.body(buf);
192                            }
193                            Err(e) => return Err(datadog::Error::Io(e)),
194                        }
195                    }
196                    "deflate" => {
197                        let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
198                        let _ = enc.write_all(ser.into_inner().as_slice());
199                        match enc.finish() {
200                            Ok(buf) => {
201                                local_req_builder = local_req_builder.body(buf);
202                            }
203                            Err(e) => return Err(datadog::Error::Io(e)),
204                        }
205                    }
206                    "zstd1" => {
207                        let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
208                        let _ = enc.write_all(ser.into_inner().as_slice());
209                        match enc.finish() {
210                            Ok(buf) => {
211                                local_req_builder = local_req_builder.body(buf);
212                            }
213                            Err(e) => return Err(datadog::Error::Io(e)),
214                        }
215                    }
216                    _ => {
217                        local_req_builder = local_req_builder.body(ser.into_inner());
218                    }
219                }
220            } else {
221                local_req_builder = local_req_builder.body(ser.into_inner());
222            }
223        }
224
225        local_req_builder = local_req_builder.headers(headers);
226        let local_req = local_req_builder.build()?;
227        log::debug!("request content: {:?}", local_req.body());
228        let local_resp = local_client.execute(local_req).await?;
229
230        let local_status = local_resp.status();
231        let local_content = local_resp.text().await?;
232        log::debug!("response content: {}", local_content);
233
234        if !local_status.is_client_error() && !local_status.is_server_error() {
235            match serde_json::from_str::<crate::datadogV2::model::ResolveVulnerableSymbolsResponse>(
236                &local_content,
237            ) {
238                Ok(e) => {
239                    return Ok(datadog::ResponseContent {
240                        status: local_status,
241                        content: local_content,
242                        entity: Some(e),
243                    })
244                }
245                Err(e) => return Err(datadog::Error::Serde(e)),
246            };
247        } else {
248            let local_entity: Option<CreateSCAResolveVulnerableSymbolsError> =
249                serde_json::from_str(&local_content).ok();
250            let local_error = datadog::ResponseContent {
251                status: local_status,
252                content: local_content,
253                entity: local_entity,
254            };
255            Err(datadog::Error::ResponseError(local_error))
256        }
257    }
258
259    pub async fn create_sca_result(
260        &self,
261        body: crate::datadogV2::model::ScaRequest,
262    ) -> Result<(), datadog::Error<CreateSCAResultError>> {
263        match self.create_sca_result_with_http_info(body).await {
264            Ok(_) => Ok(()),
265            Err(err) => Err(err),
266        }
267    }
268
269    pub async fn create_sca_result_with_http_info(
270        &self,
271        body: crate::datadogV2::model::ScaRequest,
272    ) -> Result<datadog::ResponseContent<()>, datadog::Error<CreateSCAResultError>> {
273        let local_configuration = &self.config;
274        let operation_id = "v2.create_sca_result";
275        if local_configuration.is_unstable_operation_enabled(operation_id) {
276            warn!("Using unstable operation {operation_id}");
277        } else {
278            let local_error = datadog::UnstableOperationDisabledError {
279                msg: "Operation 'v2.create_sca_result' is not enabled".to_string(),
280            };
281            return Err(datadog::Error::UnstableOperationDisabledError(local_error));
282        }
283
284        let local_client = &self.client;
285
286        let local_uri_str = format!(
287            "{}/api/v2/static-analysis-sca/dependencies",
288            local_configuration.get_operation_host(operation_id)
289        );
290        let mut local_req_builder =
291            local_client.request(reqwest::Method::POST, local_uri_str.as_str());
292
293        // build headers
294        let mut headers = HeaderMap::new();
295        headers.insert("Content-Type", HeaderValue::from_static("application/json"));
296        headers.insert("Accept", HeaderValue::from_static("*/*"));
297
298        // build user agent
299        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
300            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
301            Err(e) => {
302                log::warn!("Failed to parse user agent header: {e}, falling back to default");
303                headers.insert(
304                    reqwest::header::USER_AGENT,
305                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
306                )
307            }
308        };
309
310        // build auth
311        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
312            headers.insert(
313                "DD-API-KEY",
314                HeaderValue::from_str(local_key.key.as_str())
315                    .expect("failed to parse DD-API-KEY header"),
316            );
317        };
318        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
319            headers.insert(
320                "DD-APPLICATION-KEY",
321                HeaderValue::from_str(local_key.key.as_str())
322                    .expect("failed to parse DD-APPLICATION-KEY header"),
323            );
324        };
325
326        // build body parameters
327        let output = Vec::new();
328        let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
329        if body.serialize(&mut ser).is_ok() {
330            if let Some(content_encoding) = headers.get("Content-Encoding") {
331                match content_encoding.to_str().unwrap_or_default() {
332                    "gzip" => {
333                        let mut enc = GzEncoder::new(Vec::new(), Compression::default());
334                        let _ = enc.write_all(ser.into_inner().as_slice());
335                        match enc.finish() {
336                            Ok(buf) => {
337                                local_req_builder = local_req_builder.body(buf);
338                            }
339                            Err(e) => return Err(datadog::Error::Io(e)),
340                        }
341                    }
342                    "deflate" => {
343                        let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
344                        let _ = enc.write_all(ser.into_inner().as_slice());
345                        match enc.finish() {
346                            Ok(buf) => {
347                                local_req_builder = local_req_builder.body(buf);
348                            }
349                            Err(e) => return Err(datadog::Error::Io(e)),
350                        }
351                    }
352                    "zstd1" => {
353                        let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
354                        let _ = enc.write_all(ser.into_inner().as_slice());
355                        match enc.finish() {
356                            Ok(buf) => {
357                                local_req_builder = local_req_builder.body(buf);
358                            }
359                            Err(e) => return Err(datadog::Error::Io(e)),
360                        }
361                    }
362                    _ => {
363                        local_req_builder = local_req_builder.body(ser.into_inner());
364                    }
365                }
366            } else {
367                local_req_builder = local_req_builder.body(ser.into_inner());
368            }
369        }
370
371        local_req_builder = local_req_builder.headers(headers);
372        let local_req = local_req_builder.build()?;
373        log::debug!("request content: {:?}", local_req.body());
374        let local_resp = local_client.execute(local_req).await?;
375
376        let local_status = local_resp.status();
377        let local_content = local_resp.text().await?;
378        log::debug!("response content: {}", local_content);
379
380        if !local_status.is_client_error() && !local_status.is_server_error() {
381            Ok(datadog::ResponseContent {
382                status: local_status,
383                content: local_content,
384                entity: None,
385            })
386        } else {
387            let local_entity: Option<CreateSCAResultError> =
388                serde_json::from_str(&local_content).ok();
389            let local_error = datadog::ResponseContent {
390                status: local_status,
391                content: local_content,
392                entity: local_entity,
393            };
394            Err(datadog::Error::ResponseError(local_error))
395        }
396    }
397}