bijux-dag-app 0.4.1

Application orchestration and response-shaping layer for Bijux DAG command surfaces.
Documentation
use crate::ExitCode;
use bijux_dag_core::Graph;
use bijux_dag_runtime::{build_policy_enforcement_report, CacheMode, RuntimeConfig};
use serde_json::{json, Value};

pub(crate) fn policy_surface_payload(
    graph: &Graph,
    options: &RuntimeConfig,
    hermetic: bool,
) -> Result<Value, ExitCode> {
    let enforcement =
        build_policy_enforcement_report(graph, options).map_err(|_| ExitCode::from(3))?;
    Ok(json!({
        "profile": hermetic_profile_payload(hermetic),
        "enforcement": enforcement,
    }))
}

pub(crate) fn hermetic_profile_payload(hermetic: bool) -> Value {
    if hermetic {
        return json!({
            "enabled": true,
            "mode": "best_effort_local_policy_profile",
            "summary": "forces deny-network, deny-clock, and clean-env for local execution",
            "limitations": [
                "shell execution still relies on declared-effect gates and environment shaping",
                "hermetic mode does not claim syscall sandboxing or host filesystem isolation"
            ]
        });
    }

    json!({
        "enabled": false,
        "mode": "explicit_policy_flags",
        "summary": "uses only the policy flags requested by the operator plus the default clean environment",
        "limitations": []
    })
}

pub(crate) fn replay_sandbox_scope_payload(sandbox: bool) -> Value {
    if sandbox {
        return json!({
            "enabled": true,
            "mode": "source_run_write_boundary",
            "summary": "forbids replay outputs from being written inside the source run directory",
            "limitations": [
                "sandbox mode does not create a process sandbox for replay execution",
                "sandbox mode does not claim network, clock, or filesystem syscall isolation"
            ]
        });
    }

    json!({
        "enabled": false,
        "mode": "standard",
        "summary": "replay uses the requested output directory without the source-run write boundary",
        "limitations": []
    })
}

pub(crate) fn cache_surface_payload(options: &RuntimeConfig) -> Value {
    let read_order = if options.remote_cache_dir.is_some() && options.cache_dir.is_some() {
        vec!["local", "shared"]
    } else if options.remote_cache_dir.is_some() {
        vec!["shared"]
    } else if options.cache_dir.is_some() {
        vec!["local"]
    } else {
        Vec::new()
    };
    let write_targets = if matches!(options.cache_mode, CacheMode::ReadWrite) {
        if options.remote_cache_dir.is_some() && options.cache_dir.is_some() {
            vec!["local", "shared"]
        } else if options.remote_cache_dir.is_some() {
            vec!["shared"]
        } else if options.cache_dir.is_some() {
            vec!["local"]
        } else {
            Vec::new()
        }
    } else {
        Vec::new()
    };
    json!({
        "mode": match options.cache_mode {
            CacheMode::Off => "off",
            CacheMode::Read => "read",
            CacheMode::ReadWrite => "readwrite",
        },
        "local_dir": options.cache_dir.as_ref().map(|path| path.display().to_string()),
        "shared_dir": options.remote_cache_dir.as_ref().map(|path| path.display().to_string()),
        "read_order": read_order,
        "write_targets": write_targets,
    })
}