tsafe-cli 1.0.28

Secrets runtime for developers — inject credentials into processes via exec, never into shell history or .env files
Documentation
//! Integration tests for `tsafe snapshot`.

use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::tempdir;

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

fn init_vault(dir: &std::path::Path) {
    tsafe()
        .args(["init"])
        .env("TSAFE_VAULT_DIR", dir)
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success();
}

#[test]
fn snapshot_list_empty_after_init() {
    let dir = tempdir().unwrap();
    init_vault(dir.path());

    // Vault just created — no writes have happened yet, so no snapshot exists.
    tsafe()
        .args(["snapshot", "list"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success()
        .stdout(predicates::str::contains("No snapshots"));
}

#[test]
fn snapshot_list_shows_entry_after_write() {
    let dir = tempdir().unwrap();
    init_vault(dir.path());

    // A write operation (set) snapshots the vault before saving.
    tsafe()
        .args(["set", "SNAP_KEY", "snap-val"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success();

    tsafe()
        .args(["snapshot", "list"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success()
        .stdout(predicates::str::contains("snapshot").or(predicates::str::contains(".snap")));
}

#[test]
fn snapshot_restore_rolls_back_write() {
    let dir = tempdir().unwrap();
    init_vault(dir.path());

    // Add a key — this snapshots the empty vault first.
    tsafe()
        .args(["set", "ROLLBACK_KEY", "rollback-val"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success();

    // Confirm the key is present.
    tsafe()
        .args(["get", "ROLLBACK_KEY"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success()
        .stdout(predicates::str::contains("rollback-val"));

    // Restore the snapshot (pre-set state).
    tsafe()
        .args(["snapshot", "restore"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success()
        .stdout(predicates::str::contains("restored"));

    // After restore the key should be absent.
    tsafe()
        .args(["get", "ROLLBACK_KEY"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .failure();
}

#[test]
fn snapshot_restore_without_snapshot_fails() {
    let dir = tempdir().unwrap();
    init_vault(dir.path());

    // No writes after init → no snapshot → restore must fail cleanly.
    tsafe()
        .args(["snapshot", "restore"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .failure()
        .stderr(predicates::str::contains("snapshot").or(predicates::str::contains("no snapshot")));
}

#[test]
fn snapshot_multiple_writes_accumulate_snapshots() {
    let dir = tempdir().unwrap();
    init_vault(dir.path());

    for i in 0..3 {
        tsafe()
            .args(["set", &format!("KEY_{i}"), &format!("val-{i}")])
            .env("TSAFE_VAULT_DIR", dir.path())
            .env("TSAFE_PASSWORD", "test-pw")
            .assert()
            .success();
    }

    // Should have 3 snapshots (one taken before each set).
    let output = tsafe()
        .args(["snapshot", "list"])
        .env("TSAFE_VAULT_DIR", dir.path())
        .env("TSAFE_PASSWORD", "test-pw")
        .assert()
        .success()
        .get_output()
        .stdout
        .clone();

    let stdout = String::from_utf8_lossy(&output);
    // Should mention at least one snapshot path.
    assert!(
        stdout.contains(".snap") || stdout.contains("snapshot"),
        "expected snapshot list output, got: {stdout}"
    );
}