tsafe-cli 1.0.21

tsafe CLI — local secret and credential manager (replaces .env files)
Documentation
//! Integration tests for `tsafe gen`.

use assert_cmd::Command;
use predicates::str::contains;
use tempfile::tempdir;

fn tsafe() -> Command {
    Command::cargo_bin("tsafe").unwrap()
}

#[test]
fn gen_stores_and_prints_value() {
    let dir = tempdir().unwrap();
    // Init vault first.
    tsafe()
        .args(["init"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success();

    // Generate a 32-char hex secret with --print.
    let out = tsafe()
        .args([
            "gen",
            "SESSION_KEY",
            "--length",
            "32",
            "--charset",
            "hex",
            "--print",
        ])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success()
        .get_output()
        .stdout
        .clone();

    let value = String::from_utf8(out).unwrap();
    let trimmed = value.trim();
    assert_eq!(
        trimmed.len(),
        32,
        "expected 32-char output, got {}: {trimmed:?}",
        trimmed.len()
    );
    assert!(
        trimmed.chars().all(|c| c.is_ascii_hexdigit()),
        "expected hex chars: {trimmed:?}"
    );
}

#[test]
fn gen_exclude_ambiguous_removes_ambiguous_chars() {
    let dir = tempdir().unwrap();
    tsafe()
        .args(["init"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success();

    // Generate a long secret so the probability of it being clean is very high.
    let out = tsafe()
        .args([
            "gen",
            "CLEAN_KEY",
            "--length",
            "128",
            "--charset",
            "alnum",
            "--exclude-ambiguous",
            "--print",
        ])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success()
        .get_output()
        .stdout
        .clone();

    let value = String::from_utf8(out).unwrap();
    let trimmed = value.trim();
    assert_eq!(
        trimmed.len(),
        128,
        "expected 128 chars, got {}: {trimmed:?}",
        trimmed.len()
    );
    for ch in ['0', 'O', 'l', '1', 'I'] {
        assert!(
            !trimmed.contains(ch),
            "expected ambiguous char '{ch}' to be absent, got: {trimmed:?}"
        );
    }
}

#[test]
fn gen_entropy_note_shown_in_output() {
    let dir = tempdir().unwrap();
    tsafe()
        .args(["init"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success();

    tsafe()
        .args(["gen", "ENTROPY_KEY", "--length", "32", "--charset", "alnum"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success()
        .stdout(contains("bits entropy"));
}

#[test]
fn gen_zero_length_rejected() {
    let dir = tempdir().unwrap();
    tsafe()
        .args(["init"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success();

    tsafe()
        .args(["gen", "BAD", "--length", "0"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .failure()
        .stderr(contains("length"));
}