2020
2121jobs :
2222 build-push :
23- runs-on : ubuntu-latest
24- permissions :
25- attestations : write
26- # dependency-submission needs contents write permission.
27- contents : write
28- # attest-build-provenance needs id-token write permission.
29- id-token : write
30- packages : write
31- pull-requests : write
3223 strategy :
3324 matrix :
3425 flavor : ["cpp", "rust"]
26+ runner : ["ubuntu-latest", "ubuntu-24.04-arm"]
27+ runs-on : ${{ matrix.runner }}
28+ permissions :
29+ packages : write
3530 steps :
3631 - uses : step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
3732 with :
@@ -46,72 +41,125 @@ jobs:
4641 registry : ${{ env.REGISTRY }}
4742 username : ${{ github.actor }}
4843 password : ${{ secrets.GITHUB_TOKEN }}
49- - uses : actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
50- if : matrix.flavor == 'cpp'
51- id : buildkit-cache
52- with :
53- path : root-ccache
54- key : buildkit-cache-${{ github.run_id }}
55- restore-keys : |
56- buildkit-cache
57- - uses : reproducible-containers/buildkit-cache-dance@653a570f730e3b9460adc576db523788ba59a0d7 # v3.2.0
58- if : matrix.flavor == 'cpp'
59- with :
60- cache-map : |
61- {
62- "root-ccache": "/root/.ccache"
63- }
64- skip-extraction : ${{ steps.buildkit-cache.outputs.cache-hit }}
6544 - uses : docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
66- id : metadata
6745 env :
68- DOCKER_METADATA_ANNOTATIONS_LEVELS : manifest,index
46+ DOCKER_METADATA_SET_OUTPUT_ENV : false
47+ id : metadata
6948 with :
7049 images : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}
71- # Generate Docker tags based on the following events/attributes
72- tags : |
73- type=raw,value=latest,enable={{is_default_branch}}
74- type=ref,event=pr
75- type=semver,pattern={{raw}}
76- type=semver,pattern={{version}}
77- type=semver,pattern={{major}}.{{minor}}
78- type=semver,pattern={{major}}
7950 # Generate image LABEL for devcontainer.metadata
8051 # the sed expression is a workaround for quotes being eaten in arrays (e.g. ["x", "y", "z"] -> ["x",y,"z"])
8152 - run : echo "metadata=$(jq -cj '[.]' .devcontainer/${{ matrix.flavor }}/devcontainer-metadata-vscode.json | sed 's/,"/, "/g')" >> "$GITHUB_OUTPUT"
8253 id : devcontainer-metadata
8354 - run : echo "git-commit-epoch=$(git log -1 --pretty=%ct)" >> "$GITHUB_OUTPUT"
8455 id : devcontainer-epoch
56+ - run : echo "arch=${RUNNER_ARCH@L}" >> "$GITHUB_OUTPUT"
57+ id : devcontainer-arch
8558 - uses : docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
8659 id : build-and-push
8760 env :
8861 SOURCE_DATE_EPOCH : ${{ steps.devcontainer-epoch.outputs.git-commit-epoch }}
8962 with :
9063 file : .devcontainer/${{ matrix.flavor }}/Dockerfile
91- platforms : linux/amd64,linux/arm64
9264 push : ${{ github.event_name != 'merge_group' }}
93- tags : ${{ steps.metadata.outputs.tags }}
65+ tags : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}
9466 labels : |
9567 ${{ steps.metadata.outputs.labels }}
9668 devcontainer.metadata=${{ steps.devcontainer-metadata.outputs.metadata }}
9769 annotations : ${{ steps.metadata.outputs.annotations }}
9870 sbom : true
99- cache-from : type=gha,scope=${{ github.repository }}-${{ matrix.flavor }}
100- cache-to : type=gha,mode=max,scope=${{ github.repository }}-${{ matrix.flavor }}
71+ outputs : type=image,push-by-digest=true,name-canonical=true
72+ cache-to : type=gha,mode=max,scope=${{ github.repository }}-${{ matrix.flavor }}-${{ matrix.runner }}
73+ cache-from : type=gha,scope=${{ github.repository }}-${{ matrix.flavor }}-${{ matrix.runner }}
74+ - name : Export digest
75+ run : |
76+ mkdir -p ${{ runner.temp }}/digests
77+ digest="${{ steps.build-and-push.outputs.digest }}"
78+ touch "${{ runner.temp }}/digests/${digest#sha256:}"
79+ - uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
80+ with :
81+ name : digests-${{ matrix.flavor }}-${{ steps.devcontainer-arch.outputs.arch }}
82+ path : ${{ runner.temp }}/digests/*
83+ if-no-files-found : error
84+ retention-days : 1
85+
86+ merge-image :
87+ strategy :
88+ matrix :
89+ flavor : ["cpp", "rust"]
90+ runs-on : ubuntu-latest
91+ needs : build-push
92+ permissions :
93+ attestations : write
94+ # dependency-submission needs contents write permission.
95+ contents : write
96+ # attest-build-provenance needs id-token write permission.
97+ id-token : write
98+ packages : write
99+ pull-requests : write
100+ steps :
101+ - uses : step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
102+ with :
103+ egress-policy : audit
104+ - uses : actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
105+ with :
106+ persist-credentials : false
107+ - uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
108+ with :
109+ path : ${{ runner.temp }}/digests
110+ pattern : digests-${{ matrix.flavor }}-*
111+ merge-multiple : true
112+ - uses : docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
113+ - uses : docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
114+ if : github.event_name != 'merge_group'
115+ with :
116+ registry : ${{ env.REGISTRY }}
117+ username : ${{ github.actor }}
118+ password : ${{ secrets.GITHUB_TOKEN }}
119+ - uses : docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
120+ id : metadata
121+ env :
122+ DOCKER_METADATA_ANNOTATIONS_LEVELS : index
123+ DOCKER_METADATA_SET_OUTPUT_ENV : false
124+ with :
125+ images : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}
126+ # Generate Docker tags based on the following events/attributes
127+ tags : |
128+ type=raw,value=latest,enable={{is_default_branch}}
129+ type=ref,event=pr
130+ type=semver,pattern={{raw}}
131+ type=semver,pattern={{version}}
132+ type=semver,pattern={{major}}.{{minor}}
133+ type=semver,pattern={{major}}
134+ - name : Create manifest list and push
135+ working-directory : ${{ runner.temp }}/digests
136+ run : |
137+ set -Eeuo pipefail
138+ # shellcheck disable=SC2046
139+ docker buildx imagetools create \
140+ $(echo '${{ steps.metadata.outputs.json }}' | jq -r '.tags | map("--tag " + .) | join(" ")') \
141+ $(printf '${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@sha256:%s ' *)
142+ - name : Inspect manifest and extract digest
143+ id : inspect-manifest
144+ run : |
145+ set -Eeuo pipefail
146+ output=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}:${{ steps.metadata.outputs.version }} --format '{{json .}}')
147+ digest=$(echo "$output" | jq -r '.manifest.digest // .manifests[0].digest')
148+ echo "digest=$digest" >> "$GITHUB_OUTPUT"
101149 - uses : ./.github/actions/container-size-diff
102150 id : container-size-diff
103151 with :
104152 from-container : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}:latest
105- to-container : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@ ${{ steps.build-and-push .outputs.digest }}
153+ to-container : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}: ${{ steps.metadata .outputs.version }}
106154 - uses : marocchino/sticky-pull-request-comment@67d0dec7b07ed060a405f9b2a64b8ab319fdd7db # v2.9.2
107155 with :
108156 header : container-size-diff-${{ matrix.flavor }}
109157 message : |
110158 ${{ steps.container-size-diff.outputs.size-diff-markdown }}
111159 - uses : anchore/sbom-action@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0
112- if : steps.build-and-push .outputs.digest != '' && github.event_name != 'merge_group'
160+ if : steps.inspect-manifest .outputs.digest != '' && github.event_name != 'merge_group'
113161 with :
114- image : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.build-and-push .outputs.digest }}
162+ image : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.inspect-manifest .outputs.digest }}
115163 dependency-snapshot : true
116164 - uses : actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1
117165 if : github.event_name == 'pull_request'
@@ -122,22 +170,22 @@ jobs:
122170 if : github.event_name != 'merge_group'
123171 with :
124172 subject-name : ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}
125- subject-digest : ${{ steps.build-and-push .outputs.digest }}
173+ subject-digest : ${{ steps.inspect-manifest .outputs.digest }}
126174 push-to-registry : true
127175 - name : Verify attestation
128176 if : github.event_name != 'merge_group'
129177 env :
130178 GH_TOKEN : ${{ github.token }}
131179 run : |
132- gh attestation verify --repo ${{ github.repository }} oci://${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.build-and-push .outputs.digest }}
180+ gh attestation verify --repo ${{ github.repository }} oci://${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.inspect-manifest .outputs.digest }}
133181 - name : Upload provenance to release
134182 if : startsWith(github.ref, 'refs/tags/')
135183 env :
136184 GH_TOKEN : ${{ github.token }}
137185 run : |
138- RAW_SHA=${{ steps.build-and-push .outputs.digest }}
186+ RAW_SHA=${{ steps.inspect-manifest .outputs.digest }}
139187 FORMATTED_SHA=${RAW_SHA//:/_}
140- gh attestation verify --repo ${{ github.repository }} oci://${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.build-and-push .outputs.digest }} --format json --jq '.[] | .attestation.bundle.dsseEnvelope | select(.payloadType == "application/vnd.in-toto+json").payload' | base64 -d | jq . > "${{ github.repository_owner }}-${{ github.event.repository.name }}-${{ matrix.flavor }}_${FORMATTED_SHA}.intoto.jsonl"
188+ gh attestation verify --repo ${{ github.repository }} oci://${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.inspect-manifest .outputs.digest }} --format json --jq '.[] | .attestation.bundle.dsseEnvelope | select(.payloadType == "application/vnd.in-toto+json").payload' | base64 -d | jq . > "${{ github.repository_owner }}-${{ github.event.repository.name }}-${{ matrix.flavor }}_${FORMATTED_SHA}.intoto.jsonl"
141189 gh release upload ${{ github.ref_name }} ./*.intoto.jsonl
142190 - name : Update package details in release
143191 if : startsWith(github.ref, 'refs/tags/')
@@ -146,12 +194,45 @@ jobs:
146194 run : |
147195 UPDATED_NOTES=$(gh release view ${{ github.ref_name }} --json body -q '.body')
148196 UPDATED_NOTES=${UPDATED_NOTES//'{{ amp-devcontainer-${{ matrix.flavor }}-version }}'/'${{ github.ref_name }}'}
149- UPDATED_NOTES=${UPDATED_NOTES//'{{ amp-devcontainer-${{ matrix.flavor }}-sha }}'/'${{ steps.build-and-push .outputs.digest }}'}
197+ UPDATED_NOTES=${UPDATED_NOTES//'{{ amp-devcontainer-${{ matrix.flavor }}-sha }}'/'${{ steps.inspect-manifest .outputs.digest }}'}
150198 gh release edit ${{ github.ref_name }} --notes "${UPDATED_NOTES}"
199+
200+ integration-test :
201+ if : github.event_name == 'pull_request'
202+ strategy :
203+ matrix :
204+ flavor : [cpp, rust]
205+ runner : ["ubuntu-latest", "ubuntu-24.04-arm"]
206+ needs : merge-image
207+ secrets : inherit
208+ uses : ./.github/workflows/integration-test.yml
209+ with :
210+ flavor : ${{ matrix.flavor }}
211+ runner : ${{ matrix.runner }}
212+
151213 acceptance-test :
152214 if : github.event_name == 'pull_request'
153- needs : build-push
215+ needs : merge-image
154216 secrets : inherit
155217 uses : ./.github/workflows/acceptance-test.yml
156218 with :
157219 flavor : cpp
220+
221+ publish-test-results :
222+ runs-on : ubuntu-latest
223+ permissions :
224+ checks : write
225+ pull-requests : write
226+ needs : [acceptance-test, integration-test]
227+ if : always()
228+ steps :
229+ - uses : step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
230+ with :
231+ egress-policy : audit
232+ - uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
233+ with :
234+ merge-multiple : true
235+ pattern : test-results-*
236+ - uses : EnricoMi/publish-unit-test-result-action@3a74b2957438d0b6e2e61d67b05318aa25c9e6c6 # v2.20.0
237+ with :
238+ files : test-report-*.xml
0 commit comments