Skip to content

ci: Add GitHub Container Registry (ghcr.io) publishing - #4013

Merged
akshaydeo merged 2 commits into
maximhq:devfrom
intarweb:feat/add-ghcr-publishing
Jun 15, 2026
Merged

ci: Add GitHub Container Registry (ghcr.io) publishing#4013
akshaydeo merged 2 commits into
maximhq:devfrom
intarweb:feat/add-ghcr-publishing

Conversation

@terafin

@terafin terafin commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds GitHub Container Registry (ghcr.io) as an additional publishing target alongside Docker Hub.

Motivation

Docker Hub's rate limiting (100 pulls/6hrs anonymous, 200 free) increasingly impacts CI/CD and self-hosted infrastructure. ghcr.io provides no rate limits for public images, a unified code+containers ecosystem, needs no extra secrets (uses the existing GITHUB_TOKEN), and reuses the same build — just an additional registry target.

Changes

All changes are in .github/workflows/release-pipeline.yml and its two manifest helper scripts; they are strictly additive and leave the existing Docker Hub build logic, tags, platforms, cache, and build args unchanged.

  • .github/workflows/release-pipeline.yml:
    • The four Docker build jobs (docker-build-amd64, docker-build-arm64, docker-build-ubi9-amd64, docker-build-ubi9-arm64) gain packages: write permission, a ghcr.io:443 egress allow-list entry, and a "Log in to GitHub Container Registry" step (docker/login-action@v3, registry ghcr.io, username github.actor, password secrets.GITHUB_TOKEN) immediately after the existing Docker Hub login.
    • Each build job's "Determine Docker tags" step now also emits a matching ghcr.io/${{ github.repository }} per-arch tag (lowercased) alongside the unchanged Docker Hub tag, so docker/build-push-action pushes to both registries in one build.
    • The two manifest jobs (docker-manifest, docker-manifest-ubi9) gain permissions: contents: read / packages: write, a ghcr.io:443 egress entry, and the same ghcr login step after the Docker Hub login.
  • .github/workflows/scripts/create-docker-manifest.sh and create-docker-manifest-ubi9.sh: after the existing Docker Hub manifest creation/push, append an additive, GITHUB_REPOSITORY-guarded block that assembles and pushes the same multi-arch manifest tags (:vX.Y.Z, :latest, :vX.Y.Z-ubi9, :latest-ubi9 per the existing stable-version rules) to ghcr.io. The Docker Hub manifest logic is untouched.

Backward Compatibility

Fully backward compatible — Docker Hub publishing is unchanged; this only adds an additional registry target.

Testing

  • Workflow YAML validated
  • Builds in maintainer CI on merge

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Docker images (amd64/arm64) and multi-arch manifests — including UBI9 variants — are now also published to GitHub Container Registry (GHCR) alongside Docker Hub.
    • Release jobs now perform GHCR login, grant package publishing permission, and allow egress to ghcr.io:443.
    • GHCR publishing is best-effort: failures emit workflow warnings and do not block Docker Hub publishing.
    • Tagging emits corresponding GHCR tags for versioned and latest artifacts where applicable.

🔧 One-time maintainer step: make the GHCR package public

Heads-up for maintainers: the first time this workflow publishes to ghcr.io/maximhq/bifrost, GitHub creates the package as private by default. To let users docker pull it without authentication, a maintainer needs to set its visibility to Public once:

Repo Packages → the new bifrost package → Package settingsDanger ZoneChange visibilityPublic

It's a one-time action — subsequent pushes inherit the setting. (Flagged by an automated reviewer; surfacing it here so the rollout is smooth.)

@terafin
terafin requested a review from a team as a code owner June 3, 2026 10:51
@CLAassistant

CLAassistant commented Jun 3, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
0 out of 2 committers have signed the CLA.

❌ akshaydeo
❌ woody-apple
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Release pipeline now publishes Docker images and multi-arch manifests to GitHub Container Registry (GHCR) alongside Docker Hub. Build and manifest jobs gain GHCR permissions, egress allowlist entries, and login steps; manifest scripts conditionally mirror multi-arch manifests to GHCR when repository context exists.

Changes

GitHub Container Registry Publishing

Layer / File(s) Summary
AMD64 build job with GHCR support
.github/workflows/release-pipeline.yml
Docker amd64 build job adds packages: write, allows ghcr.io:443, performs GHCR login, and emits Docker Hub and GHCR tags for the amd64 image.
ARM64 build job with GHCR support
.github/workflows/release-pipeline.yml
Docker arm64 build job adds packages: write, allows ghcr.io:443, performs GHCR login, and emits Docker Hub and GHCR tags for the arm64 image.
UBI9 amd64 build job with GHCR support
.github/workflows/release-pipeline.yml
UBI9 amd64 build job adds packages: write, allows ghcr.io:443, performs GHCR login, and emits Docker Hub and GHCR tags for the UBI9 amd64 image.
UBI9 arm64 build job with GHCR support
.github/workflows/release-pipeline.yml
UBI9 arm64 build job adds packages: write, allows ghcr.io:443, performs GHCR login, and emits Docker Hub and GHCR tags for the UBI9 arm64 image.
Multi-arch manifest jobs with GHCR support
.github/workflows/release-pipeline.yml
docker-manifest and docker-manifest-ubi9 request packages: write, allow ghcr.io:443, add GHCR login, and create/push multi-arch manifests (GHCR mirroring added alongside existing Docker Hub behavior).
Manifest shell scripts with GHCR mirroring
.github/workflows/scripts/create-docker-manifest.sh, .github/workflows/scripts/create-docker-manifest-ubi9.sh
Scripts add guarded GHCR mirroring: compute ghcr.io/<owner>/<repo>, fetch per-arch digests, create/push versioned and (for stable) latest multi-arch manifests to GHCR; failures emit workflow warnings and do not affect Docker Hub publishing.

Sequence Diagram

sequenceDiagram
  participant CI as Release Workflow
  participant DockerHub as docker.io/<owner>/<repo>
  participant GHCR as ghcr.io/<owner>/<repo>
  CI->>CI: build per-arch images (amd64, arm64, UBI9 variants)
  CI->>DockerHub: push per-arch images
  CI->>GHCR: login (github.actor + GITHUB_TOKEN)
  CI->>GHCR: imagetools create / push multi-arch manifests (mirror Docker Hub)
  CI->>CI: emit dockerhub-tag and ghcr-tag outputs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • maximhq/bifrost#3772: Overlapping changes to Harden Runner egress allowlists affecting registry endpoints.
  • maximhq/bifrost#3784: Related edits to manifest scripts and digest handling used when creating multi-arch manifests.
  • maximhq/bifrost#3453: Related changes to Harden Runner allowed-endpoints for UBI9 image build jobs.

Suggested reviewers

  • akshaydeo
  • danpiths

Poem

🐇 I hopped through CI with a tiny patch,

I stitched two registries in one batch.
Tags marched out to Hub and GHCR,
Manifests mirrored near and far,
I nibble carrots, guard the cache.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding GHCR as an additional publishing target alongside Docker Hub.
Description check ✅ Passed The description is comprehensive and well-structured, covering summary, motivation, detailed changes, backward compatibility, and testing notes. It includes the recommended template sections with appropriate content.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

Safe to merge — changes are strictly additive CI/CD plumbing; Docker Hub publishing is completely untouched and GHCR mirroring is wrapped in best-effort error handling throughout.

The change is purely additive CI configuration. Docker Hub flows are unchanged. GHCR steps use continue-on-error: true in the build jobs and a (set -e; ...) || warning subshell in the manifest scripts, so no GHCR failure can block a release. Permissions follow least-privilege, pinned SHA actions are consistent with the existing workflow, and the egress allow-list is correctly updated.

No files require special attention. The one minor observation (jq multi-line output) is inside the best-effort subshell and would only cause a GHCR-side warning, not a Docker Hub regression.

Important Files Changed

Filename Overview
.github/workflows/release-pipeline.yml Adds GHCR login, packages: write permission, and egress entries to all six Docker jobs; per-arch build jobs mirror to GHCR with continue-on-error: true via buildx imagetools create; manifest jobs delegate to updated scripts
.github/workflows/scripts/create-docker-manifest.sh Fixes the positional-digest issue by selecting digests via platform.architecture; appends a best-effort GHCR manifest-creation block guarded by GITHUB_REPOSITORY with graceful error handling
.github/workflows/scripts/create-docker-manifest-ubi9.sh Same fixes and GHCR block as create-docker-manifest.sh, applied to the UBI9 variant; structure and error handling are identical

Reviews (13): Last reviewed commit: "Merge branch 'dev' into feat/add-ghcr-pu..." | Re-trigger Greptile

Comment thread .github/workflows/scripts/create-docker-manifest.sh Outdated
Comment thread .github/workflows/scripts/create-docker-manifest.sh Outdated

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/release-pipeline.yml (2)

1673-1697: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Decouple Docker Hub publishing from GHCR publishing.

Each build job builds and pushes both registries in one docker/build-push-action by passing a combined tag list (${BASE_TAG} for Docker Hub + ${GHCR_TAG} for GHCR) via tags: ${{ steps.tags.outputs.tags }}. A GHCR auth/availability failure will fail the shared step and block Docker Hub publication too. Split into separate push steps per registry (or push once by digest and then fan out tags per registry).

Also applies to: 1777-1801, 1927-1953, 2034-2060

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-pipeline.yml around lines 1673 - 1697, The current
build step "Build and push AMD64 Docker image" is pushing both Docker Hub
(BASE_TAG) and GHCR (GHCR_TAG) in a single docker/build-push-action invocation
using steps.tags.outputs.tags, which causes a failure in one registry to block
the other; modify the workflow so the image build and pushes are decoupled:
either (a) run one build that outputs an image digest (use build-push-action
with push: false and output the image digest), then add two separate
docker/build-push-action steps that only push the already-built image to each
registry/tag (one using BASE_TAG for Docker Hub, another using GHCR_TAG for
GHCR), or (b) keep the build+push but split into two distinct build-push-action
invocations — one that only pushes BASE_TAG and one that only pushes GHCR_TAG —
ensuring each uses its own registry credentials; apply this refactor to the
similarly structured steps that create tags and push images (the blocks that
generate BASE_TAG/GHCR_TAG and use steps.tags.outputs.tags).

1628-1640: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add pkg-containers.githubusercontent.com:443 to the harden-runner allowed-endpoints for GHCR publish/manifest jobs.

docker-build-amd64, docker-build-arm64, docker-build-ubi9-amd64, docker-build-ubi9-arm64, docker-manifest, and docker-manifest-ubi9 allow ghcr.io:443 but omit pkg-containers.githubusercontent.com:443; with egress-policy: block, GHCR redirects for blob/manifest operations can fail. Other GHCR-consuming jobs in this workflow already include pkg-containers.githubusercontent.com:443, so align these blocks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-pipeline.yml around lines 1628 - 1640, The
harden-runner job blocks for docker-build-amd64, docker-build-arm64,
docker-build-ubi9-amd64, docker-build-ubi9-arm64, docker-manifest, and
docker-manifest-ubi9 are missing pkg-containers.githubusercontent.com:443 in
their allowed-endpoints list; update each of those allowed-endpoints entries to
include "pkg-containers.githubusercontent.com:443" alongside ghcr.io:443 so GHCR
blob/manifest redirects succeed under egress-policy: block.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/scripts/create-docker-manifest.sh:
- Around line 41-67: The GHCR mirroring block (uses GHCR_IMAGE,
GHCR_AMD64_DIGEST, GHCR_ARM64_DIGEST and runs docker manifest
inspect/create/push) can fail under set -e and thus mark the whole job failed;
make the GHCR steps best-effort by isolating their exit status: either disable
errexit around that block (e.g., set +e before the GHCR commands and restore set
-e after) or run the whole block in a subshell and swallow failures (e.g., ( ...
) || true), ensuring you still log errors from docker manifest
inspect/create/push but do not let a non-zero exit code from those commands
abort the script.

---

Outside diff comments:
In @.github/workflows/release-pipeline.yml:
- Around line 1673-1697: The current build step "Build and push AMD64 Docker
image" is pushing both Docker Hub (BASE_TAG) and GHCR (GHCR_TAG) in a single
docker/build-push-action invocation using steps.tags.outputs.tags, which causes
a failure in one registry to block the other; modify the workflow so the image
build and pushes are decoupled: either (a) run one build that outputs an image
digest (use build-push-action with push: false and output the image digest),
then add two separate docker/build-push-action steps that only push the
already-built image to each registry/tag (one using BASE_TAG for Docker Hub,
another using GHCR_TAG for GHCR), or (b) keep the build+push but split into two
distinct build-push-action invocations — one that only pushes BASE_TAG and one
that only pushes GHCR_TAG — ensuring each uses its own registry credentials;
apply this refactor to the similarly structured steps that create tags and push
images (the blocks that generate BASE_TAG/GHCR_TAG and use
steps.tags.outputs.tags).
- Around line 1628-1640: The harden-runner job blocks for docker-build-amd64,
docker-build-arm64, docker-build-ubi9-amd64, docker-build-ubi9-arm64,
docker-manifest, and docker-manifest-ubi9 are missing
pkg-containers.githubusercontent.com:443 in their allowed-endpoints list; update
each of those allowed-endpoints entries to include
"pkg-containers.githubusercontent.com:443" alongside ghcr.io:443 so GHCR
blob/manifest redirects succeed under egress-policy: block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: dac36b0f-0ba1-449a-8f25-335b2eddadc6

📥 Commits

Reviewing files that changed from the base of the PR and between bd9d432 and 73aceee.

📒 Files selected for processing (3)
  • .github/workflows/release-pipeline.yml
  • .github/workflows/scripts/create-docker-manifest-ubi9.sh
  • .github/workflows/scripts/create-docker-manifest.sh

Comment thread .github/workflows/scripts/create-docker-manifest.sh

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/release-pipeline.yml (2)

1673-1696: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Decouple GHCR pushes from the Docker Hub build-push step

docker/build-push-action pushes all tags/registries configured in the same step; if the GHCR push fails (auth/outage/permissions), the whole step typically fails—turning GHCR into a hard dependency that can block the Docker Hub release path even though downstream manifest scripts treat GHCR as best-effort.

Suggested pattern
       - name: Determine Docker tags
         id: tags
         run: |
           VERSION="${{ needs.detect-changes.outputs.transport-version }}"
           BASE_TAG="${{ env.REGISTRY }}/${{ env.ACCOUNT }}/${{ env.IMAGE_NAME }}:v${VERSION}-amd64"
           GHCR_REPO=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
-          GHCR_TAG="ghcr.io/${GHCR_REPO}:v${VERSION}-amd64"
-          {
-            echo "tags<<EOF"
-            echo "${BASE_TAG}"
-            echo "${GHCR_TAG}"
-            echo "EOF"
-          } >> $GITHUB_OUTPUT
+          echo "dockerhub_tag=${BASE_TAG}" >> $GITHUB_OUTPUT
+          echo "ghcr_tag=ghcr.io/${GHCR_REPO}:v${VERSION}-amd64" >> $GITHUB_OUTPUT

-      - name: Build and push AMD64 Docker image
+      - name: Build and push AMD64 Docker image to Docker Hub
         uses: step-security/docker-build-push-action@846549baaf047e867d038826129a64d81df0f704
         with:
           push: true
-          tags: ${{ steps.tags.outputs.tags }}
+          tags: ${{ steps.tags.outputs.dockerhub_tag }}

+      - name: Mirror AMD64 Docker image to GHCR
+        continue-on-error: true
+        uses: step-security/docker-build-push-action@846549baaf047e867d038826129a64d81df0f704
+        with:
+          push: true
+          tags: ${{ steps.tags.outputs.ghcr_tag }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-pipeline.yml around lines 1673 - 1696, The current
build step "Build and push AMD64 Docker image" pushes all tags returned by the
"tags" step making GHCR failures block the Docker Hub push; change the "Build
and push AMD64 Docker image" step to only push the Docker Hub tag (use the
BASE_TAG output from the tags step) and add a separate step that pushes the
GHCR_TAG (from steps.tags.outputs) with isolated auth and failure handling
(e.g., its own push action or the same action but targeting only GHCR) and mark
that GHCR push step as non-blocking (continue-on-error or conditional on auth)
so GHCR becomes best-effort while the Docker Hub release remains reliable.

1628-1640: ⚠️ Potential issue | 🟠 Major

Add pkg-containers.githubusercontent.com:443 to the harden-runner allowlist for the GHCR publish/manifest jobs

In .github/workflows/release-pipeline.yml, the GHCR egress allowlists for the GHCR-related publish/manifest steps include only ghcr.io:443 (e.g., blocks around 1628-1640, 1737-1744, 1822-1827, 1886-1894, 1993-2001, 2081-2085) and omit pkg-containers.githubusercontent.com:443. These jobs run .github/workflows/scripts/create-docker-manifest.sh / create-docker-manifest-ubi9.sh, which performs docker manifest inspect/docker manifest push against ghcr.io. GitHub Container Registry can serve image-layer/blob content from pkg-containers.githubusercontent.com even when interacting with ghcr.io, so restricting egress to ghcr.io can still break GHCR image operations—align this allowlist with the other GHCR-consuming jobs that already allow pkg-containers.githubusercontent.com:443.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-pipeline.yml around lines 1628 - 1640, The
GHCR-related egress allowlist in the release pipeline's harden-runner steps
currently lists ghcr.io:443 but omits pkg-containers.githubusercontent.com:443,
which can cause docker manifest inspect/push (scripts create-docker-manifest.sh
and create-docker-manifest-ubi9.sh) to fail when layers are served from
pkg-containers.githubusercontent.com; update the allowed-endpoints block (the
allowed-endpoints entry used by the GHCR publish/manifest jobs) to include
pkg-containers.githubusercontent.com:443 alongside ghcr.io:443 so the runner can
access image layer/blob content for GHCR operations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/release-pipeline.yml:
- Around line 1673-1696: The current build step "Build and push AMD64 Docker
image" pushes all tags returned by the "tags" step making GHCR failures block
the Docker Hub push; change the "Build and push AMD64 Docker image" step to only
push the Docker Hub tag (use the BASE_TAG output from the tags step) and add a
separate step that pushes the GHCR_TAG (from steps.tags.outputs) with isolated
auth and failure handling (e.g., its own push action or the same action but
targeting only GHCR) and mark that GHCR push step as non-blocking
(continue-on-error or conditional on auth) so GHCR becomes best-effort while the
Docker Hub release remains reliable.
- Around line 1628-1640: The GHCR-related egress allowlist in the release
pipeline's harden-runner steps currently lists ghcr.io:443 but omits
pkg-containers.githubusercontent.com:443, which can cause docker manifest
inspect/push (scripts create-docker-manifest.sh and
create-docker-manifest-ubi9.sh) to fail when layers are served from
pkg-containers.githubusercontent.com; update the allowed-endpoints block (the
allowed-endpoints entry used by the GHCR publish/manifest jobs) to include
pkg-containers.githubusercontent.com:443 alongside ghcr.io:443 so the runner can
access image layer/blob content for GHCR operations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 441164bd-e397-4490-a32d-4c76f8d55bfe

📥 Commits

Reviewing files that changed from the base of the PR and between caf2e64 and ee153c4.

📒 Files selected for processing (1)
  • .github/workflows/release-pipeline.yml

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/release-pipeline.yml (1)

1661-1672: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider using consistent action sources for Docker logins.

Docker Hub login uses step-security/docker-login-action while GHCR login uses docker/login-action. Both are SHA-pinned and functionally equivalent, but using the same provider would improve consistency with the rest of the workflow's hardening approach.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-pipeline.yml around lines 1661 - 1672, Replace the
mixed Docker login actions with a single consistent provider: update the "Log in
to Docker Hub" step that currently uses step-security/docker-login-action to use
the same action provider as the GHCR step (docker/login-action) with an
appropriate SHA/pinned version (matching the GHCR step's c94ce9fb4685... or
other vetted SHA), ensuring the inputs (username/password) remain ${{
secrets.DOCKER_USERNAME }} and ${{ secrets.DOCKER_PASSWORD }} and that the "Log
in to GitHub Container Registry" step continues to specify registry: ghcr.io and
use ${{ github.actor }} / ${{ secrets.GITHUB_TOKEN }} so both login steps use
docker/login-action consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/release-pipeline.yml:
- Around line 1661-1672: Replace the mixed Docker login actions with a single
consistent provider: update the "Log in to Docker Hub" step that currently uses
step-security/docker-login-action to use the same action provider as the GHCR
step (docker/login-action) with an appropriate SHA/pinned version (matching the
GHCR step's c94ce9fb4685... or other vetted SHA), ensuring the inputs
(username/password) remain ${{ secrets.DOCKER_USERNAME }} and ${{
secrets.DOCKER_PASSWORD }} and that the "Log in to GitHub Container Registry"
step continues to specify registry: ghcr.io and use ${{ github.actor }} / ${{
secrets.GITHUB_TOKEN }} so both login steps use docker/login-action
consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: afbf4b51-f177-4612-be92-8e23bc82efb2

📥 Commits

Reviewing files that changed from the base of the PR and between ee153c4 and e0d9b87.

📒 Files selected for processing (1)
  • .github/workflows/release-pipeline.yml

@terafin
terafin force-pushed the feat/add-ghcr-publishing branch from e0d9b87 to d68f2ab Compare June 4, 2026 04:47
@terafin
terafin force-pushed the feat/add-ghcr-publishing branch 2 times, most recently from 5039c19 to 8715758 Compare June 4, 2026 16:14
@terafin

terafin commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 4f1c80eb1 addressing the three review concerns:

  1. .manifests[0].digest positional assumption (greptile P2). Switched all four digest-extraction sites in create-docker-manifest.sh and create-docker-manifest-ubi9.sh from jq -er '.manifests[0].digest' to a platform-matching filter: jq -er '.manifests[] | select(.platform.architecture == "amd64") | .digest' (and arm64 likewise). Robust against buildx changing the index ordering of the platform image vs the provenance attestation manifest.

  2. GHCR private-by-default (greptile P2). Added a header comment block in create-docker-manifest.sh documenting the one-time visibility flip a maintainer needs to do at https://github.com/orgs/maximhq/packages/container/bifrost/settings after the first run that creates the package. Cross-referenced from create-docker-manifest-ubi9.sh. The GHCR REST API does not currently expose a visibility-PATCH endpoint for container packages, so this can't be automated in the workflow.

  3. set -e isolation so GHCR failure can't regress Docker Hub publish (coderabbitai). This was already handled in the original PR — the GHCR block is wrapped in a subshell ( set -e; ... ) with || echo "::warning::GHCR mirroring failed; Docker Hub publish unaffected" afterward, so a non-zero exit from the GHCR block prints a workflow warning but doesn't fail the parent script (which has set -euo pipefail at the top). The Docker Hub manifest create + push runs before the GHCR block, so a successful Docker Hub publish is preserved regardless of GHCR outcome.

Outside-diff coderabbitai comment about decoupling Docker Hub publishing from GHCR publishing — happy to discuss in a follow-up; current scope is the additive GHCR mirror within the existing release pipeline. A full decouple (separate jobs / separate triggers) is a larger structural change I'd want maintainer direction on before scoping.

@akshaydeo

Copy link
Copy Markdown
Contributor

prefect thank you - ill get it merged tomorrow

@terafin
terafin force-pushed the feat/add-ghcr-publishing branch from 939d662 to 98d5a4c Compare June 8, 2026 10:57
@greptile-apps

greptile-apps Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Want your agent to iterate on Greptile's feedback? Try greploops.

Adds ghcr.io as an additional publishing target alongside Docker Hub.
Docker Hub publishing is unchanged; this is strictly additive.

Changes in .github/workflows/release-pipeline.yml + the two manifest
helper scripts (create-docker-manifest.sh, create-docker-manifest-ubi9.sh):

- Four Docker build jobs (amd64, arm64, ubi9-amd64, ubi9-arm64) gain
  packages: write permission, a ghcr.io:443 egress allow-list entry,
  and a "Log in to GitHub Container Registry" step using GITHUB_TOKEN
  after the existing Docker Hub login. Tag step emits a matching
  ghcr.io/${{ github.repository }} per-arch tag (lowercased), so
  docker/build-push-action pushes to both registries in one build.
- Two manifest jobs (docker-manifest, docker-manifest-ubi9) gain
  packages: write and the same ghcr login + egress entry.
- Both manifest scripts append a GITHUB_REPOSITORY-guarded block after
  the Docker Hub manifest push that builds and pushes the same
  multi-arch manifest tags to ghcr.io. The Docker Hub block is
  untouched; the GHCR block is wrapped in a subshell with a warning
  fallback so a GHCR failure cannot regress Docker Hub publish.

Manifest digest selector matches by platform.architecture (jq
'.manifests[] | select(.platform.architecture == "amd64") | .digest')
instead of positional [0], since buildx with default provenance
produces an OCI index containing both the platform image manifest and
a provenance attestation manifest with no guaranteed ordering.

A header comment in create-docker-manifest.sh documents the one-time
maintainer step required after first publish (GHCR packages default to
private; the REST API does not expose a visibility-PATCH endpoint for
container packages, so the flip to Public has to be done once in the
package settings UI).

Squashed from 2 commits.
@akshaydeo
akshaydeo merged commit 578e250 into maximhq:dev Jun 15, 2026
5 of 6 checks passed
akshaydeo added a commit that referenced this pull request Jun 15, 2026
Adds ghcr.io as an additional publishing target alongside Docker Hub.
Docker Hub publishing is unchanged; this is strictly additive.

Changes in .github/workflows/release-pipeline.yml + the two manifest
helper scripts (create-docker-manifest.sh, create-docker-manifest-ubi9.sh):

- Four Docker build jobs (amd64, arm64, ubi9-amd64, ubi9-arm64) gain
  packages: write permission, a ghcr.io:443 egress allow-list entry,
  and a "Log in to GitHub Container Registry" step using GITHUB_TOKEN
  after the existing Docker Hub login. Tag step emits a matching
  ghcr.io/${{ github.repository }} per-arch tag (lowercased), so
  docker/build-push-action pushes to both registries in one build.
- Two manifest jobs (docker-manifest, docker-manifest-ubi9) gain
  packages: write and the same ghcr login + egress entry.
- Both manifest scripts append a GITHUB_REPOSITORY-guarded block after
  the Docker Hub manifest push that builds and pushes the same
  multi-arch manifest tags to ghcr.io. The Docker Hub block is
  untouched; the GHCR block is wrapped in a subshell with a warning
  fallback so a GHCR failure cannot regress Docker Hub publish.

Manifest digest selector matches by platform.architecture (jq
'.manifests[] | select(.platform.architecture == "amd64") | .digest')
instead of positional [0], since buildx with default provenance
produces an OCI index containing both the platform image manifest and
a provenance attestation manifest with no guaranteed ordering.

A header comment in create-docker-manifest.sh documents the one-time
maintainer step required after first publish (GHCR packages default to
private; the REST API does not expose a visibility-PATCH endpoint for
container packages, so the flip to Public has to be done once in the
package settings UI).

Squashed from 2 commits.

Co-authored-by: Justin Wood <woody@apple.com>
Co-authored-by: Akshay Deo <akshay@akshaydeo.com>
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.

5 participants