Перейти к основному содержимому

Code Review и автоматизация

Чек-лист для Code Review

Ревьюер MUST убедиться, что:

XSS и рендеринг

  • Не используется вставка контента без санитизации (dangerouslySetInnerHTML, innerHTML через ref)
  • При необходимости рендеринга HTML/markdown используется проверенная библиотека санитизации (dompurify)
  • Данные из пользовательского ввода, client storage считаются недоверенными
  • Применяется whitelist подход для разрешенных тегов

Client-side Storage

  • В client-side storage отсутствуют:
    • Access tokens / Refresh tokens
    • PII (Personally Identifiable Information): email, телефон, адрес
    • Секретные ключи / API keys
    • Данные платежных карт
  • Данные, читаемые из client storage, валидируются (через zod, yup)
  • Cookies для токенов имеют флаги: HttpOnly, Secure, SameSite

Environment Variables

  • Клиентские env-переменные (например, NEXT_PUBLIC_*) не содержат секретов
  • Секретные ключи используются только на сервере
  • Проведена валидация env-переменных при старте приложения
  • Не передаются серверные переменные в клиентские компоненты

CSP (Content Security Policy)

  • CSP настроен для приложений с пользовательским контентом
  • Нет использования unsafe-inline или unsafe-eval
  • Inline-скрипты используют nonces
  • frame-ancestors настроен корректно

Browser APIs

  • postMessage проверяет origin отправителя
  • Нет использования wildcard (*) в targetOrigin
  • Данные от postMessage валидируются через схему
  • Используется whitelist разрешенных origins

Логирование

  • Debug-логи отключены в production
  • Токены и PII не логируются
  • Source maps не публикуются на production сервере (productionBrowserSourceMaps: false)
  • Используется санитизация логов

Зависимости

  • Lock-файлы в репозитории и актуальны
  • npm audit не показывает критических уязвимостей
  • Проверены новые зависимости (активность, размер, лицензия)
  • Нет подозрительных lifecycle scripts (postinstall, preinstall)
  • Настроены автоматические проверки в CI/CD

Автоматизация проверок

ESLint конфигурация

// .eslintrc.js
module.exports = {
extends: ['next/core-web-vitals'],
rules: {
// ❌ FORBIDDEN: dangerouslySetInnerHTML без явного исключения
'react/no-danger': 'error',

// ❌ FORBIDDEN: eval и new Function
'no-eval': 'error',
'no-implied-eval': 'error',
'no-new-func': 'error',

// ⚠️ Предупреждение о console.log в production
'no-console': ['warn', { allow: ['warn', 'error'] }],

// ❌ FORBIDDEN: небезопасные регулярные выражения
'no-unsafe-regex': 'error',

// ⚠️ SHOULD: Проверка типов
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unsafe-assignment': 'warn',
},
overrides: [
{
// Более строгие правила для production кода
files: ['src/**/*.ts', 'src/**/*.tsx'],
excludedFiles: ['**/*.test.ts', '**/*.test.tsx', '**/*.stories.tsx'],
rules: {
'no-console': 'error', // Строгий запрет в production
'@typescript-eslint/no-explicit-any': 'error',
},
},
],
};

TypeScript конфигурация

// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,

// Дополнительные проверки
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}

Pre-commit хуки

# Установка husky и lint-staged
npm install -D husky lint-staged
npx husky init
// .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged
npm audit --audit-level=high
// package.json
{
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix --max-warnings=0",
"prettier --write"
],
"*.{js,jsx}": [
"eslint --fix --max-warnings=0",
"prettier --write"
],
"package.json": [
"npm audit --audit-level=high"
]
}
}

GitHub Actions

# .github/workflows/security-checks.yml
name: Security Checks

on:
pull_request:
push:
branches: [main, develop]

jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'

- name: Install dependencies
run: npm ci --ignore-scripts

- name: Lint check
run: npm run lint

- name: Type check
run: npm run type-check

- name: Security audit
run: npm audit --audit-level=moderate

- name: Check for secrets in code
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD

- name: Run tests
run: npm test
# .github/workflows/dependency-review.yml
name: Dependency Review

on: [pull_request]

permissions:
contents: read

jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3

- name: Dependency Review
uses: actions/dependency-review-action@v3
with:
fail-on-severity: moderate

Дополнительные инструменты

Проверка секретов

# .github/workflows/secret-scan.yml
name: Secret Scanning

on: [push, pull_request]

jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: TruffleHog
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD

- name: GitLeaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Проверка бандла

// package.json
{
"scripts": {
"analyze": "ANALYZE=true next build",
"analyze:bundle": "npx bundle-analyzer .next/analyze/client.html"
}
}
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});

module.exports = withBundleAnalyzer({
// Next.js config
});

SonarQube/SonarCloud

# .github/workflows/sonar.yml
name: SonarCloud Scan

on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]

jobs:
sonarcloud:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

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

Контрольный список перед деплоем

Безопасность

  • Все токены и секреты только на сервере
  • CSP настроен и активен
  • Source maps отключены в production
  • Debug-логи отключены
  • npm audit не показывает критических уязвимостей
  • HTTPS включен (Secure cookies)
  • Rate limiting настроен для API endpoints

Конфигурация

  • Environment variables проверены
  • productionBrowserSourceMaps: false
  • Error boundaries настроены
  • Мониторинг ошибок настроен (Sentry)
  • Analytics не логирует PII

Производительность

  • Bundle size проверен (npx bundlephobia)
  • Lazy loading для больших компонентов
  • Images оптимизированы (Next.js Image)
  • Lighthouse score > 90

Тестирование

  • Unit tests покрывают критичную логику
  • Integration tests для основных флоу
  • E2E tests для критичных путей
  • Security headers тестированы

Примеры проверки PR

Комментарии ревьюера

## Security Review

### ✅ Approved:
- Environment variables properly separated
- Input validation added for user data
- CSRF tokens implemented

### ⚠️ Issues Found:
1. **Line 45**: `dangerouslySetInnerHTML` without sanitization
- Recommendation: Use `dompurify` to sanitize HTML before rendering
- Severity: High

2. **Line 78**: Token stored in localStorage
- Recommendation: Move to HttpOnly cookie
- Severity: Critical

3. **Line 120**: Missing origin validation in postMessage
- Recommendation: Add whitelist of allowed origins
- Severity: High

### 📋 Checklist:
- [x] No secrets in code
- [x] Dependencies audited
- [ ] CSP configured (missing)
- [x] Logging sanitized

### 🔧 Action Required:
Please address the critical issues before merge.

Автоматические комментарии

# .github/workflows/pr-comment.yml
name: PR Security Comment

on: pull_request

jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Run audit
id: audit
run: |
npm audit --json > audit-results.json || true

- name: Comment PR
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const audit = JSON.parse(fs.readFileSync('audit-results.json'));

const vulnerabilities = audit.metadata?.vulnerabilities;

if (vulnerabilities?.high > 0 || vulnerabilities?.critical > 0) {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `⚠️ **Security Alert**: Found ${vulnerabilities.critical} critical and ${vulnerabilities.high} high severity vulnerabilities. Please run \`npm audit fix\` before merging.`
});
}

📌 Ключевые моменты:

  • MUST: Code Review обязателен для всех изменений
  • MUST: Автоматические проверки в CI/CD
  • MUST: ESLint правила для безопасности
  • MUST: Pre-commit хуки для ранней проверки
  • Блокировка merge при найденных уязвимостях