Skip to content

Commit 00c8661

Browse files
authored
Merge pull request #408 from thevibeworks/feat/proxy-builds-407
fix(build): proxy-aware version resolution and Docker builds, hardened
2 parents 7a8f094 + f554d24 commit 00c8661

6 files changed

Lines changed: 196 additions & 63 deletions

File tree

Makefile

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ RUST_TARGETS ?= wasm32-unknown-unknown
4444
DOCKER_BUILD_EXTRA_ARGS ?=
4545
SKIP_BUILD_NETWORK_CHECK ?= 0
4646

47+
# Forward host proxy env vars to Docker build (BuildKit predefined ARGs —
48+
# available in all stages without Dockerfile ARG declarations, excluded
49+
# from cache key so proxy changes don't bust layer cache).
50+
# Rewrite localhost proxy addresses: 127.0.0.1/localhost on the host is the
51+
# container's own loopback during build — host.docker.internal reaches the
52+
# host. The @-patterns catch authenticated proxies (user:pass@127.0.0.1).
53+
_dproxy = $(subst @localhost,@host.docker.internal,$(subst @127.0.0.1,@host.docker.internal,$(subst ://localhost,://host.docker.internal,$(subst ://127.0.0.1,://host.docker.internal,$1))))
54+
PROXY_BUILD_ARGS := \
55+
$(if $(HTTP_PROXY),--build-arg HTTP_PROXY=$(call _dproxy,$(HTTP_PROXY))) \
56+
$(if $(HTTPS_PROXY),--build-arg HTTPS_PROXY=$(call _dproxy,$(HTTPS_PROXY))) \
57+
$(if $(http_proxy),--build-arg http_proxy=$(call _dproxy,$(http_proxy))) \
58+
$(if $(https_proxy),--build-arg https_proxy=$(call _dproxy,$(https_proxy))) \
59+
$(if $(NO_PROXY),--build-arg NO_PROXY=$(NO_PROXY)) \
60+
$(if $(no_proxy),--build-arg no_proxy=$(no_proxy))
61+
62+
# host.docker.internal resolves implicitly on Docker Desktop/OrbStack only;
63+
# native Linux Engine needs the explicit host-gateway mapping during build.
64+
ifneq ($(strip $(HTTP_PROXY)$(HTTPS_PROXY)$(http_proxy)$(https_proxy)),)
65+
PROXY_BUILD_ARGS += --add-host host.docker.internal:host-gateway
66+
endif
67+
68+
DOCKER_BUILD_FLAGS = $(PROXY_BUILD_ARGS) $(DOCKER_BUILD_EXTRA_ARGS)
69+
4770
TOOLCHAIN_BUILD_ARGS := \
4871
--build-arg NODE_MAJOR=$(NODE_MAJOR) \
4972
--build-arg GO_VERSION=$(GO_VERSION) \
@@ -112,7 +135,7 @@ build-network-check:
112135
printf '%s\n' \
113136
'FROM node:$(NODE_MAJOR)-bookworm-slim' \
114137
'RUN node -e "require('\''dns'\'').lookup('\''registry.npmjs.org'\'',{all:true},(e,a)=>{if(e){console.error(e);process.exit(1)};console.log(a.map(x=>x.address).slice(0,3).join('\'','\''))})"' \
115-
| docker build $(DOCKER_BUILD_EXTRA_ARGS) --progress=plain --no-cache -f - . >/dev/null; \
138+
| docker build $(DOCKER_BUILD_FLAGS) --progress=plain --no-cache -f - . >/dev/null; \
116139
fi
117140

118141
build-main: build-network-check
@@ -159,23 +182,23 @@ build-main: build-network-check
159182
fi; \
160183
fi
161184
@echo "Hint: override via GO_VERSION=... CLAUDE_CODE_VERSION=... or run 'make versions-pin'"
162-
docker build $(DOCKER_BUILD_EXTRA_ARGS) -f $(DOCKERFILE) $(MAIN_BUILD_ARGS) -t $(MAIN_IMAGE) .
185+
docker build $(DOCKER_BUILD_FLAGS) -f $(DOCKERFILE) $(MAIN_BUILD_ARGS) -t $(MAIN_IMAGE) .
163186
@echo "✅ Build completed: $(MAIN_IMAGE)"
164187

165188
rebuild:
166189
@echo "🔨 Rebuilding Docker image (no cache) with $(DOCKERFILE)..."
167-
docker build $(DOCKER_BUILD_EXTRA_ARGS) -f $(DOCKERFILE) --no-cache $(MAIN_BUILD_ARGS) -t $(MAIN_IMAGE) .
190+
docker build $(DOCKER_BUILD_FLAGS) -f $(DOCKERFILE) --no-cache $(MAIN_BUILD_ARGS) -t $(MAIN_IMAGE) .
168191
@echo "✅ Rebuild completed: $(MAIN_IMAGE)"
169192

170193

171194
build-core:
172195
@echo "🔨 Building stable core image..."
173-
docker build $(DOCKER_BUILD_EXTRA_ARGS) -f $(DOCKERFILE) --target agent-base $(CORE_BUILD_ARGS) -t $(CORE_IMAGE) .
196+
docker build $(DOCKER_BUILD_FLAGS) -f $(DOCKERFILE) --target agent-base $(CORE_BUILD_ARGS) -t $(CORE_IMAGE) .
174197
@echo "✅ Core build completed: $(CORE_IMAGE)"
175198

176199
build-rust-image: build-network-check
177200
@echo "🔨 Building Rust Docker image..."
178-
docker build $(DOCKER_BUILD_EXTRA_ARGS) -f $(RUST_DOCKERFILE) \
201+
docker build $(DOCKER_BUILD_FLAGS) -f $(RUST_DOCKERFILE) \
179202
--build-arg BASE_IMAGE=$(CORE_IMAGE) \
180203
$(RUST_BUILD_ARGS) \
181204
-t $(RUST_IMAGE) .
@@ -192,27 +215,27 @@ build-all:
192215

193216
buildx:
194217
@echo "🔨 Building with docker buildx..."
195-
docker buildx build -f $(DOCKERFILE) --load $(MAIN_BUILD_ARGS) -t $(MAIN_IMAGE) .
218+
docker buildx build $(DOCKER_BUILD_FLAGS) -f $(DOCKERFILE) --load $(MAIN_BUILD_ARGS) -t $(MAIN_IMAGE) .
196219
@echo "✅ Buildx completed: $(MAIN_IMAGE)"
197220

198221
buildx-multi:
199222
@echo "🔨 Building multi-arch images for amd64 and arm64..."
200-
docker buildx build -f $(DOCKERFILE) --platform $(MULTI_ARCH_PLATFORMS) \
223+
docker buildx build $(DOCKER_BUILD_FLAGS) -f $(DOCKERFILE) --platform $(MULTI_ARCH_PLATFORMS) \
201224
$(MAIN_BUILD_ARGS) \
202225
--push -t $(MAIN_IMAGE) .
203226
@echo "✅ Multi-arch build completed and pushed: $(MAIN_IMAGE)"
204227

205228
buildx-multi-rust:
206229
@echo "🔨 Building multi-arch Rust images for amd64 and arm64..."
207-
docker buildx build -f $(RUST_DOCKERFILE) --platform $(MULTI_ARCH_PLATFORMS) \
230+
docker buildx build $(DOCKER_BUILD_FLAGS) -f $(RUST_DOCKERFILE) --platform $(MULTI_ARCH_PLATFORMS) \
208231
--build-arg BASE_IMAGE=$(MAIN_IMAGE) \
209232
$(RUST_BUILD_ARGS) \
210233
--push -t $(RUST_IMAGE) .
211234
@echo "✅ Multi-arch Rust build completed and pushed: $(RUST_IMAGE)"
212235

213236
buildx-multi-local:
214237
@echo "🔨 Building multi-arch images locally..."
215-
docker buildx build -f $(DOCKERFILE) --platform $(MULTI_ARCH_PLATFORMS) \
238+
docker buildx build $(DOCKER_BUILD_FLAGS) -f $(DOCKERFILE) --platform $(MULTI_ARCH_PLATFORMS) \
216239
$(MAIN_BUILD_ARGS) \
217240
-t $(MAIN_IMAGE) .
218241
@echo "✅ Multi-arch build completed locally: $(MAIN_IMAGE)"

scripts/install-agent-tooling.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,25 @@ download_to() {
118118
curl -fsSL "$url" -o "$dest"
119119
}
120120

121+
log_proxy_config() {
122+
# Proxy userinfo is credential material and this output lands in build
123+
# logs — redact user:pass@ before printing.
124+
local has_proxy=0
125+
for var in HTTP_PROXY HTTPS_PROXY http_proxy https_proxy NO_PROXY no_proxy; do
126+
if [ -n "${!var:-}" ]; then
127+
log " $var=$(printf '%s' "${!var}" | sed -E 's#://[^@/]*@#://***@#')"
128+
has_proxy=1
129+
fi
130+
done
131+
if [ "$has_proxy" -eq 0 ]; then
132+
log " (no proxy configured)"
133+
fi
134+
}
135+
121136
install_npm_agent_tooling() {
122137
log "Installing npm agent tooling"
138+
log "Proxy config:"
139+
log_proxy_config
123140
log "Requested versions: claude=${CLAUDE_CODE_VERSION} codex=${CODEX_VERSION} gemini=${GEMINI_CLI_VERSION} grok=${GROK_CLI_VERSION}"
124141

125142
mkdir -p "$DEVA_HOME/.npm-global" "$DEVA_HOME/.local/bin"

scripts/release-utils.sh

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,23 @@ format_datetime() {
175175
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
176176
# Version Fetching (by type)
177177
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
178+
_npm_registry_latest() {
179+
curl -fsSL --max-time 10 \
180+
"https://registry.npmjs.org/-/package/$1/dist-tags" 2>/dev/null | \
181+
sed -n 's/.*"latest":"\([^"]*\)".*/\1/p'
182+
}
183+
178184
fetch_latest_version() {
179185
local tool=$1
180186
local type=$(get_tool_field "$tool" type)
181187
local source=$(get_tool_field "$tool" source)
182188

183189
case $type in
184190
npm)
185-
npm view "$source" version 2>/dev/null || echo ""
191+
# Soft-fail like the gh arms below: a transient registry error
192+
# must reach load_versions' warn-and-fallback path, not abort
193+
# the whole run under set -e.
194+
_npm_registry_latest "$source" || echo ""
186195
;;
187196
github-release)
188197
gh api "repos/$source/releases/latest" --jq '.tag_name' 2>/dev/null || echo ""
@@ -203,8 +212,9 @@ fetch_version_date() {
203212
case $type in
204213
npm)
205214
local v=$(normalize_version "$version")
206-
npm view "$source@$v" time --json 2>/dev/null | \
207-
jq -r --arg ver "$v" '.[$ver] // .' 2>/dev/null | head -1 || echo ""
215+
local encoded=${source/\//%2f}
216+
curl -fsSL --max-time 10 "https://registry.npmjs.org/$encoded" 2>/dev/null | \
217+
jq -r --arg ver "$v" '.time[$ver] // empty' 2>/dev/null | head -1 || echo ""
208218
;;
209219
github-release)
210220
gh api "repos/$source/releases/tags/$version" --jq '.published_at' 2>/dev/null || echo ""

scripts/update-version-pins.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ EOF
1919
}
2020

2121
fetch_npm_version() {
22-
npm view "$1" version 2>/dev/null || true
22+
curl -fsSL --max-time 10 \
23+
"https://registry.npmjs.org/-/package/$1/dist-tags" 2>/dev/null | \
24+
sed -n 's/.*"latest":"\([^"]*\)".*/\1/p' || true
2325
}
2426

2527
fetch_latest_git_tag() {

scripts/version-upgrade.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,24 @@ source "$SCRIPT_DIR/version-pins.sh"
2828
CHECK_IMAGE=${MAIN_IMAGE:-ghcr.io/thevibeworks/deva:latest}
2929
BUILD_IMAGE=${BUILD_IMAGE:-ghcr.io/thevibeworks/deva:latest}
3030
CORE_IMAGE=${CORE_IMAGE:-ghcr.io/thevibeworks/deva:core}
31+
32+
# Forward host proxy env vars to Docker build stages.
33+
# Rewrite 127.0.0.1/localhost → host.docker.internal so the build
34+
# container reaches the host's proxy instead of its own loopback.
35+
# The @-patterns catch authenticated proxies (user:pass@127.0.0.1).
36+
_dproxy() { sed 's|://127\.0\.0\.1|://host.docker.internal|g; s|://localhost|://host.docker.internal|g; s|@127\.0\.0\.1|@host.docker.internal|g; s|@localhost|@host.docker.internal|g' <<< "$1"; }
37+
# Proxy userinfo is credential material — never print it raw.
38+
_redact_proxy() { sed -E 's#://[^@/]*@#://***@#' <<< "$1"; }
39+
PROXY_ARGS=()
40+
[[ -n ${HTTP_PROXY:-} ]] && PROXY_ARGS+=(--build-arg "HTTP_PROXY=$(_dproxy "$HTTP_PROXY")")
41+
[[ -n ${HTTPS_PROXY:-} ]] && PROXY_ARGS+=(--build-arg "HTTPS_PROXY=$(_dproxy "$HTTPS_PROXY")")
42+
[[ -n ${http_proxy:-} ]] && PROXY_ARGS+=(--build-arg "http_proxy=$(_dproxy "$http_proxy")")
43+
[[ -n ${https_proxy:-} ]] && PROXY_ARGS+=(--build-arg "https_proxy=$(_dproxy "$https_proxy")")
44+
[[ -n ${NO_PROXY:-} ]] && PROXY_ARGS+=(--build-arg "NO_PROXY=$NO_PROXY")
45+
[[ -n ${no_proxy:-} ]] && PROXY_ARGS+=(--build-arg "no_proxy=$no_proxy")
46+
# host.docker.internal resolves implicitly on Docker Desktop/OrbStack only;
47+
# native Linux Engine needs the explicit host-gateway mapping during build.
48+
[[ ${#PROXY_ARGS[@]} -gt 0 ]] && PROXY_ARGS+=(--add-host "host.docker.internal:host-gateway")
3149
RUST_IMAGE=${RUST_IMAGE:-ghcr.io/thevibeworks/deva:rust}
3250
DOCKERFILE=${DOCKERFILE:-Dockerfile}
3351
RUST_DOCKERFILE=${RUST_DOCKERFILE:-Dockerfile.rust}
@@ -200,8 +218,17 @@ main() {
200218
echo -e "${GREEN}Proceeding with build...${RESET}"
201219
echo ""
202220

221+
if [[ ${#PROXY_ARGS[@]} -gt 0 ]]; then
222+
echo -e "${DIM}Proxy forwarding to Docker build:${RESET}"
223+
for _pa in "${PROXY_ARGS[@]}"; do
224+
echo -e " ${DIM}$(_redact_proxy "${_pa#--build-arg }")${RESET}"
225+
done
226+
echo ""
227+
fi
228+
203229
section "Building Core Image"
204230
docker build -f "$DOCKERFILE" \
231+
${PROXY_ARGS[@]+"${PROXY_ARGS[@]}"} \
205232
--target agent-base \
206233
--build-arg NODE_MAJOR="$NODE_MAJOR" \
207234
--build-arg GO_VERSION="$GO_VERSION" \
@@ -215,6 +242,7 @@ main() {
215242
echo ""
216243
section "Building Main Image"
217244
docker build -f "$DOCKERFILE" \
245+
${PROXY_ARGS[@]+"${PROXY_ARGS[@]}"} \
218246
--build-arg NODE_MAJOR="$NODE_MAJOR" \
219247
--build-arg GO_VERSION="$GO_VERSION" \
220248
--build-arg PYTHON_VERSION="$PYTHON_VERSION" \
@@ -233,6 +261,7 @@ main() {
233261
echo ""
234262
section "Building Rust Image"
235263
docker build -f "$RUST_DOCKERFILE" \
264+
${PROXY_ARGS[@]+"${PROXY_ARGS[@]}"} \
236265
--build-arg BASE_IMAGE="$CORE_IMAGE" \
237266
--build-arg CLAUDE_CODE_VERSION="$claude_ver" \
238267
--build-arg CCTRACE_VERSION="$cctrace_ver" \

0 commit comments

Comments
 (0)