Skip to content

Commit defdb9b

Browse files
authored
Update syntax for argument to unlock (#14)
2 parents ebf5472 + bf95874 commit defdb9b

4 files changed

Lines changed: 50 additions & 55 deletions

File tree

README.md

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -138,23 +138,26 @@ This will show the raw content as stored in the repository. So even if `cat my-s
138138

139139
### Unlock a repository
140140

141-
After you freshly clone a repository which contains files which have been encrypted by `git-conceal`, you need to provide the symmetric key that your coworkers would have shared with you to decrypt it:
141+
After you freshly clone a repository which contains files which have been encrypted by `git-conceal`, you need to provide the symmetric key (that your coworkers would have shared with you) to decrypt it:
142142

143143
```bash
144-
# Option 1: Provide the key via an environment variable (base64 encoded). Recommended on CI.
145-
export GIT_SECRETS_KEY="YOUR_BASE64_KEY"
146-
git-conceal unlock env:GIT_SECRETS_KEY
147-
148-
# Option 2: Provide the Base64-encoded key as command line argument. (Only use locally, as on CI this could leak the key in logs).
149-
git-conceal unlock "base64:c3VwcG9zZWRseS15b3VyLWJpbmFyeS1zZWNyZXRrZXk="
150-
151-
# Option 3: Provide a path to a from file containing the raw binary, 32 bytes key.
152-
git-conceal unlock /path/to/key.bin
153-
154-
# Option 4: Provide it via stdin (expects raw binary, 32 bytes as input)
155-
cat /path/to/key.bin | git-conceal unlock -
156-
# Or convert from base64. (Only use locally, as on CI this could leak the key in logs).
157-
echo "c3VwcG9zZWRseS15b3VyLWJpbmFyeS1zZWNyZXRrZXk=" | base64 -d | git-conceal unlock -
144+
# Option 1: Provide the Base64-encoded key directly as command line argument.
145+
# Only use locally, as on CI this could leak the key in logs.
146+
# Tip: start your command with a space to avoid it (and thus the key) being added to your shell's history
147+
$ git-conceal unlock "c3VwcG9zZWRseS15b3VyLWJpbmFyeS1zZWNyZXRrZXk="
148+
149+
# Option 2: Provide the key via an environment variable (base64 encoded), by using the `env:` prefix.
150+
# Recommended on CI, where secret values like the key are usually exposed to jobs as env vars.
151+
# Prefer this over `git-conceal unlock $GIT_CONCEAL_SECRET_KEY` to reduce the risk of accidentally leaking
152+
# the key e.g. in CI logs (which might resolve `$VAR` env vars before printing the resolved command in logs)
153+
$ git-conceal unlock env:GIT_CONCEAL_SECRET_KEY
154+
155+
# Option 3: Provide it via stdin (expects raw binary, 32 bytes as input)
156+
# For example, if you have the binary key in a file (which you would hopefully have protected properly!)
157+
$ git-conceal unlock - </path/to/keyfile.bin
158+
# Or if you have the base64-encoded key in your clipboard, you could do:
159+
$ pbpaste | base64 -d | git-conceal unlock -
160+
# (Though in that case `git-conceal unlock $(pbpaste)` would achieve the same thing)
158161
```
159162

160163
This will:
@@ -186,7 +189,7 @@ git-conceal status
186189
This shows:
187190
- Whether the repository is locked or unlocked
188191
- Whether filters are configured
189-
- Which file patterns are encrypted (from `.gitattributes`)
192+
- Which files are handled by `git-conceal` (i.e. tracked files matching one of the patterns with `filter=git-conceal` in your `.gitattributes`)
190193

191194
```bash
192195
git-conceal status <FILES>
@@ -205,7 +208,7 @@ git-conceal key show
205208
### Rotate the encryption key
206209

207210
There are times when you might need to rotate the encryption key used in an encrypted repository.
208-
For example, in the unfortunate even of the key leaking or when a coworker leaves your team/company and you want to ensure they can't access new secrets.
211+
For example, in the unfortunate event of the key leaking, or when a coworker leaves your team/company and you want to ensure they can't access new secrets.
209212

210213
You can rotate the encryption key with:
211214

@@ -245,15 +248,19 @@ For detailed security information, including key management, deterministic encry
245248

246249
## New releases
247250

248-
Releases are automated by our CI every time we make a `git tag` on the repo. Be sure to update the version in the `Cargo.toml` first though.
251+
Releases are automated by our CI every time we make a `git tag` on the repo.
252+
253+
<details><summary>Release instructions for maintainers</summary>
249254

250255
- Create a `release/x.y.z` branch
251256
- Edit `Cargo.toml` to update the `version = "x.y.z"` field
252-
- Run `cargo check` to update the `Cargo.lock` and validate the code still compiles
257+
- Run `cargo check` to update the `Cargo.lock` with the new version and validate the code still compiles
253258
- `git add Cargo.toml Cargo.lock` then `git commit -m "Bump version to x.y.z"`
254-
- Create a PR and get it merged
259+
- Create a PR with those changes and get it merged into `trunk`
255260
- Once it has landed in `trunk`, push a new tag (`git tag "x.y.z"` then `git push origin "x.y.z"`)
256-
- Then let the CI build the release binaries for all platforms, create the GitHub Release, and attach the compiled binaries as assets.
261+
262+
The CI will trigger on the Git tag and take care of building the release binaries for all platforms and creating the GitHub Release with those binaries attached as assets.
263+
</details>
257264

258265
## License
259266

src/commands/init.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,14 @@ fn init_instructions(key_b64: &str) -> String {
4343
{key_b64}
4444
4545
Once you share this key with users you trust, they can unlock their working copy using one of these methods:
46+
- From base64-encoded key passed directly as argument:
47+
{bin_name} unlock "{key_b64}"
4648
- From environment variable (base64):
47-
export GIT_SECRETS_KEY='{key_b64}'
48-
{bin_name} unlock env:GIT_SECRETS_KEY
49-
- From base64-encoded key in the command line:
50-
{bin_name} unlock "base64:{key_b64}"
51-
- From file (raw binary, 32 bytes):
52-
{bin_name} unlock /path/to/key.bin
49+
export GIT_CONCEAL_SECRET_KEY='{key_b64}'
50+
{bin_name} unlock env:GIT_CONCEAL_SECRET_KEY
5351
- From stdin (raw binary, 32 bytes):
5452
echo '{key_b64}' | base64 -d | {bin_name} unlock -
53+
{bin_name} unlock - < /path/to/raw-binary-key.bin
5554
5655
To start adding files to be encrypted in this repository:
5756
- List files (or file patterns) you want to encrypt in your `.gitattributes` file, like this:

src/key.rs

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,9 @@ impl Key {
7272
/// Read encryption key from various sources
7373
///
7474
/// Supports:
75-
/// - `"-"` for reading from stdin (raw binary format, 32 bytes)
75+
/// - Base64-encoded key string (passed directly as argument)
7676
/// - `"env:VARNAME"` for reading from environment variable (base64 encoded)
77-
/// - `"base64:BASE64_KEY"` for reading from base64-encoded key
78-
/// - File path for reading from a file (raw binary format, 32 bytes)
77+
/// - `"-"` for reading from stdin (raw binary format, 32 bytes)
7978
///
8079
/// Returns the encryption key.
8180
pub fn read_from_source(key_source: &str) -> Result<Self> {
@@ -95,11 +94,9 @@ impl Key {
9594
format!("Failed to read key from environment variable {}", env_var)
9695
})?;
9796
Self::from_base64(&key_b64)
98-
} else if let Some(base64_key) = key_source.strip_prefix("base64:") {
99-
Self::from_base64(base64_key)
10097
} else {
101-
// Read from file (raw binary format)
102-
Self::from_file(Path::new(key_source))
98+
// Treat as base64-encoded key (unprefixed)
99+
Self::from_base64(key_source)
103100
}
104101
}
105102
}
@@ -301,18 +298,6 @@ mod tests {
301298
assert!(result.unwrap_err().to_string().contains("Invalid key size"));
302299
}
303300

304-
#[test]
305-
fn test_read_from_source_file() {
306-
let temp_dir = TempDir::new().unwrap();
307-
let key_file = temp_dir.path().join("test.key");
308-
309-
let key = test_key();
310-
fs::write(&key_file, key.as_bytes()).unwrap();
311-
312-
let loaded_key = Key::read_from_source(key_file.to_str().unwrap()).unwrap();
313-
assert_eq!(loaded_key.as_bytes(), key.as_bytes());
314-
}
315-
316301
/// This test must run serially (not in parallel with other tests) because it modifies
317302
/// environment variables. Environment variable modification is not thread-safe and can
318303
/// cause race conditions when tests run in parallel.
@@ -398,18 +383,23 @@ mod tests {
398383
fn test_read_from_source_base64() {
399384
let key = test_key();
400385
let b64 = key.to_base64();
401-
let loaded_key = Key::read_from_source(&format!("base64:{}", b64)).unwrap();
386+
let loaded_key = Key::read_from_source(&b64).unwrap();
402387
assert_eq!(loaded_key.as_bytes(), key.as_bytes());
403388
}
404389

405390
// Note: Testing stdin reading is complex in unit tests as it requires
406391
// mocking stdin or using a separate process. This would be better suited
407-
// for integration tests. The file and env var cases are tested above.
392+
// for integration tests. The env var and base64 cases are tested above.
408393

409394
#[test]
410-
fn test_read_from_source_invalid_source() {
411-
let result = Key::read_from_source("/nonexistent/path/key.bin");
395+
fn test_read_from_source_invalid_base64() {
396+
// A user accidentally passing a file path should be treated as base64 key and fail to decode
397+
let result = Key::read_from_source("path/to/secret-symmetric-key.bin");
412398
assert!(result.is_err());
399+
assert!(result
400+
.unwrap_err()
401+
.to_string()
402+
.contains("Failed to decode base64 key"));
413403
}
414404

415405
#[test]

src/main.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,10 @@ enum Commands {
5050
Unlock {
5151
/// Key source
5252
#[arg(
53-
value_name = "KEY_SOURCE",
54-
long_help = "- 'env:VARNAME': base64-encoded key in environment variable (recommended on CI)\n\
55-
- 'base64:BASE64_KEY': base64-encoded key\n\
56-
- '-': raw binary key from stdin\n\
57-
- <PATH>: raw binary key from file"
53+
value_name = "KEY",
54+
long_help = "- 'BASE64KEY': the base64-encoded key passed directly as argument\n\
55+
- 'env:VARNAME': read the base64-encoded key from the given environment variable (recommended on CI)\n\
56+
- '-': read the raw binary key from stdin (expects raw binary, 32 bytes as input)"
5857
)]
5958
key_source: String,
6059
},

0 commit comments

Comments
 (0)