From 92f19cb2b30d3aaee421722ce49f36c9021a8e94 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 15 Apr 2026 09:24:05 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20publish=20versioned=20agent=20images=20?= =?UTF-8?q?=E2=80=94=20compose=20should=20use=20image:=20not=20build:=20(#?= =?UTF-8?q?429)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Generated compose now uses `image: ghcr.io/disinto/{agents,edge}` instead of `build:` directives; `disinto init --build` restores local-build mode - Add VOLUME declarations to agents, reproduce, and edge Dockerfiles - Add CI pipeline (.woodpecker/publish-images.yml) to build and push images to ghcr.io/disinto on tag events - Mount projects/, .env, and state/ into agents container for runtime config - Skip pre-build binary download when compose uses registry images Co-Authored-By: Claude Opus 4.6 (1M context) --- .woodpecker/publish-images.yml | 64 ++++++++++++++++++++++++++++++++++ bin/disinto | 20 ++++++----- docker/agents/Dockerfile | 3 ++ docker/edge/Dockerfile | 3 ++ docker/reproduce/Dockerfile | 3 ++ lib/generators.sh | 25 +++++++------ 6 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 .woodpecker/publish-images.yml diff --git a/.woodpecker/publish-images.yml b/.woodpecker/publish-images.yml new file mode 100644 index 0000000..15f373d --- /dev/null +++ b/.woodpecker/publish-images.yml @@ -0,0 +1,64 @@ +# .woodpecker/publish-images.yml — Build and push versioned container images +# Triggered on tag pushes (e.g. v1.2.3). Builds and pushes: +# - ghcr.io/disinto/agents: +# - ghcr.io/disinto/reproduce: +# - ghcr.io/disinto/edge: +# +# Requires GHCR_TOKEN secret configured in Woodpecker with push access +# to ghcr.io/disinto. + +when: + event: tag + ref: refs/tags/v* + +clone: + git: + image: alpine/git + commands: + - AUTH_URL=$(printf '%s' "$CI_REPO_CLONE_URL" | sed "s|://|://token:$FORGE_TOKEN@|") + - git clone --depth 1 "$AUTH_URL" . + - git fetch --depth 1 origin "$CI_COMMIT_REF" + - git checkout FETCH_HEAD + +steps: + - name: build-and-push-agents + image: plugins/docker + settings: + repo: ghcr.io/disinto/agents + registry: ghcr.io + dockerfile: docker/agents/Dockerfile + context: . + tags: + - ${CI_COMMIT_TAG} + - latest + username: disinto + password: + from_secret: GHCR_TOKEN + + - name: build-and-push-reproduce + image: plugins/docker + settings: + repo: ghcr.io/disinto/reproduce + registry: ghcr.io + dockerfile: docker/reproduce/Dockerfile + context: . + tags: + - ${CI_COMMIT_TAG} + - latest + username: disinto + password: + from_secret: GHCR_TOKEN + + - name: build-and-push-edge + image: plugins/docker + settings: + repo: ghcr.io/disinto/edge + registry: ghcr.io + dockerfile: docker/edge/Dockerfile + context: docker/edge + tags: + - ${CI_COMMIT_TAG} + - latest + username: disinto + password: + from_secret: GHCR_TOKEN diff --git a/bin/disinto b/bin/disinto index bbb11ec..44d0364 100755 --- a/bin/disinto +++ b/bin/disinto @@ -82,6 +82,7 @@ Init options: --ci-id Woodpecker CI repo ID (default: 0 = no CI) --forge-url Forge base URL (default: http://localhost:3000) --bare Skip compose generation (bare-metal setup) + --build Use local docker build instead of registry images (dev mode) --yes Skip confirmation prompts --rotate-tokens Force regeneration of all bot tokens/passwords (idempotent by default) @@ -652,7 +653,7 @@ disinto_init() { shift # Parse flags - local branch="" repo_root="" ci_id="0" auto_yes=false forge_url_flag="" bare=false rotate_tokens=false + local branch="" repo_root="" ci_id="0" auto_yes=false forge_url_flag="" bare=false rotate_tokens=false use_build=false while [ $# -gt 0 ]; do case "$1" in --branch) branch="$2"; shift 2 ;; @@ -660,6 +661,7 @@ disinto_init() { --ci-id) ci_id="$2"; shift 2 ;; --forge-url) forge_url_flag="$2"; shift 2 ;; --bare) bare=true; shift ;; + --build) use_build=true; shift ;; --yes) auto_yes=true; shift ;; --rotate-tokens) rotate_tokens=true; shift ;; *) echo "Unknown option: $1" >&2; exit 1 ;; @@ -743,7 +745,7 @@ p.write_text(text) local forge_port forge_port=$(printf '%s' "$forge_url" | sed -E 's|.*:([0-9]+)/?$|\1|') forge_port="${forge_port:-3000}" - generate_compose "$forge_port" + generate_compose "$forge_port" "$use_build" generate_agent_docker generate_caddyfile generate_staging_index @@ -1412,13 +1414,15 @@ disinto_up() { exit 1 fi - # Pre-build: download binaries to docker/agents/bin/ to avoid network calls during docker build - echo "── Pre-build: downloading agent binaries ────────────────────────" - if ! download_agent_binaries; then - echo "Error: failed to download agent binaries" >&2 - exit 1 + # Pre-build: download binaries only when compose uses local build + if grep -q '^\s*build:' "$compose_file"; then + echo "── Pre-build: downloading agent binaries ────────────────────────" + if ! download_agent_binaries; then + echo "Error: failed to download agent binaries" >&2 + exit 1 + fi + echo "" fi - echo "" # Decrypt secrets to temp .env if SOPS available and .env.enc exists local tmp_env="" diff --git a/docker/agents/Dockerfile b/docker/agents/Dockerfile index 78fbbf6..2939230 100644 --- a/docker/agents/Dockerfile +++ b/docker/agents/Dockerfile @@ -28,6 +28,9 @@ RUN chmod +x /entrypoint.sh # Entrypoint runs polling loop directly, dropping to agent user via gosu. # All scripts execute as the agent user (UID 1000) while preserving env vars. +VOLUME /home/agent/data +VOLUME /home/agent/repos + WORKDIR /home/agent/disinto ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/edge/Dockerfile b/docker/edge/Dockerfile index 6706852..eca7d7e 100644 --- a/docker/edge/Dockerfile +++ b/docker/edge/Dockerfile @@ -1,4 +1,7 @@ FROM caddy:latest RUN apk add --no-cache bash jq curl git docker-cli python3 openssh-client autossh COPY entrypoint-edge.sh /usr/local/bin/entrypoint-edge.sh + +VOLUME /data + ENTRYPOINT ["bash", "/usr/local/bin/entrypoint-edge.sh"] diff --git a/docker/reproduce/Dockerfile b/docker/reproduce/Dockerfile index 3192744..30bc75f 100644 --- a/docker/reproduce/Dockerfile +++ b/docker/reproduce/Dockerfile @@ -7,5 +7,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN useradd -m -u 1000 -s /bin/bash agent COPY docker/reproduce/entrypoint-reproduce.sh /entrypoint-reproduce.sh RUN chmod +x /entrypoint-reproduce.sh +VOLUME /home/agent/data +VOLUME /home/agent/repos + WORKDIR /home/agent ENTRYPOINT ["/entrypoint-reproduce.sh"] diff --git a/lib/generators.sh b/lib/generators.sh index 3b42b5d..4de8708 100644 --- a/lib/generators.sh +++ b/lib/generators.sh @@ -100,9 +100,7 @@ _generate_local_model_services() { cat >> "$temp_file" <