Skip to content

Publish to MCR

Publish to MCR #15

Workflow file for this run

name: Publish to MCR
on:
# Manual trigger for testing and ad-hoc releases
workflow_dispatch:
inputs:
tag:
description: "Git tag (e.g., v1.2.3)"
required: true
ghcr_image:
description: "GHCR source image (optional, defaults to ghcr.io/azure/aks-mcp:<tag>)"
required: false
# Automatic trigger after SLSA releaser completes
workflow_run:
workflows: ["SLSA releaser"]
types: [completed]
permissions:
contents: read
packages: read
env:
GHCR_REGISTRY: ghcr.io
GHCR_IMAGE_NAME: azure/aks-mcp
jobs:
publish-to-mcr:
# Only run on successful workflow_run or manual dispatch
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
runs-on:
labels: ["self-hosted", "1ES.Pool=1es-aks-mcp-agent-pool-ubuntu"]
environment: publish-mcr
outputs:
version: ${{ steps.version.outputs.version }}
mcr_image: ${{ steps.push.outputs.mcr_image }}
image_id: ${{ steps.verify.outputs.image_id }}
steps:
- name: Determine version and source image
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG="${{ github.event.inputs.tag }}"
GHCR_IMAGE="${{ github.event.inputs.ghcr_image }}"
else
# Extract tag from workflow_run ref (refs/tags/v1.2.3 -> v1.2.3)
TAG="${{ github.event.workflow_run.head_branch }}"
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then
echo "Not a version tag, skipping MCR publish"
exit 0
fi
fi
# Use provided GHCR image or construct default
if [ -z "$GHCR_IMAGE" ]; then
GHCR_IMAGE="${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${TAG}"
fi
# Keep the version with 'v' prefix for MCR
VERSION="${TAG}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "ghcr_image=${GHCR_IMAGE}" >> "$GITHUB_OUTPUT"
echo "Git Tag: ${TAG}"
echo "MCR Version: ${VERSION}"
echo "Source GHCR Image: ${GHCR_IMAGE}"
echo "Note: MCR version keeps 'v' prefix to match GHCR"
- name: Authenticate to Azure
run: |
az login --identity
az account show
- name: Authenticate to MCR
id: mcr-auth
run: |
MCR_REGISTRY=$(echo "${{ secrets.AKS_MCP_MCR_REGISTRY }}" | tr '[:upper:]' '[:lower:]')
az acr login -n ${{ secrets.AKS_MCP_MCR_REGISTRY }}
echo "registry=${MCR_REGISTRY}" >> "$GITHUB_OUTPUT"
- name: Authenticate to GHCR
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ${{ env.GHCR_REGISTRY }} -u ${{ github.actor }} --password-stdin
- name: Pull image from GHCR
id: pull
run: |
GHCR_IMAGE="${{ steps.version.outputs.ghcr_image }}"
echo "Pulling image: ${GHCR_IMAGE}"
docker pull ${GHCR_IMAGE}
# Get the image ID (content hash) from GHCR
GHCR_IMAGE_ID=$(docker inspect ${GHCR_IMAGE} --format='{{.Id}}')
echo "ghcr_image_id=${GHCR_IMAGE_ID}" >> "$GITHUB_OUTPUT"
echo "GHCR Image ID: ${GHCR_IMAGE_ID}"
- name: Tag and push to MCR
id: push
run: |
GHCR_IMAGE="${{ steps.version.outputs.ghcr_image }}"
VERSION="${{ steps.version.outputs.version }}"
MCR_REGISTRY="${{ steps.mcr-auth.outputs.registry }}"
MCR_INTERNAL_IMAGE="${MCR_REGISTRY}.azurecr.io/public/aks/aks-mcp"
MCR_PUBLIC_IMAGE="mcr.microsoft.com/aks/aks-mcp"
# Tag and push (suppress output to avoid exposing internal registry)
docker tag ${GHCR_IMAGE} ${MCR_INTERNAL_IMAGE}:${VERSION}
docker tag ${GHCR_IMAGE} ${MCR_INTERNAL_IMAGE}:latest
docker push ${MCR_INTERNAL_IMAGE}:${VERSION} > /dev/null 2>&1
docker push ${MCR_INTERNAL_IMAGE}:latest > /dev/null 2>&1
# Output the public MCR image for display (not the internal registry)
echo "mcr_image=${MCR_PUBLIC_IMAGE}:${VERSION}" >> "$GITHUB_OUTPUT"
echo "mcr_internal_image=${MCR_INTERNAL_IMAGE}:${VERSION}" >> "$GITHUB_OUTPUT"
echo "Successfully pushed to mcr.microsoft.com/aks/aks-mcp:${VERSION}"
- name: Verify image consistency
id: verify
run: |
GHCR_IMAGE="${{ steps.version.outputs.ghcr_image }}"
MCR_INTERNAL_IMAGE="${{ steps.push.outputs.mcr_internal_image }}"
MCR_PUBLIC_IMAGE="${{ steps.push.outputs.mcr_image }}"
# Pull and inspect (suppress output to avoid exposing internal registry)
docker pull ${MCR_INTERNAL_IMAGE} > /dev/null 2>&1
MCR_IMAGE_ID=$(docker inspect ${MCR_INTERNAL_IMAGE} --format='{{.Id}}')
echo "Source: ${GHCR_IMAGE}"
echo "Published: ${MCR_PUBLIC_IMAGE}"
echo "Image ID: ${MCR_IMAGE_ID}"
# Get and compare layer information (more reliable than Image ID)
GHCR_LAYERS=$(docker inspect ${GHCR_IMAGE} --format='{{range .RootFS.Layers}}{{println .}}{{end}}' | sort)
MCR_LAYERS=$(docker inspect ${MCR_INTERNAL_IMAGE} --format='{{range .RootFS.Layers}}{{println .}}{{end}}' | sort)
echo ""
echo "=== Layer Verification ==="
GHCR_LAYER_COUNT=$(echo "${GHCR_LAYERS}" | wc -l)
MCR_LAYER_COUNT=$(echo "${MCR_LAYERS}" | wc -l)
echo "GHCR Layer Count: ${GHCR_LAYER_COUNT}"
echo "MCR Layer Count: ${MCR_LAYER_COUNT}"
if [ "${GHCR_LAYERS}" = "${MCR_LAYERS}" ]; then
echo "✅ Image verification PASSED - All layers are identical"
echo "image_id=${MCR_IMAGE_ID}" >> "$GITHUB_OUTPUT"
else
echo "❌ Image verification FAILED - Layers differ!"
echo ""
echo "GHCR Layers:"
echo "${GHCR_LAYERS}"
echo ""
echo "MCR Layers:"
echo "${MCR_LAYERS}"
exit 1
fi
# Verification complete
echo ""
echo "✅ Image layers verified successfully"
- name: Summary
run: |
echo "## MCR Publishing Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Successfully published to MCR" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Git Tag**: ${{ steps.version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
echo "- **MCR Version**: ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Source Image**: ${{ steps.version.outputs.ghcr_image }}" >> $GITHUB_STEP_SUMMARY
echo "- **MCR Image**: ${{ steps.push.outputs.mcr_image }}" >> $GITHUB_STEP_SUMMARY
echo "- **Image ID**: ${{ steps.verify.outputs.image_id }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Verification" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ steps.push.outputs.mcr_image }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY