Skip to content

feat: add docker-hub-webhooks skill - #204

Merged
garethx merged 2 commits into
mainfrom
feat/docker-hub-webhooks
Sep 28, 2026
Merged

garethx merged 2 commits into
mainfrom
feat/docker-hub-webhooks

Conversation

@garethx

@garethx garethx commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Adds docker-hub-webhooks, a skill for receiving Docker Hub repository webhooks, with Express, Next.js and FastAPI examples (19 tests each).

The scheme: there isn't one

Docker Hub webhooks are unsigned. The webhooks docs describe no signature header, shared secret, HMAC, timestamp or auth option, and the create form takes only a name and a destination URL (255 characters max). The skill therefore ships no verifier. What it does instead:

  • Secret URL token in the path (/webhooks/docker-hub/<token>), compared in constant time. It fails closed with 500 when DOCKER_HUB_WEBHOOK_TOKEN is unset. The docs are explicit that this is a bearer secret in a URL and not a Docker signature.
  • Repository allowlist (DOCKER_HUB_ALLOWED_REPOS, 403 for anything else), plus shape validation on push_data.tag and repository.repo_name (400 if missing).
  • Optional re-check against the Hub API GetRepositoryTag before acting, with a recommendation to pull by digest.

Other mechanics it covers:

Things a reviewer might flag (checked)

  • No verifier is deliberate, since Docker Hub doesn't sign anything. The code has no HMAC, no invented X-Docker-Signature header and no IP allowlist.
  • Hub API auth: a raw PAT/OAT is not a bearer token. The Hub API reference says each credential must go through POST /v2/auth/token to get a JWT (valid 10 min). The examples exchange the credential and cache the JWT, and send no Authorization header for public repos. I checked on 2026-09-28: GET .../library/repositories/alpine/tags/latest returns 200 with no auth and 401 with an unrecognised bearer.
  • Hedged, not asserted: pushed_at is in Unix seconds, inferred from the 10-digit example. Retry policy, timeout and request headers are not documented, and the skill says so rather than giving numbers. The documented example payload dates from 2014, so the skill only relies on a small set of fields.

Cross-checked against hookdeck/core (merged in hookdeck/core#5669)

Core's DOCKER_HUB source type is "No verification (schema only)", uses managed POST, and has external_docs_url = https://docs.docker.com/docker-hub/repos/manage/webhooks/. That matches the primary docs and this skill, with no disagreements. The skill says Hookdeck doesn't verify Docker Hub (there's nothing to verify). It also says Hookdeck's own outbound signature only secures the Hookdeck → destination hop. Docker Hub isn't in the hookdeck.com/docs/sources list yet (checked 2026-09-28).

Testing

  • validate-provider.sh docker-hub-webhooks: passes
  • Express (Node 22): 19/19 passing
  • Next.js (Node 24 / npm 11): 19/19 passing
  • FastAPI (fresh venv, Python 3.14): 19/19 passing
  • No live account, so there was no end-to-end delivery test.

🤖 Generated with Claude Code

garethx and others added 2 commits September 28, 2026 15:18
…their sources

Cite docker/docs#23955 for the callback_url 404 report, and ground the
raw-PAT-as-bearer warning in the Hub API reference's auth guidance plus
the observed 401 for an unrecognised bearer on a public repo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@garethx
garethx marked this pull request as ready for review September 28, 2026 14:26
@garethx
garethx merged commit 7ef13e7 into main Sep 28, 2026
8 checks passed
@garethx
garethx deleted the feat/docker-hub-webhooks branch September 28, 2026 14:26
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.

1 participant