diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index b274e2d..e08d5ed 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -18,6 +18,10 @@ concurrency: env: IMAGE : ${{ github.repository_owner }}/openstreetmap-tile-server TAG : ${{ github.sha }} + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: ${{ github.repository }} permissions: contents: read @@ -40,7 +44,8 @@ jobs: MOUNT : /data/database/ PLATFORM : linux/${{ matrix.arch }}${{ (matrix.variant != '' && format('/{0}', matrix.variant)) || '' }} steps: - - name: Harden the runner (Audit all outbound calls) + - + name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit @@ -48,6 +53,13 @@ jobs: - name: Checkout uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + # Install the cosign tool except on PR + # https://github.com/sigstore/cosign-installer + - + name: Install cosign + if: github.event_name != 'pull_request' + uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 #v3.9.2 - name: Set up QEMU uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 @@ -146,50 +158,39 @@ jobs: - name: Checkout uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Environment - run : | - echo IMAGE=$(echo ${{ env.IMAGE }} | tr '[:upper:]' '[:lower:]') >>$GITHUB_ENV - echo DOCKERHUB_IMAGE=$([ "${{ secrets.DOCKERHUB_USERNAME }}" != '' ] && [ "${{ secrets.DOCKERHUB_PASSWORD }}" != "" ] && echo "$IMAGE") >>$GITHUB_ENV - - - name: Docker meta - id: meta - uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 - with: - images: | - ${{ env.DOCKERHUB_IMAGE }} - ghcr.io/${{ env.IMAGE }} - tags: | - type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} + - name: Set up QEMU uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 with: platforms: amd64,arm64 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - - - name: Login to DockerHub - uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 - if: ${{ env.DOCKERHUB_IMAGE != '' }} - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} + - name: Login to GHCR + if: github.event_name != 'pull_request' uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 with: - registry : ghcr.io - username : ${{ github.repository_owner }} - password : ${{ secrets.GITHUB_TOKEN }} + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - name: Build and push + id: build-and-push uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: + sbom : true pull : true push : true platforms : linux/amd64,linux/arm64/v8 @@ -200,3 +201,28 @@ jobs: cache-from: | type=gha,scope=${{ github.workflow }}:linux/amd64 type=gha,scope=${{ github.workflow }}:linux/arm64/v8 + cache-to: type=gha,mode=max + + # Sign the resulting Docker image digest except on PRs. + # This will only write to the public Rekor transparency log when the Docker + # repository is public to avoid leaking data. If you would like to publish + # transparency data even for private images, pass --force to cosign below. + # https://github.com/sigstore/cosign + - name: Sign the published Docker image + if: ${{ github.event_name != 'pull_request' }} + env: + # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + TAGS: ${{ steps.meta.outputs.tags }} + DIGEST: ${{ steps.build-and-push.outputs.digest }} + # This step uses the identity token to provision an ephemeral certificate + # against the sigstore community Fulcio instance. + run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} + + - name: Attest + if: github.event_name != 'pull_request' + uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 + id: attest + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + subject-digest: ${{ steps.build-and-push.outputs.digest }} + push-to-registry: true \ No newline at end of file diff --git a/.github/workflows/docker-scan.yml b/.github/workflows/docker-scan.yml new file mode 100644 index 0000000..e4fdeff --- /dev/null +++ b/.github/workflows/docker-scan.yml @@ -0,0 +1,98 @@ +name: Docker Image Grype scan + +on: + push: + branches: [master] + tags: + - '*' + workflow_dispatch: + +permissions: + contents: read + +jobs: + wait-for-build: + name: Wait for build + runs-on: ubuntu-latest + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + with: + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + release-assets.githubusercontent.com:443 + index.rubygems.org:443 + rubygems.org:443 + + - name: Wait for build + uses: lewagon/wait-on-check-action@0dceb95e7c4cad8cc7422aee3885998f5cab9c79 # v1.4.0 + with: + ref: ${{ github.ref }} + check-name: 'build' + repo-token: ${{ secrets.GITHUB_TOKEN }} + wait-interval: 15 + allowed-conclusions: success,skipped + + docker: + needs: wait-for-build + permissions: + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + runs-on: ubuntu-latest + steps: + - + name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + with: + egress-policy: block + allowed-endpoints: > + api.github.com:443 + auth.docker.io:443 + files.pythonhosted.org:443 + github.com:443 + grype.anchore.io:443 + objects.githubusercontent.com:443 + production.cloudflare.docker.com:443 + pypi.org:443 + raw.githubusercontent.com:443 + registry-1.docker.io:443 + release-assets.githubusercontent.com:443 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + - + name: Build + id: docker_build + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + push: false + load: true + tags: localbuild/testimage:latest + cache-from: type=gha + cache-to: type=gha,mode=max + - + name: Generate SBOM and upload dependency results + uses: anchore/sbom-action@da167eac915b4e86f08b264dbdbc867b61be6f0c # v0.20.5 + with: + image: localbuild/testimage:latest + artifact-name: "${{ github.event.repository.name }}.cyclonedx-sbom.json" + output-file: "/tmp/${{ github.event.repository.name }}.cyclonedx-sbom.json" + dependency-snapshot: false + format: cyclonedx-json + upload-artifact: true + - + name: Scan SBOM + uses: anchore/scan-action@1638637db639e0ade3258b51db49a9a137574c3e # v6.5.1 + id: scan + with: + add-cpes-if-none: true + fail-build: false + sbom: "/tmp/${{ github.event.repository.name }}.cyclonedx-sbom.json" + output-format: sarif + - + name: Upload Anchore scan SARIF report + uses: github/codeql-action/upload-sarif@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5 + with: + sarif_file: ${{ steps.scan.outputs.sarif }} \ No newline at end of file