Skip to content

fix: resolve security, routing, and accessibility issues #199

fix: resolve security, routing, and accessibility issues

fix: resolve security, routing, and accessibility issues #199

Workflow file for this run

name: CI / Neon Preview
on:
push:
branches: [main]
pull_request:
types:
- opened
- reopened
- synchronize
- closed
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
setup:
name: Setup
outputs:
branch: ${{ steps.branch_name.outputs.current_branch }}
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Get branch name
id: branch_name
uses: tj-actions/branch-names@dde14ac574a8b9b1cedc59a1cf312788af43d8d8 # v8.2.1
changes:
name: Detect Changes
runs-on: [self-hosted, macOS]
outputs:
db: ${{ steps.filter.outputs.db }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: filter
with:
filters: |
db:
- 'server/db/**'
- 'shared/schemas/**'
- 'drizzle/**'
- 'server/scripts/migrate.ts'
verify_port:
name: Verify Port (Strict 5002)
if: github.event.action != 'closed'
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
cache: "npm"
- run: npm ci
- name: Verify Port 5002 Compliance
run: npm run verify-port
build_shared:
name: Build Shared Package
if: github.event.action != 'closed'
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
cache: "npm"
- run: npm ci
- name: Build Shared
run: npm run build --prefix shared
# Parallel quality checks for faster feedback
lint:
name: Lint (Biome)
needs: build_shared
if: github.event.action != 'closed'
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
cache: "npm"
- run: npm ci
- name: Build Shared Declarations
run: npm run build --prefix shared
- name: Build Server Declarations
run: npx tsc -b server/tsconfig.json
- name: Run Biome Check
run: npm run check
typecheck:
name: Type Check (TSC)
needs: build_shared
if: github.event.action != 'closed'
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
cache: "npm"
- run: npm ci
- name: Build Shared Declarations
run: npm run build --prefix shared
- name: Build Server Declarations
run: npx tsc -b server/tsconfig.json
- run: npm run typecheck
security_audit:
name: Security Audit
if: github.event.action != 'closed'
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
cache: "npm"
- run: npm ci
- name: Run npm audit
run: npm audit --audit-level=high
docs_check:
name: Docs Check
if: github.event.action != 'closed'
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
cache: "npm"
- run: npm ci
- name: Check Documentation Links
run: npm run check:docs
test:
name: Test & Verify
needs: [setup, build_shared]
if: |
github.event_name == 'pull_request' && (
github.event.action == 'synchronize'
|| github.event.action == 'opened'
|| github.event.action == 'reopened')
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Get branch expiration date
id: get_expiration_date
run: echo "EXPIRES_AT=$(date -u -v+24h +'%Y-%m-%dT%H:%M:%SZ')" >> "$GITHUB_ENV"
- name: Create Neon Branch
id: create_neon_branch
if: needs.changes.outputs.db == 'true'
continue-on-error: true
uses: neondatabase/create-branch-action@fb620d43d4c565abaf088b848a4e28e5c4ea4d9c # 6.3.1
with:
project_id: ${{ secrets.NEON_PROJECT_ID }}
branch_name: preview/pr-${{ github.event.number }}-${{ needs.setup.outputs.branch }}
api_key: ${{ secrets.NEON_API_KEY }}
expires_at: ${{ env.EXPIRES_AT }}
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
cache: "npm"
- run: npm ci
- name: Build Shared Locally
run: npm run build --prefix shared
- name: Push Database Schema
continue-on-error: ${{ steps.create_neon_branch.outcome == 'failure' }}
run: npm run db:push
env:
DATABASE_URL: ${{ needs.changes.outputs.db == 'true' && steps.create_neon_branch.outputs.db_url_with_pooler || secrets.DATABASE_URL_PREVIEW }}
CLOUD_TASKS_AUDIENCE: "placeholder"
CLOUD_TASKS_SERVICE_ACCOUNT_EMAIL: "placeholder@example.com"
- name: Run Tests with Coverage
run: npx vitest run --coverage
env:
DATABASE_URL: ${{ needs.changes.outputs.db == 'true' && steps.create_neon_branch.outputs.db_url_with_pooler || secrets.DATABASE_URL_PREVIEW }}
CLOUD_TASKS_AUDIENCE: "placeholder"
CLOUD_TASKS_SERVICE_ACCOUNT_EMAIL: "placeholder@example.com"
- name: Check Coverage Thresholds
run: |
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
if (( $(echo "$COVERAGE < 40" | bc -l) )); then
echo "Coverage $COVERAGE% is below 40% threshold"
exit 1
fi
- name: Upload Coverage Report
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
with:
name: coverage-report
path: coverage/
retention-days: 7
- name: Upload to Codecov
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
if: always()
with:
files: ./coverage/lcov.info
fail_ci_if_error: false
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
build:
name: Build
needs: [lint, typecheck, test]
if: |
github.event_name == 'pull_request' && (
github.event.action == 'synchronize'
|| github.event.action == 'opened'
|| github.event.action == 'reopened')
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
cache: "npm"
- run: npm ci
- name: Cache Turbo
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: node_modules/.cache/turbo
key: turbo-${{ runner.os }}-${{ github.sha }}
restore-keys: |
turbo-${{ runner.os }}-
- name: Build
run: npm run build
env:
DATABASE_URL: postgresql://placeholder:placeholder@localhost:5432/placeholder
CLOUD_TASKS_AUDIENCE: "placeholder"
CLOUD_TASKS_SERVICE_ACCOUNT_EMAIL: "placeholder@example.com"
- name: Check Bundle Size
run: npm run check:bundle
- name: Upload Source Maps to Sentry
if: env.SENTRY_AUTH_TOKEN != ''
run: |
npx @sentry/cli sourcemaps inject ./client/build
npx @sentry/cli sourcemaps upload ./client/build --org ${{ secrets.SENTRY_ORG }} --project ${{ secrets.SENTRY_PROJECT }}
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
delete_neon_branch:
name: Delete Neon Branch
needs: [setup, changes]
if: github.event_name == 'pull_request' && github.event.action == 'closed' && needs.changes.outputs.db == 'true'
runs-on: [self-hosted, macOS]
steps:
- name: Delete Neon Branch
uses: neondatabase/delete-branch-action@4468d825d5a88ef4012f1705a82f02ec3072f776 # v3.2.1
with:
project_id: ${{ secrets.NEON_PROJECT_ID }}
branch: preview/pr-${{ github.event.number }}-${{ needs.setup.outputs.branch }}
api_key: ${{ secrets.NEON_API_KEY }}