Build and Publish to GHCR and MCR #1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build and Publish to GHCR and MCR | |
on: [workflow_dispatch] | |
permissions: | |
contents: read | |
jobs: | |
common: | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
defaults: | |
run: | |
shell: pwsh | |
steps: | |
- name: Harden Runner | |
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 | |
with: | |
egress-policy: audit | |
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
- name: Get Changelog Entry | |
id: changelog_reader | |
uses: mindsers/changelog-reader-action@b97ce03a10d9bdbb07beb491c76a5a01d78cd3ef # v2.2.2 | |
with: | |
validation_depth: 10 | |
path: ./CHANGELOG.md | |
- name: Get Version Info | |
id: read_metadata | |
run: | | |
echo "Version: ${{ steps.changelog_reader.outputs.version }}" | |
echo "Changes: ${{ steps.changelog_reader.outputs.changes }}" | |
$owner = "${{ github.repository_owner }}".ToLower() | |
echo "acr_image_id=${{ vars.AZURE_REGISTRY_SERVER }}/public/aks/periscope" >> $env:GITHUB_OUTPUT | |
echo "ghcr_image_id=ghcr.io/$owner/aks/periscope" >> $env:GITHUB_OUTPUT | |
echo "tag_id_base=${{ steps.changelog_reader.outputs.version }}" >> $env:GITHUB_OUTPUT | |
outputs: | |
acr_image_id: ${{ steps.read_metadata.outputs.acr_image_id }} | |
ghcr_image_id: ${{ steps.read_metadata.outputs.ghcr_image_id }} | |
tag_id_base: ${{ steps.read_metadata.outputs.tag_id_base }} | |
version: ${{ steps.changelog_reader.outputs.version }} | |
changes: ${{ steps.changelog_reader.outputs.changes }} | |
release: | |
runs-on: ubuntu-latest | |
needs: common | |
permissions: | |
contents: write | |
steps: | |
- name: Harden Runner | |
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 | |
with: | |
egress-policy: audit | |
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
publish: | |
runs-on: | |
labels: [self-hosted, "1ES.Pool=${{ matrix.runner }}"] | |
needs: common | |
permissions: | |
contents: read | |
id-token: write | |
packages: write | |
strategy: | |
max-parallel: 4 | |
matrix: | |
os: [ubuntu-latest, windows-2019, windows-2022] | |
include: | |
- os: ubuntu-latest | |
runner: ${{ vars.RUNNER_BASE_NAME }}-ubuntu | |
file: ./builder/Dockerfile.linux | |
baseimage: 'mcr.microsoft.com/cbl-mariner/distroless/base:2.0' | |
tagext: 'mariner2.0' | |
canpatch: true | |
- os: windows-2019 | |
runner: ${{ vars.RUNNER_BASE_NAME }}-win2019 | |
file: ./builder/Dockerfile.windows | |
baseimage: 'mcr.microsoft.com/windows/nanoserver:ltsc2019' | |
tagext: 'nanoserver2019' | |
canpatch: false | |
- os: windows-2022 | |
runner: ${{ vars.RUNNER_BASE_NAME }}-win2022 | |
file: ./builder/Dockerfile.windows | |
baseimage: 'mcr.microsoft.com/windows/nanoserver:ltsc2022' | |
tagext: 'nanoserver2022' | |
canpatch: false | |
defaults: | |
run: | |
shell: pwsh | |
steps: | |
- name: Harden Runner | |
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 | |
with: | |
egress-policy: audit | |
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
# Perform a 'docker login' so that we can push to the ACR that provides the MCR images. | |
# This requires an Az login first. | |
- name: Authenticate to ACR | |
run: | | |
az login --identity | |
az acr login -n ${{ vars.AZURE_REGISTRY_SERVER }} | |
# Perform a 'docker login' so that we can push to the current repo's GHCR. We will push the unpatched | |
# images to GHCR first, run a Trivy scan and Copa patch on those, and then push the patched images | |
# to both GHCR and ACR. | |
- name: Authenticate to GHCR | |
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
# Work out the target image references (registry images and tags) for publishing. | |
- name: Get Image References | |
id: getref | |
run: | | |
$tag_id = "${{ needs.common.outputs.tag_id_base }}-${{ matrix.tagext }}" | |
echo "tag_id=$tag_id" >> $env:GITHUB_OUTPUT | |
echo "acr_image_ref=${{ needs.common.outputs.acr_image_id }}:$tag_id" >> $env:GITHUB_OUTPUT | |
echo "ghcr_image_ref=${{ needs.common.outputs.ghcr_image_id }}:$tag_id" >> $env:GITHUB_OUTPUT | |
echo "${{ matrix.os }}-acr-image-ref=${{ needs.common.outputs.acr_image_id }}:$tag_id" >> $env:GITHUB_OUTPUT | |
echo "${{ matrix.os }}-ghcr-image-ref=${{ needs.common.outputs.ghcr_image_id }}:$tag_id" >> $env:GITHUB_OUTPUT | |
- name: Build Image | |
id: build | |
run: docker build -f ${{ matrix.file }} --build-arg BASE_IMAGE=${{ matrix.baseimage }} -t ${{ steps.getref.outputs.ghcr_image_ref }} . | |
# If this OS supports patching images using Copa, push the unpatched image to GHCR with the tag suffix '-unpatched'. | |
# Then, scan and patch this image, and re-tag it with the original tag (no suffix). | |
- name: Push Unpatched Image to GHCR | |
if: matrix.canpatch | |
run: | | |
docker tag ${{ steps.getref.outputs.ghcr_image_ref }} ${{ steps.getref.outputs.ghcr_image_ref }}-unpatched | |
docker push ${{ steps.getref.outputs.ghcr_image_ref }}-unpatched | |
- name: Generate Trivy Report | |
if: matrix.canpatch | |
uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef # v0.17.0 | |
with: | |
scan-type: 'image' | |
format: 'json' | |
output: 'report.json' | |
ignore-unfixed: true | |
vuln-type: 'os' | |
image-ref: ${{ steps.getref.outputs.ghcr_image_ref }}-unpatched | |
- name: Check Vuln Count | |
if: matrix.canpatch | |
id: vulncount | |
run: | | |
$report_file = "report.json" | |
cat $report_file | |
$vuln_count = jq '.Results[0].Vulnerabilities | length' $report_file | |
echo "vuln_count=$vuln_count" >> $env:GITHUB_OUTPUT | |
- name: Copa Action | |
if: matrix.canpatch && steps.vulncount.outputs.vuln_count != '0' | |
id: copa | |
uses: project-copacetic/copa-action@9a4406210914e570a473abf3f1e6c4fd952c7749 # v1.1.0 | |
with: | |
image: ${{ steps.getref.outputs.ghcr_image_ref }}-unpatched | |
image-report: 'report.json' | |
patched-tag: ${{ steps.getref.outputs.tag_id }} | |
buildkit-version: 'v0.12.1' | |
# Push to both GHCR and ACR. The image being pushed will be the patched one, if patching is supported, | |
# or the original built image otherwise. | |
- name: Push Image to GHCR | |
run: docker push ${{ steps.getref.outputs.ghcr_image_ref }} | |
- name: Push Image to ACR | |
id: publish | |
run: | | |
docker tag ${{ steps.getref.outputs.ghcr_image_ref }} ${{ steps.getref.outputs.acr_image_ref }} | |
docker push ${{ steps.getref.outputs.acr_image_ref }} | |
outputs: | |
ghcr_linux: ${{ steps.getref.outputs.ubuntu-latest-ghcr-image-ref }} | |
ghcr_win2019: ${{ steps.getref.outputs.windows-2019-ghcr-image-ref }} | |
ghcr_win2022: ${{ steps.getref.outputs.windows-2022-ghcr-image-ref }} | |
acr_linux: ${{ steps.getref.outputs.ubuntu-latest-acr-image-ref }} | |
acr_win2019: ${{ steps.getref.outputs.windows-2019-acr-image-ref }} | |
acr_win2022: ${{ steps.getref.outputs.windows-2022-acr-image-ref }} | |
update-manifest: | |
runs-on: | |
labels: ["self-hosted", "1ES.Pool=${{ vars.RUNNER_BASE_NAME }}-ubuntu"] | |
needs: [common, publish] | |
permissions: | |
id-token: write | |
packages: write | |
defaults: | |
run: | |
shell: pwsh | |
steps: | |
# As for the 'publish' job, we need to 'docker login' to both GHCR and ACR to push manifests. | |
- name: Harden Runner | |
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 | |
with: | |
egress-policy: audit | |
- name: Authenticate to ACR | |
run: | | |
az login --identity | |
az acr login -n ${{ vars.AZURE_REGISTRY_SERVER }} | |
- name: Authenticate to GHCR | |
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Publish Cross-Platform Manifest | |
id: publish | |
run: | | |
$ghcr_xplat_image_ref = "${{ needs.common.outputs.ghcr_image_id }}:${{ needs.common.outputs.tag_id_base }}" | |
$acr_xplat_image_ref = "${{ needs.common.outputs.acr_image_id }}:${{ needs.common.outputs.tag_id_base }}" | |
docker manifest create $ghcr_xplat_image_ref ${{ needs.publish.outputs.ghcr_linux }} ${{ needs.publish.outputs.ghcr_win2019 }} ${{ needs.publish.outputs.ghcr_win2022 }} | |
docker manifest create $acr_xplat_image_ref ${{ needs.publish.outputs.acr_linux }} ${{ needs.publish.outputs.acr_win2019 }} ${{ needs.publish.outputs.acr_win2022 }} | |
docker manifest push $ghcr_xplat_image_ref | |
docker manifest push $acr_xplat_image_ref |