@@ -105,6 +105,7 @@ jobs:
105105 permissions :
106106 contents : read
107107 packages : write
108+ id-token : write # Needed for provenance attestation
108109
109110 steps :
110111 - name : Checkout repository
@@ -115,6 +116,9 @@ jobs:
115116 with :
116117 go-version : ' 1.24'
117118
119+ - name : Set up QEMU
120+ uses : docker/setup-qemu-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
121+
118122 - name : Set up Docker Buildx
119123 uses : docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
120124
@@ -139,37 +143,77 @@ jobs:
139143 # Extract server name from filename (without .yaml extension)
140144 server_name=$(basename "$config_file" .yaml)
141145 echo "server_name=$server_name" >> $GITHUB_OUTPUT
146+
147+ # Generate image name
148+ image_name="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${protocol}/${server_name}"
149+ echo "image_name=$image_name" >> $GITHUB_OUTPUT
142150
143- - name : Build and capture container info
144- id : build
151+ - name : Generate Dockerfile
152+ id : dockerfile
145153 run : |
146- echo "Building container for ${{ steps.meta.outputs.config_file }}"
154+ echo "Generating Dockerfile for ${{ steps.meta.outputs.config_file }}"
147155
148- # Capture the output which includes the built image name
149- output =$(go run main.go -config "${{ steps.meta.outputs.config_file }}" 2>&1 )
150- echo "$output "
156+ # Create a temporary directory for the Dockerfile
157+ dockerfile_dir =$(mktemp -d )
158+ dockerfile_path="${dockerfile_dir}/Dockerfile "
151159
152- # Extract the image name from the last line of output
153- image_name=$(echo "$output" | grep "Successfully built container image:" | sed 's/Successfully built container image: //')
154- echo "image_name=$image_name" >> $GITHUB_OUTPUT
155- echo "Captured built image: $image_name"
160+ # Generate the Dockerfile using our tool
161+ go run main.go -config "${{ steps.meta.outputs.config_file }}" -output "${dockerfile_path}"
162+
163+ echo "dockerfile_dir=$dockerfile_dir" >> $GITHUB_OUTPUT
164+ echo "dockerfile_path=$dockerfile_path" >> $GITHUB_OUTPUT
165+
166+ # Display the generated Dockerfile for debugging
167+ echo "Generated Dockerfile:"
168+ cat "${dockerfile_path}"
156169
157- - name : Push container image
158- if : github.event_name != 'pull_request' && steps.build.outputs.image_name != ''
159- run : |
160- image_name="${{ steps.build.outputs.image_name }}"
161- echo "Pushing image: $image_name"
162- docker push "$image_name"
170+ - name : Extract metadata for Docker
171+ id : docker-meta
172+ uses : docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5
173+ with :
174+ images : ${{ steps.meta.outputs.image_name }}
175+ tags : |
176+ type=ref,event=branch
177+ type=ref,event=pr
178+ type=semver,pattern={{version}}
179+ type=semver,pattern={{major}}.{{minor}}
180+ type=sha,prefix={{branch}}-
181+ type=raw,value=latest,enable={{is_default_branch}}
182+
183+ - name : Build and push Docker image
184+ uses : docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6
185+ with :
186+ context : ${{ steps.dockerfile.outputs.dockerfile_dir }}
187+ file : ${{ steps.dockerfile.outputs.dockerfile_path }}
188+ platforms : linux/amd64,linux/arm64
189+ push : ${{ github.event_name != 'pull_request' }}
190+ tags : ${{ steps.docker-meta.outputs.tags }}
191+ labels : ${{ steps.docker-meta.outputs.labels }}
192+ cache-from : type=gha
193+ cache-to : type=gha,mode=max
194+ sbom : true
195+ provenance : true
196+ annotations : |
197+ org.opencontainers.image.title=${{ steps.meta.outputs.server_name }}
198+ org.opencontainers.image.description=MCP server for ${{ steps.meta.outputs.server_name }}
199+ org.opencontainers.image.vendor=Stacklok
200+ org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
201+ org.opencontainers.image.revision=${{ github.sha }}
163202
164203 - name : Generate image summary
165204 run : |
166205 echo "## Container Build Summary" >> $GITHUB_STEP_SUMMARY
167206 echo "- **Config**: ${{ steps.meta.outputs.config_file }}" >> $GITHUB_STEP_SUMMARY
168207 echo "- **Protocol**: ${{ steps.meta.outputs.protocol }}" >> $GITHUB_STEP_SUMMARY
169208 echo "- **Server**: ${{ steps.meta.outputs.server_name }}" >> $GITHUB_STEP_SUMMARY
170- echo "- **Image**: ${{ steps.build.outputs.image_name }}" >> $GITHUB_STEP_SUMMARY
209+ echo "- **Image**: ${{ steps.meta.outputs.image_name }}" >> $GITHUB_STEP_SUMMARY
210+ echo "- **Platforms**: linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
211+ echo "- **SBOM**: ✅ Included" >> $GITHUB_STEP_SUMMARY
212+ echo "- **Provenance**: ✅ Attested" >> $GITHUB_STEP_SUMMARY
171213 if [ "${{ github.event_name }}" != "pull_request" ]; then
172214 echo "- **Status**: ✅ Built and pushed" >> $GITHUB_STEP_SUMMARY
215+ echo "- **Tags**:" >> $GITHUB_STEP_SUMMARY
216+ echo "${{ steps.docker-meta.outputs.tags }}" | sed 's/^/ - /' >> $GITHUB_STEP_SUMMARY
173217 else
174218 echo "- **Status**: ✅ Built (not pushed - PR)" >> $GITHUB_STEP_SUMMARY
175219 fi
@@ -189,6 +233,11 @@ jobs:
189233
190234 if [ "${{ needs.build-containers.result }}" == "success" ]; then
191235 echo "- **Build Status**: ✅ All changed containers built successfully" >> $GITHUB_STEP_SUMMARY
236+ echo "- **Features**:" >> $GITHUB_STEP_SUMMARY
237+ echo " - 🏗️ Multi-architecture support (amd64, arm64)" >> $GITHUB_STEP_SUMMARY
238+ echo " - 📦 SBOM (Software Bill of Materials) included" >> $GITHUB_STEP_SUMMARY
239+ echo " - 🔐 Provenance attestation for supply chain security" >> $GITHUB_STEP_SUMMARY
240+ echo " - 🚀 GitHub Actions cache for faster builds" >> $GITHUB_STEP_SUMMARY
192241 elif [ "${{ needs.build-containers.result }}" == "failure" ]; then
193242 echo "- **Build Status**: ❌ Some containers failed to build" >> $GITHUB_STEP_SUMMARY
194243 elif [ "${{ needs.build-containers.result }}" == "skipped" ]; then
0 commit comments