nsip 0.7.0

NSIP Search API client for nsipsearch.nsip.org/api
Documentation
---
name: Docker

"on":
  push:
    tags:
      - "v*.*.*"
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: false

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

# Least privilege at the top: build-and-push only needs to read the repo and
# push to GHCR. The id-token/attestations write scopes for signing live on the
# docker-sign / docker-verify / attest-* reusable-caller jobs below.
permissions:
  contents: read
  packages: write

jobs:
  build-and-push:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest
    outputs:
      image-digest: ${{ steps.push.outputs.digest }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10  # v6.0.3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@c887d9748da14dcb42b11cf8bcc773b301ea55b5  # v3.9.0

      - name: Log in to Container Registry
        uses: docker/login-action@3864d6aed8ff134b2ed894ce00c87695c709c870  # v3.4.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9  # v6.1.0
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}
            type=sha

      - name: Build and push Docker image
        id: push
        uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf  # v6.10.0
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          build-args: |
            RUST_VERSION=1.92

  # ---------------------------------------------------------------------------
  # Image signing + attestation (gh-attested) — the central sign-and-attest
  # reusable (cosign, SLSA Build L3 isolation boundary) signs the image and
  # attaches provenance; verify-attestation then fail-closed verifies it.
  # Supersedes the previous inline attest-build-provenance step. Note: cosign
  # publishes signature referrers to ghcr (visible in the Packages UI), unlike
  # the prior push-to-registry: false provenance-only approach.
  # ---------------------------------------------------------------------------
  docker-sign:
    name: Sign and Attest Image
    needs: [build-and-push]
    permissions:
      id-token: write
      attestations: write
      packages: write
      contents: read
    # zircote/.github main @ 77a87549 (merged 2026-06-16)
    uses: >-
      zircote/.github/.github/workflows/sign-and-attest.yml@740cb8efb57af0187f88e9b4f939355b871a5895
    with:
      image-name: ghcr.io/${{ github.repository }}
      image-digest: ${{ needs.build-and-push.outputs.image-digest }}

  docker-verify:
    name: Verify Image Attestations
    needs: [build-and-push, docker-sign]
    permissions:
      id-token: write
      attestations: read
      packages: read
      contents: read
    # zircote/.github main @ e8f0dbde (merged 2026-06-16)
    uses: >-
      zircote/.github/.github/workflows/verify-attestation.yml@e8f0dbde068cc0701e443e7b8d57ae9917de7da3
    with:
      image-ref: >-
        ghcr.io/${{ github.repository }}@${{
        needs.build-and-push.outputs.image-digest }}
      attestation-repo: ${{ github.repository }}

  # ---------------------------------------------------------------------------
  # Container vulnerability gate attestation (gh-attested) — Trivy scans the
  # pushed image, then the verdict is signed and bound to the image digest by
  # the central attest-scan reusable. Supersedes the standalone (dormant)
  # container-scan.yml: same Trivy image scan, now SARIF -> code-scanning hub
  # AND a digest-bound signed attestation. Reusables SHA-pinned to
  # zircote/.github.
  # ---------------------------------------------------------------------------
  gate-image:
    name: Gate — Trivy (image)
    needs: [build-and-push]
    permissions:
      contents: read
      security-events: write
      actions: read
      packages: read
    # zircote/.github main @ 77a87549 (merged 2026-06-16)
    uses: >-
      zircote/.github/.github/workflows/reusable-trivy.yml@77a87549a65c6c978a0e87efe0168ed3517f7ca4
    with:
      image-ref: >-
        ghcr.io/${{ github.repository }}@${{
        needs.build-and-push.outputs.image-digest }}
      scan-iac: false

  attest-container-scan:
    name: Attest — Container scan
    needs: [build-and-push, gate-image]
    permissions:
      id-token: write
      attestations: write
      contents: read
    # zircote/.github main @ 77a87549 (merged 2026-06-16)
    uses: >-
      zircote/.github/.github/workflows/reusable-attest-scan.yml@740cb8efb57af0187f88e9b4f939355b871a5895
    with:
      subject-name: ghcr.io/${{ github.repository }}
      subject-digest: ${{ needs.build-and-push.outputs.image-digest }}
      predicate-type: https://zircote.github.io/attestations/container-scan/v1
      predicate-artifact: ${{ needs.gate-image.outputs.image-sarif-artifact }}
      predicate-filename: ${{ needs.gate-image.outputs.image-sarif-filename }}