periplon 0.2.0

Rust SDK for building multi-agent AI workflows and automation
Documentation
/// Integration test to verify bash commands execute without permission prompts
/// when using bypassPermissions mode in DSL workflows
use periplon_sdk::dsl::parser::parse_workflow;
use periplon_sdk::dsl::validator::validate_workflow;
use std::fs;
use std::path::Path;

#[tokio::test]
#[ignore] // Run with: cargo test --test bash_permissions_test -- --ignored --nocapture
async fn test_bash_commands_without_permission_prompts() {
    // Load the test workflow
    let workflow_path = "test_bash_permissions.yaml";

    // Verify the workflow file exists
    assert!(
        Path::new(workflow_path).exists(),
        "Test workflow file not found: {}",
        workflow_path
    );

    // Parse the workflow
    let yaml_content = fs::read_to_string(workflow_path).expect("Failed to read workflow file");

    let workflow = parse_workflow(&yaml_content).expect("Failed to parse workflow");

    // Validate the workflow
    validate_workflow(&workflow).expect("Workflow validation failed");

    // Verify the agent has bypassPermissions mode
    let bash_agent = workflow
        .agents
        .get("bash_agent")
        .expect("bash_agent not found in workflow");

    assert_eq!(
        bash_agent.permissions.mode, "bypassPermissions",
        "Agent should have bypassPermissions mode"
    );

    println!("✓ Workflow loaded and validated successfully");
    println!("✓ Agent configured with bypassPermissions mode");
    println!("\nNOTE: This test verifies configuration only.");
    println!("To fully test non-interactive execution:");
    println!("  1. Run: cargo run --bin dsl-executor run test_bash_permissions.yaml");
    println!("  2. Verify no permission prompts appear");
    println!("  3. Verify tasks execute bash commands successfully");
}

#[tokio::test]
#[ignore] // Run with: cargo test --test bash_permissions_test test_permission_modes -- --ignored --nocapture
async fn test_permission_modes() {
    // Test that all permission modes are correctly parsed
    let test_cases = vec![
        ("default", "default"),
        ("acceptEdits", "acceptEdits"),
        ("plan", "plan"),
        ("bypassPermissions", "bypassPermissions"),
    ];

    for (mode, expected) in test_cases {
        let yaml = format!(
            r#"
name: "Permission Test"
version: "1.0.0"

agents:
  test_agent:
    description: "Test agent"
    permissions:
      mode: "{}"
    tools:
      - Bash

tasks:
  test_task:
    description: "Test task"
    agent: test_agent
"#,
            mode
        );

        let workflow = parse_workflow(&yaml)
            .unwrap_or_else(|_| panic!("Failed to parse workflow with mode: {}", mode));

        let agent = workflow
            .agents
            .get("test_agent")
            .expect("test_agent not found");

        assert_eq!(
            agent.permissions.mode, expected,
            "Permission mode mismatch for: {}",
            mode
        );

        println!("✓ Permission mode '{}' parsed correctly", mode);
    }
}

#[test]
fn test_bypass_permissions_in_agent_options() {
    // Test that bypassPermissions mode is correctly converted to AgentOptions
    use periplon_sdk::dsl::schema::{AgentSpec, PermissionsSpec};

    let agent_spec = AgentSpec {
        description: "Test agent with bypass permissions".to_string(),
        provider: None,
        model: None,
        system_prompt: None,
        cwd: None,
        create_cwd: None,
        inputs: Default::default(),
        outputs: Default::default(),
        tools: vec!["Bash".to_string()],
        permissions: PermissionsSpec {
            mode: "bypassPermissions".to_string(),
            allowed_directories: vec![],
        },
        max_turns: None,
    };

    // Verify the permission mode is set correctly
    assert_eq!(agent_spec.permissions.mode, "bypassPermissions");
    println!("✓ AgentSpec with bypassPermissions mode created successfully");
}

#[test]
#[ignore] // Missing test_bash_permissions.yaml file
fn test_workflow_structure_for_bash_tasks() {
    use periplon_sdk::dsl::parser::parse_workflow;
    use std::fs;

    // Load and parse the test workflow
    let yaml_content =
        fs::read_to_string("test_bash_permissions.yaml").expect("Failed to read test workflow");

    let workflow = parse_workflow(&yaml_content).expect("Failed to parse workflow");

    // Verify workflow structure
    assert_eq!(workflow.name, "Test Bash Permissions");
    assert_eq!(workflow.version, "1.0.0");

    // Verify agent configuration
    assert!(
        workflow.agents.contains_key("bash_agent"),
        "bash_agent not found"
    );
    let agent = &workflow.agents["bash_agent"];
    assert_eq!(agent.permissions.mode, "bypassPermissions");
    assert!(
        agent.tools.contains(&"Bash".to_string()),
        "Bash tool not enabled"
    );

    // Verify tasks exist
    assert!(
        workflow.tasks.contains_key("test_basic_bash"),
        "test_basic_bash task not found"
    );

    // Verify the task has the bash_agent assigned
    let task = &workflow.tasks["test_basic_bash"];
    assert_eq!(
        task.agent,
        Some("bash_agent".to_string()),
        "Task should use bash_agent"
    );

    // Verify the task has an output file configured
    assert_eq!(
        task.output,
        Some("test_results.txt".to_string()),
        "Task should have output file configured"
    );

    println!("✓ Workflow structure verified");
    println!("✓ All tasks configured with bash_agent");
    println!("✓ Task dependencies configured correctly");
}