name: CI on: pull_request: branches: [main] push: branches: [main] workflow_dispatch: permissions: contents: read concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: audit: name: Dependency audit runs-on: ubuntu-22.04 steps: - name: Checkout repository uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Node.js uses: actions/setup-node@v6 with: node-version: "22" # Reads package-lock.json and queries the registry — no install needed, so # this stays fast. Blocking at `high` catches high/critical advisories # without reddening CI for the moderate/low noise Dependabot handles via PR. - name: Audit npm dependencies (high and critical) run: npm audit --audit-level=high e2e: name: E2E smoke (Playwright) runs-on: ubuntu-22.04 steps: - name: Checkout repository uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Node.js uses: actions/setup-node@v6 with: node-version: "22" cache: npm cache-dependency-path: package-lock.json - name: Install dependencies run: npm ci - name: Resolve Playwright version id: pw run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT" - name: Cache Playwright browsers id: pw-cache uses: actions/cache@v6 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ steps.pw.outputs.version }} - name: Install Playwright Chromium (cache miss) if: steps.pw-cache.outputs.cache-hit != 'true' run: npx playwright install --with-deps chromium - name: Install Playwright system deps (cache hit) if: steps.pw-cache.outputs.cache-hit == 'true' run: npx playwright install-deps chromium - name: Run E2E smoke tests run: npm run test:e2e env: VITE_GEE_OAUTH_CLIENT_ID: ${{ secrets.VITE_GEE_OAUTH_CLIENT_ID }} - name: Upload Playwright report if: ${{ failure() }} uses: actions/upload-artifact@v4 with: name: playwright-report path: | playwright-report/ test-results/ retention-days: 7 citation: name: Validate CITATION.cff runs-on: ubuntu-22.04 steps: - name: Checkout repository uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.12" - name: Install cffconvert run: python -m pip install cffconvert - name: Validate CITATION.cff against the CFF schema run: cffconvert --validate -i CITATION.cff - name: Ensure version matches package.json run: | cff_version="$(sed -n 's/^version: *//p' CITATION.cff | tr -d '"' | head -n1)" pkg_version="$(python -c "import json; print(json.load(open('package.json'))['version'])")" echo "CITATION.cff version: $cff_version" echo "package.json version: $pkg_version" if [ "$cff_version" != "$pkg_version" ]; then echo "::error file=CITATION.cff::version ($cff_version) does not match package.json ($pkg_version). Update CITATION.cff version and date-released when bumping the release version." exit 1 fi checks: name: Build and test runs-on: ubuntu-22.04 steps: - name: Checkout repository uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Node.js uses: actions/setup-node@v6 with: node-version: "22" cache: npm cache-dependency-path: package-lock.json - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.12" cache: pip cache-dependency-path: backend/geolibre_server/pyproject.toml - name: Install Rust stable uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: toolchain: stable - name: Cache Rust dependencies uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: workspaces: apps/geolibre-desktop/src-tauri -> target - name: Install Linux desktop dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ curl \ file \ libayatana-appindicator3-dev \ libssl-dev \ libwebkit2gtk-4.1-dev \ libxdo-dev \ patchelf \ wget - name: Install frontend dependencies run: npm ci - name: Install backend test dependencies # The full test suite needs the optional engines; without them the # vector/raster/SQL/ML tests skip themselves and CI is green but hollow. run: python -m pip install -e "backend/geolibre_server[test]" # Audit the resolved backend environment for known advisories. Non-blocking # (continue-on-error): the sidecar pulls a heavy geospatial/ML dependency # tree whose transitive advisories are often upstream and not immediately # fixable, so this surfaces them without halting the release cadence. # Dependabot opens the fix PRs; this step keeps the signal visible in CI. # # pip-audit runs in a throwaway venv against a frozen snapshot of the test # environment (--exclude-editable drops the local geolibre_server checkout, # which isn't on PyPI). This keeps its own dependency resolution from # mutating the environment the "Run CI gate" step below tests against. - name: Audit Python dependencies (advisory, non-blocking) continue-on-error: true run: | python -m pip freeze --exclude-editable > /tmp/backend-freeze.txt python -m venv /tmp/pip-audit-venv /tmp/pip-audit-venv/bin/pip install --quiet pip-audit /tmp/pip-audit-venv/bin/pip-audit \ --progress-spinner off \ --requirement /tmp/backend-freeze.txt # Drive the documented `npm run ci` gate directly (lint -> build -> # frontend+worker+backend coverage -> rust) so this workflow cannot drift # from the script in package.json. - name: Run CI gate (lint, build, frontend/worker/backend tests, rust) run: npm run ci env: VITE_GEE_OAUTH_CLIENT_ID: ${{ secrets.VITE_GEE_OAUTH_CLIENT_ID }}