diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7f6490e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,79 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +jobs: + unit: + name: unit tests + build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + with: + version: 8 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - run: pnpm install --frozen-lockfile + - run: npx prisma generate + - run: pnpm test + - run: pnpm build + + integration: + name: e2e against the production server + runs-on: ubuntu-latest + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_USER: hyperchessuser + POSTGRES_PASSWORD: hyperchess + POSTGRES_DB: hyperchess + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U hyperchessuser -d hyperchess" + --health-interval 5s + --health-timeout 3s + --health-retries 10 + env: + DATABASE_URL: postgresql://hyperchessuser:hyperchess@localhost:5432/hyperchess + ORIGIN: http://localhost:3000 + BASE: http://localhost:3000 + E2E_SECURE: '1' # production build sets the Secure cookie attribute + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + with: + version: 8 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - run: pnpm install --frozen-lockfile + - run: npx prisma generate + - run: npx prisma migrate deploy + - run: pnpm build + + - name: start server + run: | + node server.js & + echo $! > server.pid + curl --retry 20 --retry-delay 1 --retry-connrefused -sf http://localhost:3000/healthcheck + + - name: run e2e suite (auth + rooms + match over HTTP/WS) + run: pnpm e2e + + - name: stop server + if: always() + run: kill "$(cat server.pid)" || true diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml deleted file mode 100644 index 6f3d140..0000000 --- a/.github/workflows/static.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Deploy to GitHub Pages - -on: - push: - branches: 'gh-pages' - -jobs: - build_site: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - # If you're using pnpm, add this step then change the commands and cache key below to use `pnpm` - # - name: Install pnpm - # uses: pnpm/action-setup@v2 - # with: - # version: 8 - - - name: Install Node.js - uses: actions/setup-node@v3 - with: - node-version: 19 - cache: npm - - - name: Install dependencies - run: npm install - - - name: build - env: - BASE_PATH: '/hyperchess' - run: | - npm run build - touch build/.nojekyll - - - name: Upload Artifacts - uses: actions/upload-pages-artifact@v1 - with: - # this should match the `pages` option in your adapter-static options - path: 'build/' - - deploy: - needs: build_site - runs-on: ubuntu-latest - - permissions: - pages: write - id-token: write - - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - - steps: - - name: Deploy - id: deployment - uses: actions/deploy-pages@v1 diff --git a/e2e/auth.e2e.mjs b/e2e/auth.e2e.mjs index 4acc474..2875743 100644 --- a/e2e/auth.e2e.mjs +++ b/e2e/auth.e2e.mjs @@ -18,7 +18,11 @@ assert(!!cookie, `signup set ${COOKIE} cookie (status ${signup.status})`); const attrs = cookieAttrs(signup); assert(/HttpOnly/i.test(attrs), 'cookie is HttpOnly'); assert(/SameSite=Lax/i.test(attrs), 'cookie is SameSite=Lax'); -assert(!/Secure/i.test(attrs), 'cookie has no Secure on localhost'); +// dev server omits Secure (http localhost); the production build sets it. +// Scripts replay the cookie header directly, so both modes work — set +// E2E_SECURE=1 when targeting a production server. +const expectSecure = process.env.E2E_SECURE === '1'; +assert(/;\s*Secure/i.test(attrs) === expectSecure, `cookie Secure attribute matches mode (expect ${expectSecure})`); const authed = (c) => (path, opts = {}) => fetch(`${BASE}${path}`, { ...opts, headers: { ...(opts.headers || {}), cookie: c, origin: BASE } });