@opencode-cloud/core 1.0.10 → 3.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +3 -3
- package/README.md +49 -30
- package/package.json +1 -1
- package/src/config/schema.rs +91 -0
- package/src/docker/Dockerfile +105 -84
- package/src/docker/README.dockerhub.md +39 -0
- package/src/docker/container.rs +114 -3
- package/src/docker/dockerfile.rs +15 -12
- package/src/docker/mod.rs +25 -4
- package/src/docker/mount.rs +330 -0
- package/src/docker/state.rs +120 -0
- package/src/host/ssh_config.rs +1 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//! Image state tracking for provenance information
|
|
2
|
+
//!
|
|
3
|
+
//! Tracks where the current Docker image came from (prebuilt or built)
|
|
4
|
+
//! and which registry it was pulled from.
|
|
5
|
+
|
|
6
|
+
use chrono::Utc;
|
|
7
|
+
use serde::{Deserialize, Serialize};
|
|
8
|
+
use std::path::PathBuf;
|
|
9
|
+
|
|
10
|
+
/// Image provenance state
|
|
11
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
12
|
+
pub struct ImageState {
|
|
13
|
+
/// Image version (e.g., "1.0.12")
|
|
14
|
+
pub version: String,
|
|
15
|
+
/// Source: "prebuilt" or "build"
|
|
16
|
+
pub source: String,
|
|
17
|
+
/// Registry if prebuilt: "ghcr.io" or "docker.io", None for build
|
|
18
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
19
|
+
pub registry: Option<String>,
|
|
20
|
+
/// When the image was acquired (ISO8601)
|
|
21
|
+
pub acquired_at: String,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
impl ImageState {
|
|
25
|
+
/// Create a new ImageState for a prebuilt image
|
|
26
|
+
pub fn prebuilt(version: &str, registry: &str) -> Self {
|
|
27
|
+
Self {
|
|
28
|
+
version: version.to_string(),
|
|
29
|
+
source: "prebuilt".to_string(),
|
|
30
|
+
registry: Some(registry.to_string()),
|
|
31
|
+
acquired_at: Utc::now().to_rfc3339(),
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Create a new ImageState for a locally built image
|
|
36
|
+
pub fn built(version: &str) -> Self {
|
|
37
|
+
Self {
|
|
38
|
+
version: version.to_string(),
|
|
39
|
+
source: "build".to_string(),
|
|
40
|
+
registry: None,
|
|
41
|
+
acquired_at: Utc::now().to_rfc3339(),
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// Get the path to the image state file
|
|
47
|
+
pub fn get_state_path() -> Option<PathBuf> {
|
|
48
|
+
crate::config::paths::get_data_dir().map(|p| p.join("image-state.json"))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Save image state to disk
|
|
52
|
+
pub fn save_state(state: &ImageState) -> anyhow::Result<()> {
|
|
53
|
+
let path = get_state_path().ok_or_else(|| anyhow::anyhow!("Could not determine state path"))?;
|
|
54
|
+
|
|
55
|
+
// Ensure parent directory exists
|
|
56
|
+
if let Some(parent) = path.parent() {
|
|
57
|
+
std::fs::create_dir_all(parent)?;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let json = serde_json::to_string_pretty(state)?;
|
|
61
|
+
std::fs::write(&path, json)?;
|
|
62
|
+
Ok(())
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Load image state from disk
|
|
66
|
+
pub fn load_state() -> Option<ImageState> {
|
|
67
|
+
let path = get_state_path()?;
|
|
68
|
+
let content = std::fs::read_to_string(&path).ok()?;
|
|
69
|
+
serde_json::from_str(&content).ok()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// Clear image state (e.g., after image removal)
|
|
73
|
+
pub fn clear_state() -> anyhow::Result<()> {
|
|
74
|
+
if let Some(path) = get_state_path() {
|
|
75
|
+
if path.exists() {
|
|
76
|
+
std::fs::remove_file(&path)?;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
Ok(())
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#[cfg(test)]
|
|
83
|
+
mod tests {
|
|
84
|
+
use super::*;
|
|
85
|
+
|
|
86
|
+
#[test]
|
|
87
|
+
fn test_image_state_prebuilt() {
|
|
88
|
+
let state = ImageState::prebuilt("1.0.12", "ghcr.io");
|
|
89
|
+
assert_eq!(state.version, "1.0.12");
|
|
90
|
+
assert_eq!(state.source, "prebuilt");
|
|
91
|
+
assert_eq!(state.registry, Some("ghcr.io".to_string()));
|
|
92
|
+
assert!(!state.acquired_at.is_empty());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#[test]
|
|
96
|
+
fn test_image_state_built() {
|
|
97
|
+
let state = ImageState::built("1.0.12");
|
|
98
|
+
assert_eq!(state.version, "1.0.12");
|
|
99
|
+
assert_eq!(state.source, "build");
|
|
100
|
+
assert!(state.registry.is_none());
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
#[test]
|
|
104
|
+
fn test_image_state_serialize_deserialize() {
|
|
105
|
+
let state = ImageState::prebuilt("1.0.12", "docker.io");
|
|
106
|
+
let json = serde_json::to_string(&state).unwrap();
|
|
107
|
+
let parsed: ImageState = serde_json::from_str(&json).unwrap();
|
|
108
|
+
assert_eq!(state.version, parsed.version);
|
|
109
|
+
assert_eq!(state.source, parsed.source);
|
|
110
|
+
assert_eq!(state.registry, parsed.registry);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#[test]
|
|
114
|
+
fn test_get_state_path() {
|
|
115
|
+
let path = get_state_path();
|
|
116
|
+
assert!(path.is_some());
|
|
117
|
+
let p = path.unwrap();
|
|
118
|
+
assert!(p.to_string_lossy().contains("image-state.json"));
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/host/ssh_config.rs
CHANGED