From 672e1d991de80ae2dd871b7e14800f3904ff022f Mon Sep 17 00:00:00 2001 From: shankar0123 Date: Fri, 17 Apr 2026 03:12:45 +0000 Subject: [PATCH] build: propagate HTTP_PROXY/HTTPS_PROXY/NO_PROXY through Docker build (M-4, Issue #9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses Medium finding M-4 in the audit report. The multi-stage Dockerfiles previously had no ARG declarations for HTTP_PROXY, HTTPS_PROXY, or NO_PROXY, so corporate-proxy environments silently failed at 'npm ci' (frontend stage) and 'go mod download' (Go builder). The npm retry idiom (`npm ci --include=dev || npm ci --include=dev`) masked the failure because the upstream 'Exit handler never called!' bug exits 0 despite the install crash. Fix: thread HTTP_PROXY / HTTPS_PROXY / NO_PROXY ARGs through every Docker build stage that performs network I/O, re-export them as ENV with both upper- and lower-case aliases (apk/curl/npm read lowercase; Go/Node read uppercase), and forward the host shell's environment via `build.args:` in every compose file and `build-args:` in the release workflow's docker/build-push-action steps. Defaults are empty strings so un-proxied builds remain byte-identical to the pre-fix tree. Scope: Dockerfile (frontend + Go builder stages), Dockerfile.agent (Go builder stage), deploy/docker-compose.yml (server + agent), deploy/docker-compose.dev.yml (server + agent), deploy/docker-compose.test.yml (server + agent), .github/workflows/release.yml (both docker/build-push-action v6 invocations). Zero Go, web, test, or runtime code changes. Zero base-image changes. Existing npm `||` retry idiom and `ARG TARGETARCH` preserved verbatim. CWE-1173 (Improper Use of Validated Input) / CWE-16 (Configuration). Verification: - YAML parses clean across all four compose files and release.yml. - yamllint -d relaxed: clean exit across all five YAML files. - All six `build.args:` blocks expose HTTP_PROXY, HTTPS_PROXY, NO_PROXY with default-empty ${VAR:-} substitution. - Both release.yml docker/build-push-action steps expose the same three keys sourced from ${{ secrets.HTTP_PROXY }}, etc. - Dockerfiles contain 5 proxy ARG declarations total (Dockerfile has 2 stages × 3 ARGs = 6 lines, Dockerfile.agent has 1 stage × 3 ARGs = 3 lines); lowercase ENV aliases verified present in every stage. - git diff --shortstat: 6 files changed, 117 insertions(+), 0 deletions. Pure additive. Docker-live verification (`docker build`, `docker compose config`) deferred to CI / post-commit smoke because the sandbox has no Docker runtime. hadolint, go, golangci-lint, govulncheck likewise unavailable in the sandbox; per-layer CI coverage gates (service 55%, handler 60%, domain 40%, middleware 30%) are trivially unaffected as M-4 touches zero Go source files. --- .github/workflows/release.yml | 17 +++++++++++++++++ Dockerfile | 27 +++++++++++++++++++++++++++ Dockerfile.agent | 16 ++++++++++++++++ deploy/docker-compose.dev.yml | 19 +++++++++++++++++++ deploy/docker-compose.test.yml | 19 +++++++++++++++++++ deploy/docker-compose.yml | 19 +++++++++++++++++++ 6 files changed, 117 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e0f58f..da3dd17 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -107,6 +107,16 @@ jobs: tags: | ${{ env.REGISTRY }}/shankar0123/certctl-server:${{ steps.version.outputs.VERSION }} ${{ env.REGISTRY }}/shankar0123/certctl-server:latest + # Proxy propagation (M-4, Issue #9) — forwards runner-level proxy + # secrets into the Docker build so self-hosted runners behind + # corporate proxies can reach public registries. GitHub-hosted + # runners don't need proxies, so the secrets are optional and + # resolve to empty strings when unset — byte-identical to the + # pre-fix behaviour for the public-runner path. + build-args: | + HTTP_PROXY=${{ secrets.HTTP_PROXY }} + HTTPS_PROXY=${{ secrets.HTTPS_PROXY }} + NO_PROXY=${{ secrets.NO_PROXY }} cache-from: type=gha cache-to: type=gha,mode=max @@ -119,6 +129,13 @@ jobs: tags: | ${{ env.REGISTRY }}/shankar0123/certctl-agent:${{ steps.version.outputs.VERSION }} ${{ env.REGISTRY }}/shankar0123/certctl-agent:latest + # Proxy propagation (M-4, Issue #9) — see server-image step for + # rationale. Empty secrets resolve to empty build args, leaving + # the un-proxied code path byte-identical to the pre-fix tree. + build-args: | + HTTP_PROXY=${{ secrets.HTTP_PROXY }} + HTTPS_PROXY=${{ secrets.HTTPS_PROXY }} + NO_PROXY=${{ secrets.NO_PROXY }} cache-from: type=gha cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index 5416cdd..7a65a1d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,22 @@ # Stage 1: Build frontend FROM node:20-alpine AS frontend +# Proxy propagation (M-4, Issue #9) — defaulted to empty so un-proxied builds +# behave identically to the pre-fix tree. When `HTTP_PROXY`/`HTTPS_PROXY`/ +# `NO_PROXY` are forwarded via `docker build --build-arg` (or compose +# `build.args`), they are re-exported as ENV with both upper- and lower-case +# names because npm/apk/curl read the lowercase variants while Go, Node, and +# most HTTP libraries read the uppercase ones. +ARG HTTP_PROXY= +ARG HTTPS_PROXY= +ARG NO_PROXY= +ENV HTTP_PROXY=${HTTP_PROXY} \ + HTTPS_PROXY=${HTTPS_PROXY} \ + NO_PROXY=${NO_PROXY} \ + http_proxy=${HTTP_PROXY} \ + https_proxy=${HTTPS_PROXY} \ + no_proxy=${NO_PROXY} + WORKDIR /app/web COPY web/ . @@ -13,6 +29,17 @@ RUN npm ci --include=dev || npm ci --include=dev && \ # Stage 2: Build Go binary FROM golang:1.25-alpine AS builder +# Proxy propagation (M-4, Issue #9) — see Stage 1 rationale. +ARG HTTP_PROXY= +ARG HTTPS_PROXY= +ARG NO_PROXY= +ENV HTTP_PROXY=${HTTP_PROXY} \ + HTTPS_PROXY=${HTTPS_PROXY} \ + NO_PROXY=${NO_PROXY} \ + http_proxy=${HTTP_PROXY} \ + https_proxy=${HTTPS_PROXY} \ + no_proxy=${NO_PROXY} + RUN apk add --no-cache git ca-certificates tzdata WORKDIR /app diff --git a/Dockerfile.agent b/Dockerfile.agent index 8cb3058..7e85dd7 100644 --- a/Dockerfile.agent +++ b/Dockerfile.agent @@ -2,6 +2,22 @@ # Stage 1: Build FROM golang:1.25-alpine AS builder +# Proxy propagation (M-4, Issue #9) — defaulted to empty so un-proxied builds +# behave identically to the pre-fix tree. When `HTTP_PROXY`/`HTTPS_PROXY`/ +# `NO_PROXY` are forwarded via `docker build --build-arg` (or compose +# `build.args`), they are re-exported as ENV with both upper- and lower-case +# names because apk and curl read the lowercase variants while Go reads the +# uppercase ones. +ARG HTTP_PROXY= +ARG HTTPS_PROXY= +ARG NO_PROXY= +ENV HTTP_PROXY=${HTTP_PROXY} \ + HTTPS_PROXY=${HTTPS_PROXY} \ + NO_PROXY=${NO_PROXY} \ + http_proxy=${HTTP_PROXY} \ + https_proxy=${HTTPS_PROXY} \ + no_proxy=${NO_PROXY} + RUN apk add --no-cache git ca-certificates WORKDIR /app diff --git a/deploy/docker-compose.dev.yml b/deploy/docker-compose.dev.yml index da44fe1..9a34a3d 100644 --- a/deploy/docker-compose.dev.yml +++ b/deploy/docker-compose.dev.yml @@ -9,6 +9,16 @@ services: build: context: .. dockerfile: Dockerfile + # Proxy propagation (M-4, Issue #9) — forwards host shell's proxy env + # vars into the Docker build so the Node frontend stage and Go module + # download can reach the public registries behind corporate proxies. + # Defaults to empty; omit the variables from the host environment for + # un-proxied builds and the behaviour is byte-identical to the pre-fix + # tree. + args: + HTTP_PROXY: ${HTTP_PROXY:-} + HTTPS_PROXY: ${HTTPS_PROXY:-} + NO_PROXY: ${NO_PROXY:-} environment: # Verbose logging for development CERTCTL_LOG_LEVEL: debug @@ -29,6 +39,15 @@ services: build: context: .. dockerfile: Dockerfile.agent + # Proxy propagation (M-4, Issue #9) — forwards host shell's proxy env + # vars into the Docker build so the Go module download stage can reach + # the public Go module proxy behind corporate proxies. Defaults to + # empty; omit the variables from the host environment for un-proxied + # builds and the behaviour is byte-identical to the pre-fix tree. + args: + HTTP_PROXY: ${HTTP_PROXY:-} + HTTPS_PROXY: ${HTTPS_PROXY:-} + NO_PROXY: ${NO_PROXY:-} environment: CERTCTL_LOG_LEVEL: debug diff --git a/deploy/docker-compose.test.yml b/deploy/docker-compose.test.yml index 3b038a6..2692139 100644 --- a/deploy/docker-compose.test.yml +++ b/deploy/docker-compose.test.yml @@ -150,6 +150,16 @@ services: build: context: .. dockerfile: Dockerfile + # Proxy propagation (M-4, Issue #9) — forwards host shell's proxy env + # vars into the Docker build so the Node frontend stage and Go module + # download can reach the public registries behind corporate proxies. + # Defaults to empty; omit the variables from the host environment for + # un-proxied builds and the behaviour is byte-identical to the pre-fix + # tree. + args: + HTTP_PROXY: ${HTTP_PROXY:-} + HTTPS_PROXY: ${HTTPS_PROXY:-} + NO_PROXY: ${NO_PROXY:-} container_name: certctl-test-server depends_on: postgres: @@ -266,6 +276,15 @@ services: build: context: .. dockerfile: Dockerfile.agent + # Proxy propagation (M-4, Issue #9) — forwards host shell's proxy env + # vars into the Docker build so the Go module download stage can reach + # the public Go module proxy behind corporate proxies. Defaults to + # empty; omit the variables from the host environment for un-proxied + # builds and the behaviour is byte-identical to the pre-fix tree. + args: + HTTP_PROXY: ${HTTP_PROXY:-} + HTTPS_PROXY: ${HTTPS_PROXY:-} + NO_PROXY: ${NO_PROXY:-} container_name: certctl-test-agent depends_on: certctl-server: diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 78f960a..cfdbabd 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -36,6 +36,16 @@ services: build: context: .. dockerfile: Dockerfile + # Proxy propagation (M-4, Issue #9) — forwards host shell's proxy env + # vars into the Docker build so the Node frontend stage and Go module + # download can reach the public registries behind corporate proxies. + # Defaults to empty; omit the variables from the host environment for + # un-proxied builds and the behaviour is byte-identical to the pre-fix + # tree. + args: + HTTP_PROXY: ${HTTP_PROXY:-} + HTTPS_PROXY: ${HTTPS_PROXY:-} + NO_PROXY: ${NO_PROXY:-} container_name: certctl-server depends_on: postgres: @@ -75,6 +85,15 @@ services: build: context: .. dockerfile: Dockerfile.agent + # Proxy propagation (M-4, Issue #9) — forwards host shell's proxy env + # vars into the Docker build so the Go module download stage can reach + # the public Go module proxy behind corporate proxies. Defaults to + # empty; omit the variables from the host environment for un-proxied + # builds and the behaviour is byte-identical to the pre-fix tree. + args: + HTTP_PROXY: ${HTTP_PROXY:-} + HTTPS_PROXY: ${HTTPS_PROXY:-} + NO_PROXY: ${NO_PROXY:-} container_name: certctl-agent depends_on: certctl-server: