tsafe-cli 1.1.0

Local-first secrets runtime for developers — inject credentials via exec, never shell history or .env files
Documentation
//! Integration tests for `tsafe explain`.

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

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

fn any_pull_feature_enabled() -> bool {
    cfg!(any(
        feature = "akv-pull",
        feature = "cloud-pull-aws",
        feature = "cloud-pull-gcp",
        feature = "cloud-pull-vault",
        feature = "cloud-pull-1password",
        feature = "cloud-pull-bitwarden",
        feature = "cloud-pull-keepass",
        feature = "multi-pull"
    ))
}

fn explain_lists_topic(stdout: &str, topic: &str) -> bool {
    stdout.lines().any(|line| {
        let trimmed = line.trim_start();
        trimmed
            .strip_prefix(topic)
            .is_some_and(|rest| rest.starts_with(char::is_whitespace))
    })
}

#[test]
fn explain_lists_topics_without_topic_arg() {
    let assert = tsafe().arg("explain").assert().success();
    let stdout = String::from_utf8(assert.get_output().stdout.clone()).unwrap();

    assert!(explain_lists_topic(&stdout, "exec"));
    assert!(explain_lists_topic(&stdout, "exec-security"));
    assert!(explain_lists_topic(&stdout, "namespaces"));

    if any_pull_feature_enabled() {
        assert!(explain_lists_topic(&stdout, "pull"));
        assert!(explain_lists_topic(&stdout, "pull-auth"));
        assert!(explain_lists_topic(&stdout, "pull-reliability"));
    } else {
        assert!(!explain_lists_topic(&stdout, "pull"));
        assert!(!explain_lists_topic(&stdout, "pull-auth"));
        assert!(!explain_lists_topic(&stdout, "pull-reliability"));
    }
}

#[test]
fn explain_exec_prints_workflow() {
    tsafe()
        .args(["explain", "exec"])
        .assert()
        .success()
        .stdout(contains("dry-run"))
        .stdout(contains("whole vault"))
        .stdout(contains("stripped"))
        .stdout(contains("abort the spawn"))
        .stdout(contains("--"));
}

#[cfg_attr(
    not(all(feature = "cloud-pull-aws", feature = "cloud-pull-gcp")),
    ignore = "requires cloud-pull-aws and cloud-pull-gcp features"
)]
#[test]
fn explain_pull_prints_sources() {
    tsafe()
        .args(["explain", "pull"])
        .assert()
        .success()
        .stdout(contains("local-first runtime authority"))
        .stdout(contains("Cloud providers are read-only"))
        .stdout(contains("sources — secrets are synced in"))
        .stdout(contains("Nothing is written back to the cloud"))
        .stdout(contains("tsafe exec scopes them to one process"))
        .stdout(contains("aws-pull"))
        .stdout(contains("gcp-pull"))
        .stdout(contains("ssm-pull"))
        .stdout(contains("kv-pull"))
        .stdout(contains(".tsafe.yml"));
}

#[cfg_attr(not(feature = "agent"), ignore = "requires agent feature")]
#[test]
fn explain_agent_prints_temporary_local_session_boundary() {
    tsafe()
        .args(["explain", "agent"])
        .assert()
        .success()
        .stdout(contains("starts a session (TTL"))
        .stdout(contains("agent socket"))
        .stdout(contains("without typing the master"))
        .stdout(contains("tsafe agent lock"));
}

#[cfg_attr(
    not(all(
        feature = "cloud-pull-aws",
        feature = "cloud-pull-gcp",
        feature = "cloud-pull-vault"
    )),
    ignore = "requires cloud-pull-aws, cloud-pull-gcp, and cloud-pull-vault features"
)]
#[test]
fn explain_pull_auth_prints_provider_credentials() {
    tsafe()
        .args(["explain", "pull-auth"])
        .assert()
        .success()
        .stdout(contains("AWS_ACCESS_KEY_ID"))
        .stdout(contains("GOOGLE_CLOUD_PROJECT"))
        .stdout(contains("AZURE_TENANT_ID"))
        .stdout(contains("VAULT_TOKEN"));
}

#[cfg_attr(
    not(any(
        feature = "akv-pull",
        feature = "cloud-pull-aws",
        feature = "cloud-pull-gcp",
        feature = "cloud-pull-vault",
        feature = "cloud-pull-1password",
        feature = "cloud-pull-bitwarden",
        feature = "cloud-pull-keepass",
        feature = "multi-pull"
    )),
    ignore = "requires a pull feature"
)]
#[test]
fn explain_pull_reliability_prints_error_modes() {
    tsafe()
        .args(["explain", "pull-reliability"])
        .assert()
        .success()
        .stdout(contains("--on-error fail-all"))
        .stdout(contains("--on-error skip-failed"))
        .stdout(contains("HTTP 429"));
}

#[test]
fn explain_contracts_prints_manifest_shape() {
    tsafe()
        .args(["explain", "contracts"])
        .assert()
        .success()
        .stdout(contains("allowed_secrets"))
        .stdout(contains("allowed_targets"))
        .stdout(contains("trust_level"))
        .stdout(contains("inherit"))
        .stdout(contains("deny_dangerous_env"))
        .stdout(contains("redact_output"))
        .stdout(contains("cannot widen"));
}

#[test]
fn explain_vault_recovery_prints_recovery_paths() {
    tsafe()
        .args(["explain", "vault-recovery"])
        .assert()
        .success()
        .stdout(contains("biometric"))
        .stdout(contains("TSAFE_PASSWORD"));
}

#[test]
fn explain_unknown_topic_fails() {
    tsafe().args(["explain", "nope"]).assert().failure();
}