fix: avoid leaking details on dbg print (#678)

Ticket: ENG-1156
This commit is contained in:
BenjaminCh
2022-03-31 18:04:17 +02:00
committed by GitHub
parent fd1889ce5e
commit 8ea79a0efc
5 changed files with 95 additions and 4 deletions

12
Cargo.lock generated
View File

@@ -493,6 +493,17 @@ version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2 1.0.28",
"quote 1.0.9",
"syn 1.0.74",
]
[[package]] [[package]]
name = "deunicode" name = "deunicode"
version = "0.4.3" version = "0.4.3"
@@ -2076,6 +2087,7 @@ dependencies = [
"base64 0.13.0", "base64 0.13.0",
"chrono", "chrono",
"cmd_lib", "cmd_lib",
"derivative",
"digitalocean", "digitalocean",
"dirs", "dirs",
"flate2", "flate2",

View File

@@ -9,6 +9,7 @@ edition = "2018"
[dependencies] [dependencies]
chrono = "0.4.19" chrono = "0.4.19"
cmd_lib = "1.0.13" cmd_lib = "1.0.13"
derivative = "2.2.0"
git2 = "0.14.2" git2 = "0.14.2"
walkdir = "2.3.2" walkdir = "2.3.2"
itertools = "0.10.0" itertools = "0.10.0"

View File

@@ -1004,13 +1004,13 @@ where
service.progress_scope(), service.progress_scope(),
ProgressLevel::Error, ProgressLevel::Error,
Some(format!( Some(format!(
"{} error {} {} : error => {}", "{} error {} {} : error => {:?}",
action_verb, action_verb,
service.service_type().name().to_lowercase(), service.service_type().name().to_lowercase(),
service.name(), service.name(),
// Note: env vars are not leaked to legacy listeners since it can holds sensitive data // Note: env vars are not leaked to legacy listeners since it can holds sensitive data
// such as secrets and such. // such as secrets and such.
err.message(ErrorMessageVerbosity::FullDetailsWithoutEnvVars) err
)), )),
kubernetes.context().execution_id(), kubernetes.context().execution_id(),
); );

View File

@@ -1,5 +1,6 @@
pub mod io; pub mod io;
extern crate derivative;
extern crate url; extern crate url;
use crate::build_platform::BuildError; use crate::build_platform::BuildError;
@@ -12,6 +13,7 @@ use crate::events::{EventDetails, GeneralStep, Stage, Transmitter};
use crate::io_models::QoveryIdentifier; use crate::io_models::QoveryIdentifier;
use crate::models::types::VersionsNumber; use crate::models::types::VersionsNumber;
use crate::object_storage::errors::ObjectStorageError; use crate::object_storage::errors::ObjectStorageError;
use derivative::Derivative;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
@@ -24,13 +26,16 @@ pub enum ErrorMessageVerbosity {
} }
/// CommandError: command error, mostly returned by third party tools. /// CommandError: command error, mostly returned by third party tools.
#[derive(Clone, Debug, Error, PartialEq)] #[derive(Derivative, Clone, Error, PartialEq)]
#[derivative(Debug)]
pub struct CommandError { pub struct CommandError {
/// full_details: full error message, can contains unsafe text such as passwords and tokens. /// full_details: full error message, can contains unsafe text such as passwords and tokens.
full_details: String, full_details: String,
/// message_safe: error message omitting displaying any protected data such as passwords and tokens. /// message_safe: error message omitting displaying any protected data such as passwords and tokens.
message_safe: Option<String>, message_safe: Option<String>,
/// env_vars: environments variables including touchy data such as secret keys. /// env_vars: environments variables including touchy data such as secret keys.
/// env_vars field is ignored from any wild Debug printing because of it touchy data it carries.
#[derivative(Debug = "ignore")]
env_vars: Option<Vec<(String, String)>>, env_vars: Option<Vec<(String, String)>>,
} }
@@ -2977,4 +2982,55 @@ mod tests {
assert!(!res.contains("my_secret")); assert!(!res.contains("my_secret"));
assert!(!res.contains("my_secret_value")); assert!(!res.contains("my_secret_value"));
} }
#[test]
fn test_command_error_test_hidding_env_vars_in_debug() {
// setup:
let command_err = CommandError::new_with_env_vars(
"my raw message".to_string(),
Some("my safe message".to_string()),
Some(vec![("my_secret".to_string(), "my_secret_value".to_string())]),
);
// execute:
let res = format!("{:?}", command_err);
// verify:
assert!(!res.contains("my_secret"));
assert!(!res.contains("my_secret_value"));
}
#[test]
fn test_engine_error_test_hidding_env_vars_in_debug() {
// setup:
let command_err = CommandError::new_with_env_vars(
"my raw message".to_string(),
Some("my safe message".to_string()),
Some(vec![("my_secret".to_string(), "my_secret_value".to_string())]),
);
let cluster_id = QoveryIdentifier::new_random();
let engine_err = EngineError::new_unknown(
EventDetails::new(
Some(Kind::Scw),
QoveryIdentifier::new_random(),
QoveryIdentifier::new_random(),
QoveryIdentifier::new_random(),
Some(ScwRegion::Paris.as_str().to_string()),
Stage::Infrastructure(InfrastructureStep::Create),
Transmitter::Kubernetes(cluster_id.to_string(), cluster_id.to_string()),
),
"qovery_log_message".to_string(),
"user_log_message".to_string(),
Some(command_err.clone()),
None,
None,
);
// execute:
let res = format!("{:?}", engine_err);
// verify:
assert!(!res.contains("my_secret"));
assert!(!res.contains("my_secret_value"));
}
} }

View File

@@ -4,11 +4,13 @@
pub mod io; pub mod io;
extern crate derivative;
extern crate url; extern crate url;
use crate::cloud_provider::Kind; use crate::cloud_provider::Kind;
use crate::errors::{CommandError, EngineError, ErrorMessageVerbosity}; use crate::errors::{CommandError, EngineError, ErrorMessageVerbosity};
use crate::io_models::QoveryIdentifier; use crate::io_models::QoveryIdentifier;
use derivative::Derivative;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -63,7 +65,8 @@ impl From<EventMessageVerbosity> for ErrorMessageVerbosity {
} }
} }
#[derive(Debug, Clone)] #[derive(Derivative, Clone)]
#[derivative(Debug)]
/// EventMessage: represents an event message. /// EventMessage: represents an event message.
pub struct EventMessage { pub struct EventMessage {
// Message which is known to be safe: doesn't expose any credentials nor touchy info. // Message which is known to be safe: doesn't expose any credentials nor touchy info.
@@ -71,6 +74,8 @@ pub struct EventMessage {
// String containing full details including touchy data (passwords and tokens). // String containing full details including touchy data (passwords and tokens).
full_details: Option<String>, full_details: Option<String>,
// Environments variables including touchy data such as secret keys. // Environments variables including touchy data such as secret keys.
// env_vars field is ignored from any wild Debug printing because of it touchy data it carries.
#[derivative(Debug = "ignore")]
env_vars: Option<Vec<(String, String)>>, env_vars: Option<Vec<(String, String)>>,
} }
@@ -612,4 +617,21 @@ mod tests {
assert!(!res.contains("my_secret")); assert!(!res.contains("my_secret"));
assert!(!res.contains("my_secret_value")); assert!(!res.contains("my_secret_value"));
} }
#[test]
fn test_event_message_test_hidding_env_vars_in_debug() {
// setup:
let event_message = EventMessage::new_with_env_vars(
"my safe message".to_string(),
Some("my full message".to_string()),
Some(vec![("my_secret".to_string(), "my_secret_value".to_string())]),
);
// execute:
let res = format!("{:?}", event_message);
// verify:
assert!(!res.contains("my_secret"));
assert!(!res.contains("my_secret_value"));
}
} }