use std::fs;
use std::path::PathBuf;
use base64::Engine;
use base64::engine::general_purpose::STANDARD as BASE64_STD;
use tempfile::tempdir;
use uselesskey_cli::{
MaterializeFixtureSpec, MaterializeKind, MaterializeManifest, emit_include_bytes_module,
materialize_manifest_to_dir,
};
use uselesskey_test_support::{TestResult, ensure, ensure_eq, require_ok};
fn manifest_with(fixtures: Vec<MaterializeFixtureSpec>) -> MaterializeManifest {
MaterializeManifest {
version: Some(1),
fixtures,
}
}
#[test]
fn pem_block_shape_emits_block_with_normalized_label() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let out = dir.path().to_path_buf();
let manifest = manifest_with(vec![MaterializeFixtureSpec {
id: Some("pem-key".to_string()),
out: PathBuf::from("issuer.pem"),
kind: MaterializeKind::PemBlockShape,
seed: "pem-block-seed".to_string(),
label: Some("acme key".to_string()), len: Some(96),
}]);
let summary = require_ok(
materialize_manifest_to_dir(&manifest, &out, false),
"materialize",
)?;
ensure_eq!(summary.count, 1);
let pem = require_ok(
fs::read_to_string(out.join("issuer.pem")),
"read materialized pem",
)?;
ensure!(
pem.starts_with("-----BEGIN ACME_KEY-----\n"),
"PEM should start with normalized BEGIN line, got: {pem}"
);
ensure!(
pem.contains("-----END ACME_KEY-----\n"),
"PEM should contain matching END line, got: {pem}"
);
let body: String = pem
.lines()
.filter(|line| !line.starts_with("-----"))
.collect::<Vec<_>>()
.join("");
require_ok(
BASE64_STD.decode(body.as_bytes()),
"PEM body must be base64",
)?;
Ok(())
}
#[test]
fn pem_block_shape_label_with_only_special_chars_falls_back_to_secret() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let out = dir.path().to_path_buf();
let manifest = manifest_with(vec![MaterializeFixtureSpec {
id: Some("blank-label".to_string()),
out: PathBuf::from("blank.pem"),
kind: MaterializeKind::PemBlockShape,
seed: "blank-pem-seed".to_string(),
label: Some("@@@".to_string()), len: Some(32),
}]);
require_ok(
materialize_manifest_to_dir(&manifest, &out, false),
"materialize",
)?;
let pem = require_ok(fs::read_to_string(out.join("blank.pem")), "read pem")?;
ensure!(
pem.starts_with("-----BEGIN ___-----\n"),
"non-alnum label should normalize to underscores, got: {pem}"
);
Ok(())
}
#[test]
fn pem_block_shape_empty_label_falls_back_to_secret() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let out = dir.path().to_path_buf();
let manifest = manifest_with(vec![MaterializeFixtureSpec {
id: Some("empty-label".to_string()),
out: PathBuf::from("named.pem"),
kind: MaterializeKind::PemBlockShape,
seed: "empty-label-seed".to_string(),
label: None,
len: Some(32),
}]);
require_ok(
materialize_manifest_to_dir(&manifest, &out, false),
"materialize",
)?;
let pem = require_ok(fs::read_to_string(out.join("named.pem")), "read pem")?;
ensure!(
pem.starts_with("-----BEGIN NAMED-----\n"),
"label from file stem `named.pem` should normalize to NAMED, got: {pem}"
);
Ok(())
}
#[test]
fn token_api_key_kind_emits_non_empty_token_value() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let out = dir.path().to_path_buf();
let manifest = manifest_with(vec![MaterializeFixtureSpec {
id: Some("svc-token".to_string()),
out: PathBuf::from("svc.token"),
kind: MaterializeKind::TokenApiKey,
seed: "api-key-seed".to_string(),
label: Some("svc-token".to_string()),
len: None,
}]);
require_ok(
materialize_manifest_to_dir(&manifest, &out, false),
"materialize",
)?;
let token = require_ok(fs::read_to_string(out.join("svc.token")), "read token")?;
ensure!(!token.is_empty(), "api-key token must be non-empty");
ensure!(
!token.contains('.'),
"api-key token should not look like a JWT (no dots), got: {token}"
);
Ok(())
}
#[test]
fn token_api_key_is_deterministic_across_runs() -> TestResult<()> {
let dir_a = require_ok(tempdir(), "tempdir-a")?;
let dir_b = require_ok(tempdir(), "tempdir-b")?;
let spec = MaterializeFixtureSpec {
id: Some("svc-token".to_string()),
out: PathBuf::from("svc.token"),
kind: MaterializeKind::TokenApiKey,
seed: "api-key-determinism".to_string(),
label: Some("svc".to_string()),
len: None,
};
let manifest = manifest_with(vec![spec]);
require_ok(
materialize_manifest_to_dir(&manifest, dir_a.path(), false),
"materialize a",
)?;
require_ok(
materialize_manifest_to_dir(&manifest, dir_b.path(), false),
"materialize b",
)?;
let a = require_ok(fs::read_to_string(dir_a.path().join("svc.token")), "read a")?;
let b = require_ok(fs::read_to_string(dir_b.path().join("svc.token")), "read b")?;
ensure_eq!(a, b);
Ok(())
}
#[test]
fn ssh_public_key_shape_with_only_disallowed_label_falls_back_to_fixture() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let out = dir.path().to_path_buf();
let manifest = manifest_with(vec![MaterializeFixtureSpec {
id: Some("ssh-empty".to_string()),
out: PathBuf::from("id_ed25519.pub"),
kind: MaterializeKind::SshPublicKeyShape,
seed: "ssh-shape-seed".to_string(),
label: None,
len: None,
}]);
require_ok(
materialize_manifest_to_dir(&manifest, &out, false),
"materialize",
)?;
let content = require_ok(fs::read_to_string(out.join("id_ed25519.pub")), "read ssh")?;
ensure!(
content.starts_with("ssh-ed25519 "),
"ssh public key shape should start with algorithm marker, got: {content}"
);
ensure!(
content.trim_end().ends_with(" id_ed25519"),
"label-less spec should use sanitized file stem `id_ed25519` as comment, got: {content}"
);
Ok(())
}
#[test]
fn entropy_bytes_kind_uses_default_length_when_unset() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let out = dir.path().to_path_buf();
let manifest = manifest_with(vec![MaterializeFixtureSpec {
id: Some("entropy-default-len".to_string()),
out: PathBuf::from("default.bin"),
kind: MaterializeKind::EntropyBytes,
seed: "default-len-seed".to_string(),
label: None,
len: None, }]);
require_ok(
materialize_manifest_to_dir(&manifest, &out, false),
"materialize",
)?;
let bytes = require_ok(fs::read(out.join("default.bin")), "read entropy")?;
ensure_eq!(bytes.len(), 32, "entropy default length should be 32 bytes");
Ok(())
}
#[test]
fn materialize_to_dir_with_empty_manifest_errors() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let manifest = manifest_with(Vec::new());
let result = materialize_manifest_to_dir(&manifest, dir.path(), false);
match result {
Err(uselesskey_cli::MaterializeError::InvalidManifest(msg)) => {
ensure!(
msg.contains("no fixtures"),
"empty manifest error should mention 'no fixtures', got: {msg}"
);
Ok(())
}
other => Err(uselesskey_test_support::TestError(format!(
"expected InvalidManifest error, got {other:?}"
))),
}
}
#[test]
fn emit_include_bytes_module_with_empty_manifest_errors() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let manifest = manifest_with(Vec::new());
let module = dir.path().join("fixtures.rs");
let result = emit_include_bytes_module(&manifest, dir.path(), &module);
match result {
Err(uselesskey_cli::MaterializeError::InvalidManifest(msg)) => {
ensure!(
msg.contains("empty"),
"empty manifest emit error should mention 'empty', got: {msg}"
);
Ok(())
}
other => Err(uselesskey_test_support::TestError(format!(
"expected InvalidManifest error, got {other:?}"
))),
}
}
#[test]
fn emit_include_bytes_module_rejects_duplicate_const_names() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let module = dir.path().join("fixtures.rs");
let manifest = manifest_with(vec![
MaterializeFixtureSpec {
id: Some("key-a".to_string()),
out: PathBuf::from("key_a.bin"),
kind: MaterializeKind::EntropyBytes,
seed: "dup-emit-seed".to_string(),
label: None,
len: Some(8),
},
MaterializeFixtureSpec {
id: Some("key.a".to_string()),
out: PathBuf::from("key_a_other.bin"),
kind: MaterializeKind::EntropyBytes,
seed: "dup-emit-seed".to_string(),
label: None,
len: Some(8),
},
]);
let result = emit_include_bytes_module(&manifest, dir.path(), &module);
match result {
Err(uselesskey_cli::MaterializeError::InvalidManifest(msg)) => {
ensure!(
msg.contains("duplicate") && msg.contains("KEY_A"),
"duplicate constant error should name the conflicting symbol, got: {msg}"
);
Ok(())
}
other => Err(uselesskey_test_support::TestError(format!(
"expected InvalidManifest duplicate error, got {other:?}"
))),
}
}
#[test]
fn emit_include_bytes_module_prefixes_underscore_for_digit_leading_id() -> TestResult<()> {
let dir = require_ok(tempdir(), "tempdir")?;
let out_dir = dir.path().join("out");
let module = dir.path().join("fixtures.rs");
let manifest = manifest_with(vec![MaterializeFixtureSpec {
id: Some("2fa-secret".to_string()),
out: PathBuf::from("two-fa.bin"),
kind: MaterializeKind::EntropyBytes,
seed: "digit-prefix-seed".to_string(),
label: None,
len: Some(8),
}]);
require_ok(
emit_include_bytes_module(&manifest, &out_dir, &module),
"emit module",
)?;
let emitted = require_ok(fs::read_to_string(&module), "read emitted module")?;
ensure!(
emitted.contains("pub const _2FA_SECRET: &[u8]"),
"digit-leading id should prefix `_` to the emitted constant, got:\n{emitted}"
);
Ok(())
}