feat: add Docker Hub as primary registry for anonymous pulls

GHCR requires authentication even for public packages on some systems.
CI now pushes to both GHCR and Docker Hub. docker-compose.yml and Helm
chart point to Docker Hub where anonymous pulls always work. Build
directives kept as fallback for source-based builds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
anoracleofra-code
2026-03-28 08:13:14 -06:00
parent 66df14a93c
commit a3e7a2bc6b
6 changed files with 113 additions and 43 deletions
+94 -24
View File
@@ -6,9 +6,11 @@ on:
tags: ["v*.*.*"]
pull_request:
branches: ["main"]
env:
REGISTRY: ghcr.io
GHCR_REGISTRY: ghcr.io
DOCKERHUB_BACKEND: bigbodycobain/shadowbroker-backend
DOCKERHUB_FRONTEND: bigbodycobain/shadowbroker-frontend
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
@@ -44,19 +46,26 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: Log into registry ${{ env.REGISTRY }}
- name: Log into GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log into Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend
- name: Build and push Docker image by digest
id: build
@@ -68,7 +77,7 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=frontend-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=frontend-${{ matrix.platform }}
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
- name: Export digest
if: github.event_name != 'pull_request'
@@ -108,29 +117,56 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: Log into registry ${{ env.REGISTRY }}
- name: Log into GHCR
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
- name: Log into Docker Hub
uses: docker/login-action@v3.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata (GHCR)
id: meta-ghcr
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Create and push manifest
- name: Extract Docker metadata (Docker Hub)
id: meta-hub
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.DOCKERHUB_FRONTEND }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Create and push GHCR manifest
working-directory: /tmp/digests/frontend
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend@sha256:%s ' *)
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend@sha256:%s ' *)
env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta-ghcr.outputs.json }}
- name: Push to Docker Hub
working-directory: /tmp/digests/frontend
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend@sha256:%s ' *)
env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta-hub.outputs.json }}
build-backend:
needs: ci-gate
@@ -159,19 +195,26 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: Log into registry ${{ env.REGISTRY }}
- name: Log into GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log into Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-backend
- name: Build and push Docker image by digest
id: build
@@ -184,7 +227,7 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=backend-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=backend-${{ matrix.platform }}
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-backend,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
- name: Export digest
if: github.event_name != 'pull_request'
@@ -224,26 +267,53 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: Log into registry ${{ env.REGISTRY }}
- name: Log into GHCR
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
- name: Log into Docker Hub
uses: docker/login-action@v3.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata (GHCR)
id: meta-ghcr
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-backend
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Create and push manifest
- name: Extract Docker metadata (Docker Hub)
id: meta-hub
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.DOCKERHUB_BACKEND }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Create and push GHCR manifest
working-directory: /tmp/digests/backend
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend@sha256:%s ' *)
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-backend@sha256:%s ' *)
env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta-ghcr.outputs.json }}
- name: Push to Docker Hub
working-directory: /tmp/digests/backend
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}-backend@sha256:%s ' *)
env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta-hub.outputs.json }}
+4 -7
View File
@@ -46,17 +46,14 @@ if [ ! -f "$COMPOSE_FILE" ]; then
fi
# Detect stale compose file from pre-migration clones (before March 2026).
# The current compose file uses "image:" to pull pre-built images from GHCR.
# Old versions had "build:" directives that compile from local source — much
# slower and will NOT pick up new releases.
if grep -q '^\s*build:' "$COMPOSE_FILE" 2>/dev/null; then
# Old versions used ghcr.io which requires auth. Current file uses Docker Hub.
if grep -q 'ghcr\.io' "$COMPOSE_FILE" 2>/dev/null; then
echo ""
echo "================================================================"
echo " [!] WARNING: Your docker-compose.yml is outdated."
echo ""
echo " It contains 'build:' directives, which means Docker is"
echo " compiling from local source instead of pulling pre-built"
echo " images. You will NOT receive updates this way."
echo " It references ghcr.io which may require authentication."
echo " The current version uses Docker Hub for anonymous pulls."
echo ""
echo " Fix: re-clone the repository:"
echo " cd .. && rm -rf $(basename "$SCRIPT_DIR")"
+7 -2
View File
@@ -1,6 +1,9 @@
services:
backend:
image: ghcr.io/bigbodycobain/shadowbroker-backend:latest
image: bigbodycobain/shadowbroker-backend:latest
build:
context: .
dockerfile: backend/Dockerfile
container_name: shadowbroker-backend
ports:
- "${BIND:-127.0.0.1}:8000:8000"
@@ -33,7 +36,9 @@ services:
cpus: '2'
frontend:
image: ghcr.io/bigbodycobain/shadowbroker-frontend:latest
image: bigbodycobain/shadowbroker-frontend:latest
build:
context: ./frontend
container_name: shadowbroker-frontend
ports:
- "${BIND:-127.0.0.1}:3000:3000"
+2 -2
View File
@@ -13,7 +13,7 @@ shadowbroker:
runAsGroup: 1001
image:
pullPolicy: Always
repository: ghcr.io/bigbodycobain/shadowbroker-backend
repository: bigbodycobain/shadowbroker-backend
tag: latest
env:
AIS_API_KEY:
@@ -41,7 +41,7 @@ shadowbroker:
runAsGroup: 1001
image:
pullPolicy: Always
repository: ghcr.io/bigbodycobain/shadowbroker-frontend
repository: bigbodycobain/shadowbroker-frontend
tag: latest
env:
+3 -4
View File
@@ -7,15 +7,14 @@ echo ===================================================
echo.
:: Check for stale docker-compose.yml from pre-migration clones
findstr /R /C:"build:" docker-compose.yml >nul 2>&1
findstr /C:"ghcr.io" docker-compose.yml >nul 2>&1
if %errorlevel% equ 0 (
echo.
echo ================================================================
echo [!] WARNING: Your docker-compose.yml is outdated.
echo.
echo It contains 'build:' directives, which means Docker will
echo compile from local source instead of pulling pre-built images.
echo You will NOT receive updates this way.
echo It references ghcr.io which may require authentication.
echo The current version uses Docker Hub for anonymous pulls.
echo.
echo If you use Docker, re-clone the repository:
echo git clone https://github.com/BigBodyCobain/Shadowbroker.git
+3 -4
View File
@@ -10,14 +10,13 @@ echo ""
# Check for stale docker-compose.yml from pre-migration clones
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
if [ -f "$SCRIPT_DIR/docker-compose.yml" ] && grep -q '^\s*build:' "$SCRIPT_DIR/docker-compose.yml" 2>/dev/null; then
if [ -f "$SCRIPT_DIR/docker-compose.yml" ] && grep -q 'ghcr\.io' "$SCRIPT_DIR/docker-compose.yml" 2>/dev/null; then
echo ""
echo "================================================================"
echo " [!] WARNING: Your docker-compose.yml is outdated."
echo ""
echo " It contains 'build:' directives, which means Docker will"
echo " compile from local source instead of pulling pre-built images."
echo " You will NOT receive updates this way."
echo " It references ghcr.io which may require authentication."
echo " The current version uses Docker Hub for anonymous pulls."
echo ""
echo " If you use Docker, re-clone the repository:"
echo " git clone https://github.com/BigBodyCobain/Shadowbroker.git"