Skip to main content

microsandbox_image/
config.rs

1//! OCI image configuration parsing.
2
3use std::collections::HashMap;
4
5use crate::error::ImageError;
6
7//--------------------------------------------------------------------------------------------------
8// Types
9//--------------------------------------------------------------------------------------------------
10
11/// Runtime configuration parsed from an OCI image config blob.
12///
13/// These are defaults — `SandboxBuilder` fields override them.
14/// Fields are `Option` where the OCI spec allows omission.
15#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
16pub struct ImageConfig {
17    /// Environment variables (`KEY=VALUE` format).
18    pub env: Vec<String>,
19
20    /// Default command.
21    pub cmd: Option<Vec<String>>,
22
23    /// Entrypoint.
24    pub entrypoint: Option<Vec<String>>,
25
26    /// Working directory for the default process.
27    pub working_dir: Option<String>,
28
29    /// Default user (`uid`, `uid:gid`, `username`, or `username:group`).
30    pub user: Option<String>,
31
32    /// Ports the image declares as exposed (informational only).
33    pub exposed_ports: Vec<String>,
34
35    /// Volume mount points declared by the image (informational).
36    pub volumes: Vec<String>,
37
38    /// Image labels (key-value metadata).
39    pub labels: HashMap<String, String>,
40
41    /// Signal to send for graceful shutdown (e.g., `SIGTERM`).
42    pub stop_signal: Option<String>,
43}
44
45//--------------------------------------------------------------------------------------------------
46// Methods
47//--------------------------------------------------------------------------------------------------
48
49impl ImageConfig {
50    /// Parse from raw OCI config JSON bytes, returning the config and diff_ids.
51    pub fn parse(bytes: &[u8]) -> Result<(Self, Vec<String>), ImageError> {
52        let oci_config: oci_spec::image::ImageConfiguration = serde_json::from_slice(bytes)
53            .map_err(|e| ImageError::ConfigParse(format!("failed to parse image config: {e}")))?;
54
55        let config = oci_config.config();
56
57        let image_config = Self {
58            env: config
59                .as_ref()
60                .and_then(|c| c.env().clone())
61                .unwrap_or_default(),
62            cmd: config.as_ref().and_then(|c| c.cmd().clone()),
63            entrypoint: config.as_ref().and_then(|c| c.entrypoint().clone()),
64            working_dir: config.as_ref().and_then(|c| c.working_dir().clone()),
65            user: config.as_ref().and_then(|c| c.user().clone()),
66            exposed_ports: config
67                .as_ref()
68                .and_then(|c| c.exposed_ports().clone())
69                .unwrap_or_default(),
70            volumes: config
71                .as_ref()
72                .and_then(|c| c.volumes().clone())
73                .unwrap_or_default(),
74            labels: config
75                .as_ref()
76                .and_then(|c| c.labels().as_ref())
77                .cloned()
78                .unwrap_or_default(),
79            stop_signal: config.as_ref().and_then(|c| c.stop_signal().clone()),
80        };
81
82        let diff_ids = oci_config.rootfs().diff_ids().to_vec();
83
84        Ok((image_config, diff_ids))
85    }
86}