chore(deps): update docker-images #2390
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Copyright 2026 Phillip Cloud | |
| # Licensed under the Apache License, Version 2.0 | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| env: | |
| CGO_ENABLED: "0" | |
| TZ: UTC | |
| jobs: | |
| changes: | |
| name: Detect Changes | |
| runs-on: blacksmith-2vcpu-ubuntu-2404 | |
| outputs: | |
| go: ${{ steps.detect.outputs.go }} | |
| ci: ${{ steps.detect.outputs.ci }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| deploy-on-self-hosted-vm: true | |
| egress-policy: block | |
| disable-telemetry: true | |
| disable-sudo-and-containers: true | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| github.com:443 | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| sparse-checkout: .github/detect-ci-changes.bash | |
| sparse-checkout-cone-mode: false | |
| persist-credentials: false | |
| - name: Check for changes | |
| id: detect | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| BEFORE_SHA: ${{ github.event.before }} | |
| HEAD_SHA: ${{ github.sha }} | |
| run: | | |
| bash .github/detect-ci-changes.bash \ | |
| "$EVENT_NAME" "$PR_NUMBER" "$BEFORE_SHA" "$HEAD_SHA" >> "$GITHUB_OUTPUT" | |
| test: | |
| name: Build & Test (${{ matrix.os }}) | |
| needs: changes | |
| if: needs.changes.outputs.go == 'true' | |
| runs-on: ${{ matrix.os }} | |
| concurrency: | |
| group: ci-test-${{ matrix.os }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| strategy: | |
| fail-fast: ${{ github.event_name == 'pull_request' }} | |
| matrix: | |
| os: | |
| - blacksmith-4vcpu-ubuntu-2404 | |
| - blacksmith-4vcpu-ubuntu-2404-arm | |
| - macos-latest | |
| - windows-latest | |
| - windows-11-arm | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| deploy-on-self-hosted-vm: true | |
| egress-policy: block | |
| disable-telemetry: true | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| api.zippopotam.us:443 | |
| archive.ubuntu.com:80 | |
| azure.archive.ubuntu.com:80 | |
| esm.ubuntu.com:443 | |
| github.com:443 | |
| mirrors.ubuntu.com:80 | |
| packages.microsoft.com:443 | |
| ports.ubuntu.com:80 | |
| proxy.golang.org:443 | |
| release-assets.githubusercontent.com:443 | |
| security.ubuntu.com:80 | |
| storage.googleapis.com:443 | |
| us-west-2.ec2.archive.ubuntu.com:80 | |
| us-west-2.ec2.ports.ubuntu.com:80 | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 | |
| with: | |
| go-version: "1.26" | |
| - name: Install extraction tools (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y poppler-utils tesseract-ocr imagemagick | |
| - name: Symlink magick to convert (Linux) | |
| if: runner.os == 'Linux' | |
| run: command -v magick || sudo ln -s "$(command -v convert)" /usr/local/bin/magick | |
| - name: Install extraction tools (macOS) | |
| if: runner.os == 'macOS' | |
| run: brew install poppler tesseract imagemagick-full ghostscript | |
| - name: Add imagemagick-full to PATH (macOS) | |
| if: runner.os == 'macOS' | |
| run: echo "$(brew --prefix imagemagick-full)/bin" >> "$GITHUB_PATH" | |
| # winget is not installed on the windows-11-arm runner image | |
| # (https://github.com/actions/partner-runner-images/issues/95), so use | |
| # direct downloads from the upstream release assets on both Windows | |
| # architectures. The installers and the Poppler zip match what winget | |
| # was resolving to previously. | |
| - name: Install extraction tools (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $arch = if ($env:RUNNER_ARCH -eq 'ARM64') { 'arm64' } else { 'x64' } | |
| $downloadDir = Join-Path $env:RUNNER_TEMP 'extract-tools' | |
| New-Item -ItemType Directory -Path $downloadDir -Force | Out-Null | |
| function Invoke-SilentInstaller { | |
| param([string]$Name, [string]$Url, [string[]]$Arguments) | |
| $outFile = Join-Path $downloadDir (Split-Path $Url -Leaf) | |
| Write-Host "Downloading $Name from $Url" | |
| Invoke-WebRequest -Uri $Url -OutFile $outFile | |
| Write-Host "Running: $outFile $($Arguments -join ' ')" | |
| $proc = Start-Process -FilePath $outFile -ArgumentList $Arguments -Wait -PassThru | |
| if ($proc.ExitCode -ne 0) { | |
| throw "$Name installer exited with code $($proc.ExitCode)" | |
| } | |
| } | |
| # Poppler: portable zip (arch-neutral; x64 binaries run under emulation on ARM64) | |
| $popplerZip = Join-Path $downloadDir 'poppler.zip' | |
| Write-Host "Downloading Poppler" | |
| Invoke-WebRequest -Uri 'https://github.com/oschwartz10612/poppler-windows/releases/download/v25.07.0-0/Release-25.07.0-0.zip' -OutFile $popplerZip | |
| Expand-Archive -Path $popplerZip -DestinationPath $downloadDir -Force | |
| # Tesseract: NSIS installer (x64 only; runs under emulation on ARM64) | |
| Invoke-SilentInstaller 'Tesseract' ` | |
| 'https://github.com/tesseract-ocr/tesseract/releases/download/5.5.0/tesseract-ocr-w64-setup-5.5.0.20241111.exe' ` | |
| @('/S') | |
| # ImageMagick: Inno Setup installer (arch-specific native build) | |
| Invoke-SilentInstaller 'ImageMagick' ` | |
| "https://github.com/ImageMagick/ImageMagick/releases/download/7.1.2-19/ImageMagick-7.1.2-19-Q16-HDRI-${arch}-dll.exe" ` | |
| @('/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART', '/SP-') | |
| - name: Add extraction tools to PATH (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $downloadDir = Join-Path $env:RUNNER_TEMP 'extract-tools' | |
| $popplerBin = Get-ChildItem "$downloadDir\poppler-*\Library\bin" -Directory | | |
| Select-Object -First 1 -ExpandProperty FullName | |
| if (-not $popplerBin) { throw "Poppler bin directory not found under $downloadDir" } | |
| Add-Content $env:GITHUB_PATH $popplerBin | |
| Add-Content $env:GITHUB_PATH "$env:ProgramFiles\Tesseract-OCR" | |
| # Prefer the most recently modified ImageMagick dir in case the runner | |
| # image ships one preinstalled (e.g. windows-11-arm). | |
| $imageMagickDir = Get-ChildItem "$env:ProgramFiles\ImageMagick-*" -Directory | | |
| Sort-Object LastWriteTime -Descending | | |
| Select-Object -First 1 -ExpandProperty FullName | |
| if (-not $imageMagickDir) { throw "ImageMagick directory not found under $env:ProgramFiles" } | |
| Add-Content $env:GITHUB_PATH $imageMagickDir | |
| - name: Generate sample PDF fixture | |
| shell: bash | |
| run: bash internal/extract/gen-sample-pdf.bash | |
| - name: Generate invoice PNG fixture | |
| shell: bash | |
| run: bash internal/extract/gen-invoice-png.bash | |
| - name: Generate sample text PNG fixture | |
| shell: bash | |
| run: bash internal/extract/gen-sample-text-png.bash | |
| - name: Generate scanned PDF fixture | |
| shell: bash | |
| run: bash internal/extract/gen-scanned-pdf.bash | |
| - name: Generate mixed PDF fixture | |
| shell: bash | |
| run: bash internal/extract/gen-mixed-pdf.bash | |
| - name: Build | |
| run: go build ./cmd/micasa | |
| - name: Test | |
| if: runner.os != 'Windows' || runner.arch != 'ARM64' | |
| env: | |
| CGO_ENABLED: "1" | |
| MICASA_TEST_SEED: ${{ github.run_id }} | |
| run: go test -race -shuffle on -timeout 5m ./... | |
| - name: Test (no race) | |
| if: runner.os == 'Windows' && runner.arch == 'ARM64' | |
| env: | |
| MICASA_TEST_SEED: ${{ github.run_id }} | |
| run: go test -shuffle on -timeout 5m ./... | |
| pgtest: | |
| name: Postgres Integration (${{ matrix.variant }}) | |
| needs: changes | |
| if: needs.changes.outputs.go == 'true' | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| strategy: | |
| matrix: | |
| include: | |
| - variant: debian | |
| image: postgres@sha256:b994732fcf33f73776c65d3a5bf1f80c00120ba5007e8ab90307b1a743c1fc16 # 17 | |
| - variant: alpine | |
| image: postgres@sha256:6f30057d31f5861b66f3545d4821f987aacf1dd920765f0acadea0c58ff975b1 # 17-alpine | |
| concurrency: | |
| group: ci-pgtest-${{ matrix.variant }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| services: | |
| postgres: | |
| image: ${{ matrix.image }} | |
| env: | |
| POSTGRES_USER: micasa | |
| POSTGRES_PASSWORD: testpass | |
| POSTGRES_DB: micasa_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U micasa" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| deploy-on-self-hosted-vm: true | |
| egress-policy: block | |
| disable-telemetry: true | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| github.com:443 | |
| proxy.golang.org:443 | |
| release-assets.githubusercontent.com:443 | |
| storage.googleapis.com:443 | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 | |
| with: | |
| go-version: "1.26" | |
| - name: Test relay (with Postgres) | |
| env: | |
| CGO_ENABLED: "1" | |
| RELAY_POSTGRES_DSN: "postgres://micasa:testpass@localhost:5432/micasa_test?sslmode=disable" | |
| run: go test -race -shuffle on -timeout 5m ./internal/relay/ | |
| - name: Test sync round-trip (with Postgres) | |
| env: | |
| CGO_ENABLED: "1" | |
| RELAY_POSTGRES_DSN: "postgres://micasa:testpass@localhost:5432/micasa_test?sslmode=disable" | |
| run: go test -race -shuffle on -timeout 5m -run TestSyncRoundTripPgStore ./internal/sync/ | |
| benchmarks: | |
| name: Benchmarks (smoke) | |
| needs: changes | |
| if: needs.changes.outputs.go == 'true' | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| concurrency: | |
| group: ci-benchmarks-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| deploy-on-self-hosted-vm: true | |
| egress-policy: block | |
| disable-telemetry: true | |
| disable-sudo-and-containers: true | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| github.com:443 | |
| proxy.golang.org:443 | |
| release-assets.githubusercontent.com:443 | |
| storage.googleapis.com:443 | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 | |
| with: | |
| go-version: "1.26" | |
| - name: Run smoke benchmarks | |
| run: go test -bench . -benchtime 1x -timeout 5m -run '^$' ./... | |
| nix-build: | |
| name: Nix Build | |
| needs: changes | |
| if: needs.changes.outputs.go == 'true' | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| concurrency: | |
| group: ci-nix-build-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| deploy-on-self-hosted-vm: true | |
| egress-policy: block | |
| disable-telemetry: true | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| cache.nixos.org:443 | |
| github.com:443 | |
| proxy.golang.org:443 | |
| release-assets.githubusercontent.com:443 | |
| releases.nixos.org:443 | |
| storage.googleapis.com:443 | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6 | |
| - name: Build with Nix | |
| run: nix build '.#micasa' | |
| docs: | |
| name: Docs Build | |
| needs: changes | |
| if: needs.changes.outputs.ci == 'true' | |
| runs-on: blacksmith-2vcpu-ubuntu-2404 | |
| concurrency: | |
| group: ci-docs-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| deploy-on-self-hosted-vm: true | |
| egress-policy: block | |
| disable-telemetry: true | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| cache.nixos.org:443 | |
| github.com:443 | |
| releases.nixos.org:443 | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6 | |
| - name: Build docs | |
| run: nix run '.#docs' | |
| # --------------------------------------------------------------------------- | |
| # Semantic Release (dry-run on PRs to exercise the full release pipeline) | |
| # --------------------------------------------------------------------------- | |
| semantic-release-dry-run: | |
| name: Semantic Release (dry-run) | |
| needs: changes | |
| if: github.event_name == 'pull_request' && needs.changes.outputs.ci == 'true' | |
| runs-on: blacksmith-2vcpu-ubuntu-2404 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| deploy-on-self-hosted-vm: true | |
| egress-policy: block | |
| disable-telemetry: true | |
| disable-sudo-and-containers: true | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| github.com:443 | |
| registry.npmjs.org:443 | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: lts/* | |
| - name: Simulate release (dry-run) | |
| run: bash ci/release/dry-run.bash | |
| docker-build: | |
| name: Docker Build | |
| needs: changes | |
| if: needs.changes.outputs.go == 'true' | |
| runs-on: blacksmith-2vcpu-ubuntu-2404 | |
| concurrency: | |
| group: ci-docker-build-${{ matrix.build_tags }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| strategy: | |
| matrix: | |
| build_tags: ["", "selfhosted"] | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| deploy-on-self-hosted-vm: true | |
| egress-policy: block | |
| disable-telemetry: true | |
| # The two r2.cloudflarestorage.com entries are Docker Hub's | |
| # R2 buckets (layers and images). The hashed subdomains are | |
| # Docker Inc's Cloudflare account IDs -- stable per-account | |
| # but not self-describing; update if Docker Hub reshards. | |
| allowed-endpoints: > | |
| 1ede90a8395416f286ba9f692dc6bacf.r2.cloudflarestorage.com:443 | |
| api.github.com:443 | |
| auth.docker.io:443 | |
| docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com:443 | |
| github.com:443 | |
| gcr.io:443 | |
| production.cloudflare.docker.com:443 | |
| proxy.golang.org:443 | |
| registry-1.docker.io:443 | |
| storage.googleapis.com:443 | |
| sum.golang.org:443 | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Blacksmith Builder | |
| uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1 | |
| - name: Build relay image${{ matrix.build_tags && format(' ({0})', matrix.build_tags) }} | |
| run: docker build --build-arg BUILD_TAGS=${{ matrix.build_tags }} -f deploy/relay/Dockerfile . | |
| # --------------------------------------------------------------------------- | |
| # Gate: single required check that rolls up all jobs above. | |
| # Ruleset requires "CI Result", "Lint Result", "Security Result". | |
| # --------------------------------------------------------------------------- | |
| result: | |
| name: CI Result | |
| if: always() | |
| needs: [changes, test, pgtest, benchmarks, nix-build, docs, semantic-release-dry-run, docker-build] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| egress-policy: block | |
| disable-telemetry: true | |
| disable-sudo-and-containers: true | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| github.com:443 | |
| - run: exit 1 | |
| if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') |