mod test_utils;
use assert_cmd::Command;
use chrono::{Duration, Utc};
use std::env;
use std::fs::File;
use tempfile::TempDir;
use test_utils::dir_url;
use tough::{RepositoryLoader, TargetName};
fn get_profile() -> String {
env::var("AWS_PROFILE").unwrap_or_default()
}
fn initialize_root_json(root_json: &str) {
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "init", root_json])
.assert()
.success();
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "expire", root_json, "3030-09-22T00:00:00Z"])
.assert()
.success();
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "set-threshold", root_json, "root", "1"])
.assert()
.success();
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "set-threshold", root_json, "snapshot", "1"])
.assert()
.success();
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "set-threshold", root_json, "targets", "1"])
.assert()
.success();
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "set-threshold", root_json, "timestamp", "1"])
.assert()
.success();
}
fn gen_key(key: &str, root_json: &str) {
Command::cargo_bin("tuftool")
.unwrap()
.args(&[
"root",
"gen-rsa-key",
root_json,
key,
"--role",
"root",
"-b",
"3072",
])
.assert()
.success();
}
fn add_root_key(key: &str, root_json: &str) {
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "add-key", root_json, key, "--role", "root"])
.assert()
.success();
}
fn add_key_all_role(key: &str, root_json: &str) {
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "add-key", root_json, key, "--role", "snapshot"])
.assert()
.success();
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "add-key", root_json, key, "--role", "targets"])
.assert()
.success();
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "add-key", root_json, key, "--role", "timestamp"])
.assert()
.success();
}
fn sign_root_json(key: &str, root_json: &str) {
Command::cargo_bin("tuftool")
.unwrap()
.args(&["root", "sign", root_json, "-k", key])
.assert()
.success();
}
fn create_repository(root_key: &str, auto_generate: bool) {
let root_json_dir = TempDir::new().unwrap();
let root_json = root_json_dir.path().join("root.json");
initialize_root_json(root_json.to_str().unwrap());
if auto_generate {
gen_key(root_key, root_json.to_str().unwrap());
} else {
add_root_key(root_key, root_json.to_str().unwrap());
}
add_key_all_role(root_key, root_json.to_str().unwrap());
sign_root_json(root_key, root_json.to_str().unwrap());
let timestamp_expiration = Utc::now().checked_add_signed(Duration::days(3)).unwrap();
let timestamp_version: u64 = 1234;
let snapshot_expiration = Utc::now().checked_add_signed(Duration::days(21)).unwrap();
let snapshot_version: u64 = 5432;
let targets_expiration = Utc::now().checked_add_signed(Duration::days(13)).unwrap();
let targets_version: u64 = 789;
let targets_input_dir = test_utils::test_data()
.join("tuf-reference-impl")
.join("targets");
let repo_dir = TempDir::new().unwrap();
Command::cargo_bin("tuftool")
.unwrap()
.args(&[
"create",
"-t",
targets_input_dir.to_str().unwrap(),
"-o",
repo_dir.path().to_str().unwrap(),
"-k",
root_key,
"--root",
root_json.to_str().unwrap(),
"--targets-expires",
targets_expiration.to_rfc3339().as_str(),
"--targets-version",
format!("{}", targets_version).as_str(),
"--snapshot-expires",
snapshot_expiration.to_rfc3339().as_str(),
"--snapshot-version",
format!("{}", snapshot_version).as_str(),
"--timestamp-expires",
timestamp_expiration.to_rfc3339().as_str(),
"--timestamp-version",
format!("{}", timestamp_version).as_str(),
])
.assert()
.success();
let repo = RepositoryLoader::new(
File::open(root_json).unwrap(),
dir_url(repo_dir.path().join("metadata")),
dir_url(repo_dir.path().join("targets")),
)
.load()
.unwrap();
let file1 = TargetName::new("file1.txt").unwrap();
assert_eq!(
test_utils::read_to_end(repo.read_target(&file1).unwrap().unwrap()),
&b"This is an example target file."[..]
);
let file2 = TargetName::new("file2.txt").unwrap();
assert_eq!(
test_utils::read_to_end(repo.read_target(&file2).unwrap().unwrap()),
&b"This is an another example target file."[..]
);
let file3 = TargetName::new("file3.txt").unwrap();
assert_eq!(
test_utils::read_to_end(repo.read_target(&file3).unwrap().unwrap()),
&b"This is role1's target file."[..]
);
assert_eq!(repo.targets().signed.version.get(), targets_version);
assert_eq!(repo.targets().signed.expires, targets_expiration);
assert_eq!(repo.targets().signed.targets.len(), 3);
assert_eq!(repo.targets().signed.targets[&file1].length, 31);
assert_eq!(repo.targets().signed.targets[&file2].length, 39);
assert_eq!(repo.targets().signed.targets[&file3].length, 28);
assert_eq!(repo.targets().signatures.len(), 1);
assert_eq!(repo.snapshot().signed.version.get(), snapshot_version);
assert_eq!(repo.snapshot().signed.expires, snapshot_expiration);
assert_eq!(repo.snapshot().signed.meta.len(), 1);
assert_eq!(
repo.snapshot().signed.meta["targets.json"].version.get(),
targets_version
);
assert_eq!(repo.snapshot().signatures.len(), 1);
assert_eq!(repo.timestamp().signed.version.get(), timestamp_version);
assert_eq!(repo.timestamp().signed.expires, timestamp_expiration);
assert_eq!(repo.timestamp().signed.meta.len(), 1);
assert_eq!(
repo.timestamp().signed.meta["snapshot.json"].version.get(),
snapshot_version
);
assert_eq!(repo.snapshot().signatures.len(), 1);
root_json_dir.close().unwrap();
}
#[test]
#[cfg_attr(not(feature = "integ"), ignore)]
fn create_repository_local_key() {
let root_key_dir = TempDir::new().unwrap();
let root_key_path = root_key_dir.path().join("local_key.pem");
let root_key = &format!("file://{}", root_key_path.to_str().unwrap());
create_repository(root_key, true);
}
#[test]
#[cfg_attr(not(feature = "integ"), ignore)]
fn create_repository_ssm_key() {
let root_key = &format!("aws-ssm://{}/tough-integ/key-a", get_profile());
create_repository(root_key, true);
}
#[test]
#[cfg_attr(not(feature = "integ"), ignore)]
fn create_repository_kms_key() {
let root_key = &format!("aws-kms://{}/alias/tough-integ/key-a", get_profile());
create_repository(root_key, false);
}