Skip to content

chore(deps): update docker-images #2390

chore(deps): update docker-images

chore(deps): update docker-images #2390

Workflow file for this run

# 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')