Skip to content

feat(react-bits): Phase 2 - Landing page professional UI enhancements #258

feat(react-bits): Phase 2 - Landing page professional UI enhancements

feat(react-bits): Phase 2 - Landing page professional UI enhancements #258

Workflow file for this run

name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run TypeScript type check
run: npm run type-check
- name: Static scan (dead links, env parity)
run: node scripts/static-scan.js
build:
name: Build Application
runs-on: ubuntu-latest
needs: lint-and-typecheck
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
env:
# Mock environment variables for build
NEXT_PUBLIC_CONVEX_URL: "https://mock.convex.cloud"
CONVEX_DEPLOYMENT: "mock-deployment"
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: "pk_test_mock"
CLERK_SECRET_KEY: "sk_test_mock"
NEXT_PUBLIC_CLERK_FRONTEND_API_URL: "https://mock.clerk.accounts.dev"
OPENAI_API_KEY: "sk_test_mock_for_build"
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-files
path: .next/
retention-days: 1
unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
needs: lint-and-typecheck
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm run test:unit:run
- name: Upload coverage reports
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
security-scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run npm audit
run: npm audit --audit-level=moderate
continue-on-error: true
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
continue-on-error: true
e2e-tests:
name: E2E Tests
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-files
path: .next/
- name: Start application
run: |
npm run build && npm start &
npx wait-on http://localhost:3000
env:
NEXT_PUBLIC_CONVEX_URL: "https://mock.convex.cloud"
CONVEX_DEPLOYMENT: "mock-deployment"
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: "pk_test_mock"
CLERK_SECRET_KEY: "sk_test_mock"
NEXT_PUBLIC_CLERK_FRONTEND_API_URL: "https://mock.clerk.accounts.dev"
- name: Run E2E tests
run: npm run test:e2e
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
fail-on-severity: moderate
healthcare-compliance-check:
name: Healthcare Compliance Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check for PHI in code
run: |
set -eo pipefail
PHI_TMP="$(mktemp)"
PHI_FILTERED="${PHI_TMP}_filtered"
ALLOWLIST=".github/phi-allowlist.txt"
grep -RInE "ssn|social\.security|date\.of\.birth|dob|patient\.id" \
--include="*.ts" \
--include="*.tsx" \
--include="*.js" \
--include="*.jsx" \
--exclude=lib/prompts.ts \
--exclude=mentoloop-gpt5-template/prompt-engineering.ts \
--exclude-dir=.next \
--exclude-dir=playwright-report \
--exclude-dir=test-results \
. > "$PHI_TMP" || true
if [ -s "$PHI_TMP" ]; then
if [ -f "$ALLOWLIST" ]; then
grep -v -F -f "$ALLOWLIST" "$PHI_TMP" > "$PHI_FILTERED" || true
else
cp "$PHI_TMP" "$PHI_FILTERED"
fi
if [ -s "$PHI_FILTERED" ]; then
echo "⚠️ Potential PHI found in code. Please review." >&2
cat "$PHI_FILTERED" >&2
exit 1
fi
fi
echo "✅ No obvious PHI patterns detected."
- name: Check for API keys in code
run: |
if grep -r -E "(sk_|pk_|api_key|secret_key)" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . | grep -v ".env" | grep -v test | grep -v mock | grep -v example | grep -v "lib/clerk-config.ts"; then
echo "⚠️ Potential hardcoded secrets found. Please review."
exit 1
else
echo "✅ No hardcoded secrets detected."
fi
deploy-preview:
name: Deploy Preview
runs-on: ubuntu-latest
needs: [build, unit-tests]
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to Netlify Preview
uses: netlify/actions/cli@master
with:
args: deploy --dir=.next --alias=preview-${{ github.event.number }}
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
- name: Comment PR with preview link
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## 🚀 Preview Deployment
Your changes have been deployed to: https://preview-${{ github.event.number }}--mentoloop.netlify.app
- ✅ Build successful
- ✅ Tests passing
- 🔍 Ready for review`
})
notify-status:
name: Notify Team
runs-on: ubuntu-latest
needs: [build, unit-tests, security-scan]
if: always() && github.ref == 'refs/heads/main'
steps:
- name: Notify Discord
uses: sarisia/actions-status-discord@v1
if: always()
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
title: "MentoLoop CI/CD Status"
description: "Build and test results for main branch"
color: ${{ job.status == 'success' && '0x00ff00' || '0xff0000' }}