| | @@ -0,0 +1,130 @@ |
| + | name: build-sign-verify |
| + | |
| + | on: |
| + | push: |
| + | branches: [main] |
| + | tags: ["v*"] |
| + | pull_request: |
| + | branches: [main] |
| + | |
| + | env: |
| + | REGISTRY: ghcr.io |
| + | IMAGE_NAME: ${{ github.repository }} |
| + | |
| + | permissions: |
| + | contents: read |
| + | packages: write |
| + | id-token: write |
| + | attestations: write |
| + | |
| + | jobs: |
| + | build: |
| + | runs-on: ubuntu-latest |
| + | outputs: |
| + | digest: ${{ steps.push.outputs.digest }} |
| + | tags: ${{ steps.meta.outputs.tags }} |
| + | steps: |
| + | - uses: actions/checkout@v4 |
| + | |
| + | - uses: docker/setup-buildx-action@v3 |
| + | |
| + | - id: meta |
| + | uses: docker/metadata-action@v5 |
| + | with: |
| + | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} |
| + | tags: | |
| + | type=sha |
| + | type=ref,event=branch |
| + | type=semver,pattern={{version}} |
| + | |
| + | - uses: docker/login-action@v3 |
| + | if: github.event_name != 'pull_request' |
| + | with: |
| + | registry: ${{ env.REGISTRY }} |
| + | username: ${{ github.actor }} |
| + | password: ${{ secrets.GITHUB_TOKEN }} |
| + | |
| + | - id: push |
| + | uses: docker/build-push-action@v6 |
| + | with: |
| + | context: . |
| + | push: ${{ github.event_name != 'pull_request' }} |
| + | tags: ${{ steps.meta.outputs.tags }} |
| + | labels: ${{ steps.meta.outputs.labels }} |
| + | provenance: true |
| + | sbom: true |
| + | |
| + | scan: |
| + | runs-on: ubuntu-latest |
| + | needs: build |
| + | if: github.event_name != 'pull_request' |
| + | steps: |
| + | - uses: actions/checkout@v4 |
| + | |
| + | - id: sbom |
| + | uses: anchore/sbom-action@v0 |
| + | with: |
| + | image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }} |
| + | format: spdx-json |
| + | output-file: sbom.spdx.json |
| + | |
| + | - uses: anchore/scan-action@v5 |
| + | id: grype |
| + | with: |
| + | image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }} |
| + | fail-build: true |
| + | severity-cutoff: high |
| + | |
| + | - uses: actions/upload-artifact@v4 |
| + | with: |
| + | name: sbom |
| + | path: sbom.spdx.json |
| + | |
| + | sign: |
| + | runs-on: ubuntu-latest |
| + | needs: [build, scan] |
| + | if: github.event_name != 'pull_request' |
| + | steps: |
| + | - uses: sigstore/cosign-installer@v3 |
| + | |
| + | - uses: docker/login-action@v3 |
| + | with: |
| + | registry: ${{ env.REGISTRY }} |
| + | username: ${{ github.actor }} |
| + | password: ${{ secrets.GITHUB_TOKEN }} |
| + | |
| + | - name: sign image keyless |
| + | run: cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }} |
| + | |
| + | - uses: actions/download-artifact@v4 |
| + | with: |
| + | name: sbom |
| + | |
| + | - name: attach sbom attestation |
| + | run: | |
| + | cosign attest --yes \ |
| + | --predicate sbom.spdx.json \ |
| + | --type spdxjson \ |
| + | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }} |
| + | |
| + | verify: |
| + | runs-on: ubuntu-latest |
| + | needs: [build, sign] |
| + | if: github.event_name != 'pull_request' |
| + | steps: |
| + | - uses: sigstore/cosign-installer@v3 |
| + | |
| + | - name: verify signature and provenance |
| + | run: | |
| + | cosign verify \ |
| + | --certificate-identity-regexp "^https://github.com/${{ github.repository_owner }}/" \ |
| + | --certificate-oidc-issuer https://token.actions.githubusercontent.com \ |
| + | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }} |
| + | |
| + | - name: verify sbom attestation |
| + | run: | |
| + | cosign verify-attestation \ |
| + | --type spdxjson \ |
| + | --certificate-identity-regexp "^https://github.com/${{ github.repository_owner }}/" \ |
| + | --certificate-oidc-issuer https://token.actions.githubusercontent.com \ |
| + | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }} |