Skip to content

Commit 29a2a17

Browse files
committed
fix: harden upgrade builds and shared agent mounts
- pass resolved tool versions into rust image builds and cover it in CI - normalize .agents mount targets so overrides and container reuse work
1 parent 09ca3b0 commit 29a2a17

7 files changed

Lines changed: 187 additions & 6 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ jobs:
4444
chmod +x scripts/version-check.sh
4545
./scripts/version-check.sh
4646
47+
- name: Test versions-up build args
48+
shell: bash
49+
run: bash ./tests/version-upgrade.sh
50+
4751
smoke:
4852
name: Installer Smoke Test
4953
runs-on: ubuntu-latest

Dockerfile.rust

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ RUN echo 'export PATH="/opt/cargo/bin:$PATH"' >> "$DEVA_HOME/.zshrc" && \
8080
echo 'alias cl="cargo clippy"' >> "$DEVA_HOME/.zshrc"
8181

8282
USER $DEVA_USER
83+
WORKDIR $DEVA_HOME
8384

8485
COPY --chown=deva:deva scripts/install-agent-tooling.sh /tmp/install-agent-tooling.sh
8586

deva.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,12 @@ user_volume_mounts_target() {
416416
local target="$1"
417417
local spec remainder dest
418418

419+
target="$(normalize_container_bind_target "$target")"
420+
419421
for spec in "${USER_VOLUMES[@]+"${USER_VOLUMES[@]}"}"; do
420422
remainder="${spec#*:}"
421423
dest="${remainder%%:*}"
424+
dest="$(normalize_container_bind_target "$dest")"
422425
if [ "$dest" = "$target" ]; then
423426
return 0
424427
fi
@@ -427,6 +430,27 @@ user_volume_mounts_target() {
427430
return 1
428431
}
429432

433+
normalize_container_bind_target() {
434+
local path="$1"
435+
436+
while [ "$path" != "/" ] && [[ "$path" == */ ]]; do
437+
path="${path%/}"
438+
done
439+
440+
printf '%s' "$path"
441+
}
442+
443+
append_shared_agents_mount() {
444+
local target="/home/deva/.agents"
445+
446+
[ "$QUICK_MODE" = false ] || return 0
447+
[ -d "$HOME/.agents" ] || return 0
448+
449+
if ! user_volume_mounts_target "$target"; then
450+
USER_VOLUMES+=("$HOME/.agents:$target")
451+
fi
452+
}
453+
430454
prepare_claude_chrome_detection_mount() {
431455
local profile_path=""
432456
local user_data_dir=""
@@ -2425,6 +2449,7 @@ autolink_legacy_into_deva_root() {
24252449
24262450
check_agent "$ACTIVE_AGENT"
24272451
prepare_claude_chrome_bridge
2452+
append_shared_agents_mount
24282453
24292454
if [ -n "$CONFIG_HOME" ] && [ "$DRY_RUN" != true ]; then
24302455
if [ ! -d "$CONFIG_HOME" ]; then

scripts/install-agent-tooling.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ npm cache clean --force
2222
"$DEVA_HOME/.npm-global/bin/claude-trace" --help >/dev/null
2323
(npm list -g --depth=0 @anthropic-ai/claude-code @openai/codex @google/gemini-cli || true)
2424

25+
cd "$DEVA_HOME"
2526
curl -fsSL "https://raw.githubusercontent.com/lroolle/atlas-cli/${ATLAS_CLI_VERSION}/install.sh" \
2627
| bash -s -- --skill-dir "$DEVA_HOME/.skills"

scripts/release-utils.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,13 @@ for section in sections:
203203
if cur_v < v <= lat_v:
204204
lines = section.strip().split("\n")
205205
output = [lines[0].replace("## ", "")]
206-
content_lines = [l for l in lines[1:] if l.strip()][:10]
206+
content_lines = [l for l in lines[1:] if l.strip()]
207207
output.extend(content_lines)
208208
changes.append("\n".join(output))
209209
except:
210210
continue
211211
212-
for change in reversed(changes[-3:]):
212+
for change in reversed(changes):
213213
print(change)
214214
print()
215215
' "$current" "$latest" <<< "$data" 2>/dev/null || true
@@ -256,10 +256,10 @@ for rel in releases:
256256
except:
257257
continue
258258
259-
for v, ver, body in sorted(changes, key=lambda x: x[0], reverse=True)[:3]:
259+
for v, ver, body in sorted(changes, key=lambda x: x[0], reverse=True):
260260
print(f"{ver}")
261261
if body:
262-
for line in [l.rstrip() for l in body.split("\n") if l.strip()][:15]:
262+
for line in [l.rstrip() for l in body.split("\n") if l.strip()]:
263263
print(f" {line}")
264264
print()
265265
' "$current" "$latest" <<< "$json" 2>/dev/null || true
@@ -467,7 +467,7 @@ for section in sections:
467467
continue
468468
lines = section.strip().split("\n")
469469
print(lines[0].replace("## ", ""))
470-
for line in [l for l in lines[1:] if l.strip()][:8]:
470+
for line in [l for l in lines[1:] if l.strip()]:
471471
print(line)
472472
print()
473473
printed += 1
@@ -497,7 +497,7 @@ for rel in releases:
497497
body = (rel.get("body") or "").replace("\r\n", "\n").strip()
498498
print(ver)
499499
if body:
500-
for line in [l.rstrip() for l in body.split("\n") if l.strip()][:12]:
500+
for line in [l.rstrip() for l in body.split("\n") if l.strip()]:
501501
print(f" {line}")
502502
print()
503503
printed += 1

scripts/version-upgrade.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ main() {
107107
section "Building Rust Image"
108108
docker build -f "$RUST_DOCKERFILE" \
109109
--build-arg BASE_IMAGE="$BUILD_IMAGE" \
110+
--build-arg CLAUDE_CODE_VERSION="$claude_ver" \
111+
--build-arg CODEX_VERSION="$codex_ver" \
112+
--build-arg GEMINI_CLI_VERSION="$gemini_ver" \
113+
--build-arg ATLAS_CLI_VERSION="$atlas_ver" \
110114
-t "$RUST_IMAGE" .
111115

112116
echo ""

tests/version-upgrade.sh

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
6+
7+
TMP_ROOT="$(mktemp -d)"
8+
FAKE_BIN="$TMP_ROOT/bin"
9+
DOCKER_BUILD_LOG="$TMP_ROOT/docker-build.log"
10+
mkdir -p "$FAKE_BIN"
11+
12+
cleanup() {
13+
rm -rf "$TMP_ROOT"
14+
}
15+
trap cleanup EXIT
16+
17+
cat >"$FAKE_BIN/docker" <<'EOF'
18+
#!/usr/bin/env bash
19+
set -euo pipefail
20+
21+
case "${1:-}" in
22+
inspect)
23+
cat <<'JSON'
24+
[{"Config":{"Labels":{
25+
"org.opencontainers.image.claude_code_version":"2.1.81",
26+
"org.opencontainers.image.codex_version":"0.116.0",
27+
"org.opencontainers.image.gemini_cli_version":"0.35.0",
28+
"org.opencontainers.image.atlas_cli_version":"v0.1.4",
29+
"org.opencontainers.image.copilot_api_version":"0ea08febdd7e3e055b03dd298bf57e669500b5c1"
30+
}}}]
31+
JSON
32+
;;
33+
build)
34+
printf '%s\n' "$*" >>"$DOCKER_BUILD_LOG"
35+
;;
36+
*)
37+
echo "unexpected docker invocation: $*" >&2
38+
exit 1
39+
;;
40+
esac
41+
EOF
42+
43+
cat >"$FAKE_BIN/npm" <<'EOF'
44+
#!/usr/bin/env bash
45+
set -euo pipefail
46+
47+
if [[ "${1:-}" != "view" ]]; then
48+
echo "unexpected npm invocation: $*" >&2
49+
exit 1
50+
fi
51+
52+
case "${2:-}" in
53+
@anthropic-ai/claude-code)
54+
echo "2.1.87"
55+
;;
56+
@anthropic-ai/claude-code@2.1.87)
57+
echo '{"2.1.87":"2026-03-29T01:40:00Z"}'
58+
;;
59+
@openai/codex)
60+
echo "0.117.0"
61+
;;
62+
@openai/codex@0.117.0)
63+
echo '{"0.117.0":"2026-03-26T22:28:00Z"}'
64+
;;
65+
@google/gemini-cli)
66+
echo "0.35.3"
67+
;;
68+
@google/gemini-cli@0.35.3)
69+
echo '{"0.35.3":"2026-03-28T03:17:00Z"}'
70+
;;
71+
*)
72+
echo "unexpected npm view args: $*" >&2
73+
exit 1
74+
;;
75+
esac
76+
EOF
77+
78+
cat >"$FAKE_BIN/gh" <<'EOF'
79+
#!/usr/bin/env bash
80+
set -euo pipefail
81+
82+
if [[ "${1:-}" != "api" ]]; then
83+
echo "unexpected gh invocation: $*" >&2
84+
exit 1
85+
fi
86+
87+
case "${2:-}" in
88+
repos/lroolle/atlas-cli/releases/latest)
89+
echo "v0.1.4"
90+
;;
91+
repos/ericc-ch/copilot-api/branches/master)
92+
echo "0ea08febdd7e3e055b03dd298bf57e669500b5c1"
93+
;;
94+
repos/lroolle/atlas-cli/releases/tags/v0.1.4)
95+
echo "2026-01-16T05:42:00Z"
96+
;;
97+
repos/ericc-ch/copilot-api/commits/0ea08febdd7e3e055b03dd298bf57e669500b5c1)
98+
echo "2025-10-05T03:49:00Z"
99+
;;
100+
repos/openai/codex/releases)
101+
echo '[]'
102+
;;
103+
*)
104+
echo "unexpected gh api args: $*" >&2
105+
exit 1
106+
;;
107+
esac
108+
EOF
109+
110+
cat >"$FAKE_BIN/curl" <<'EOF'
111+
#!/usr/bin/env bash
112+
set -euo pipefail
113+
printf ''
114+
EOF
115+
116+
chmod +x "$FAKE_BIN/docker" "$FAKE_BIN/npm" "$FAKE_BIN/gh" "$FAKE_BIN/curl"
117+
118+
PATH="$FAKE_BIN:$PATH" \
119+
DOCKER_BUILD_LOG="$DOCKER_BUILD_LOG" \
120+
AUTO_YES=1 \
121+
CHECK_IMAGE="ghcr.io/thevibeworks/deva:rust" \
122+
BUILD_IMAGE="ghcr.io/thevibeworks/deva:latest" \
123+
RUST_IMAGE="ghcr.io/thevibeworks/deva:rust" \
124+
"$REPO_ROOT/scripts/version-upgrade.sh" >/dev/null
125+
126+
main_build="$(sed -n '1p' "$DOCKER_BUILD_LOG")"
127+
rust_build="$(sed -n '2p' "$DOCKER_BUILD_LOG")"
128+
129+
[[ -n "$main_build" ]] || { echo "missing main build invocation" >&2; exit 1; }
130+
[[ -n "$rust_build" ]] || { echo "missing rust build invocation" >&2; exit 1; }
131+
132+
for expected in \
133+
"--build-arg CLAUDE_CODE_VERSION=2.1.87" \
134+
"--build-arg CODEX_VERSION=0.117.0" \
135+
"--build-arg GEMINI_CLI_VERSION=0.35.3" \
136+
"--build-arg ATLAS_CLI_VERSION=v0.1.4"
137+
do
138+
[[ "$main_build" == *"$expected"* ]] || {
139+
echo "main build missing expected arg: $expected" >&2
140+
exit 1
141+
}
142+
[[ "$rust_build" == *"$expected"* ]] || {
143+
echo "rust build missing expected arg: $expected" >&2
144+
exit 1
145+
}
146+
done

0 commit comments

Comments
 (0)