warg_server/
args.rs

1use anyhow::{bail, Context, Result};
2use secrecy::SecretString;
3use std::{fs, path::PathBuf};
4
5/// Returns the value of an option giving precedence of command line options
6/// over environment variables, and file source over directly specifying the
7/// value.
8pub fn get_opt_secret(
9    base_opt_name: &str,
10    path: Option<PathBuf>,
11    val: Option<SecretString>,
12) -> Result<SecretString> {
13    match (path, val) {
14        (Some(_), Some(_)) => unreachable!("options should conflict"),
15        (Some(path), None) => fs::read_to_string(&path)
16            .with_context(|| format!("failed to read file `{path}`", path = path.display()))
17            .map(Into::into),
18        (None, Some(val)) => Ok(val),
19        (None, None) => {
20            bail!("either option `{base_opt_name}-file` or `{base_opt_name}` needs to be specified")
21        }
22    }
23}
24
25#[cfg(test)]
26mod tests {
27    use secrecy::ExposeSecret;
28
29    use super::*;
30
31    const BASE_OPT_NAME: &str = "db-password";
32
33    #[test]
34    fn test_missing_file_arg() {
35        let path_opt = Some(PathBuf::from("tests/welcome456.txt"));
36        let val_opt = None;
37
38        assert_eq!(
39            get_opt_secret(BASE_OPT_NAME, path_opt, val_opt)
40                .unwrap_err()
41                .to_string(),
42            "failed to read file `tests/welcome456.txt`"
43        );
44    }
45
46    #[test]
47    fn test_cli_arg_priority() {
48        let path_opt: Option<PathBuf> = None;
49        let val_opt = Some(String::from("welcome456").into());
50
51        let content = get_opt_secret(BASE_OPT_NAME, path_opt, val_opt).unwrap();
52        assert_eq!(content.expose_secret(), "welcome456");
53    }
54
55    #[test]
56    fn test_no_arg_set() {
57        let path_opt: Option<PathBuf> = None;
58        let val_opt: Option<SecretString> = None;
59
60        assert_eq!(
61            get_opt_secret(BASE_OPT_NAME, path_opt, val_opt)
62                .unwrap_err()
63                .to_string(),
64            "either option `db-password-file` or `db-password` needs to be specified"
65        );
66    }
67}