2424
2525env :
2626 REGISTRY : ghcr.io
27+ IMAGE_NAME : ${{ github.repository_owner }}/synkronus
2728
2829jobs :
2930 build-and-push :
3031 runs-on : ubuntu-latest
3132 name : Build and push combined Synkronus image
3233 permissions :
33- contents : write
34+ contents : read
3435 packages : write
3536 id-token : write
3637 attestations : write
37-
38+
3839 steps :
3940 - name : Checkout repository
4041 uses : actions/checkout@v4
4142 with :
4243 fetch-depth : 0 # Full history so git describe can reach the last tag
43-
44+
4445 - name : Set up QEMU
45- uses : docker/setup-qemu-action@v3
46- with :
47- platforms : all
48-
49- - name : Set up Docker Buildx
50- uses : docker/setup-buildx-action@v3
51-
52- - name : Log in to GitHub Container Registry
53- uses : docker/login-action@v3
46+ run : |
47+ sudo apt-get update
48+ sudo apt-get install -y qemu-user-static binfmt-support
49+ sudo update-binfmts --enable qemu-aarch64
50+
51+ - name : Log in to Github Container Registry
52+ uses : redhat-actions/podman-login@v1
5453 with :
55- registry : ${{ env.REGISTRY }}
5654 username : ${{ github.actor }}
5755 password : ${{ secrets.GITHUB_TOKEN }}
58-
56+ registry : ${{ env.REGISTRY }}
57+
5958 - name : Determine Synkronus version from git
6059 id : version
6160 run : |
@@ -71,51 +70,69 @@ jobs:
7170 fi
7271 echo "version=${VERSION}" >> $GITHUB_OUTPUT
7372 echo "Building Synkronus with version: ${VERSION}"
74-
75- - name : Extract metadata ( tags, labels)
76- id : meta
77- uses : docker/metadata-action@v5
73+
74+ - name : Compute image tags and labels
75+ id : tags
76+ uses : docker/metadata-action@v6
7877 with :
79- images : ${{ env.REGISTRY }}/opendataensemble/synkronus
78+ images : |
79+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
8080 tags : |
81- # For main branch: latest + version tag (manual dispatch) or release tag
82- type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
83- # For dev branch: tag as both dev and latest (for demo server auto-updates)
84- type=raw,value=dev,enable=${{ github.ref == 'refs/heads/dev' }}
85- type=raw,value=latest,enable=${{ github.ref == 'refs/heads/dev' }}
86- # When triggered from a GitHub Release event, use the release tag name as the semver source
87- type=semver,pattern=v{{version}},enable=${{ github.event_name == 'release' }},value=${{ github.event.release.tag_name }}
88- type=semver,pattern=v{{major}}.{{minor}},enable=${{ github.event_name == 'release' }},value=${{ github.event.release.tag_name }}
89- # For other branches: branch name (pre-release)
90- type=ref,event=branch,enable=${{ github.event_name != 'release' && github.ref != 'refs/heads/main' && github.ref != 'refs/heads/dev' }}
91- # For PRs: pr-number
92- type=ref,event=pr
93- # SHA for traceability (only for non-release events)
94- type=sha,prefix=sha-,enable=${{ github.event_name != 'release' && github.event_name != 'pull_request' }}
95- labels : |
96- org.opencontainers.image.title=Synkronus
97- org.opencontainers.image.description=Synchronization API and Web Portal for offline-first applications
98- org.opencontainers.image.vendor=Open Data Ensemble
99-
100- - name : Build and push Docker image
101- id : build
102- uses : docker/build-push-action@v5
81+ # Release event: v<version> + v<major>.<minor>
82+ type=semver,pattern=v{{version}},value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }},priority=1000
83+ type=semver,pattern=v{{major}}.{{minor}},value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }},priority=900
84+ # Pull requests: pr-<number>
85+ type=ref,event=pr,priority=1000
86+ # Non-release/non-PR refs: main/dev/other branches + sha
87+ type=raw,value=latest,enable=${{ github.event_name != 'release' && github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }},priority=1000
88+ type=raw,value=dev,enable=${{ github.event_name != 'release' && github.event_name != 'pull_request' && github.ref == 'refs/heads/dev' }},priority=1000
89+ type=raw,value=latest,enable=${{ github.event_name != 'release' && github.event_name != 'pull_request' && github.ref == 'refs/heads/dev' }},priority=900
90+ type=ref,event=branch,enable=${{ github.event_name != 'release' && github.event_name != 'pull_request' && github.ref != 'refs/heads/main' && github.ref != 'refs/heads/dev' }},priority=1000
91+ type=sha,enable=${{ github.event_name != 'release' && github.event_name != 'pull_request' }},priority=100
92+
93+ - name : Build multi-arch image with Buildah
94+ id : build-image
95+ uses : redhat-actions/buildah-build@v2
10396 with :
104- context : .
105- file : ./Dockerfile
106- platforms : linux/amd64
107- push : ${{ github.event_name != 'pull_request' }}
108- tags : ${{ steps.meta.outputs.tags }}
109- labels : ${{ steps.meta.outputs.labels }}
97+ image : ${{ env.IMAGE_NAME }}
98+ tags : ${{ steps.tags.outputs.tag-names }}
99+ labels : ${{ steps.tags.outputs.labels }}
100+ archs : amd64,arm64
101+ containerfiles : |
102+ ./Dockerfile
110103 build-args : |
111104 SYNKRONUS_VERSION=${{ steps.version.outputs.version }}
112- cache-from : type=gha
113- cache-to : type=gha,mode=max
114-
105+
106+ - name : Push image manifest to registry
107+ if : github.event_name != 'pull_request'
108+ id : push-image
109+ uses : redhat-actions/push-to-registry@v2
110+ with :
111+ image : ${{ steps.build-image.outputs.image }}
112+ tags : ${{ steps.build-image.outputs.tags }}
113+ registry : ${{ env.REGISTRY }}
114+
115+ - name : Verify image
116+ if : github.event_name != 'pull_request'
117+ shell : bash
118+ run : |
119+ set -euo pipefail
120+ IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
121+ PRIMARY_TAG="${{ steps.tags.outputs.version }}"
122+
123+ # Confirm the manifest list includes both target platforms.
124+ skopeo inspect --raw "docker://${IMAGE}:${PRIMARY_TAG}" | \
125+ jq -e '[.manifests[].platform | "\(.os)/\(.architecture)"] | index("linux/amd64") and index("linux/arm64")' >/dev/null
126+ echo "Verified manifest platforms for ${IMAGE}:${PRIMARY_TAG}"
127+
128+ # Pull each platform explicitly to confirm the runtime layers are accessible.
129+ podman pull --arch amd64 "${IMAGE}:${PRIMARY_TAG}"
130+ podman pull --arch arm64 "${IMAGE}:${PRIMARY_TAG}"
131+
115132 - name : Generate artifact attestation
116133 if : github.event_name != 'pull_request'
117134 uses : actions/attest-build-provenance@v1
118135 with :
119- subject-name : ${{ env.REGISTRY }}/opendataensemble/synkronus
120- subject-digest : ${{ steps.build .outputs.digest }}
136+ subject-name : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
137+ subject-digest : ${{ steps.push-image .outputs.digest }}
121138 push-to-registry : true
0 commit comments