diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..5cfdb2b --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,127 @@ +name: Release pizza image + +on: + push: + tags: + - 'v*' + +permissions: + actions: read + packages: write # for publish to ghcr.io + id-token: write # for signing image + +jobs: + build: + name: Build and publish image + runs-on: ubuntu-latest + env: + IMAGE_URI: ghcr.io/${{ github.repository }} + IMAGE_URI_TAG: ghcr.io/${{ github.repository }}:${{ github.ref_name }} + outputs: + image: ${{ env.IMAGE_URI }} + digest: ${{ steps.image_digest.outputs.IMAGE_DIGEST }} + steps: + - name: Checkout code + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # tag=v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to GitHub Container Registry + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Cross build + run: | + #!/usr/bin/env bash + + docker buildx bake \ + -f ./docker-bake.hcl \ + --set build.args.GO_LDFLAGS="$GO_LDFLAGS" \ + --set cross.tags=ghcr.io/${{ github.repository }}:${{ github.ref_name }} \ + --push \ + cross + + - name: Install crane + if: startsWith(github.ref, 'refs/tags/') + uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c # v0.3 + - name: Output image digest + if: startsWith(github.ref, 'refs/tags/') + id: image_digest + run: echo "IMAGE_DIGEST=$(crane digest ${IMAGE_URI_TAG})" >> $GITHUB_OUTPUT + + sign: + name: Sign image and generate sbom + runs-on: ubuntu-latest + needs: [build] + if: startsWith(github.ref, 'refs/tags/') + steps: + - name: Checkout code + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # tag=v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Run Trivy in fs mode to generate SBOM + uses: aquasecurity/trivy-action@e5f43133f6e8736992c9f3c1b3296e24b37e17f2 # master + with: + scan-type: 'fs' + format: 'spdx-json' + output: 'spdx.sbom.json' + - name: Install cosign + uses: sigstore/cosign-installer@dd6b2e2b610a11fd73dd187a43d57cc1394e35f9 # main + - name: Sign image and sbom + run: | + #!/usr/bin/env bash + set -euo pipefail + cosign sign -a git_sha=$GITHUB_SHA ${IMAGE_URI_DIGEST} --yes + cosign attach sbom --sbom spdx.sbom.json ${IMAGE_URI_DIGEST} + cosign sign -a git_sha=$GITHUB_SHA --attachment sbom ${IMAGE_URI_DIGEST} --yes + shell: bash + env: + IMAGE_URI_DIGEST: ${{ needs.build.outputs.image }}@${{ needs.build.outputs.digest }} + + provenance: + needs: [build] + if: startsWith(github.ref, 'refs/tags/') + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.6.0 + with: + image: ${{ needs.build.outputs.image }} + digest: ${{ needs.build.outputs.digest }} + registry-username: ${{ github.actor }} + secrets: + registry-password: ${{ secrets.GITHUB_TOKEN }} + + verify: + name: Verify image and provenance + runs-on: ubuntu-latest + needs: [build, sign, provenance] + if: startsWith(github.ref, 'refs/tags/') + steps: + - name: Login to GitHub Container Registry + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Install cosign + uses: sigstore/cosign-installer@dd6b2e2b610a11fd73dd187a43d57cc1394e35f9 # main + - name: Install slsa-verifier + uses: slsa-framework/slsa-verifier/actions/installer@c9abffe4d2ab2ffa0b2ea9b2582b84164f390adc # v2.3.0 + - name: Verify image and provenance + run: | + #!/usr/bin/env bash + set -euo pipefail + cosign verify ${IMAGE_URI_DIGEST} \ + --certificate-oidc-issuer ${GITHUB_ACITONS_OIDC_ISSUER} \ + --certificate-identity ${COSIGN_KEYLESS_SIGNING_CERT_SUBJECT} + slsa-verifier verify-image \ + --source-uri github.com/${{ github.repository }} ${IMAGE_URI_DIGEST} + shell: bash + env: + IMAGE_URI_DIGEST: ${{ needs.build.outputs.image }}@${{ needs.build.outputs.digest }} + GITHUB_ACITONS_OIDC_ISSUER: https://token.actions.githubusercontent.com + COSIGN_KEYLESS_SIGNING_CERT_SUBJECT: https://github.com/${{ github.repository }}/.github/workflows/release.yaml@${{ github.ref }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 08b9b33..50e285f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,20 @@ -FROM --platform=${BUILDPLATFORM:-linux/amd64} cgr.dev/chainguard/go:1.20 AS builder +#syntax=docker/dockerfile:1.4 +FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.1.0 AS xx + +FROM --platform=$BUILDPLATFORM golang:1.20-alpine AS builder ARG TARGETPLATFORM ARG BUILDPLATFORM ARG TARGETOS ARG TARGETARCH +# copy xx scripts to the builder stage +COPY --from=xx / / WORKDIR /app COPY . . -RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o pizza-oven . +RUN --mount=target=/go/pkg/mod,type=cache \ + --mount=target=/root/.cache,type=cache \ + xx-go build -ldflags="${GO_LDFLAGS}" -o pizza-oven . -FROM --platform=${TARGETPLATFORM:-linux/amd64} cgr.dev/chainguard/glibc-dynamic +FROM scratch COPY --from=builder /app/pizza-oven /usr/bin/ -CMD ["/usr/bin/pizza-oven"] +CMD ["/usr/bin/pizza-oven"] \ No newline at end of file diff --git a/Makefile b/Makefile index 1251f91..719aed1 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ local: go build -o build/pizza-oven main.go build: - docker build . -t pizza-oven:latest + docker buildx bake setup-test-env: ./hack/setup.sh diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..b746a85 --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,20 @@ +variable "GO_LDFLAGS" { + default = "-w -s" +} + +group "default" { + targets = ["build"] +} + +target "build" { + dockerfile = "Dockerfile" + args = { + GO_LDFLAGS = "${GO_LDFLAGS}" + } +} + +target "cross" { + inherits = ["build"] + platforms = ["linux/amd64", "linux/386", "linux/arm64", "linux/arm", "linux/ppc64le", "linux/s390x", "darwin/amd64", "darwin/arm64", "windows/amd64", "windows/arm64", "freebsd/amd64", "freebsd/arm64"] + tags = ["ghcr.io/open-sauced/pizza"] +} \ No newline at end of file