Skip to content

Commit 0044a3f

Browse files
fix(env): pin the infra images' base images by digest, and let Dependabot bump them (#283)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 258f430 commit 0044a3f

6 files changed

Lines changed: 36 additions & 4 deletions

File tree

‎.github/dependabot.yml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ updates:
3131
groups:
3232
npm-minor-and-patch:
3333
update-types: ["minor", "patch"]
34+
# The infra images the release publishes. Each base is pinned by digest, and a release rebuilds an image only when its
35+
# sources change, so a bump here is what picks up a base's fixes: the next release builds and publishes the image.
36+
- package-ecosystem: "docker"
37+
directories:
38+
- "/src/agent_env/env/gateway"
39+
- "/src/agent_env/env/envs/service_db"
40+
- "/src/agent_env/env/envs/website_browser"
41+
schedule:
42+
interval: "weekly"
43+
open-pull-requests-limit: 5
44+
groups:
45+
infra-base-images:
46+
patterns: ["*"]
3447
- package-ecosystem: "github-actions"
3548
directory: "/"
3649
schedule:

‎AGENTS.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ package to PyPI. Run by hand on `main`, the workflow publishes the images alone.
281281
Its jobs that run agent-env (`.github/scripts/infra_images.py`) hold no token that writes; the jobs that push
282282
images or publish to PyPI install nothing and check what they're handed (`.github/scripts/infra_build.py`,
283283
standard library and the docker CLI only).
284-
Actions are pinned to commit SHAs; Dependabot updates them, the pinned uv, `uv.lock` and the UI's npm packages.
284+
Actions are pinned to commit SHAs; Dependabot updates them, the pinned uv, `uv.lock`, the UI's npm packages and
285+
the infra images' base images, each pinned by digest so that a bump rebuilds and republishes the image.
285286

286287
## Conventions
287288

‎CONTRIBUTING.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ the previous release, so a clear pull request title is also the release note. A
9191
A release also publishes the infra images agent-env ships, once the `PUBLISH_INFRA_IMAGES` repository variable is
9292
`true`: one per Dockerfile under `src/agent_env/env`, at `ghcr.io/scaleapi/agentenv-<name>:src-<hex>` for linux/amd64
9393
and linux/arm64, where the tag is the build context's source digest, so an unchanged Dockerfile is not built again.
94+
Each of them pins its base images by digest, and Dependabot bumps those pins, so a base's fixes reach the published
95+
image: a bump changes the sources, and the next release builds it again.
9496
Installs pull them instead of building the infra images: a run on local stores registers a kind's images when GHCR has
9597
every one for the sources installed, by the digest the wheel records or, with no record, the one GHCR serves, and
9698
builds them otherwise; a sandbox that can't pull one builds it from its build context. The wheel and the release notes

‎src/agent_env/env/envs/service_db/Dockerfile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM public.ecr.aws/docker/library/postgres:16-alpine
1+
FROM public.ecr.aws/docker/library/postgres:16-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea
22

33
# ServiceDBEnv - PostgreSQL database for MCP services
44
#

‎src/agent_env/env/envs/service_db/Dockerfile.db-mcp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# The Docker Hub image (crystaldba/postgres-mcp:latest) ships MCP 1.6.0,
33
# which only supports stdio and SSE transports.
44

5-
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
5+
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim@sha256:e5b65587bce7de595f299855d7385fe7fca39b8a74baa261ba1b7147afa78e58 AS builder
66
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
77
ENV UV_PYTHON_DOWNLOADS=0
88

@@ -24,7 +24,7 @@ RUN sed -i 's/mcp = FastMCP("postgres-mcp")/from mcp.server.transport_security i
2424

2525
RUN uv sync --frozen --no-dev
2626

27-
FROM public.ecr.aws/docker/library/python:3.12-slim-bookworm
27+
FROM public.ecr.aws/docker/library/python:3.12-slim-bookworm@sha256:6a0e06f5ba0b373d051aabd3fffb9b873f27f9a2a3a14bcbe37dee6f0e3bbc70
2828
RUN groupadd -r app && useradd -r -g app app
2929
COPY --from=builder --chown=app:app /app /app
3030

‎tst/unit/test_release_infra_images.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import pytest
1010
import yaml
1111

12+
from agent_env.env import bootstrap
1213
from agent_env.env.published_images import RELEASE_FILE
1314

1415
REPO = Path(__file__).resolve().parents[2]
@@ -135,3 +136,18 @@ def test_what_a_registry_can_rate_limit_is_tried_again():
135136
assert 'infra_build.py retry docker push "$BUILT"' in build
136137
assert "infra_build.py retry docker buildx imagetools create" in publish
137138
assert JOBS["infra-build"]["strategy"]["max-parallel"] <= 4
139+
140+
141+
def test_every_infra_image_pins_its_bases_by_digest_and_dependabot_bumps_them():
142+
"""A release rebuilds an image only when its sources change, so a base behind a bare tag never picks up its
143+
fixes; pinned, the pin is a source, and Dependabot bumping it is what rebuilds and republishes the image."""
144+
dependabot = yaml.safe_load((REPO / ".github" / "dependabot.yml").read_text())
145+
(docker,) = [update for update in dependabot["updates"] if update["package-ecosystem"] == "docker"]
146+
147+
for image in bootstrap.PUBLISHED_IMAGES:
148+
text = image.dockerfile.read_text()
149+
stages = set(re.findall(r"^FROM\s+\S+\s+AS\s+(\S+)", text, re.IGNORECASE | re.MULTILINE))
150+
bases = [ref for ref in re.findall(r"^FROM\s+(?:--\S+\s+)*(\S+)", text, re.IGNORECASE | re.MULTILINE)
151+
if ref not in stages]
152+
assert bases and all(re.search(r"@sha256:[0-9a-f]{64}$", ref) for ref in bases), (image.name, bases)
153+
assert f"/{image.dockerfile.parent.relative_to(REPO)}" in docker["directories"], image.name

0 commit comments

Comments
 (0)