Built alone from an empty CARGO_HOME, its tests passed, and flowrsc checked, ran and exported a document from the conformance corpus; the export built alone. Co-Authored-By: Claude Opus 5.5 <[email protected]>
101 lines
3.3 KiB
Rust
101 lines
3.3 KiB
Rust
//! `flowrsc` resolves a graph's `secret:NAME` from FLOWRS_SECRET_NAME and the file
|
|
//! FLOWRS_SECRETS names, refuses a credential file others can read, and prints no
|
|
//! credential: the readings and the report show the marker where one was.
|
|
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::Command;
|
|
|
|
fn canary() -> String {
|
|
format!("{}-{}-{}", "flowrs", "canary", "cli-1b7e3d")
|
|
}
|
|
|
|
fn scratch(name: &str) -> PathBuf {
|
|
let d = std::env::temp_dir().join(format!("flowrsc-secrets-{}-{name}", std::process::id()));
|
|
std::fs::create_dir_all(&d).unwrap();
|
|
d
|
|
}
|
|
|
|
/// A Particle call holding `token`, its `auth` checked by `flowrsc test`.
|
|
fn graph(dir: &Path, token: &str) -> (PathBuf, PathBuf) {
|
|
let mut g = flowrs_core::Graph::new();
|
|
let n = g.add_node("cloud.particle.function", 0.0, 0.0);
|
|
g.nodes
|
|
.get_mut(&n)
|
|
.unwrap()
|
|
.properties
|
|
.insert("token".into(), token.into());
|
|
let doc = dir.join("g.flowrs");
|
|
std::fs::write(&doc, flowrs_core::graph::document::save(&g)).unwrap();
|
|
let expect = dir.join("expect.json");
|
|
std::fs::write(
|
|
&expect,
|
|
format!(
|
|
"{{\"{}.auth\": {:?}, \"{}.url\": \"https://api.particle.io/v1/devices/my_device/led\"}}",
|
|
n.0,
|
|
flowrs_core::graph::secret::MARKER,
|
|
n.0
|
|
),
|
|
)
|
|
.unwrap();
|
|
(doc, expect)
|
|
}
|
|
|
|
fn flowrsc(args: &[&Path], env: &[(&str, &str)]) -> (i32, String) {
|
|
let mut c = Command::new(env!("CARGO_BIN_EXE_flowrsc"));
|
|
c.arg("test").arg(args[0]).arg("--expect").arg(args[1]);
|
|
c.env_remove("FLOWRS_SECRETS");
|
|
for (k, v) in env {
|
|
c.env(k, v);
|
|
}
|
|
let out = c.output().unwrap();
|
|
(
|
|
out.status.code().unwrap_or(-1),
|
|
format!(
|
|
"{}{}",
|
|
String::from_utf8_lossy(&out.stdout),
|
|
String::from_utf8_lossy(&out.stderr)
|
|
),
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn flowrsc_resolves_a_reference_and_prints_no_credential() {
|
|
let dir = scratch("env");
|
|
let (doc, expect) = graph(&dir, "secret:PARTICLE");
|
|
let value = canary();
|
|
let (code, text) = flowrsc(&[&doc, &expect], &[("FLOWRS_SECRET_PARTICLE", &value)]);
|
|
assert_eq!(code, 0, "{text}");
|
|
assert!(
|
|
!flowrs_core::graph::secret::holds(&text, &[value]),
|
|
"{text}"
|
|
);
|
|
let _ = std::fs::remove_dir_all(&dir);
|
|
}
|
|
|
|
#[test]
|
|
fn a_credential_file_others_can_read_is_refused() {
|
|
let dir = scratch("file");
|
|
let (doc, expect) = graph(&dir, "secret:PARTICLE");
|
|
let file = dir.join("secrets");
|
|
std::fs::write(&file, format!("PARTICLE={}\n", canary())).unwrap();
|
|
#[cfg(unix)]
|
|
{
|
|
use std::os::unix::fs::PermissionsExt;
|
|
std::fs::set_permissions(&file, std::fs::Permissions::from_mode(0o644)).unwrap();
|
|
let (code, text) = flowrsc(
|
|
&[&doc, &expect],
|
|
&[("FLOWRS_SECRETS", file.to_str().unwrap())],
|
|
);
|
|
assert_ne!(code, 0, "{text}");
|
|
assert!(text.contains("chmod 600"), "{text}");
|
|
assert!(!text.contains(&canary()), "{text}");
|
|
std::fs::set_permissions(&file, std::fs::Permissions::from_mode(0o600)).unwrap();
|
|
}
|
|
let (code, text) = flowrsc(
|
|
&[&doc, &expect],
|
|
&[("FLOWRS_SECRETS", file.to_str().unwrap())],
|
|
);
|
|
assert_eq!(code, 0, "{text}");
|
|
assert!(!text.contains(&canary()), "{text}");
|
|
let _ = std::fs::remove_dir_all(&dir);
|
|
}
|