Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 140 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
backend-test:
name: Backend Install · Build · Test
name: Backend - Install, Build, Test, Lint
runs-on: ubuntu-latest

steps:
Expand All @@ -24,6 +24,9 @@ jobs:
- name: Install dependencies
run: npm install

- name: Lint backend
run: npm run lint --workspace=apps/backend

- name: Build backend
run: npm run build --workspace=apps/backend

Expand All @@ -36,7 +39,7 @@ jobs:
continue-on-error: true

backend-integration-test:
name: Backend Integration Tests (PostgreSQL)
name: Backend - Integration Tests (PostgreSQL)
runs-on: ubuntu-latest

services:
Expand All @@ -63,7 +66,7 @@ jobs:
NODE_ENV: test

backend-soroban-test:
name: Backend Soroban Testnet Tests
name: Backend - Soroban Testnet Tests
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'

Expand Down Expand Up @@ -101,7 +104,7 @@ jobs:
STELLAR_SECRET_KEY: ${{ secrets.STELLAR_SECRET_KEY }}

frontend-build:
name: Frontend Install · Build
name: Frontend - Install, Build, Lint
runs-on: ubuntu-latest

steps:
Expand All @@ -117,11 +120,14 @@ jobs:
- name: Install dependencies
run: npm install

- name: Lint frontend
run: npm run lint --workspace=apps/frontend

- name: Build frontend
run: npm run build --workspace=apps/frontend

chromatic-visual-tests:
name: Frontend Visual Regression Tests (Chromatic)
name: Frontend - Visual Regression Tests (Chromatic)
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'

Expand Down Expand Up @@ -151,7 +157,7 @@ jobs:
exitZeroOnChanges: true

contracts-check:
name: Contracts Test · Format · Lint
name: Contracts - Test, Format, Lint, Audit, Deny
runs-on: ubuntu-latest

steps:
Expand All @@ -176,8 +182,14 @@ jobs:
- name: cargo clippy
run: cargo clippy -- -D warnings

- name: cargo audit
run: cargo audit --deny warnings

- name: cargo deny
run: cargo deny check

load-tests:
name: Load Tests k6
name: Load Tests - k6
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'

Expand All @@ -194,3 +206,124 @@ jobs:
env:
API_URL: http://localhost:3000
continue-on-error: true

sonarcloud:
name: Code Quality - SonarCloud
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm install

- name: Generate frontend coverage
run: npm run test:coverage --workspace=apps/frontend
continue-on-error: true

- name: Generate backend coverage
run: npm run test --workspace=apps/backend -- --coverage
working-directory: apps/backend
continue-on-error: true

- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

security-scan:
name: Security - OWASP ZAP Scan
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'

services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: brainstorm_test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

redis:
image: redis:7
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm install

- name: Start backend server
run: npm run start:prod --workspace=apps/backend &
env:
NODE_ENV: production
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/brainstorm_test
REDIS_URL: redis://localhost:6379
timeout-minutes: 2

- name: Wait for backend to be ready
run: |
for i in {1..30}; do
if curl -f http://localhost:3000/health; then
echo "Backend is ready"
exit 0
fi
echo "Waiting for backend... ($i/30)"
sleep 2
done
echo "Backend failed to start"
exit 1

- name: Run OWASP ZAP baseline scan
uses: zaproxy/[email protected]
with:
target: 'http://localhost:3000'
rules_file_name: '.zap/rules.tsv'
cmd_options: '-a'

- name: Upload ZAP report
if: always()
uses: actions/upload-artifact@v4
with:
name: zap-report
path: report_html.html
retention-days: 30

- name: Check for HIGH severity findings
run: |
if grep -q "HIGH" report_html.html; then
echo "HIGH severity findings detected in ZAP scan"
exit 1
fi
continue-on-error: true
11 changes: 11 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
node_modules
dist
coverage
.next
out
build
*.lock
*.log
.env
.env.local
.env.*.local
9 changes: 9 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always"
}
28 changes: 28 additions & 0 deletions apps/backend/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js', 'dist', 'coverage'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_' },
],
},
};
1 change: 1 addition & 0 deletions apps/backend/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ module.exports = {
},
collectCoverageFrom: ['**/*.(t|j)s'],
coverageDirectory: '../coverage',
coverageReporters: ['text', 'lcov', 'html'],
testEnvironment: 'node',
};
11 changes: 11 additions & 0 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
"start:dev": "nest start --watch",
"build": "nest build",
"start:prod": "node dist/main",
"lint": "eslint src --ext .ts",
"lint:fix": "eslint src --ext .ts --fix",
"format:check": "prettier --check .",
"format": "prettier --write .",
"test": "jest",
"test:integration": "jest --config jest-integration.config.js --runInBand",
"test:e2e": "jest --config jest-e2e.config.js --runInBand",
Expand Down Expand Up @@ -38,14 +42,21 @@
"typeorm": "^0.3.0"
},
"devDependencies": {
"@eslint/js": "^8.56.0",
"@nestjs/cli": "^10.0.0",
"@nestjs/testing": "^10.4.22",
"@pact-foundation/pact": "^4.5.0",
"@testcontainers/postgresql": "^10.0.0",
"@types/jest": "^29.0.0",
"@types/node": "^20.0.0",
"@types/nodemailer": "^6.4.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.0.0",
"prettier": "^3.0.0",
"testcontainers": "^10.0.0",
"ts-jest": "^29.4.6",
"typescript": "^5.4.0"
Expand Down
39 changes: 39 additions & 0 deletions apps/frontend/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
plugins: ['@typescript-eslint/eslint-plugin', 'react', 'react-hooks'],
extends: [
'next/core-web-vitals',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
browser: true,
es2020: true,
node: true,
},
ignorePatterns: ['.eslintrc.js', '.next', 'out', 'dist', 'coverage'],
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_' },
],
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
},
settings: {
react: {
version: 'detect',
},
},
};
13 changes: 12 additions & 1 deletion apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
"build": "next build",
"postbuild": "next-sitemap",
"start": "next start",
"lint": "next lint",
"lint": "eslint src --ext .ts,.tsx",
"lint:fix": "eslint src --ext .ts,.tsx --fix",
"format:check": "prettier --check .",
"format": "prettier --write .",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
Expand Down Expand Up @@ -53,11 +56,19 @@
"@testing-library/user-event": "^14.5.0",
"@types/node": "^20.0.0",
"@types/react": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.3.0",
"@vitest/coverage-v8": "^1.6.0",
"chromatic": "^10.0.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react": "^7.34.0",
"eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^24.1.0",
"msw": "^2.3.0",
"prettier": "^3.0.0",
"typescript": "^5.4.0",
"vitest": "^1.6.0"
}
Expand Down
Loading
Loading