From f358badb370fd61e0ce00482a5bcd432d2570c7c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 11 Jul 2026 15:10:00 +0000 Subject: [PATCH 1/3] Stamp the release version into published images (was "dev") The Dockerfile defaulted AGENT_VERSION to "dev" and the release workflow never passed a real value, so every published image reported its version as "dev" (visible in the control panel and agent overview). Default the build to the current release (matching internal/version.Value) and have the release workflow stamp the git tag's semver onto tagged builds. Claude-Session: https://claude.ai/code/session_01DsRvKKSEzvJCXe4x656ZzU --- .github/workflows/docker-image.yml | 4 ++++ CHANGELOG.md | 3 +++ Dockerfile | 5 ++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index c194104..7fc0082 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -61,6 +61,10 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + # Stamp the binary's reported version: the git tag's semver on a + # tagged release, otherwise the Dockerfile's release default. + build-args: | + AGENT_VERSION=${{ startsWith(github.ref, 'refs/tags/') && steps.meta.outputs.version || '1.0.0' }} # Keep the manifest list clean (one entry per arch, no "unknown/unknown" # provenance entries that confuse some ARM runtimes / imagetools). provenance: false diff --git a/CHANGELOG.md b/CHANGELOG.md index e9f016c..8c6d7dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ The Site Agent and central Overwatch are versioned independently. - Restore the central-dispatched cache commands (status refresh, cache resync, cache purge) that had been dropped in an earlier refactor, so operating an agent from Overwatch works again. +- Published container images now report the real release version instead of + `dev`: the Docker build defaults the version to the current release and the + release workflow stamps the git tag's version onto tagged builds. ## [1.0.0] — 2026-07-11 diff --git a/Dockerfile b/Dockerfile index 2e2cec0..69c64a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,10 @@ # amd64/arm64/armv7 all build without QEMU — matches docker-image.yml, which # sets up buildx only (no setup-qemu). FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS build -ARG AGENT_VERSION=dev +# Default to the current release so an un-tagged build (e.g. main -> :latest) +# still reports a real version, not "dev". Tagged releases override this via a +# build-arg (see docker-image.yml). Keep in sync with internal/version.Value. +ARG AGENT_VERSION=1.0.0 ARG TARGETOS TARGETARCH TARGETVARIANT WORKDIR /src COPY go.mod go.sum ./ From b507e206a5211a42f4918343d28986ed0eec15e7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 12 Jul 2026 02:31:35 +0000 Subject: [PATCH 2/3] v1.0.1: stamp the real version on every build path (kill "dev") MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cut 1.0.1, releasing the pending fixes (central cache-command restore and the version-stamping fix). internal/version.Value -> 1.0.1, Dockerfile + release workflow default to 1.0.1, and the changelog is dated. The agent also honours an AGENT_VERSION env override to correct the reported version on an already-built image without a rebuild. Gates: gofmt, go vet, go test — all green. https://claude.ai/code/session_01VdkwmAyuVF5EqwZUB5Ertr --- .github/workflows/docker-image.yml | 2 +- CHANGELOG.md | 10 ++++++---- Dockerfile | 2 +- internal/version/version.go | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 7fc0082..9bfcd52 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -64,7 +64,7 @@ jobs: # Stamp the binary's reported version: the git tag's semver on a # tagged release, otherwise the Dockerfile's release default. build-args: | - AGENT_VERSION=${{ startsWith(github.ref, 'refs/tags/') && steps.meta.outputs.version || '1.0.0' }} + AGENT_VERSION=${{ startsWith(github.ref, 'refs/tags/') && steps.meta.outputs.version || '1.0.1' }} # Keep the manifest list clean (one entry per arch, no "unknown/unknown" # provenance entries that confuse some ARM runtimes / imagetools). provenance: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c6d7dd..ccc4928 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,18 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The Site Agent and central Overwatch are versioned independently. -## [Unreleased] +## [1.0.1] — 2026-07-12 ### Fixed - Restore the central-dispatched cache commands (status refresh, cache resync, cache purge) that had been dropped in an earlier refactor, so operating an agent from Overwatch works again. -- Published container images now report the real release version instead of - `dev`: the Docker build defaults the version to the current release and the - release workflow stamps the git tag's version onto tagged builds. +- The agent no longer reports its version as `dev`. Every build path now stamps + the real release version — the standalone and monorepo Docker builds default + to it, both publish workflows stamp a clean SemVer, and an `AGENT_VERSION` + environment variable overrides the reported version on an already-built image + without a rebuild. ## [1.0.0] — 2026-07-11 diff --git a/Dockerfile b/Dockerfile index 69c64a8..2710a7d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS build # Default to the current release so an un-tagged build (e.g. main -> :latest) # still reports a real version, not "dev". Tagged releases override this via a # build-arg (see docker-image.yml). Keep in sync with internal/version.Value. -ARG AGENT_VERSION=1.0.0 +ARG AGENT_VERSION=1.0.1 ARG TARGETOS TARGETARCH TARGETVARIANT WORKDIR /src COPY go.mod go.sum ./ diff --git a/internal/version/version.go b/internal/version/version.go index cfaad4d..92e9a30 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -6,4 +6,4 @@ package version // -ldflags "-X overwatch/agent/internal/version.Value=v1.2.3" // // or at runtime with the AGENT_VERSION environment variable. -var Value = "1.0.0" +var Value = "1.0.1" From 1973c1ced740f2ea813da74900ed6ad39c7c22d7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 12 Jul 2026 02:53:49 +0000 Subject: [PATCH 3/3] Bound outgoing frame payload to MaxPayload (parity with central) Replicate the monorepo agent's defensive Frame() payload bound so an over-size print-server frame's length can never overflow the uint32 header field. Brings the public repo's Go source to full parity with the central monorepo agent. Rolled into the 1.0.1 entry. https://claude.ai/code/session_01VdkwmAyuVF5EqwZUB5Ertr --- CHANGELOG.md | 2 ++ internal/ozoneproto/ozoneproto.go | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccc4928..a7d7589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ The Site Agent and central Overwatch are versioned independently. to it, both publish workflows stamp a clean SemVer, and an `AGENT_VERSION` environment variable overrides the reported version on an already-built image without a rebuild. +- Defensively bound an outgoing print-server frame's payload to `MaxPayload`, so + the length always fits the 32-bit header field (parity with central). ## [1.0.0] — 2026-07-11 diff --git a/internal/ozoneproto/ozoneproto.go b/internal/ozoneproto/ozoneproto.go index 8c6f0e1..3f3fb50 100644 --- a/internal/ozoneproto/ozoneproto.go +++ b/internal/ozoneproto/ozoneproto.go @@ -21,9 +21,16 @@ const ( ) // Frame wraps a JSON payload in the 5-byte header: little-endian length + 0x28. +// Payloads are bounded by MaxPayload, so the length always fits the uint32 header +// field; an over-size payload (never expected in practice) is capped defensively +// rather than overflowing the length. func Frame(payload []byte) []byte { - out := make([]byte, HeaderSize+len(payload)) - binary.LittleEndian.PutUint32(out[:4], uint32(len(payload))) + if len(payload) > MaxPayload { + payload = payload[:MaxPayload] + } + n := len(payload) // 0 <= n <= MaxPayload, so it fits in uint32 + out := make([]byte, HeaderSize+n) + binary.LittleEndian.PutUint32(out[:4], uint32(n)) out[4] = TokenByte copy(out[HeaderSize:], payload) return out