rash_core 2.20.0

Declarative shell scripting using Rust native bindings
Documentation
use crate::cli::modules::run_test;
use std::fs;
use tempfile::tempdir;

#[test]
fn test_sudoers_check_mode() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Allow nginx to restart service
  sudoers:
    name: nginx-service
    user: nginx
    commands: /usr/sbin/service nginx restart
    nopassword: true
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff", "--check"];
    let (stdout, stderr) = run_test(&script_text, &args);

    assert!(stderr.is_empty());
    assert!(stdout.contains("changed:"));
    assert!(stdout.contains("NOPASSWD"));
}

#[test]
fn test_sudoers_add_rule() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Allow nginx to restart service
  sudoers:
    name: nginx-service
    user: nginx
    commands: /usr/sbin/service nginx restart
    nopassword: true
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff"];
    let (stdout, stderr) = run_test(&script_text, &args);

    assert!(stderr.is_empty());
    assert!(stdout.contains("changed:"));

    let rule_path = sudoers_path.join("nginx-service");
    assert!(rule_path.exists());

    let content = fs::read_to_string(&rule_path).unwrap();
    assert!(content.contains("nginx"));
    assert!(content.contains("NOPASSWD"));
}

#[test]
fn test_sudoers_no_change() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");
    fs::create_dir_all(&sudoers_path).unwrap();

    let rule_path = sudoers_path.join("nginx-service");
    fs::write(
        &rule_path,
        "nginx ALL=(ALL) NOPASSWD: /usr/sbin/service nginx restart\n",
    )
    .unwrap();

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Allow nginx to restart service
  sudoers:
    name: nginx-service
    user: nginx
    commands: /usr/sbin/service nginx restart
    nopassword: true
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff"];
    let (stdout, stderr) = run_test(&script_text, &args);

    assert!(stderr.is_empty());
    assert!(!stdout.contains("changed:"));
}

#[test]
fn test_sudoers_remove_rule() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");
    fs::create_dir_all(&sudoers_path).unwrap();

    let rule_path = sudoers_path.join("nginx-service");
    fs::write(
        &rule_path,
        "nginx ALL=(ALL) NOPASSWD: /usr/sbin/service nginx restart\n",
    )
    .unwrap();

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Remove nginx sudoers rule
  sudoers:
    name: nginx-service
    user: nginx
    commands: /usr/sbin/service nginx restart
    state: absent
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff"];
    let (stdout, stderr) = run_test(&script_text, &args);

    assert!(stderr.is_empty());
    assert!(stdout.contains("changed:"));
    assert!(!rule_path.exists());
}

#[test]
fn test_sudoers_multiple_commands() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Allow nginx multiple commands
  sudoers:
    name: nginx-service
    user: nginx
    commands:
      - /usr/sbin/service nginx restart
      - /usr/sbin/service nginx status
    nopassword: true
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff"];
    let (stdout, stderr) = run_test(&script_text, &args);

    assert!(stderr.is_empty());
    assert!(stdout.contains("changed:"));

    let rule_path = sudoers_path.join("nginx-service");
    let content = fs::read_to_string(&rule_path).unwrap();
    assert!(content.contains("/usr/sbin/service nginx restart"));
    assert!(content.contains("/usr/sbin/service nginx status"));
}

#[test]
fn test_sudoers_group_user() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Allow developers group docker access
  sudoers:
    name: docker-developers
    user: "%developers"
    commands: /usr/bin/docker
    nopassword: true
    setenv: true
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff"];
    let (stdout, stderr) = run_test(&script_text, &args);

    assert!(stderr.is_empty());
    assert!(stdout.contains("changed:"));

    let rule_path = sudoers_path.join("docker-developers");
    let content = fs::read_to_string(&rule_path).unwrap();
    assert!(content.contains("%developers"));
    assert!(content.contains("NOPASSWD"));
    assert!(content.contains("SETENV"));
}

#[test]
fn test_sudoers_invalid_name_dot() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Invalid sudoers name
  sudoers:
    name: nginx.service
    user: nginx
    commands: /usr/sbin/service nginx restart
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff"];
    let (_stdout, stderr) = run_test(&script_text, &args);

    assert!(!stderr.is_empty());
    assert!(stderr.contains("periods"));
}

#[test]
fn test_sudoers_all_commands() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Allow admin all commands
  sudoers:
    name: admin-user
    user: admin
    commands: ALL
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff"];
    let (stdout, stderr) = run_test(&script_text, &args);

    assert!(stderr.is_empty());
    assert!(stdout.contains("changed:"));

    let rule_path = sudoers_path.join("admin-user");
    let content = fs::read_to_string(&rule_path).unwrap();
    assert!(content.contains("admin ALL=(ALL) ALL"));
}

#[test]
fn test_sudoers_diff_output() {
    let dir = tempdir().unwrap();
    let sudoers_path = dir.path().join("sudoers.d");
    fs::create_dir_all(&sudoers_path).unwrap();

    let rule_path = sudoers_path.join("nginx-service");
    fs::write(
        &rule_path,
        "nginx ALL=(ALL) NOPASSWD: /usr/sbin/service nginx status\n",
    )
    .unwrap();

    let script_text = format!(
        r#"
#!/usr/bin/env rash
- name: Modify nginx sudoers rule
  sudoers:
    name: nginx-service
    user: nginx
    commands: /usr/sbin/service nginx restart
    nopassword: true
    sudoers_path: {}
        "#,
        sudoers_path.display()
    );

    let args = ["--diff", "--check"];
    let (stdout, stderr) = run_test(&script_text, &args);

    assert!(stderr.is_empty());
    assert!(stdout.contains("-") || stdout.contains("+"));
}