mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
RAW (DNG) processing crashed on ImageMagick's deprecated ufraw-batch delegate, which fails on modern formats such as iPhone ProRAW DNG. Root cause: the dcraw_emu (LibRaw) decode tier read the wrong output path. dcraw_emu APPENDS the output extension (raw-in-X.dng -> raw-in-X.dng.tiff) but the code looked for raw-in-X.tiff (replaced extension), so readFile threw on every RAW, the tier silently fell through to ufraw, and the 24MB TIFF leaked into the temp dir on each attempt. - Repair the dcraw_emu output path; clean it up in finally (fixes the leak) - Prefer LibRaw full decode over embedded-preview extraction so a full-resolution RAW is never silently returned as a reduced-size preview (sample DNG: was 1024x683 preview, now 3474x2314 full) - Add RAW decode regression tests (DNG full-resolution + all 6 RAW formats); these were absent, which let the bug ship - Install libraw-bin on CI test runners so dcraw_emu is actually exercised
271 lines
9.7 KiB
YAML
271 lines
9.7 KiB
YAML
name: CI
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
push:
|
|
branches: [main]
|
|
paths-ignore:
|
|
- "README.md"
|
|
- "CONTRIBUTING.md"
|
|
- "branding/**"
|
|
- "apps/docs/**"
|
|
- "apps/landing/**"
|
|
- "docs/**"
|
|
pull_request:
|
|
branches: [main]
|
|
paths-ignore:
|
|
- "README.md"
|
|
- "CONTRIBUTING.md"
|
|
- "branding/**"
|
|
- "apps/docs/**"
|
|
- "apps/landing/**"
|
|
- "docs/**"
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
lint:
|
|
name: Lint
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm lint
|
|
- name: License boundary check (D15)
|
|
run: pnpm check:license-boundary
|
|
|
|
typecheck:
|
|
name: Typecheck
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm typecheck
|
|
|
|
test-unit:
|
|
name: Unit Tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
|
|
- name: Install system dependencies (HEIC + ExifTool + ImageMagick + exotic format tools)
|
|
run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libheif-examples libheif-plugin-x265 libheif-plugin-libde265 libimage-exiftool-perl libraw-bin imagemagick ghostscript libjxl-tools libopenjp2-tools
|
|
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm vitest run tests/unit/ --reporter=verbose
|
|
|
|
test-integration:
|
|
name: Integration (${{ matrix.shard }}/4)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
shard: [1, 2, 3, 4]
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
|
|
- name: Install system dependencies (image formats + doc-engine qpdf/pandoc/LibreOffice)
|
|
run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libheif-examples libheif-plugin-x265 libheif-plugin-libde265 libimage-exiftool-perl libraw-bin imagemagick ghostscript libjxl-tools libopenjp2-tools qpdf pandoc libreoffice-calc libreoffice-impress libreoffice-writer
|
|
|
|
- name: Install pdfcpu (doc-engine PDF layout binary; matches docker/Dockerfile v0.13.0)
|
|
run: |
|
|
curl -fsSL https://github.com/pdfcpu/pdfcpu/releases/download/v0.13.0/pdfcpu_0.13.0_Linux_x86_64.tar.xz -o /tmp/pdfcpu.tar.xz
|
|
tar -xJf /tmp/pdfcpu.tar.xz -C /tmp
|
|
sudo install "$(find /tmp -type f -name pdfcpu | head -1)" /usr/local/bin/pdfcpu
|
|
pdfcpu version
|
|
|
|
- name: Allow ImageMagick to read EPS/PS via Ghostscript delegate
|
|
run: |
|
|
POLICY_FILE=$(find /etc/ImageMagick* -name policy.xml 2>/dev/null | head -1)
|
|
if [ -n "$POLICY_FILE" ]; then
|
|
sudo sed -i 's/<policy domain="coder" rights="none" pattern="EPS"/<policy domain="coder" rights="read" pattern="EPS"/' "$POLICY_FILE"
|
|
sudo sed -i 's/<policy domain="coder" rights="none" pattern="PS"/<policy domain="coder" rights="read" pattern="PS"/' "$POLICY_FILE"
|
|
fi
|
|
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm vitest run tests/integration/ --reporter=verbose --shard=${{ matrix.shard }}/4
|
|
|
|
test-e2e-smoke:
|
|
name: E2E Smoke (Chromium)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
services:
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
env:
|
|
POSTGRES_USER: snapotter
|
|
POSTGRES_PASSWORD: snapotter
|
|
POSTGRES_DB: snapotter
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd "pg_isready -U snapotter"
|
|
--health-interval 5s
|
|
--health-timeout 3s
|
|
--health-retries 10
|
|
redis:
|
|
image: redis:8-alpine
|
|
ports:
|
|
- 6379:6379
|
|
options: >-
|
|
--health-cmd "redis-cli ping"
|
|
--health-interval 5s
|
|
--health-timeout 3s
|
|
--health-retries 10
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- name: Get Playwright version
|
|
id: pw-version
|
|
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT"
|
|
- name: Cache Playwright browsers
|
|
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }}
|
|
- name: Install Playwright Chromium
|
|
run: pnpm playwright install --with-deps chromium
|
|
- name: Run smoke specs
|
|
# tools-all.spec.ts is the full 157-tool per-tool render matrix (~170 tests)
|
|
# -- a comprehensive check, not a PR-gate smoke test. It runs in the nightly
|
|
# e2e-full bucket, which executes the whole suite sharded. Keep this gate to
|
|
# genuinely fast sanity specs so it finishes well inside the timeout.
|
|
run: pnpm playwright test tests/e2e/smoke.spec.ts tests/e2e/navigation.spec.ts tests/e2e/home-page.spec.ts --project=chromium
|
|
env:
|
|
PW_WORKERS: "2"
|
|
- name: Upload report on failure
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: failure()
|
|
with:
|
|
name: e2e-smoke-report
|
|
path: playwright-report/
|
|
retention-days: 7
|
|
|
|
test-e2e-mobile-smoke:
|
|
name: E2E Mobile Smoke (Chromium)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
services:
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
env:
|
|
POSTGRES_USER: snapotter
|
|
POSTGRES_PASSWORD: snapotter
|
|
POSTGRES_DB: snapotter
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd "pg_isready -U snapotter"
|
|
--health-interval 5s
|
|
--health-timeout 3s
|
|
--health-retries 10
|
|
redis:
|
|
image: redis:8-alpine
|
|
ports:
|
|
- 6379:6379
|
|
options: >-
|
|
--health-cmd "redis-cli ping"
|
|
--health-interval 5s
|
|
--health-timeout 3s
|
|
--health-retries 10
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- name: Get Playwright version
|
|
id: pw-version
|
|
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT"
|
|
- name: Cache Playwright browsers
|
|
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }}
|
|
- name: Install Playwright Chromium
|
|
run: pnpm playwright install --with-deps chromium
|
|
- name: Run mobile device specs (Pixel 7)
|
|
run: pnpm playwright test --project=mobile-chromium --grep @mobile --grep-invert @visual
|
|
env:
|
|
PW_WORKERS: "2"
|
|
- name: Upload report on failure
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: failure()
|
|
with:
|
|
name: e2e-mobile-smoke-report
|
|
path: playwright-report/
|
|
retention-days: 7
|
|
|
|
pip-audit:
|
|
name: Python Dependency Audit
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: "3.11"
|
|
|
|
- run: pip install "pip-audit==2.10.0"
|
|
- name: Run pip-audit (ignoring CVEs blocked by dependency constraints)
|
|
# CVE-2025-3000: torch 2.12.0, no fixed release available as of 2026-06-11
|
|
run: >-
|
|
pip-audit -r packages/ai/python/requirements.txt
|
|
--ignore-vuln CVE-2024-27763
|
|
--ignore-vuln CVE-2025-3000
|
|
--ignore-vuln CVE-2026-40086
|
|
--ignore-vuln CVE-2026-25990
|
|
--ignore-vuln CVE-2026-40192
|
|
--ignore-vuln GHSA-55v6-g8pm-pw4c
|
|
--ignore-vuln CVE-2026-42308
|
|
--ignore-vuln CVE-2026-42310
|
|
--ignore-vuln CVE-2026-42311
|
|
--ignore-vuln PYSEC-2025-189
|
|
--ignore-vuln PYSEC-2025-190
|
|
--ignore-vuln PYSEC-2025-191
|
|
--ignore-vuln PYSEC-2025-192
|
|
--ignore-vuln PYSEC-2025-193
|
|
--ignore-vuln PYSEC-2025-194
|
|
--ignore-vuln PYSEC-2025-195
|
|
--ignore-vuln PYSEC-2025-196
|
|
--ignore-vuln PYSEC-2025-197
|
|
--ignore-vuln PYSEC-2025-210
|
|
--ignore-vuln PYSEC-2026-139
|
|
--ignore-vuln PYSEC-2024-277
|
|
--ignore-vuln PYSEC-2026-89
|
|
|
|
build:
|
|
name: Build
|
|
runs-on: ubuntu-latest
|
|
needs: [lint, typecheck, test-unit, test-integration, test-e2e-smoke, test-e2e-mobile-smoke]
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm build
|
|
|
|
# docker:
|
|
# name: Docker Build Test
|
|
# runs-on: ubuntu-latest
|
|
# steps:
|
|
# - uses: actions/checkout@v4
|
|
# - uses: docker/setup-buildx-action@v3
|
|
# - name: Log in to GHCR (for registry cache)
|
|
# uses: docker/login-action@v3
|
|
# with:
|
|
# registry: ghcr.io
|
|
# username: ${{ github.repository_owner }}
|
|
# password: ${{ secrets.GHCR_TOKEN }}
|
|
# - uses: docker/build-push-action@v6
|
|
# with:
|
|
# context: .
|
|
# file: docker/Dockerfile
|
|
# push: false
|
|
# tags: snapotter:ci
|
|
# build-args: SKIP_MODEL_DOWNLOADS=true
|
|
# cache-from: type=registry,ref=ghcr.io/snapotter-hq/snapotter:cache-linux-amd64
|
|
# cache-to: type=registry,ref=ghcr.io/snapotter-hq/snapotter:cache-ci,mode=max
|