Repository: tikv/tikv
File: components/security/src/lib.rs (Rust)

Code before:
    CertificateRequestType, Channel, ChannelBuilder, ChannelCredentialsBuilder, CheckResult,
    RpcContext, RpcStatus, RpcStatusCode, ServerBuilder, ServerChecker, ServerCredentialsBuilder,
    ServerCredentialsFetcher,
};
use log_wrappers::RedactOption;
use online_config::{ConfigChange, ConfigManager, OnlineConfig, Result as CfgResult};
use tikv_util::info;

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default, OnlineConfig)]
#[serde(default)]
#[serde(rename_all = "kebab-case")]
pub struct SecurityConfig {
    // SSL configs.
    #[online_config(skip)]
    pub ca_path: String,
    #[online_config(skip)]
    pub cert_path: String,
    #[online_config(skip)]
    pub key_path: String,
    // Test purpose only.
    #[serde(skip)]
    #[online_config(skip)]
    pub override_ssl_target: String,
    #[online_config(skip)]
    pub cert_allowed_cn: HashSet<String>,
    pub redact_info_log: String,
    #[online_config(skip)]
    pub encryption: EncryptionConfig,
}

/// Checks and opens key file. Returns `Ok(None)` if the path is empty.
///
///  # Arguments
///
///  - `tag`: only used in the error message, like "ca key", "cert key",
///    "private key", etc.
fn check_key_file(tag: &str, path: &str) -> Result<Option<File>, Box<dyn Error>> {
    if path.is_empty() {
        return Ok(None);
    }
    match File::open(path) {
        Err(e) => Err(format!("failed to open {} to load {}: {:?}", path, tag, e).into()),
        Ok(f) => Ok(Some(f)),
    }
}

/// Loads key file content. Returns `Ok(vec![])` if the path is empty.
fn load_key(tag: &str, path: &str) -> Result<Vec<u8>, Box<dyn Error>> {
    let mut key = vec![];
    let f = check_key_file(tag, path)?;
    match f {

Review comment (bug):
legit unit test error:

```
thread 'config::tests::test_compatibility_with_old_config_template' panicked at src/config/mod.rs:7220:70:

called `Result::unwrap()` on an `Err` value: Error { inner: ErrorInner { kind: Custom, line: Some(1233), col: 19, at: Some(51640), message: "invalid type: boolean `false`, expected a string", key: ["security", "redact-info-log"] } }
```

This change failed the `test_compatibility_with_old_config_template` test --- existing config which used `redact-info-log = false` will no longer work after this PR.

It must be changed from `String` to something that is compatible with all of `true`, `false` and `"marker"`. Maybe change this to `redact_info_log: RedactOption` and implement additional traits on that type?

Code after:
    CertificateRequestType, Channel, ChannelBuilder, ChannelCredentialsBuilder, CheckResult,
    RpcContext, RpcStatus, RpcStatusCode, ServerBuilder, ServerChecker, ServerCredentialsBuilder,
    ServerCredentialsFetcher,
};
use log_wrappers::RedactOption;
use online_config::{ConfigChange, ConfigManager, OnlineConfig, Result as CfgResult};
use tikv_util::info;

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default, OnlineConfig)]
#[serde(default)]
#[serde(rename_all = "kebab-case")]
pub struct SecurityConfig {
    // SSL configs.
    #[online_config(skip)]
    pub ca_path: String,
    #[online_config(skip)]
    pub cert_path: String,
    #[online_config(skip)]
    pub key_path: String,
    // Test purpose only.
    #[serde(skip)]
    #[online_config(skip)]
    pub override_ssl_target: String,
    #[online_config(skip)]
    pub cert_allowed_cn: HashSet<String>,
    pub redact_info_log: RedactOption,
    #[online_config(skip)]
    pub encryption: EncryptionConfig,
}

/// Checks and opens key file. Returns `Ok(None)` if the path is empty.
///
///  # Arguments
///
///  - `tag`: only used in the error message, like "ca key", "cert key",
///    "private key", etc.
fn check_key_file(tag: &str, path: &str) -> Result<Option<File>, Box<dyn Error>> {
    if path.is_empty() {
        return Ok(None);
    }
    match File::open(path) {
        Err(e) => Err(format!("failed to open {} to load {}: {:?}", path, tag, e).into()),
        Ok(f) => Ok(Some(f)),
    }
}

/// Loads key file content. Returns `Ok(vec![])` if the path is empty.
fn load_key(tag: &str, path: &str) -> Result<Vec<u8>, Box<dyn Error>> {
    let mut key = vec![];
    let f = check_key_file(tag, path)?;
    match f {