Skip to main content

start_command/
isolation_metadata.rs

1//! Metadata helpers for isolated executions.
2//!
3//! Builds the human-readable `[Isolation]` status lines and the execution
4//! record options map that describe how an isolated command was launched,
5//! including the configurable Docker runtime options (volumes, mounts,
6//! environment variables, privileged mode). Kept separate from `isolation`
7//! so the runtime backends and the metadata representation can evolve
8//! independently.
9
10use crate::args_parser::WrapperOptions;
11use std::collections::HashMap;
12
13/// Build the human-readable `[Isolation]` status lines for docker runtime
14/// options (volumes, mounts, env, privileged). Used for the start block and
15/// log header; empty collections contribute no lines.
16pub fn docker_runtime_status_lines(
17    volumes: &[String],
18    mounts: &[String],
19    env: &[String],
20    privileged: bool,
21) -> Vec<String> {
22    let mut lines = Vec::new();
23    if !volumes.is_empty() {
24        lines.push(format!("[Isolation] Volumes: {}", volumes.join(", ")));
25    }
26    if !mounts.is_empty() {
27        lines.push(format!("[Isolation] Mounts: {}", mounts.join(", ")));
28    }
29    if !env.is_empty() {
30        lines.push(format!("[Isolation] Env: {}", env.join(", ")));
31    }
32    if privileged {
33        lines.push("[Isolation] Privileged: true".to_string());
34    }
35    lines
36}
37
38/// Build the execution-record metadata entries for docker runtime options.
39/// Returns `(key, value)` pairs to merge into the options map; empty
40/// collections and a false `privileged` flag contribute no entries.
41pub fn docker_runtime_metadata(
42    volumes: &[String],
43    mounts: &[String],
44    env: &[String],
45    privileged: bool,
46) -> Vec<(String, serde_json::Value)> {
47    let arr = |items: &[String]| {
48        serde_json::Value::Array(
49            items
50                .iter()
51                .map(|s| serde_json::Value::String(s.clone()))
52                .collect(),
53        )
54    };
55    let mut entries = Vec::new();
56    if !volumes.is_empty() {
57        entries.push(("volumes".to_string(), arr(volumes)));
58    }
59    if !mounts.is_empty() {
60        entries.push(("mounts".to_string(), arr(mounts)));
61    }
62    if !env.is_empty() {
63        entries.push(("env".to_string(), arr(env)));
64    }
65    if privileged {
66        entries.push(("privileged".to_string(), serde_json::Value::Bool(true)));
67    }
68    entries
69}
70
71/// Build the execution-record options map describing how an isolated command
72/// was launched (environment, mode, session, image, docker runtime options,
73/// endpoint, user, keep-alive). Used to persist the execution record so it can
74/// be surfaced via `--status`/`--list`.
75pub fn build_isolation_options_map(
76    environment: Option<&str>,
77    mode: &str,
78    session_name: &str,
79    effective_image: Option<&str>,
80    options: &WrapperOptions,
81    created_user: Option<&str>,
82) -> HashMap<String, serde_json::Value> {
83    let str_val = |s: &str| serde_json::Value::String(s.to_string());
84    let mut opts_map = HashMap::new();
85    if let Some(env) = environment {
86        opts_map.insert("isolated".to_string(), str_val(env));
87    }
88    opts_map.insert("isolationMode".to_string(), str_val(mode));
89    opts_map.insert("sessionName".to_string(), str_val(session_name));
90    if let Some(v) = effective_image {
91        opts_map.insert("image".to_string(), str_val(v));
92    }
93    for (k, v) in docker_runtime_metadata(
94        &options.volumes,
95        &options.mounts,
96        &options.env,
97        options.privileged,
98    ) {
99        opts_map.insert(k, v);
100    }
101    if let Some(v) = &options.endpoint {
102        opts_map.insert("endpoint".to_string(), str_val(v));
103    }
104    if let Some(v) = created_user {
105        opts_map.insert("user".to_string(), str_val(v));
106    }
107    opts_map.insert(
108        "keepAlive".to_string(),
109        serde_json::Value::Bool(options.keep_alive),
110    );
111    opts_map
112}
113
114#[cfg(test)]
115#[path = "isolation_metadata_cases.rs"]
116mod tests;