Skip to content

Commit 9494c74

Browse files
committed
Tell "sops set --value-file [...]" to treat "-" as stdin
Using "-" to mean stdin/standard input is common in CLI tools; here are some examples: cat, sed, grep, tar, python, curl, openssl. Signed-off-by: Bjørn Forsman <bjorn.forsman@gmail.com>
1 parent c98d336 commit 9494c74

2 files changed

Lines changed: 61 additions & 2 deletions

File tree

cmd/sops/main.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
encodingjson "encoding/json"
66
"fmt"
7+
"io"
78
"net"
89
"net/url"
910
"os"
@@ -1387,7 +1388,7 @@ func main() {
13871388
},
13881389
cli.BoolFlag{
13891390
Name: "value-file",
1390-
Usage: "treat 'value' as a file to read the actual value from (avoids leaking secrets in process listings)",
1391+
Usage: "treat 'value' as a file to read the actual value from (avoids leaking secrets in process listings). The special value '-' means read from stdin",
13911392
},
13921393
cli.IntFlag{
13931394
Name: "shamir-secret-sharing-threshold",
@@ -1437,7 +1438,12 @@ func main() {
14371438
var data string
14381439
if c.Bool("value-file") {
14391440
filename := c.Args()[2]
1440-
content, err := os.ReadFile(filename)
1441+
var content []byte
1442+
if filename == "-" {
1443+
content, err = io.ReadAll(os.Stdin)
1444+
} else {
1445+
content, err = os.ReadFile(filename)
1446+
}
14411447
if err != nil {
14421448
return toExitError(err)
14431449
}

functional-tests/src/lib.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,59 @@ bar: baz",
538538
panic!("Output JSON does not have the expected structure");
539539
}
540540

541+
#[test]
542+
fn set_json_file_insert_with_value_file_stdin() {
543+
let file_path = prepare_temp_file(
544+
"test_set_json_file_insert_with_value_file_stdin.json",
545+
r#"{"a": 2, "b": "ba"}"#.as_bytes(),
546+
);
547+
assert!(
548+
Command::new(SOPS_BINARY_PATH)
549+
.arg("encrypt")
550+
.arg("-i")
551+
.arg(file_path.clone())
552+
.output()
553+
.expect("Error running sops")
554+
.status
555+
.success(),
556+
"sops didn't exit successfully"
557+
);
558+
let process = Command::new(SOPS_BINARY_PATH)
559+
.arg("set")
560+
.arg("--value-file")
561+
.arg(file_path.clone())
562+
.arg(r#"["c"]"#)
563+
.arg("-")
564+
.stdin(Stdio::piped())
565+
.stdout(Stdio::piped())
566+
.spawn()
567+
.expect("Error running sops");
568+
write_to_stdin(
569+
&process,
570+
b"{\"cc\": \"ccc\"}");
571+
let output = process.wait_with_output().expect("Failed to wait on sops");
572+
println!(
573+
"stdout: {}, stderr: {}",
574+
String::from_utf8_lossy(&output.stdout),
575+
String::from_utf8_lossy(&output.stderr)
576+
);
577+
assert!(output.status.success(), "sops didn't exit successfully");
578+
let mut s = String::new();
579+
File::open(file_path)
580+
.unwrap()
581+
.read_to_string(&mut s)
582+
.unwrap();
583+
let data: Value = serde_json::from_str(&s).expect("Error parsing sops's JSON output");
584+
if let Value::Mapping(data) = data {
585+
let a = data.get(&Value::String("c".to_owned())).unwrap();
586+
if let &Value::Mapping(ref a) = a {
587+
assert_encrypted!(&a, Value::String("cc".to_owned()));
588+
return;
589+
}
590+
}
591+
panic!("Output JSON does not have the expected structure");
592+
}
593+
541594
#[test]
542595
fn set_yaml_file_update() {
543596
let file_path = prepare_temp_file(

0 commit comments

Comments
 (0)