veza/.github/workflows/ci.yml
dependabot[bot] aa8b767c9c
Some checks failed
Backend API CI / test-unit (push) Failing after 0s
Backend API CI / test-integration (push) Failing after 0s
Frontend CI / test (push) Failing after 0s
Storybook Audit / Build & audit Storybook (push) Failing after 0s
chore(deps): bump actions/setup-node from 4 to 6
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-18 10:39:12 +00:00

338 lines
10 KiB
YAML

name: Veza CI/CD
on:
push:
branches: [ "main", "remediation/*", "feature/mvp-complete" ]
pull_request:
branches: [ "main", "feature/mvp-complete" ]
workflow_dispatch: # Allow manual trigger
jobs:
backend-go:
name: Backend (Go)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Check VERSION matches git tag
run: |
current_tag=$(git describe --tags --exact-match 2>/dev/null || true)
if [ -n "$current_tag" ]; then
version_file=$(cat VERSION)
tag_version=${current_tag#v}
if [ "$version_file" != "$tag_version" ]; then
echo "VERSION mismatch: VERSION=$version_file, current tag=$current_tag"
exit 1
fi
fi
- name: Set up Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
cache: 'npm'
- name: Set up Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version: '1.24'
cache: true
- name: Install dependencies
run: npm ci
- name: Run govulncheck
run: |
cd veza-backend-api
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
- name: Vet
run: |
cd veza-backend-api
go vet ./...
- name: Install golangci-lint
run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- name: Lint
run: npx turbo run lint --filter=veza-backend-api
- name: Test with coverage
run: |
cd veza-backend-api
go test ./internal/handlers/... ./internal/services/... -short -coverprofile=coverage.out -covermode=atomic
COVERAGE=$(go tool cover -func=coverage.out | tail -1 | awk '{print $3}' | tr -d '%')
echo "Coverage: ${COVERAGE}%"
echo "coverage=${COVERAGE}" >> $GITHUB_OUTPUT
if awk -v c="$COVERAGE" -v t=60 'BEGIN {exit !(c+0>=t)}'; then
echo "Coverage gate passed (>= 60%)"
else
echo "Coverage $COVERAGE% is below threshold 60%"
exit 1
fi
- name: Build
run: npx turbo run build --filter=veza-backend-api
rust-services:
name: Rust Services (Stream)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
cache: 'npm'
- name: Set up Rust
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
with:
components: rustfmt, clippy
- name: Install dependencies
run: npm ci
- name: Cache Cargo registry
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install cargo-audit
run: cargo install cargo-audit
- name: Auditing Stream Server
run: |
cd veza-stream-server
cargo audit
- name: Lint
run: npx turbo run lint --filter=veza-stream-server
- name: Build
run: npx turbo run build --filter=veza-stream-server
- name: Test
run: npx turbo run test --filter=veza-stream-server
frontend:
name: Frontend (Web)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Use Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: package-lock.json
- name: Install Dependencies
run: npm ci
- name: Security audit (npm)
run: npm audit --audit-level=critical
- name: Cache Generated Types
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: apps/web/src/types/generated
key: ${{ runner.os }}-generated-types-${{ hashFiles('veza-backend-api/openapi.yaml') }}
restore-keys: |
${{ runner.os }}-generated-types-
- name: Generate Types from OpenAPI
run: |
cd apps/web
chmod +x scripts/generate-types.sh
./scripts/generate-types.sh
continue-on-error: false
# This step ensures types are generated before typecheck
# Cache keyed on openapi.yaml hash, so types regenerate when spec changes
- name: Check types sync with OpenAPI spec
run: |
if ! git diff --exit-code apps/web/src/types/generated/; then
echo "::error::Types are out of sync with openapi.yaml. Run 'make openapi' then 'cd apps/web && ./scripts/generate-types.sh' and commit the updated types."
exit 1
fi
- name: Lint
run: npx turbo run lint --filter=veza-frontend
- name: Format Check
run: |
cd apps/web
npm run format:check --if-present
- name: Type Check
run: |
cd apps/web
npm run typecheck
- name: Test with coverage
run: npx turbo run test --filter=veza-frontend -- --run --coverage
- name: Contrast Tests
run: |
cd apps/web
npm run test -- --run src/__tests__/contrast.test.ts
- name: Build
run: npx turbo run build --filter=veza-frontend
storybook:
name: Storybook Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Build Storybook
run: npm run build-storybook
working-directory: apps/web
- name: Serve Storybook and run audit
run: |
npx serve -s storybook-static -l 6007 &
for i in $(seq 1 30); do
if curl -sf http://localhost:6007 >/dev/null; then
echo "Storybook ready"
break
fi
sleep 2
done
curl -sf http://localhost:6007 >/dev/null || (echo "Storybook failed to start"; exit 1)
npm run test:storybook
working-directory: apps/web
e2e:
name: E2E (Playwright)
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: package-lock.json
- name: Set up Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version: '1.24'
cache-dependency-path: veza-backend-api/go.sum
- name: Install dependencies
run: npm ci
- name: Add veza.fr to hosts (for Vite proxy)
run: echo "127.0.0.1 veza.fr" | sudo tee -a /etc/hosts
- name: Start backend services (Postgres, Redis, RabbitMQ)
run: |
docker-compose up -d postgres redis rabbitmq
echo "Waiting for Postgres..."
for i in $(seq 1 30); do
if docker exec veza_postgres pg_isready -U veza 2>/dev/null; then
echo "Postgres ready"
break
fi
sleep 2
done
docker-compose ps
- name: Run database migrations
env:
DATABASE_URL: postgresql://veza:devpassword@localhost:15432/veza?sslmode=disable
run: |
cd veza-backend-api
go run cmd/migrate_tool/main.go
- name: Create E2E test user
env:
DATABASE_URL: postgresql://veza:${{ secrets.E2E_DB_PASSWORD || 'devpassword' }}@localhost:15432/veza?sslmode=disable
TEST_EMAIL: e2e@test.com
TEST_PASSWORD: ${{ secrets.E2E_TEST_PASSWORD }}
TEST_USERNAME: e2e
run: |
cd veza-backend-api
go run cmd/tools/create_test_user/main.go
- name: Start backend API
env:
APP_ENV: development
APP_PORT: "18080"
DATABASE_URL: postgresql://veza:${{ secrets.E2E_DB_PASSWORD || 'devpassword' }}@localhost:15432/veza?sslmode=disable
REDIS_URL: redis://localhost:16379
JWT_SECRET: ${{ secrets.E2E_JWT_SECRET }}
COOKIE_SECURE: "false"
CORS_ALLOWED_ORIGINS: http://veza.fr:5173,http://veza.fr:5174,http://localhost:5173,http://localhost:5174
RABBITMQ_URL: ${{ secrets.E2E_RABBITMQ_URL }}
DISABLE_RATE_LIMIT_FOR_TESTS: "true"
ACCOUNT_LOCKOUT_EXEMPT_EMAILS: "e2e@test.com"
run: |
cd veza-backend-api
go build -o veza-api ./cmd/api/main.go
./veza-api &
sleep 10
curl -sf http://localhost:18080/api/v1/health > /tmp/health.json || (echo "Backend health check failed"; exit 1)
jq -e '.status == "ok"' /tmp/health.json || (echo "Health response invalid"; exit 1)
echo "Health check OK (status, DB/Redis connectivity verified)"
- name: Install Playwright Browsers
run: npx playwright install --with-deps
working-directory: apps/web
- name: Run E2E tests
run: npx playwright test
working-directory: apps/web
env:
PORT: "5174"
VITE_API_URL: '/api/v1'
VITE_DOMAIN: veza.fr
VITE_BACKEND_PORT: "18080"
PLAYWRIGHT_BASE_URL: 'http://localhost:5174'
TEST_EMAIL: e2e@test.com
TEST_PASSWORD: ${{ secrets.E2E_TEST_PASSWORD }}
- uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
if: failure()
with:
name: playwright-report
path: apps/web/playwright-report/
retention-days: 7
notify-failure:
name: Notify on failure
needs: [backend-go, rust-services, frontend, storybook, e2e]
if: failure()
runs-on: ubuntu-latest
steps:
- name: Slack notification
if: secrets.SLACK_WEBHOOK_URL != ''
run: |
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"CI failed on ${{ github.repository }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\"}" \
"${{ secrets.SLACK_WEBHOOK_URL }}"