Skip to content

Add buildx, scout, and Hub rate-limit handling#8

Merged
GavinLucas merged 12 commits into
mainfrom
feature/buildx-scout
May 12, 2026
Merged

Add buildx, scout, and Hub rate-limit handling#8
GavinLucas merged 12 commits into
mainfrom
feature/buildx-scout

Conversation

@GavinLucas
Copy link
Copy Markdown
Owner

Summary

Extends the MCP surface with two new CLI-backed modules and hardens the existing registry HTTPS path against Hub throttling.

tools/buildx.py (11 tools)

  • buildx_build, buildx_bake — modern BuildKit builds with multi-platform, cache import/export, SBOM/provenance attestations, build secrets, and SSH forwarding.
  • buildx_imagetools_inspect, buildx_imagetools_createsupersede docker manifest inspect/create/push. The standalone docker manifest command is in maintenance mode and lacks support for OCI image indexes and attestations; the docstrings and three new prompts (`inspect_multiarch_manifest`, `create_multiarch_manifest`, `migrate_from_docker_manifest`) point users to the buildx equivalents.
  • buildx_ls, buildx_inspect, buildx_du, buildx_prune — builder + cache management. buildx_prune always runs with --force (no interactive TTY available) and is documented as destructive in the README security section.
  • buildx_create, buildx_use, buildx_rm — builder admin.

tools/scout.py (5 tools)

  • scout_cves — list CVEs, filter by severity (`only_severity` accepts a list and is joined for the CLI), skip base-image issues with `ignore_base`.
  • scout_quickview — compact per-severity summary.
  • scout_recommendations — base-image upgrade suggestions.
  • scout_compare — CVE delta between two image refs; validates exactly one of `to`, `to_env`, or `to_latest` is supplied.
  • scout_sbom — SPDX, CycloneDX, or list-format SBOMs. SPDX and CycloneDX outputs are parsed; `list` is returned as text.

Each docstring notes that Scout's richest data requires `docker login` on the host running this MCP server.

Hub rate-limit handling (`tools/registry.py`)

Hybrid retry policy: when a 429 has `Retry-After ≤ 10s`, sleep + retry once transparently. Otherwise raise a descriptive RuntimeError that mentions the anonymous-pull cap and how to authenticate. Applied to both the OCI v2 code path (`_registry_get`) and the Hub UI API loops (`hub_list_tags`, `hub_repo_info`).

Prompts

Buildx / Scout walkthroughs: `plan_multiarch_build`, `audit_image_cves`, `compare_image_versions`, `recommend_base_image`.

Manifest-redirect prompts (the bridge from `docker manifest` thinking):

  • `inspect_multiarch_manifest(image)` — emits a plan using `buildx_imagetools_inspect`.
  • `create_multiarch_manifest(target_tag, source_tags)` — emits a plan using `buildx_imagetools_create` with a dry-run step before pushing.
  • `migrate_from_docker_manifest()` — returns a mapping table from each `docker manifest` subcommand to its buildx imagetools replacement.

CI: integration tests

New `integration-tests` job in `.github/workflows/premerge.yaml`:

  • Gated on `pytest-run` (unit tests).
  • Uses ubuntu-latest's pre-installed docker engine, compose v2, and buildx; scout integration tests skip cleanly via `has_plugin()` since scout isn't pre-installed.
  • Optional Hub auth via `DOCKERHUB_USER` / `DOCKERHUB_TOKEN` repo secrets to raise the anonymous rate limit; without secrets the existing skip-on-pull-failure behavior catches throttling.
  • 20-minute timeout.

Resources / docs

  • `tools/resources.py` adds `buildx`, `buildx-cli`, `buildx-bake`, `scout`, `scout-cli` to `EXTERNAL_SECTIONS`.
  • `README.md` adds the new tool groups under "What the agent can do", new prompt examples, and updates the security section.
  • `CLAUDE.md` architecture table refreshed.

Toolchain

  • `uv run pytest`: 293 passed, 25 deselected (49 new unit tests)
  • `uv run pytest -m integration --collect-only`: 25 integration tests discoverable
  • `uv run ruff check .`: clean
  • `uv run ruff format --check .`: clean
  • `uv run pyright`: 0 errors, 0 warnings, 0 informations

Test plan

  • Run unit suite: `uv run pytest -v`
  • Run integration suite locally with buildx (`uv run pytest -m integration -v`); the scout test will skip on plain Linux daemons
  • Verify the new CI `integration-tests` job runs on this PR and passes
  • Smoke-test in an MCP client: `/plan_multiarch_build image=ghcr.io/org/app:v1`, `/audit_image_cves image=alpine:3.19`, `/migrate_from_docker_manifest`
  • Verify Hub rate-limit handling by setting a low limit (e.g. `registry_list_tags` against a private mirror that 429s)

🤖 Generated with Claude Code

Extends the MCP surface with two new CLI-backed modules and hardens
the existing registry HTTPS path against Hub throttling.

tools/buildx.py (11 tools):
- buildx_build, buildx_bake — modern BuildKit builds with multi-platform,
  cache import/export, SBOM/provenance attestations
- buildx_imagetools_inspect, buildx_imagetools_create — supersede
  docker manifest inspect/create/push; docstrings call out the migration
- buildx_ls, buildx_inspect, buildx_du, buildx_prune — builder + cache management
- buildx_create, buildx_use, buildx_rm — builder admin

tools/scout.py (5 tools):
- scout_cves, scout_quickview, scout_recommendations, scout_compare,
  scout_sbom — vulnerability scanning, CVE delta, base-image recommendations,
  SBOM generation. Docstrings note that most data requires `docker login`.

Hub rate-limit handling (tools/registry.py):
- Hybrid retry: transparently retry once when Retry-After <= 10s,
  otherwise raise a descriptive RuntimeError mentioning the cap and
  how to authenticate. Applied to both the OCI v2 path and the Hub UI API.

Prompts (tools/prompts.py):
- plan_multiarch_build, audit_image_cves, compare_image_versions,
  recommend_base_image — walk-throughs for the new tools
- inspect_multiarch_manifest, create_multiarch_manifest,
  migrate_from_docker_manifest — guide users from "docker manifest"
  thinking to buildx imagetools

Resources, README, CLAUDE.md updated to match. New CI job runs the
integration suite on every push, gated on the unit-test job, with
optional Hub auth via repo secrets.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 14:35
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends docker-mcp with new CLI-backed MCP tools for Docker Buildx and Docker Scout, adds multi-arch / security-focused prompts, and hardens the HTTPS registry/Hub tooling with a 429 retry policy to better handle Docker Hub throttling.

Changes:

  • Add new CLI-backed tool modules: tools/buildx.py (BuildKit/buildx workflows) and tools/scout.py (CVE/SBOM/recommendations/compare).
  • Add new prompts for multi-arch builds, manifest inspection/creation, and Scout-based security auditing/comparison.
  • Add Hub/registry 429 handling plus new CI integration test job and accompanying unit/integration tests and docs updates.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tools/buildx.py New buildx CLI tool wrappers (build/bake/imagetools/builder management).
tools/scout.py New scout CLI tool wrappers (cves/quickview/recommendations/compare/sbom).
tools/registry.py Adds Retry-After parsing + one-retry policy for HTTP 429 on registry/Hub calls.
tools/prompts.py Adds buildx/scout workflow prompts + manifest-to-imagetools migration prompts.
tools/resources.py Extends docs resource allow-list with buildx/scout sections.
tools/__init__.py Re-exports the new tool modules.
tests/test_buildx.py Unit tests for buildx argument construction and parsing behavior.
tests/test_scout.py Unit tests for scout argument construction and JSON parsing behavior.
tests/test_registry.py Unit tests for new 429 policy and Retry-After parsing.
tests/test_prompts.py Unit tests validating new prompt outputs reference the right tools.
tests/integration/test_buildx.py Integration smoke tests for buildx plugin + daemon wiring.
tests/integration/test_scout.py Integration smoke test for scout (skips cleanly if plugin absent/offline).
README.md Documents new tool groups, prompt examples, and destructive-operation notes.
CLAUDE.md Updates architecture/tooling table with buildx/scout modules.
.github/workflows/premerge.yaml Adds a new integration-tests job for pytest -m integration.

Comment thread tools/buildx.py
Comment thread tools/buildx.py
Comment thread tools/buildx.py
Comment thread tools/scout.py Outdated
Comment thread tools/registry.py Outdated
Comment thread .github/workflows/premerge.yaml Outdated
- buildx.py: enforce mutual-exclusion the docstrings claimed but the
  code didn't: push/load (build), raw/format (imagetools_inspect),
  name/all_inactive (rm). Each pair now raises ValueError with a
  message explaining why and how to pick one.
- scout.py: clarify scout_sbom returns docstring — JSON parsing
  happens for spdx/cyclonedx/json formats (all JSON serializations),
  not only when format='json'.
- registry.py: 429 error message is now registry-agnostic. Hub-specific
  guidance ("anonymous pulls capped at ~100 / 6h") only appears when the
  URL is on registry-1.docker.io / index.docker.io / hub.docker.com;
  other registries (GHCR, ECR, GAR, …) get neutral advice about
  authenticating to raise per-registry limits.
- premerge.yaml: the Hub-login step's `if:` referenced env.DOCKERHUB_TOKEN
  before the step's own env block had been applied, so the step would
  run even with an empty secret. Gate on `secrets.DOCKERHUB_TOKEN` (and
  DOCKERHUB_USER) directly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 14:45
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Comment thread tools/buildx.py
Comment thread tools/registry.py
- buildx_build: reject context='-' explicitly. The tool doesn't forward
  stdin to run_docker, so `-` would block on the MCP server's own stdin
  rather than reading a tarball. The docstring is updated to call out
  the limitation and suggest an HTTP URL as the workaround.
- _parse_retry_after: treat naive datetimes returned by
  email.utils.parsedate_to_datetime (when the source HTTP-date used the
  `-0000` form) as UTC, per RFC 7231/9110. Without this, .timestamp()
  re-interpreted the value in the host's local timezone and could
  produce a wildly wrong delay. Test added for the -0000 vs +0000
  equivalence.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 14:55
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comment thread tools/buildx.py Outdated
Comment thread tests/test_buildx.py Outdated
Comment thread tools/prompts.py Outdated
- buildx_build / buildx_imagetools_create / buildx_create: emit one
  `--platform` with a comma-joined value instead of one flag per entry.
  Both forms work functionally (the underlying CLI flag is stringArray
  and buildx parses commas inside each entry too — verified locally),
  but comma-joined is the documented convention across upstream docs
  and avoids ambiguity for review tools. Tests updated.
- migrate_from_docker_manifest prompt: switch to keyword args
  (`buildx_imagetools_create(target=…, sources=[…])`) so the mapping
  is unambiguous and consistent with the other prompts in the file.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 15:06
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings May 12, 2026 15:13
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings May 12, 2026 15:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Comment thread tools/buildx.py Outdated
GavinLucas and others added 2 commits May 12, 2026 16:28
The buildx_build docstring noted no shell expansion of `~`, but the
`secret` example used `src=~/.npmrc` — which neither this tool nor
buildx itself would expand. Updated to show an absolute path plus an
`env=` alternative, and called out the `~` non-expansion explicitly
in the secret parameter doc.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous fix gated the Hub-login step on `secrets.DOCKERHUB_TOKEN`
in its `if:`, but GitHub Actions blocks the `secrets` context inside
step-level `if:` conditions (security policy — secrets would leak into
expression-evaluation logs). Workflow validation now fails outright:

    Unrecognized named-value: 'secrets'

Hoist the secrets to job-level `env:` instead. Job-level env IS
resolved before step `if:` is evaluated, so gating on
`env.DOCKERHUB_TOKEN` works correctly. The Hub-login step no longer
needs its own `env:` block — it inherits from the job.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 15:50
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Comment thread .github/workflows/premerge.yaml Outdated
The previous comment claimed GitHub Actions "blocks the `secrets`
context inside step-level `if:`", which is more assertive than the
authoritative GitHub docs (the policy is somewhat ambiguous and may
have evolved). Replace with a description of the observed empirical
behaviour — the workflow validator rejects `secrets.*` in step `if:`
with "Unrecognized named-value: 'secrets'" — without claiming why.
The hoist to job-level env remains correct.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 15:56
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Comment thread tools/scout.py Outdated
The previous docstring listed only "spdx"/"cyclonedx"/"list" under
args.format, but the parsing logic and returns description also
reference "json". docker scout sbom accepts all four (json is in fact
the CLI's own default). Enumerate every supported value explicitly so
the args, returns, and implementation agree.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 16:01
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Comment thread tools/buildx.py Outdated
_parse_json_lines now accepts an explicit `truncated` flag and a label.
When truncated=True the final non-blank line is dropped before parsing
(it's almost certainly a partial record from the MAX_CLI_OUTPUT_BYTES
cap in run_docker). Any remaining JSONDecodeError is converted into a
descriptive RuntimeError that includes the line number, the truncated
flag, and a snippet — so a malformed-but-not-truncated response no
longer surfaces as a bare json.JSONDecodeError.

buildx_ls and buildx_du forward the truncation flag from CliResult and
provide a human-readable label. Tests cover: partial-record drop,
descriptive raise on garbage, and the buildx_ls truncated path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 16:10
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Comment thread tools/prompts.py Outdated
Comment thread tools/prompts.py Outdated
… ref

- prompts.py: realign three new prompts (plan_multiarch_build,
  compare_image_versions, create_multiarch_manifest) to the project's
  one-`args:`-per-line docstring convention. The block style I'd
  used was inconsistent with every other prompt in this file.

- recommend_base_image: the candidate-verification step pointed at
  `registry_inspect_manifest(image=<candidate>, reference=<tag>)`,
  but `registry_inspect_manifest` strips `:tag`/`@digest` from `image`
  — so passing a full ref like `python:3.13-slim` would need to be
  split, and the prompt didn't explain how. Switch to
  `buildx_imagetools_inspect(image=<candidate>, raw=True)`, which
  accepts a full ref. Added a brief note steering callers away from
  `registry_inspect_manifest` for this use case.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-advanced-security
Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@GavinLucas GavinLucas merged commit b14c7ea into main May 12, 2026
8 checks passed
@GavinLucas GavinLucas deleted the feature/buildx-scout branch May 12, 2026 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants