Skip to content

ci(checks): publish quoter-bot image to docker hub on release - #158

Merged
julien-devatom merged 12 commits into
mainfrom
quoter-bot-docker-release-4d92b5
Aug 14, 2026
Merged

ci(checks): publish quoter-bot image to docker hub on release#158
julien-devatom merged 12 commits into
mainfrom
quoter-bot-docker-release-4d92b5

Conversation

@julien-devatom

@julien-devatom julien-devatom commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Fixes MKT-1846

Why

quoter-bot is the public reference maker bot, but no public artifact of a release exists today: Railway builds the image internally from uploaded source, so third-party operators must build from source and there is no image record of what a release shipped. This PR publishes morphoorg/quoter to Docker Hub on every quoter-bot production release — tagged with the release commit hash (a stable, greppable mapping from image to source, also stamped as OCI revision/source labels) plus latest.

Four properties drove the design, recorded in TIB-2026-08-14-quoter-bot-dockerhub-publishing:

  • No static registry credential in CI. Authentication exchanges the run's GitHub OIDC token through the Docker org's OIDC connection (docker/login-action v4.5+): id-token: write, username-only login, connection selected by DOCKERHUB_OIDC_CONNECTIONID. The trust binding (which claims may push) lives in Docker-side rulesets, not in a long-lived secret. The exchanged token's expiry is raised to 1800s because the default 300s is shorter than the workspace build that runs between login and push.
  • Only the bot ships in the public image. The Dockerfile is split into a workspace build stage and a runtime stage that receives nothing but the bot's self-contained esbuild bundle and manifest, root-owned and non-writable to the runtime user — publishing publicly must not leak the liquidators' or crossed-books source, workspace internals, or a package manager. Railway builds the same final stage, so the deployed image slims down identically (verified locally: the setpriv entrypoint runs cleanly, /repo holds only bots/quoter-bot/{dist,package.json} at root root 555, and a write attempt as the runtime user is denied). The privileged-startup guard test encodes this contract — adding a workspace COPY or a package manager to the runtime stage fails the suite.
  • The image publishes after the release, but gates nothing. Quoter-bot-image needs the Railway deploy and the release-tag job, so no image tag can publish for a failed deployment — while Release-quoter-bot still depends only on the deploy, so a Docker Hub outage cannot block a production release. The same release-quoter-bot selector (including the workflow_dispatch path) remains the single entry point, and the GitHub release stays the source of truth for what runs in production.
  • Tags behave immutably. An already-published commit tag is never rebuilt: the workflow inspects it through the authenticated session, reuses it, and recovers a missed latest by manifest retag. latest only moves forward — a rerun of an older release backfills its commit tag but skips latest whenever a quoter-bot-* release tag descends from the built commit (the pipeline's own release record decides "newest", and release runs are serialized). Hardening contributed together with prd-carapulse[bot].

The publish job is a reusable workflow_call workflow scoped by the quoter-bot-dockerhub GitHub Environment, mirroring the existing per-concern environment pattern (deploy-quoter-bot-production.yml / quoter-bot-production).

Operator checklist (environment assumptions)

  • The quoter-bot-dockerhub environment holds secret DOCKERHUB_OIDC_CONNECTIONID and variables DOCKER_USERNAME (morphoorg) / DOCKER_REPOSITORY (quoter) — a fail-loud preflight step reports exactly which value is missing if that split differs.
  • The Docker-side OIDC connection ruleset must match the environment-based subject repo:morpho-org/morpho-bots:environment:quoter-bot-dockerhub — because the job references a GitHub Environment, GitHub mints the token with an environment sub claim, and a ref:refs/heads/main-style ruleset would reject every exchange.
  • Restrict the environment's deployment-branch policy to main; that is where branch enforcement lives.
  • Docker Hub's immutable-tags setting on morphoorg/quoter is optional belt-and-braces: the workflow already never rebuilds an existing commit tag and never moves latest backward.

🤖 Generated with Claude Code

A release-quoter-bot production run now also pushes the bot image to
Docker Hub as morphoorg/quoter, tagged with the release commit hash and
latest, in parallel with the Railway deploy and gating neither the
deploy nor the GitHub release. Auth exchanges the run's GitHub OIDC
token through the Docker org's OIDC connection (docker/login-action
v4.5+), scoped by the quoter-bot-dockerhub GitHub Environment, so CI
stores no static Docker Hub credential.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@julien-devatom julien-devatom self-assigned this Aug 14, 2026
@linear-code

linear-code Bot commented Aug 14, 2026

Copy link
Copy Markdown

MKT-1846

@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@codex review

chatgpt-codex-connector[bot]

This comment was marked as resolved.

Address Codex review on #158:

- Split the Dockerfile into build + runtime stages so the published
  image ships only the bot's self-contained esbuild bundle — no other
  bot's code, workspace source, node_modules, or pnpm. Verified locally:
  entrypoint --version runs through setpriv, /repo holds only
  bots/quoter-bot/{dist,package.json}, image is 347MB.
- Document that the OIDC token's sub claim is environment-based
  (repo:...:environment:quoter-bot-dockerhub) because the job references
  an environment; a branch-style Docker ruleset would reject every
  exchange.
- Clarify sha-tag semantics: the tag names the commit; reruns rebuild
  with current base layers. Point at Docker Hub immutable tags for
  byte-level freezing instead of a skip-if-exists guard, which would
  break reruns after transient push failures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: ff2129e128

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

julien-devatom and others added 2 commits August 14, 2026 12:01
The privileged-startup test encoded the single-stage Dockerfile shape
(USER node then USER root) and crashed on the new two-stage split. It
now asserts the build stage runs all workspace installs/builds after
USER node, and the runtime stage equals exactly the eight instructions
that ship the bot bundle behind the root-owned setpriv entrypoint — so
any attempt to COPY workspace source or add a package manager to the
public image fails the suite. Verified: injecting a workspace COPY
fails the test; the committed Dockerfile passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fail closed when the Docker Hub commit-SHA tag already exists and document the immutable publish contract.
@prd-carapulse

prd-carapulse Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

@codex review

1 similar comment
@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@codex review

chatgpt-codex-connector[bot]

This comment was marked as resolved.

Codex flagged that rerunning an older release's publish job (one that
failed before pushing its commit tag) passes the new SHA-existence
guard and would drag Docker Hub latest backward. Gate latest on the
pipeline's own release record: skip it whenever a quoter-bot-* release
tag descends from the built commit. Release runs are serialized, so the
newest release cannot change mid-run. Verified against real repo data:
branch HEAD yields sha+latest; a commit behind quoter-bot-2026.08.14-1
yields sha only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@julien-devatom
julien-devatom marked this pull request as ready for review August 14, 2026 10:48
@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@codex review

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 2 potential issues.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment thread .github/workflows/publish-quoter-bot-dockerhub.yml Outdated
Comment thread bots/quoter-bot/Dockerfile Outdated
@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 3c277d4d14

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Authenticate before checking immutable Docker Hub tags so first publication can proceed, and force runtime bundle files to remain root-owned and non-writable.
@prd-carapulse

prd-carapulse Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3bed72e359

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/publish-quoter-bot-dockerhub.yml Outdated
Comment thread .github/workflows/deploy-production.yml
Reuse an existing immutable SHA image when recovering the latest tag, and publish Docker Hub tags only after the Railway deployment succeeds.
@prd-carapulse

prd-carapulse Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b0c2a764e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/deploy-production.yml Outdated
Wait for the quoter GitHub release record before publishing Docker image tags, while keeping the release independent from Docker Hub.
@prd-carapulse

prd-carapulse Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 42f2600854

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@prd-carapulse

prd-carapulse Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

@codex review

The caller job now needs both the deploy and release-tag jobs; the TIB
diagram still drew the image push parallel to the release.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 17bf3d6049

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: 51d84c4cde

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@prd-carapulse[bot] review and approve if ok

@prd-carapulse

prd-carapulse Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

❌ Not approved. Requested changes on 51d84c4cde.

Blocker: quoter-bot-dockerhub has deployment_branch_policy: null and no protection rules. Environment-based Docker OIDC trust therefore lacks required main branch restriction.

Code/CI: Clean. Lint, Typecheck, Test, and Dead-Code green. Targeted suite passes locally: 18/18.

Review: #158 (review)

@prd-carapulse prd-carapulse Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocking operational security gap: the live quoter-bot-dockerhub environment currently reports deployment_branch_policy: null and no protection rules, so it is not restricted to main. Because the Docker OIDC trust subject is environment-based (repo:morpho-org/morpho-bots:environment:quoter-bot-dockerhub) rather than ref-based, the documented main-only environment policy is the control preventing another branch workflow from minting an accepted token and pushing morphoorg/quoter.

Please restrict the environment deployment branches to main, then re-request approval. Code review otherwise clean: current-head CI is green and the targeted Railway/Dockerfile contract suite passes locally (18/18).

@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@prd-carapulse re-requesting approval: the quoter-bot-dockerhub environment is now restricted to main. Verified via the API just now — deployment_branch_policy: {custom_branch_policies: true, protected_branches: false} with exactly one branch policy {name: "main", type: "branch"}, matching quoter-bot-production's configuration. With the environment-based OIDC subject, that main-only policy is the control keeping the Docker Hub token exchange unreachable from other branches, as documented in the TIB and operator checklist.

🤖 Addressed by Claude Code

@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@prd-carapulse[bot] and now

@prd-carapulse

prd-carapulse Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

❌ Still not approved.

Blocker: quoter-bot-dockerhub allows branch main and tag quoter-bot-* (total_count: 2). workflow_dispatch can run against that tag, keeping environment-based Docker Hub OIDC reachable outside refs/heads/main.

Required fix: Remove quoter-bot-*; leave only branch main.

Code/CI: Head 51d84c4cde; all checks green. Changes-requested review submitted.

@prd-carapulse prd-carapulse Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Still blocked: live quoter-bot-dockerhub policy is not main-only. The API currently returns two allow rules: branch main and tag quoter-bot-* (total_count: 2). By contrast, quoter-bot-production has exactly one rule: branch main.

Because deploy-production.yml supports workflow_dispatch, a run can be dispatched against an allowed quoter-bot-* tag. The publish job then receives the same environment-based OIDC subject, so the tag rule keeps Docker Hub token exchange reachable outside refs/heads/main.

Please remove the quoter-bot-* tag policy from quoter-bot-dockerhub, leaving only branch main, then re-request approval. Current head 51d84c4cde and all checks remain green.

@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@prd-carapulse[bot] now

@prd-carapulse

prd-carapulse Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

✅ Approved 51d84c4cde.

• Live environment policy now allows exactly branch main; quoter-bot-* tag rule removed.
• PR mergeable. Lint, Typecheck, Test, and Dead-Code green.
• Review decision verified: APPROVED.

@julien-devatom

Copy link
Copy Markdown
Collaborator Author

@prd-carapulse re-requesting approval: the quoter-bot-* tag rule is no longer present. As of 2026-08-14T14:10:04Z, GET /repos/morpho-org/morpho-bots/environments/quoter-bot-dockerhub/deployment-branch-policies returns exactly one rule: {id: 57339389, name: "main", type: "branch"} — matching quoter-bot-production and closing the dispatch-on-tag path to the environment-based OIDC subject. Note the environment config has changed three times today (none of the mutations were mine; I hold read-only evidence) — worth confirming who is editing it so the main-only policy sticks.

🤖 Addressed by Claude Code

@prd-carapulse prd-carapulse Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved. Live quoter-bot-dockerhub environment now has exactly one deployment branch policy: branch main (total_count: 1); the quoter-bot-* tag rule is gone. Head 51d84c4cde remains mergeable with Lint, Typecheck, Test, and Dead-Code green.

@julien-devatom
julien-devatom merged commit e9e6125 into main Aug 14, 2026
7 checks passed
@julien-devatom
julien-devatom deleted the quoter-bot-docker-release-4d92b5 branch August 14, 2026 14:12
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