build(deps): bump ip-address from 10.2.0 to 10.4.0 #17
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
| name: ci | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| # One CI run per ref — a newer push cancels the older one, so rapid pushes can't race the migrate/deploy | |
| # tail (latest-push-wins). | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Least privilege: every job just reads code. Deploy auths to Cloudflare via its own token; migrate auths | |
| # to Supabase via its own token — never the GITHUB_TOKEN. | |
| permissions: | |
| contents: read | |
| # ── Shape ───────────────────────────────────────────────────────────────────────────────────────────── | |
| # Four independent lanes fan out at t=0 (each pays its own `npm ci`): `build` (+ the gzip budget, welded | |
| # behind it so the byte verdict lands the instant the build finishes), `unit` (the coverage gates), | |
| # `checks` (the cheap typecheck/lint/format/structure/seam guards grouped under one install), and `e2e` | |
| # (the real production bundle). Then, only on push to main, a serial tail the world forces on us: `migrate` | |
| # pushes the schema to the cloud database, and `deploy` ships the gated artifact — schema leads the app. | |
| # The monorepo is the sole authority: migrations live in supabase/ and CI is the only thing that touches | |
| # the cloud DB. | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - run: npm ci | |
| - name: build (public VITE_ vars baked in; empty on PRs is representative) | |
| env: | |
| VITE_SUPABASE_URL: ${{ vars.SUPABASE_URL }} | |
| VITE_SUPABASE_ANON_KEY: ${{ vars.SUPABASE_ANON_KEY }} | |
| VITE_GA4_MEASUREMENT_ID: ${{ vars.GA4_MEASUREMENT_ID }} | |
| VITE_TURNSTILE_SITEKEY: ${{ vars.TURNSTILE_SITEKEY }} | |
| run: npm run build | |
| - name: bundle budget (the gzip ceiling on the bytes we actually ship) | |
| run: npm run test:bundle-budget | |
| - name: upload the built web app (deploy ships THIS — gated == shipped, no second build) | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: web-dist | |
| path: apps/web/dist | |
| retention-days: 1 | |
| if-no-files-found: error | |
| unit: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - run: npm ci | |
| - run: npm test | |
| checks: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - run: npm ci | |
| - run: npm run typecheck | |
| - run: npm run lint | |
| - run: npm run format:check | |
| - name: test law (co-located tests) | |
| run: npm run test:structure | |
| - name: agnostic-seam guard (no web CSS in the theme core) | |
| run: npm run test:agnostic-seam | |
| e2e: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - run: npm ci | |
| - name: Cache Playwright browsers | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }} | |
| restore-keys: | | |
| playwright-${{ runner.os }}- | |
| - run: npx playwright install --with-deps chromium | |
| # Today's suite is DB-free (a build+preview smoke). When the create/share flows land, a LOCAL | |
| # supabase stack slots in right here (supabase/setup-cli + `supabase start` applies supabase/ | |
| # migrations to the local Postgres) and the suite gains a typed world factory — hermetic, never | |
| # the cloud. | |
| - name: Hermetic E2E | |
| env: | |
| CI: "true" | |
| run: npm run e2e | |
| # migrate — push to main only: apply the repo's migrations to the cloud project BEFORE the app ships, | |
| # so the schema never trails the code. A no-op while supabase/migrations is empty; the wiring is proven | |
| # from day one. Gated on every lane so nothing migrates on red. | |
| migrate: | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| needs: [build, unit, checks, e2e] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: supabase/setup-cli@v2 | |
| with: | |
| # Pin the CLI (an unpinned `latest` has broken local stacks before with no code change). | |
| version: 2.106.0 | |
| - name: Push migrations to the cloud project | |
| env: | |
| SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} | |
| SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }} | |
| run: | | |
| supabase link --project-ref ${{ vars.SUPABASE_PROJECT_REF }} | |
| supabase db push | |
| # deploy — push to main only, after the schema is live. Ships the EXACT artifact the budget gated | |
| # (download, never rebuild). The Pages project already carries its runtime env (the anon client vars + | |
| # the service-role / Turnstile secrets), so nothing secret is injected here; the Functions are compiled | |
| # fresh from source by wrangler. | |
| deploy: | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| needs: [migrate] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - name: npm ci (edge function bundling only — prepare skipped) | |
| run: npm ci --ignore-scripts | |
| - name: Download the gated web build | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: web-dist | |
| path: apps/web/dist | |
| - name: Deploy to Cloudflare Pages | |
| working-directory: apps/web | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| run: npx --yes wrangler@3 pages deploy dist --project-name mcplease --branch main |