Skip to content

feat: unify /ai/v1 auth onto NativeAuth + Android session-expiry hand… #191

feat: unify /ai/v1 auth onto NativeAuth + Android session-expiry hand…

feat: unify /ai/v1 auth onto NativeAuth + Android session-expiry hand… #191

Workflow file for this run

name: server-ci
on:
push:
paths:
- "server/**"
- ".github/workflows/server-ci.yaml"
- "core/identity/src/test/resources/identity/**"
pull_request:
paths:
- "server/**"
- ".github/workflows/server-ci.yaml"
- "core/identity/src/test/resources/identity/**"
# Cancel superseded runs on the same branch / PR.
concurrency:
group: server-ci-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
mode: [full, sync_only, ai_only]
defaults:
run:
working-directory: server
env:
# Deploy mode matrix: each cell exports the env vars that gate the app.
# Tests that depend on a specific mode (lazy-imports, modes, readyz)
# parameterize their own expectations; mode-agnostic tests run in every
# cell to surface any regression that only shows up under a non-default
# configuration.
QUIRE_SERVER_PROGRESS_ENABLED: ${{ matrix.mode != 'ai_only' && 'true' || 'false' }}
QUIRE_SERVER_AI_ENABLED: ${{ matrix.mode != 'sync_only' && 'true' || 'false' }}
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- name: Set up Python
run: uv python install 3.12
- name: Install
run: |
uv venv
uv pip install -e ".[dev]"
- name: Lint
if: matrix.mode == 'full'
run: uv run ruff check . && uv run ruff format --check .
- name: Install ripgrep (rename guard)
if: matrix.mode == 'full'
run: |
if ! command -v rg >/dev/null; then
sudo apt-get update && sudo apt-get install -y ripgrep
fi
- name: Rename guard self-test
if: matrix.mode == 'full'
working-directory: ${{ github.workspace }}
run: |
set -e
# Proves the rename-guard regex catches the previously-missed
# OPDS_SYNC_FOO pattern (the v1 plan's regex relied on \b after
# `_`, which is not a word boundary before letters).
tmp=$(mktemp /tmp/rename-guard-self-test-XXXX.txt)
printf 'OPDS_SYNC_AI_ENABLED: true\n' > "$tmp"
if ! rg -P '\bopds[-_]sync\b|(?<![A-Z0-9_])OPDS_SYNC_[A-Z0-9_]*' "$tmp" >/dev/null; then
echo "::error::Rename guard regex failed self-test (did NOT match OPDS_SYNC_AI_ENABLED)."
rm -f "$tmp"
exit 1
fi
rm -f "$tmp"
- name: Rename guard
if: matrix.mode == 'full'
working-directory: ${{ github.workspace }}
run: |
set -o pipefail
# Lock #20 allowlist:
# .claude/, CHANGELOG.md, server/migrations/versions/,
# root README.md, server/docker-compose*.yml,
# server/alembic.ini, server/.env.example (DB-name / deprecation refs).
# Defensive: tests/conftest.py + the import-graph regression test
# reference the legacy names by design.
if rg -n -P '\bopds[-_]sync\b|(?<![A-Z0-9_])OPDS_SYNC_[A-Z0-9_]*' \
-g '!.claude/**' \
-g '!CHANGELOG.md' \
-g '!server/migrations/versions/*.py' \
-g '!server/quire_server/config.py' \
-g '!server/docker-compose.yml' \
-g '!server/docker-compose.full.yml' \
-g '!server/alembic.ini' \
-g '!server/migrations/env.py' \
-g '!server/tests/conftest.py' \
-g '!server/tests/unit/test_no_stale_opds_sync_imports.py' \
. ; then
echo "::error::Rename guard found un-allowlisted OPDS_SYNC / opds-sync / opds_sync references."
exit 1
fi
- name: Test
run: uv run pytest -v
image:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
with:
context: server
push: true
sbom: true
provenance: mode=max
tags: |
ghcr.io/${{ github.repository_owner }}/quire-server:${{ github.sha }}
ghcr.io/${{ github.repository_owner }}/quire-server:latest
scan:
# SARIF upload requires Code Scanning enabled, which is free on
# public repos and gated behind GitHub Advanced Security on private
# ones. Skip until the repo is public.
needs: image
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event.repository.visibility == 'public'
permissions:
contents: read
actions: read
packages: read
security-events: write
steps:
- uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0
with:
image-ref: ghcr.io/${{ github.repository_owner }}/quire-server:${{ github.sha }}
format: sarif
output: trivy.sarif
severity: HIGH,CRITICAL
ignore-unfixed: true
- uses: github/codeql-action/upload-sarif@7c1e4cf0b20d7c1872b26569c00ba908797a59bf # v4
with:
sarif_file: trivy.sarif