• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ssh-vault / ssh-vault / 14317917208

07 Apr 2025 07:35PM UTC coverage: 90.38% (+15.2%) from 75.176%
14317917208

push

github

nbari
fix coverage

2236 of 2474 relevant lines covered (90.38%)

54.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.26
/src/cli/actions/create.rs
1
use crate::cli::actions::{Action, process_input};
2
use crate::vault::{SshVault, crypto, dio, find, online, remote};
3
use anyhow::{Result, anyhow};
4
use secrecy::SecretSlice;
5
use serde::{Deserialize, Serialize};
6
use ssh_key::PublicKey;
7
use std::io::{Read, Write};
8

9
#[derive(Serialize, Deserialize)]
10
pub struct JsonVault {
11
    vault: String,
12
    #[serde(skip_serializing_if = "Option::is_none")]
13
    private_key: Option<String>,
14
}
15

16
/// Handle the create action
17
pub fn handle(action: Action) -> Result<()> {
8✔
18
    match action {
8✔
19
        Action::Create {
20
            fingerprint,
8✔
21
            key,
8✔
22
            user,
8✔
23
            vault,
8✔
24
            json,
8✔
25
            input,
8✔
26
        } => {
8✔
27
            // print the url from where to download the key
8✔
28
            let mut helper: Option<String> = None;
8✔
29

30
            let ssh_key: PublicKey = if let Some(user) = user {
8✔
31
                // if user equals "new" ignore the key and fingerprint
32
                if user == "new" && (key.is_some() || fingerprint.is_some()) {
×
33
                    return Err(anyhow!("Options -k and -f not required when using -u new"));
×
34
                }
×
35

×
36
                let int_key: Option<u32> = key.as_ref().and_then(|s| s.parse::<u32>().ok());
×
37

38
                // get keys from GitHub or remote server
39
                let keys = remote::get_keys(&user)?;
×
40

41
                // search key using -k or -f options
42
                let ssh_key = remote::get_user_key(&keys, int_key, &fingerprint)?;
×
43

44
                // if user equals "new" then we need to create a new key
45
                if let Ok(key) = online::get_private_key_id(&ssh_key, &user) {
×
46
                    if !key.is_empty() {
×
47
                        helper = Some(key);
×
48
                    }
×
49
                }
×
50

51
                ssh_key
×
52
            } else {
53
                find::public_key(key)?
8✔
54
            };
55

56
            let key_type = find::key_type(&ssh_key.algorithm())?;
8✔
57

58
            let v = SshVault::new(&key_type, Some(ssh_key), None)?;
8✔
59

60
            let mut buffer = Vec::new();
8✔
61

8✔
62
            // check if we need to skip the editor filename == "-"
8✔
63
            let skip_editor = input.as_ref().is_some_and(|stdin| stdin == "-");
8✔
64

65
            // setup Reader(input) and Writer (output)
66
            let (mut input, output) = dio::setup_io(input, vault)?;
8✔
67

68
            if !output.is_empty()? {
8✔
69
                return Err(anyhow!("Vault file already exists"));
3✔
70
            }
5✔
71

5✔
72
            if input.is_terminal() {
5✔
73
                if skip_editor {
×
74
                    input.read_to_end(&mut buffer)?;
×
75
                } else {
76
                    // use editor to handle input
77
                    process_input(&mut buffer, None)?;
×
78
                }
79
            } else {
80
                // read from stdin
81
                input.read_to_end(&mut buffer)?;
5✔
82
            }
83

84
            // generate password (32 rand chars)
85
            let password: SecretSlice<u8> = crypto::gen_password()?;
5✔
86

87
            // create vault
88
            let vault = v.create(password, &mut buffer)?;
5✔
89

90
            // return JSON or plain text, the helper is used to decrypt the vault
91
            format(output, vault, json, helper)?;
5✔
92
        }
93
        _ => unreachable!(),
×
94
    }
95
    Ok(())
5✔
96
}
8✔
97

98
fn format<W: Write>(
9✔
99
    mut output: W,
9✔
100
    vault: String,
9✔
101
    json: bool,
9✔
102
    helper: Option<String>,
9✔
103
) -> Result<()> {
9✔
104
    // format the vault in json or plain text
9✔
105
    if json {
9✔
106
        let json_vault = JsonVault {
4✔
107
            vault,
4✔
108
            private_key: helper,
4✔
109
        };
4✔
110

111
        let json = serde_json::to_string(&json_vault)?;
4✔
112

113
        output.write_all(json.as_bytes())?;
4✔
114
    } else if let Some(helper) = helper {
5✔
115
        let format = format!("echo \"{vault}\" | ssh-vault view -k {helper}");
1✔
116
        output.write_all(format.as_bytes())?;
1✔
117
    } else {
118
        output.write_all(vault.as_bytes())?;
4✔
119
    }
120

121
    Ok(())
9✔
122
}
9✔
123

124
#[cfg(test)]
125
mod tests {
126
    use super::*;
127

128
    #[test]
129
    fn test_format() {
1✔
130
        let mut output = Vec::new();
1✔
131
        let vault = "vault".to_string();
1✔
132
        let json = false;
1✔
133
        let helper = None;
1✔
134

1✔
135
        format(&mut output, vault, json, helper).unwrap();
1✔
136

1✔
137
        assert_eq!(output, b"vault");
1✔
138
    }
1✔
139

140
    #[test]
141
    fn test_format_helper() {
1✔
142
        let mut output = Vec::new();
1✔
143
        let vault = "vault".to_string();
1✔
144
        let json = false;
1✔
145
        let helper = Some("helper".to_string());
1✔
146

1✔
147
        format(&mut output, vault, json, helper).unwrap();
1✔
148

1✔
149
        assert_eq!(output, b"echo \"vault\" | ssh-vault view -k helper");
1✔
150
    }
1✔
151

152
    #[test]
153
    fn test_format_json() {
1✔
154
        let mut output = Vec::new();
1✔
155
        let vault = "vault".to_string();
1✔
156
        let json = true;
1✔
157
        let helper = None;
1✔
158

1✔
159
        format(&mut output, vault, json, helper).unwrap();
1✔
160

1✔
161
        assert_eq!(output, b"{\"vault\":\"vault\"}");
1✔
162
    }
1✔
163

164
    #[test]
165
    fn test_format_helper_json() {
1✔
166
        let mut output = Vec::new();
1✔
167
        let vault = "vault".to_string();
1✔
168
        let json = true;
1✔
169
        let helper = Some("helper".to_string());
1✔
170

1✔
171
        format(&mut output, vault, json, helper).unwrap();
1✔
172

1✔
173
        assert_eq!(output, b"{\"vault\":\"vault\",\"private_key\":\"helper\"}");
1✔
174
    }
1✔
175
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc