Skip to content

feat: publish document-rest and document-mcp as GHCR container images - #1241

Merged
Mearman merged 3 commits into
mainfrom
feat/ghcr-container-images
Sep 11, 2026
Merged

feat: publish document-rest and document-mcp as GHCR container images#1241
Mearman merged 3 commits into
mainfrom
feat/ghcr-container-images

Conversation

@Mearman

@Mearman Mearman commented Sep 11, 2026

Copy link
Copy Markdown
Member

Publishes ghcr.io/exadev/documents.js (document-rest) and ghcr.io/exadev/document-mcp (document-mcp) as multi-arch (linux/amd64 + linux/arm64) container images on every release. document-cli is excluded -- it has no server role, only a one-shot CLI/TUI.

Wraps the identical Linux SEA binary the existing build-sea-binaries job already builds and uploads to the release, downloaded via gh release download rather than rebuilt. Base image is distroless cc-debian12, not a general-purpose image, since the binary needs only glibc/libstdc++ at runtime and never a shell or package manager.

Two real bugs surfaced while designing and verifying this, both fixed here:

  • Both document-rest and document-mcp --transport http hardcoded a 127.0.0.1 bind with no override. A container's -p mapping reaches the container's external interface, not its loopback, so the server would be unreachable no matter what port was mapped. Added a --host flag to both, default unchanged, so every existing caller keeps today's loopback-only behaviour and only the container's own ENTRYPOINT opts into 0.0.0.0.
  • distroless/cc-debian12 doesn't ship libatomic.so.1, which the SEA binary's Node runtime dynamically links against -- found by actually running the built container and hitting "cannot open shared object file", not by inspection. A small multi-stage build step extracts just that one library from a Debian builder stage.

Verified end to end locally: built a real Linux arm64 SEA binary inside a Node container, built both images against it, ran each with a real docker run -p mapping, and curled from the host to confirm actual reachability. Final image is ~256MB uncompressed but ~60MB compressed (the number that matters for a registry pull) -- the embedded SEA binary itself is the dominant contributor to size either way.

Each image publishes under its exact release version plus a floating latest, with latest only ever set from a genuine release run, never a workflow_dispatch backfill, so a historical catch-up can't regress it to an older version.

One manual step needed after the first release of each package following this merge: a brand-new GHCR package defaults to private visibility regardless of this repo's own visibility, so an org admin needs to flip ghcr.io/exadev/documents.js and ghcr.io/exadev/document-mcp to public once each (documented in the root README's Releases section).

A container's -p host:container port mapping reaches the container's
external network interface, not its loopback -- a process bound only
to 127.0.0.1 is unreachable from outside the container regardless of
what port Docker maps. --host lets a container's own ENTRYPOINT bind
0.0.0.0 explicitly while every existing caller (npx, the standalone
binary) keeps today's loopback-only default unchanged.
A container's -p host:container port mapping reaches the container's
external network interface, not its loopback -- a process bound only
to 127.0.0.1 is unreachable from outside the container regardless of
what port Docker maps. --host lets a container's own ENTRYPOINT bind
0.0.0.0 explicitly while every existing caller (npx, the standalone
binary) keeps today's loopback-only default unchanged.
…ages

Adds build-container-images (per-architecture build+push) and
publish-container-manifests (multi-arch manifest merge via docker
buildx imagetools create) as two more post-release jobs, following
the exact matrix-building and needs/if-gating pattern the SEA-binary
matrix already established. Each image wraps the Linux SEA binary
build-sea-binaries already built and uploaded to the release --
downloaded via gh release download, never rebuilt -- on a distroless
cc-debian12 base rather than a general-purpose one, since the binary
needs only glibc/libstdc++ at runtime and never a shell or package
manager. A small multi-stage build step supplies libatomic.so.1,
confirmed by direct verification to be the one runtime dependency
cc-debian12 doesn't ship on its own (the binary otherwise fails at
startup with "cannot open shared object file").

ghcr.io/exadev/documents.js (document-rest) and
ghcr.io/exadev/document-mcp (document-mcp) publish under an exact
version tag plus a floating latest, latest only from a genuine
release run and never from a workflow_dispatch backfill, so a
historical catch-up run can never regress it to an older version.
document-cli is excluded: it has no server role, only a one-shot
CLI/TUI.

Verified end to end locally: built a real Linux SEA binary inside a
Node container, built both images against it, and ran each with a
real docker run -p mapping and curl from the host -- catching the
libatomic gap this way rather than by inspection, and confirming the
resulting image is a genuinely lightweight ~60MB compressed despite
~256MB uncompressed on disk, the embedded SEA binary itself being the
dominant contributor either way.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review Completed 2026-09-11T19:10:41.059342Z 07f41bd PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Mearman
Mearman merged commit 8cf783b into main Sep 11, 2026
26 checks passed
@Mearman
Mearman deleted the feat/ghcr-container-images branch September 11, 2026 19:04
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 4.14.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant