Grcov report - show_secrets.rs

1

    use std::fs::{

2

      self,

3

      File,

4

    };

5

    use std::path::Path;

6

7

    use anyhow::Context as _;

8

    use clap::Args;

9

    use console::style;

10

    use pgp::{

11

      Deserializable as _,

12

      Message,

13

      SignedSecretKey,

14

    };

15

    use prettytable::format::consts;

16

    use prettytable::{

17

      row,

18

      Table,

19

    };

20

21

    use crate::secrets::context::Context;

22

    use crate::secrets::vault::{

23

      verify_key,

24

      verify_vault,

25

    };

26

27

    #[derive(Debug, Args)]

28

    pub struct ShowSecrets {

29

      #[arg(help = "The secret identifier or prefix to export")]

30

      path: String,

31

32

      #[arg(short, long, help = "The path to the secret store")]

33

      vault_location: Option<String>,

34

35

      #[arg(long, help = "The keys location")]

36

      keys_location: Option<String>,

37

38

      #[arg(short, long, help = "The key name")]

39

      key_name: Option<String>,

40

    }

41

42

    impl ShowSecrets {

43

      pub fn execute(&self, context: &Context) -> anyhow::Result<()> {

44

        let path: &str = &self.path.clone();

45

        let vault_location: &str = &self

46

          .vault_location

47

          .clone()

48

          .unwrap_or_else(|| context.vault_location());

49

        let keys_location: &str = &self

50

          .keys_location

51

          .clone()

52

          .unwrap_or_else(|| context.keys_location());

53

        let key_name: &str = &self.key_name.clone().unwrap_or_else(|| context.key_name());

54

55

        assert!(!path.is_empty(), "Path or prefix must be provided");

56

        assert!(!vault_location.is_empty(), "Vault location must be provided");

57

        assert!(!keys_location.is_empty(), "Keys location must be provided");

58

        assert!(!key_name.is_empty(), "Key name must be provided");

59

60

        verify_vault(vault_location)?;

61

        verify_key(keys_location, key_name)?;

62

63

        // Open the secret key file

64

        let key_name_with_ext = format!("{key_name}.key");

65

        let key_path = Path::new(keys_location).join(key_name_with_ext);

66

        let mut secret_key_string = File::open(key_path)?;

67

        let (signed_secret_key, _) = SignedSecretKey::from_armor_single(&mut secret_key_string)?;

68

        signed_secret_key.verify()?;

69

70

        let secret_path = Path::new(vault_location).join(path);

71

        let mut values = Vec::new();

72

73

        if secret_path.exists() && secret_path.is_dir() {

74

          // Check for file and subdirectories

75

          let entries = fs::read_dir(secret_path.clone())?

76

            .filter_map(Result::ok)

77

            .collect::<Vec<_>>();

78

79

          // Check for data files in the subdirectories

80

          for entry in entries {

81

            let data_path = if entry.path().is_dir() {

82

              entry.path().join("data.asc")

83

            } else {

84

              entry.path()

85

            };

86

87

            // Read the data file

88

            if data_path.exists() && data_path.is_file() {

89

              let mut data_file = File::open(data_path)?;

90

              let (message, _) = Message::from_armor_single(&mut data_file)?;

91

              let (decrypted_message, _) = message.decrypt(String::new, &[&signed_secret_key])?;

92

              let value = decrypted_message

93

                .get_literal()

94

                .ok_or_else(|| anyhow::anyhow!("Secret value is not a literal"))?

95

                .to_string()

96

                .context("Failed to read secret value")?;

97

98

              values.push(value);

99

            }

100

          }

101

102

          if values.is_empty() {

103

            println!("No secrets found for path: {}", path);

104

          } else {

105

            let mut table = Table::new();

106

            table.set_format(*consts::FORMAT_CLEAN);

107

            table.set_titles(row![Fbb->"Name", Fbb->"Value"]);

108

            for value in values {

109

              table.add_row(row![b->&path, Fg->&value]);

110

            }

111

            let msg = style("Available secrets:").bold().cyan();

112

            println!();

113

            println!("{msg}");

114

            println!();

115

            table.printstd();

116

          }

117

        } else {

118

          println!("Path does not exist or is not a directory");

119

        }

120

121

        Ok(())

122

      }

123

    }