@opencode-cloud/core 10.4.0 → 12.0.0
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 +2 -2
- package/package.json +1 -1
- package/src/config/validation.rs +18 -18
- package/src/docker/Dockerfile +62 -58
- package/src/docker/README.dockerhub.md +2 -2
- package/src/docker/image.rs +1 -1
- package/src/docker/progress.rs +8 -8
- package/src/docker/state.rs +4 -4
- package/src/host/provision.rs +9 -9
- package/src/host/schema.rs +4 -4
- package/src/host/ssh_config.rs +18 -18
- package/src/host/storage.rs +5 -5
package/Cargo.toml
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "opencode-cloud-core"
|
|
3
|
-
version = "
|
|
3
|
+
version = "12.0.0"
|
|
4
4
|
edition = "2024"
|
|
5
|
-
rust-version = "1.
|
|
5
|
+
rust-version = "1.89"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
repository = "https://github.com/pRizz/opencode-cloud"
|
|
8
8
|
homepage = "https://github.com/pRizz/opencode-cloud"
|
package/package.json
CHANGED
package/src/config/validation.rs
CHANGED
|
@@ -96,26 +96,26 @@ pub fn validate_config(config: &Config) -> Result<Vec<ValidationWarning>, Valida
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
// Legacy auth fields present
|
|
99
|
-
if let Some(ref username) = config.auth_username
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
99
|
+
if let Some(ref username) = config.auth_username
|
|
100
|
+
&& !username.is_empty()
|
|
101
|
+
{
|
|
102
|
+
warnings.push(ValidationWarning {
|
|
103
|
+
field: "auth_username".to_string(),
|
|
104
|
+
message: "Legacy auth fields present; consider using 'occ user add' instead"
|
|
105
|
+
.to_string(),
|
|
106
|
+
fix_command: "occ config set auth_username ''".to_string(),
|
|
107
|
+
});
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
if let Some(ref password) = config.auth_password
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
110
|
+
if let Some(ref password) = config.auth_password
|
|
111
|
+
&& !password.is_empty()
|
|
112
|
+
{
|
|
113
|
+
warnings.push(ValidationWarning {
|
|
114
|
+
field: "auth_password".to_string(),
|
|
115
|
+
message: "Legacy auth fields present; consider using 'occ user add' instead"
|
|
116
|
+
.to_string(),
|
|
117
|
+
fix_command: "occ config set auth_password ''".to_string(),
|
|
118
|
+
});
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
Ok(warnings)
|
package/src/docker/Dockerfile
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# A comprehensive development environment for AI-assisted coding with opencode.
|
|
5
5
|
#
|
|
6
6
|
# Features:
|
|
7
|
-
# - Ubuntu
|
|
7
|
+
# - Ubuntu 25.10 (questing) base
|
|
8
8
|
# - Non-root user with passwordless sudo
|
|
9
9
|
# - Multiple languages via mise (Node.js, Python, Rust, Go)
|
|
10
10
|
# - Modern CLI tools (ripgrep, eza, fzf, lazygit, etc.)
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
# - Self-managing installers (mise, rustup, etc.) trusted to handle versions
|
|
27
27
|
#
|
|
28
28
|
# To check for updates: just check-updates
|
|
29
|
-
# Last version audit: 2026-
|
|
29
|
+
# Last version audit: 2026-02-03
|
|
30
30
|
# -----------------------------------------------------------------------------
|
|
31
31
|
|
|
32
32
|
# -----------------------------------------------------------------------------
|
|
33
33
|
# Stage 1: Base
|
|
34
34
|
# -----------------------------------------------------------------------------
|
|
35
|
-
FROM ubuntu:
|
|
35
|
+
FROM ubuntu:25.10 AS base
|
|
36
36
|
|
|
37
37
|
# OCI Labels for image metadata
|
|
38
38
|
LABEL org.opencontainers.image.title="opencode-cloud"
|
|
@@ -45,7 +45,7 @@ LABEL org.opencontainers.image.url="https://github.com/pRizz/opencode-cloud"
|
|
|
45
45
|
LABEL org.opencontainers.image.source="https://github.com/pRizz/opencode-cloud"
|
|
46
46
|
LABEL org.opencontainers.image.vendor="pRizz"
|
|
47
47
|
LABEL org.opencontainers.image.licenses="MIT"
|
|
48
|
-
LABEL org.opencontainers.image.base.name="ubuntu:
|
|
48
|
+
LABEL org.opencontainers.image.base.name="ubuntu:25.10"
|
|
49
49
|
|
|
50
50
|
# Environment configuration
|
|
51
51
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
@@ -58,7 +58,7 @@ ENV LC_ALL=C.UTF-8
|
|
|
58
58
|
# -----------------------------------------------------------------------------
|
|
59
59
|
# Install core system packages in logical groups for better caching
|
|
60
60
|
|
|
61
|
-
# Group 1: Core utilities and build tools (2026-
|
|
61
|
+
# Group 1: Core utilities and build tools (2026-02-03)
|
|
62
62
|
# Use BuildKit cache mount for APT package lists and cache
|
|
63
63
|
RUN --mount=type=cache,target=/var/lib/apt/lists \
|
|
64
64
|
--mount=type=cache,target=/var/cache/apt \
|
|
@@ -67,51 +67,51 @@ RUN --mount=type=cache,target=/var/lib/apt/lists \
|
|
|
67
67
|
tini=0.19.* \
|
|
68
68
|
dumb-init=1.2.* \
|
|
69
69
|
# systemd for Cockpit support
|
|
70
|
-
systemd=
|
|
71
|
-
systemd-sysv=
|
|
72
|
-
dbus=1.
|
|
70
|
+
systemd=257.* \
|
|
71
|
+
systemd-sysv=257.* \
|
|
72
|
+
dbus=1.16.* \
|
|
73
73
|
# Shell and terminal
|
|
74
74
|
zsh=5.9-* \
|
|
75
|
-
tmux=3.
|
|
75
|
+
tmux=3.5a-* \
|
|
76
76
|
# Editors
|
|
77
77
|
vim=2:9.1.* \
|
|
78
|
-
neovim=0.
|
|
79
|
-
nano=
|
|
78
|
+
neovim=0.10.* \
|
|
79
|
+
nano=8.4-* \
|
|
80
80
|
# Build essentials
|
|
81
81
|
build-essential=12.* \
|
|
82
82
|
pkg-config=1.8.* \
|
|
83
|
-
cmake=3.
|
|
83
|
+
cmake=3.31.* \
|
|
84
84
|
# Version control
|
|
85
|
-
git=1:2.
|
|
86
|
-
git-lfs=3.
|
|
85
|
+
git=1:2.51.* \
|
|
86
|
+
git-lfs=3.6.* \
|
|
87
87
|
# Core utilities
|
|
88
|
-
curl=8.
|
|
89
|
-
wget=1.
|
|
88
|
+
curl=8.14.* \
|
|
89
|
+
wget=1.25.* \
|
|
90
90
|
# UNPINNED: ca-certificates - security-critical root certs, needs auto-updates
|
|
91
91
|
ca-certificates \
|
|
92
92
|
# UNPINNED: gnupg - key management security, needs auto-updates
|
|
93
93
|
gnupg \
|
|
94
94
|
lsb-release=12.* \
|
|
95
|
-
software-properties-common=0.
|
|
95
|
+
software-properties-common=0.114* \
|
|
96
96
|
sudo=1.9.* \
|
|
97
97
|
# UNPINNED: openssh-client - security-critical, needs auto-updates
|
|
98
98
|
openssh-client \
|
|
99
99
|
# Process/system tools
|
|
100
|
-
htop=3.
|
|
100
|
+
htop=3.4.* \
|
|
101
101
|
procps=2:4.0.* \
|
|
102
|
-
less=
|
|
103
|
-
file=1:5.
|
|
104
|
-
tree=2.
|
|
102
|
+
less=668-* \
|
|
103
|
+
file=1:5.46-* \
|
|
104
|
+
tree=2.2.* \
|
|
105
105
|
# JSON/YAML processing
|
|
106
|
-
jq=1.
|
|
106
|
+
jq=1.8.* \
|
|
107
107
|
# Network tools
|
|
108
|
-
netcat-openbsd=1.
|
|
109
|
-
iputils-ping=3:
|
|
110
|
-
dnsutils=1:9.
|
|
108
|
+
netcat-openbsd=1.229-* \
|
|
109
|
+
iputils-ping=3:20240905-* \
|
|
110
|
+
bind9-dnsutils=1:9.20.* \
|
|
111
111
|
# Compression
|
|
112
112
|
zip=3.0-* \
|
|
113
113
|
unzip=6.0-* \
|
|
114
|
-
xz-utils=5.
|
|
114
|
+
xz-utils=5.8.* \
|
|
115
115
|
p7zip-full=16.02* \
|
|
116
116
|
&& rm -rf /var/lib/apt/lists/*
|
|
117
117
|
|
|
@@ -123,32 +123,32 @@ RUN systemctl mask \
|
|
|
123
123
|
systemd-tmpfiles-setup.service \
|
|
124
124
|
systemd-remount-fs.service
|
|
125
125
|
|
|
126
|
-
# Group 2: Database clients (2026-
|
|
126
|
+
# Group 2: Database clients (2026-02-03)
|
|
127
127
|
# Use BuildKit cache mount for APT package lists and cache
|
|
128
128
|
RUN --mount=type=cache,target=/var/lib/apt/lists \
|
|
129
129
|
--mount=type=cache,target=/var/cache/apt \
|
|
130
130
|
apt-get update && apt-get install -y --no-install-recommends \
|
|
131
|
-
sqlite3=3.
|
|
132
|
-
postgresql-client=
|
|
131
|
+
sqlite3=3.46.* \
|
|
132
|
+
postgresql-client=17+* \
|
|
133
133
|
default-mysql-client=1.1.* \
|
|
134
134
|
&& rm -rf /var/lib/apt/lists/*
|
|
135
135
|
|
|
136
|
-
# Group 3: Development libraries for compiling tools (2026-
|
|
136
|
+
# Group 3: Development libraries for compiling tools (2026-02-03)
|
|
137
137
|
# Use BuildKit cache mount for APT package lists and cache
|
|
138
138
|
RUN --mount=type=cache,target=/var/lib/apt/lists \
|
|
139
139
|
--mount=type=cache,target=/var/cache/apt \
|
|
140
140
|
apt-get update && apt-get install -y --no-install-recommends \
|
|
141
141
|
# libssl-dev depends on libssl3t64 with exact version match
|
|
142
|
-
libssl3t64=3.
|
|
143
|
-
libssl-dev=3.
|
|
144
|
-
libffi-dev=3.
|
|
142
|
+
libssl3t64=3.5.* \
|
|
143
|
+
libssl-dev=3.5.* \
|
|
144
|
+
libffi-dev=3.5.* \
|
|
145
145
|
zlib1g-dev=1:1.3.* \
|
|
146
146
|
libbz2-dev=1.0.* \
|
|
147
|
-
libreadline-dev=8.
|
|
148
|
-
libsqlite3-dev=3.
|
|
149
|
-
libncurses-dev=6.
|
|
150
|
-
libpam0g-dev=1.
|
|
151
|
-
liblzma-dev=5.
|
|
147
|
+
libreadline-dev=8.3-* \
|
|
148
|
+
libsqlite3-dev=3.46.* \
|
|
149
|
+
libncurses-dev=6.5+* \
|
|
150
|
+
libpam0g-dev=1.7.* \
|
|
151
|
+
liblzma-dev=5.8.* \
|
|
152
152
|
&& rm -rf /var/lib/apt/lists/*
|
|
153
153
|
|
|
154
154
|
# -----------------------------------------------------------------------------
|
|
@@ -198,16 +198,16 @@ ENV PATH="/home/opencode/.local/bin:${PATH}"
|
|
|
198
198
|
RUN curl https://mise.run | sh \
|
|
199
199
|
&& echo 'eval "$(/home/opencode/.local/bin/mise activate zsh)"' >> /home/opencode/.zshrc
|
|
200
200
|
|
|
201
|
-
# Install language runtimes via mise (2026-
|
|
202
|
-
# - node@
|
|
203
|
-
# - python@3.
|
|
204
|
-
# - go@1.
|
|
205
|
-
RUN /home/opencode/.local/bin/mise install node@
|
|
206
|
-
&& /home/opencode/.local/bin/mise install python@3.
|
|
207
|
-
&& /home/opencode/.local/bin/mise install go@1.
|
|
208
|
-
&& /home/opencode/.local/bin/mise use --global node@
|
|
209
|
-
&& /home/opencode/.local/bin/mise use --global python@3.
|
|
210
|
-
&& /home/opencode/.local/bin/mise use --global go@1.
|
|
201
|
+
# Install language runtimes via mise (2026-02-03)
|
|
202
|
+
# - node@25: pinned to major version
|
|
203
|
+
# - python@3.14: pinned to major version
|
|
204
|
+
# - go@1.25: pinned to minor version
|
|
205
|
+
RUN /home/opencode/.local/bin/mise install node@25 \
|
|
206
|
+
&& /home/opencode/.local/bin/mise install python@3.14 \
|
|
207
|
+
&& /home/opencode/.local/bin/mise install go@1.25 \
|
|
208
|
+
&& /home/opencode/.local/bin/mise use --global node@25 \
|
|
209
|
+
&& /home/opencode/.local/bin/mise use --global python@3.14 \
|
|
210
|
+
&& /home/opencode/.local/bin/mise use --global go@1.25
|
|
211
211
|
|
|
212
212
|
# Set up mise shims in PATH for non-interactive shells
|
|
213
213
|
ENV PATH="/home/opencode/.local/share/mise/shims:${PATH}"
|
|
@@ -230,24 +230,25 @@ ENV PATH="/home/opencode/.cargo/bin:${PATH}"
|
|
|
230
230
|
# Switch to bash for mise activation (mise outputs bash-specific syntax)
|
|
231
231
|
SHELL ["/bin/bash", "-c"]
|
|
232
232
|
|
|
233
|
-
# Install pnpm 10.x via corepack (2026-
|
|
233
|
+
# Install pnpm 10.x via corepack (2026-02-03)
|
|
234
234
|
RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
235
|
+
&& npm install -g corepack \
|
|
235
236
|
&& corepack enable \
|
|
236
|
-
&& corepack prepare pnpm@10.28.
|
|
237
|
+
&& corepack prepare pnpm@10.28.2 --activate
|
|
237
238
|
|
|
238
239
|
# Set up pnpm global bin directory
|
|
239
240
|
ENV PNPM_HOME="/home/opencode/.local/share/pnpm"
|
|
240
241
|
ENV PATH="${PNPM_HOME}:${PATH}"
|
|
241
242
|
RUN mkdir -p "${PNPM_HOME}"
|
|
242
243
|
|
|
243
|
-
# bun - self-managing installer,
|
|
244
|
+
# bun - self-managing installer, pinned to version (2026-02-03)
|
|
244
245
|
RUN curl -fsSL https://bun.sh/install | bash -s "bun-v1.3.5" \
|
|
245
246
|
&& rm -rf /home/opencode/.bun/install/cache /home/opencode/.bun/cache /home/opencode/.cache/bun
|
|
246
247
|
|
|
247
248
|
ENV PATH="/home/opencode/.bun/bin:${PATH}"
|
|
248
249
|
|
|
249
|
-
# uv -
|
|
250
|
-
RUN curl -LsSf https://astral
|
|
250
|
+
# uv - pinned installer (fast Python package manager) (2026-02-03)
|
|
251
|
+
RUN curl -LsSf https://github.com/astral-sh/uv/releases/download/0.9.21/uv-installer.sh | sh
|
|
251
252
|
|
|
252
253
|
# Install pipx for isolated Python application installs
|
|
253
254
|
# Use BuildKit cache mount for pip cache
|
|
@@ -260,7 +261,7 @@ RUN --mount=type=cache,target=/home/opencode/.cache/pip,uid=1000,gid=1000,mode=0
|
|
|
260
261
|
# Install global TypeScript compiler
|
|
261
262
|
# NOTE: Avoid cache mount here to prevent pnpm store permission issues
|
|
262
263
|
RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
263
|
-
&& pnpm add -g typescript
|
|
264
|
+
&& pnpm add -g typescript@5.9.2
|
|
264
265
|
|
|
265
266
|
# -----------------------------------------------------------------------------
|
|
266
267
|
# Modern CLI Tools (Rust-based) - pinned versions (2026-01-22)
|
|
@@ -315,7 +316,7 @@ RUN mkdir -p /home/opencode/.cargo/registry /home/opencode/.cargo/git \
|
|
|
315
316
|
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
316
317
|
# && go install mvdan.cc/sh/v3/cmd/shfmt@v3.12.0
|
|
317
318
|
|
|
318
|
-
# Install btop system monitor (2026-
|
|
319
|
+
# Install btop system monitor (2026-02-03)
|
|
319
320
|
# Use BuildKit cache mount for APT package lists and cache
|
|
320
321
|
USER root
|
|
321
322
|
RUN --mount=type=cache,target=/var/lib/apt/lists \
|
|
@@ -342,7 +343,7 @@ USER opencode
|
|
|
342
343
|
# Cockpit Web Console (2026-01-22) - temporarily disabled
|
|
343
344
|
# -----------------------------------------------------------------------------
|
|
344
345
|
# Cockpit provides web-based administration for the container
|
|
345
|
-
# Ubuntu
|
|
346
|
+
# Ubuntu questing has cockpit 346 in main repos
|
|
346
347
|
# Use BuildKit cache mount for APT package lists and cache
|
|
347
348
|
# USER root
|
|
348
349
|
# RUN --mount=type=cache,target=/var/lib/apt/lists \
|
|
@@ -527,8 +528,11 @@ USER opencode
|
|
|
527
528
|
# -----------------------------------------------------------------------------
|
|
528
529
|
# Clone the fork and build opencode from source (as non-root user)
|
|
529
530
|
# Pin to specific commit for reproducibility
|
|
531
|
+
# NOTE: OPENCODE_COMMIT is not tied to releases/tags; it tracks the latest stable
|
|
532
|
+
# commit on the main branch of https://github.com/pRizz/opencode.
|
|
533
|
+
# Update it by running: ./scripts/update-opencode-commit.sh
|
|
530
534
|
# Build opencode from source (BuildKit cache mounts disabled for now)
|
|
531
|
-
RUN OPENCODE_COMMIT="
|
|
535
|
+
RUN OPENCODE_COMMIT="cfe79755427fd8d3b94be76e1c7912bdc943a8ab" \
|
|
532
536
|
&& rm -rf /tmp/opencode-repo \
|
|
533
537
|
&& git clone --depth 1 https://github.com/pRizz/opencode.git /tmp/opencode-repo \
|
|
534
538
|
&& cd /tmp/opencode-repo \
|
|
@@ -726,7 +730,7 @@ RUN /opt/opencode/bin/opencode --version
|
|
|
726
730
|
# Note: If this fails in container builds due to "~" path resolution, retry with
|
|
727
731
|
# OPENCODE_CONFIG_DIR=/home/opencode/.config/opencode set explicitly.
|
|
728
732
|
RUN mkdir -p /home/opencode/.npm \
|
|
729
|
-
&& npx --yes get-shit-done-cc --opencode --global \
|
|
733
|
+
&& npx --yes get-shit-done-cc@1.11.1 --opencode --global \
|
|
730
734
|
&& rm -rf /home/opencode/.npm/_cacache /home/opencode/.npm/_npx
|
|
731
735
|
|
|
732
736
|
# -----------------------------------------------------------------------------
|
|
@@ -7,9 +7,9 @@ https://github.com/pRizz/opencode-cloud (mirror: https://gitea.com/pRizz/opencod
|
|
|
7
7
|
|
|
8
8
|
## What is included
|
|
9
9
|
|
|
10
|
-
- Ubuntu
|
|
10
|
+
- Ubuntu 25.10 (questing)
|
|
11
11
|
- Non-root user with passwordless sudo
|
|
12
|
-
- mise-managed runtimes (Node.js
|
|
12
|
+
- mise-managed runtimes (Node.js 25, Python 3.14, Go 1.25)
|
|
13
13
|
- Rust toolchain via rustup
|
|
14
14
|
- Core CLI utilities (ripgrep, eza, jq, git, etc.)
|
|
15
15
|
- opencode preinstalled with the GSD plugin
|
package/src/docker/image.rs
CHANGED
|
@@ -801,7 +801,7 @@ mod tests {
|
|
|
801
801
|
#[test]
|
|
802
802
|
fn format_build_error_includes_recent_logs() {
|
|
803
803
|
let mut logs = VecDeque::new();
|
|
804
|
-
logs.push_back("Step 1/5 : FROM ubuntu:
|
|
804
|
+
logs.push_back("Step 1/5 : FROM ubuntu:24.04".to_string());
|
|
805
805
|
logs.push_back("Step 2/5 : RUN apt-get update".to_string());
|
|
806
806
|
logs.push_back("E: Unable to fetch some archives".to_string());
|
|
807
807
|
let error_logs = VecDeque::new();
|
package/src/docker/progress.rs
CHANGED
|
@@ -210,17 +210,17 @@ impl ProgressReporter {
|
|
|
210
210
|
|
|
211
211
|
// Check if we should throttle this update
|
|
212
212
|
if !is_step_message {
|
|
213
|
-
if let Some(last) = self.last_update_by_id.get(id)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
if let Some(last) = self.last_update_by_id.get(id)
|
|
214
|
+
&& now.duration_since(*last) < SPINNER_UPDATE_THROTTLE
|
|
215
|
+
{
|
|
216
|
+
return; // Throttle: too soon since last update
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
// Skip if message is identical to last one
|
|
220
|
-
if let Some(last_msg) = self.last_message_by_id.get(id)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
if let Some(last_msg) = self.last_message_by_id.get(id)
|
|
221
|
+
&& last_msg == message
|
|
222
|
+
{
|
|
223
|
+
return;
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
|
package/src/docker/state.rs
CHANGED
|
@@ -71,10 +71,10 @@ pub fn load_state() -> Option<ImageState> {
|
|
|
71
71
|
|
|
72
72
|
/// Clear image state (e.g., after image removal)
|
|
73
73
|
pub fn clear_state() -> anyhow::Result<()> {
|
|
74
|
-
if let Some(path) = get_state_path()
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
if let Some(path) = get_state_path()
|
|
75
|
+
&& path.exists()
|
|
76
|
+
{
|
|
77
|
+
std::fs::remove_file(&path)?;
|
|
78
78
|
}
|
|
79
79
|
Ok(())
|
|
80
80
|
}
|
package/src/host/provision.rs
CHANGED
|
@@ -44,9 +44,9 @@ pub struct DistroInfo {
|
|
|
44
44
|
pub family: DistroFamily,
|
|
45
45
|
/// Distribution ID (e.g., "ubuntu", "amzn", "debian")
|
|
46
46
|
pub id: String,
|
|
47
|
-
/// Pretty name (e.g., "Ubuntu
|
|
47
|
+
/// Pretty name (e.g., "Ubuntu 24.04 LTS")
|
|
48
48
|
pub pretty_name: String,
|
|
49
|
-
/// Version ID (e.g., "
|
|
49
|
+
/// Version ID (e.g., "24.04", "2023")
|
|
50
50
|
pub version_id: Option<String>,
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -327,18 +327,18 @@ mod tests {
|
|
|
327
327
|
#[test]
|
|
328
328
|
fn test_parse_os_release_ubuntu() {
|
|
329
329
|
let content = r#"
|
|
330
|
-
PRETTY_NAME="Ubuntu
|
|
330
|
+
PRETTY_NAME="Ubuntu 24.04 LTS"
|
|
331
331
|
NAME="Ubuntu"
|
|
332
|
-
VERSION_ID="
|
|
333
|
-
VERSION="
|
|
334
|
-
VERSION_CODENAME=
|
|
332
|
+
VERSION_ID="24.04"
|
|
333
|
+
VERSION="24.04 LTS (Noble Numbat)"
|
|
334
|
+
VERSION_CODENAME=noble
|
|
335
335
|
ID=ubuntu
|
|
336
336
|
ID_LIKE=debian
|
|
337
337
|
"#;
|
|
338
338
|
let info = parse_os_release(content).unwrap();
|
|
339
339
|
assert_eq!(info.family, DistroFamily::Debian);
|
|
340
340
|
assert_eq!(info.id, "ubuntu");
|
|
341
|
-
assert_eq!(info.version_id, Some("
|
|
341
|
+
assert_eq!(info.version_id, Some("24.04".to_string()));
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
#[test]
|
|
@@ -375,8 +375,8 @@ ID=debian
|
|
|
375
375
|
let debian_info = DistroInfo {
|
|
376
376
|
family: DistroFamily::Debian,
|
|
377
377
|
id: "ubuntu".to_string(),
|
|
378
|
-
pretty_name: "Ubuntu
|
|
379
|
-
version_id: Some("
|
|
378
|
+
pretty_name: "Ubuntu 24.04".to_string(),
|
|
379
|
+
version_id: Some("24.04".to_string()),
|
|
380
380
|
};
|
|
381
381
|
let commands = get_docker_install_commands(&debian_info).unwrap();
|
|
382
382
|
assert!(!commands.is_empty());
|
package/src/host/schema.rs
CHANGED
|
@@ -139,10 +139,10 @@ impl HostConfig {
|
|
|
139
139
|
let mut parts = vec!["ssh".to_string()];
|
|
140
140
|
|
|
141
141
|
// Port (if non-default)
|
|
142
|
-
if let Some(port) = self.port
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
142
|
+
if let Some(port) = self.port
|
|
143
|
+
&& port != 22
|
|
144
|
+
{
|
|
145
|
+
parts.push(format!("-p {port}"));
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
// Identity file
|
package/src/host/ssh_config.rs
CHANGED
|
@@ -137,21 +137,21 @@ pub fn write_ssh_config_entry(
|
|
|
137
137
|
})?;
|
|
138
138
|
|
|
139
139
|
// Ensure .ssh directory exists with proper permissions
|
|
140
|
-
if let Some(ssh_dir) = config_path.parent()
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
})
|
|
140
|
+
if let Some(ssh_dir) = config_path.parent()
|
|
141
|
+
&& !ssh_dir.exists()
|
|
142
|
+
{
|
|
143
|
+
fs::create_dir_all(ssh_dir).map_err(|e| {
|
|
144
|
+
HostError::SshConfigWrite(format!("Failed to create .ssh directory: {e}"))
|
|
145
|
+
})?;
|
|
145
146
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
147
|
+
// Set directory permissions to 700 on Unix
|
|
148
|
+
#[cfg(unix)]
|
|
149
|
+
{
|
|
150
|
+
use std::os::unix::fs::PermissionsExt;
|
|
151
|
+
let perms = fs::Permissions::from_mode(0o700);
|
|
152
|
+
fs::set_permissions(ssh_dir, perms).map_err(|e| {
|
|
153
|
+
HostError::SshConfigWrite(format!("Failed to set .ssh permissions: {e}"))
|
|
154
|
+
})?;
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -164,10 +164,10 @@ pub fn write_ssh_config_entry(
|
|
|
164
164
|
if let Some(u) = user {
|
|
165
165
|
entry.push_str(&format!(" User {u}\n"));
|
|
166
166
|
}
|
|
167
|
-
if let Some(p) = port
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
167
|
+
if let Some(p) = port
|
|
168
|
+
&& p != 22
|
|
169
|
+
{
|
|
170
|
+
entry.push_str(&format!(" Port {p}\n"));
|
|
171
171
|
}
|
|
172
172
|
if let Some(key) = identity_file {
|
|
173
173
|
entry.push_str(&format!(" IdentityFile {key}\n"));
|
package/src/host/storage.rs
CHANGED
|
@@ -54,11 +54,11 @@ pub fn save_hosts(hosts: &HostsFile) -> Result<(), HostError> {
|
|
|
54
54
|
.ok_or_else(|| HostError::SaveFailed("Could not determine hosts file path".to_string()))?;
|
|
55
55
|
|
|
56
56
|
// Ensure config directory exists
|
|
57
|
-
if let Some(parent) = hosts_path.parent()
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
if let Some(parent) = hosts_path.parent()
|
|
58
|
+
&& !parent.exists()
|
|
59
|
+
{
|
|
60
|
+
fs::create_dir_all(parent)
|
|
61
|
+
.map_err(|e| HostError::SaveFailed(format!("Failed to create directory: {e}")))?;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// Create backup if file exists
|