Skip to content

Commit c2c7f62

Browse files
authored
Merge pull request #765 from DataDog/julien/K9VULN-3522
Show error warning to the user when having authentication issues
2 parents cb7b3c0 + 2f888fb commit c2c7f62

File tree

3 files changed

+53
-13
lines changed

3 files changed

+53
-13
lines changed

crates/cli/src/config_file.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::constants;
2+
use crate::datadog_utils::DatadogApiError::InvalidPermission;
23
use crate::datadog_utils::{get_remote_configuration, should_use_datadog_backend};
34
use crate::git_utils::get_repository_url;
45
use anyhow::{anyhow, Context, Result};
@@ -125,9 +126,19 @@ pub fn get_config(path: &str, debug: bool) -> Result<Option<(ConfigFile, ConfigM
125126
}
126127
}
127128
Err(e) => {
128-
if debug {
129-
eprintln!("Error when attempting to fetch the remote config: {:?}", e);
130-
eprintln!("Falling back to the local configuration, if any")
129+
match e {
130+
InvalidPermission => {
131+
crate::datadog_utils::print_permission_warning("GET_CONFIG")
132+
}
133+
_ => {
134+
if debug {
135+
eprintln!(
136+
"Error when attempting to fetch the remote config: {:?}",
137+
e
138+
);
139+
eprintln!("Falling back to the local configuration, if any")
140+
}
141+
}
131142
}
132143
cf.map(|c| (c, ConfigMethod::File))
133144
}

crates/cli/src/datadog_utils.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use std::env;
22

33
use crate::datadog_utils::DatadogApiError::{
4-
CouldNotParseJson, CouldNotParseResponse, CouldNotQuery, ErrorResponse, MissingVariable,
5-
RulesetNotFound,
4+
CouldNotParseJson, CouldNotParseResponse, CouldNotQuery, ErrorResponse, InvalidPermission,
5+
MissingVariable, RulesetNotFound,
66
};
77
use crate::model::datadog_api::{
8-
ApiResponseDefaultRuleset, ConfigRequest, ConfigRequestData, ConfigRequestDataAttributes,
9-
ConfigResponse, DiffAwareData, DiffAwareRequest, DiffAwareRequestArguments,
10-
DiffAwareRequestData, DiffAwareRequestDataAttributes, DiffAwareResponse,
11-
StaticAnalysisRulesAPIResponse, StaticAnalysisSecretsAPIResponse,
8+
APIErrorResponseUnauthorized, ApiResponseDefaultRuleset, ConfigRequest, ConfigRequestData,
9+
ConfigRequestDataAttributes, ConfigResponse, DiffAwareData, DiffAwareRequest,
10+
DiffAwareRequestArguments, DiffAwareRequestData, DiffAwareRequestDataAttributes,
11+
DiffAwareResponse, StaticAnalysisRulesAPIResponse, StaticAnalysisSecretsAPIResponse,
1212
};
1313
use crate::{
1414
constants::{
@@ -55,6 +55,8 @@ pub enum DatadogApiError {
5555
CouldNotParseResponse(#[source] reqwest::Error),
5656
#[error("JSON parsing error: {0}")]
5757
CouldNotParseJson(#[source] serde_json::Error),
58+
#[error("Not Authorized")]
59+
InvalidPermission,
5860
}
5961

6062
pub type Result<T> = std::result::Result<T, DatadogApiError>;
@@ -202,11 +204,31 @@ where
202204
T: serde::de::DeserializeOwned,
203205
{
204206
let status_code = server_response.status();
207+
208+
if status_code.as_u16() == 403 {
209+
return Err(InvalidPermission);
210+
}
211+
205212
let response_text = &server_response.text().map_err(CouldNotParseResponse)?;
206213

207214
if !status_code.is_success() {
215+
// First, check if we have an error with just a list of strings
216+
let error_unauthorized_res =
217+
serde_json::from_str::<APIErrorResponseUnauthorized>(response_text);
218+
if let Ok(error_unauthorized) = error_unauthorized_res {
219+
if error_unauthorized
220+
.errors
221+
.iter()
222+
.any(|e| e == "Unauthorized")
223+
{
224+
return Err(InvalidPermission);
225+
}
226+
}
227+
228+
// Then, look for other types of errors
208229
let error =
209230
serde_json::from_str::<APIErrorResponse>(response_text).map_err(CouldNotParseJson)?;
231+
210232
let error_msg = error.errors.into_iter().next().map_or_else(
211233
|| "Unknown error".to_string(),
212234
|e| e.detail.unwrap_or(e.title),
@@ -217,6 +239,10 @@ where
217239
serde_json::from_str::<T>(response_text).map_err(CouldNotParseJson)
218240
}
219241

242+
pub(crate) fn print_permission_warning(header: &str) {
243+
eprintln!("[{header}] Error when connecting to Datadog services, make sure your DD_API_KEY, DD_APP_KEY and DD_SITE variables are correct. See https://docs.datadoghq.com/security/code_security/static_analysis/generic_ci_providers/ for more information.")
244+
}
245+
220246
// get rules from one ruleset at datadog
221247
// it connects to the API using the DD_SITE, DD_APP_KEY and DD_API_KEY and retrieve
222248
// the rulesets. We then extract all the rulesets
@@ -315,7 +341,7 @@ pub fn get_diff_aware_information(
315341
})
316342
}
317343

318-
/// Get remote configuration from the Databdog backend
344+
/// Get remote configuration from the Datadog backend
319345
pub fn get_remote_configuration(
320346
repository_url: String,
321347
config_base64: Option<String>,
@@ -334,9 +360,7 @@ pub fn get_remote_configuration(
334360
let path = "config/client";
335361
let req = make_request(RequestMethod::Post, path, false, true)?.json(&request_payload);
336362
let server_response = perform_request(req, path, debug)?;
337-
parse_response(server_response)
338-
.inspect_err(|e| eprintln!("Error when issuing the config request {:?}", e))
339-
.map(|d: ConfigResponse| d.data.attributes.config_base64)
363+
parse_response(server_response).map(|d: ConfigResponse| d.data.attributes.config_base64)
340364
}
341365

342366
#[cfg(test)]

crates/cli/src/model/datadog_api.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,11 @@ pub struct APIErrorResponse {
414414
pub errors: Vec<APIError>,
415415
}
416416

417+
#[derive(Deserialize)]
418+
pub struct APIErrorResponseUnauthorized {
419+
pub errors: Vec<String>,
420+
}
421+
417422
#[derive(Deserialize)]
418423
pub struct APIError {
419424
pub title: String,

0 commit comments

Comments
 (0)