Skip to content

fix(docker): harden the hosted image and scan it in CI - #103

Merged
rennf93 merged 1 commit into
masterfrom
fix/hosted-image-hardening
Oct 21, 2026
Merged

rennf93 merged 1 commit into
masterfrom
fix/hosted-image-hardening

Conversation

@rennf93

@rennf93 rennf93 commented Oct 21, 2026

Copy link
Copy Markdown
Member

Dockerfile.hosted builds the image release-docker.yml publishes to ghcr.io/guard-core/guard-core-mcp, and nothing in CI scanned it: DockSec keeps only files named exactly Dockerfile, so #102 never covered it. On master it fails hadolint 2.15.1 (DL3008, DL3009, DL3015, DL3013, DL3042, DL3066, exit 1) and trivy 0.74.0 config (DS-0026 no HEALTHCHECK, DS-0029 no --no-install-recommends, exit 1).

  1. Same pattern as the root Dockerfile from fix(docker): run the images as a non-root user and scan them with DockSec #102: uv copied from ghcr.io/astral-sh/uv:0.13.4 instead of pip install uv, user guard now has uid 10001 and the image runs as USER 10001, files are copied with --chown instead of a recursive chown -R layer, uv sync --no-cache.
  2. The apt block is gone. Nothing in uv.lock needs libsodium (no pynacl), and nothing in the image calls curl.
  3. HEALTHCHECK fetches /.well-known/mcp/server-card.json, the route that needs no token, on GUARD_CORE_MCP_HTTP_HOST/GUARD_CORE_MCP_HTTP_PORT (0.0.0.0 and :: map to 127.0.0.1).
  4. docksec.yml gets a Scan Dockerfile.hosted job: hadolint and trivy config pinned by digest (trivy with --skip-check-update, so results only move with the pin), then an amd64 build of the image and a wait for its HEALTHCHECK to report healthy.

Verified locally, master image vs this branch (native arm64, same probe, token minted against an inline JWKS):

  • hadolint: master exit 1, branch exit 0. trivy config: master exit 1 (2 failures), branch exit 0.
  • Image size: 519 MB to 359 MB.
  • uid 999 (guard, no HEALTHCHECK) to uid 10001 (HEALTHCHECK present).
  • Server card 200, initialize without a token 401, initialize with the token 200 (guard-core 1.7.0), tools/list returns the same 9 tools, versions reports guard-core 4.4.0, fastapi-guard 8.1.2, guard-agent 3.2.4 on both.
  • check_payload with q=<script>alert(1)</script> on the branch image: is_threat: true, category xss.
  • Health: healthy with the default host, and healthy with GUARD_CORE_MCP_HTTP_HOST=127.0.0.1, which is what the production compose sets.

Not changed: the published image only changes on the next release, the CMD, port 8020 and every GUARD_CORE_MCP_* variable. Not verified locally: the amd64 build, which the new job covers.

@rennf93 rennf93 added the no-issue Chore or dependency PR that does not need an issue label Oct 21, 2026
@github-actions github-actions Bot added the ci GitHub Actions and pre-commit label Oct 21, 2026
@rennf93
rennf93 merged commit 40ffc49 into master Oct 21, 2026
17 of 18 checks passed
@rennf93
rennf93 deleted the fix/hosted-image-hardening branch October 22, 2026 02:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci GitHub Actions and pre-commit no-issue Chore or dependency PR that does not need an issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant