--- name: static-analysis-integration description: Use when integrating SAST tools (SonarQube, ESLint, Pylint, Checkstyle), setting up security scanning, configuring code quality gates, managing false positives, or building CI/CD quality pipelines - provides tool selection, configuration patterns, and quality threshold strategies --- # Static Analysis Integration ## Overview **Core principle:** Static analysis catches bugs,security vulnerabilities, and code quality issues before code review. Automate it in CI/CD. **Rule:** Block merges on critical issues, warn on moderate issues, ignore noise. Configure thresholds carefully. ## Static Analysis vs Other Quality Checks | Check Type | When | What It Finds | Speed | |------------|------|---------------|-------| | **Static Analysis** | Pre-commit/PR | Bugs, security, style | Fast (seconds) | | **Unit Tests** | Every commit | Logic errors | Fast (seconds) | | **Integration Tests** | PR | Integration bugs | Medium (minutes) | | **Security Scanning** | PR/Nightly | Dependencies, secrets | Medium (minutes) | | **Manual Code Review** | PR | Design, readability | Slow (hours) | **Static analysis finds:** Null pointer bugs, SQL injection, unused variables, complexity issues **Static analysis does NOT find:** Business logic errors, performance issues (use profiling) --- ## Tool Selection by Language ### Python | Tool | Purpose | When to Use | |------|---------|-------------| | **Pylint** | Code quality, style, bugs | General-purpose, comprehensive | | **Flake8** | Style, simple bugs | Faster than Pylint, less strict | | **mypy** | Type checking | Type-safe codebases | | **Bandit** | Security vulnerabilities | Security-critical code | | **Black** | Code formatting | Enforce consistent style | **Recommended combo:** Black (formatting) + Flake8 (linting) + mypy (types) + Bandit (security) --- ### JavaScript/TypeScript | Tool | Purpose | When to Use | |------|---------|-------------| | **ESLint** | Code quality, style, bugs | All JavaScript projects | | **TypeScript** | Type checking | Type-safe codebases | | **Prettier** | Code formatting | Enforce consistent style | | **SonarQube** | Security, bugs, code smells | Enterprise, comprehensive | **Recommended combo:** Prettier (formatting) + ESLint (linting) + TypeScript (types) --- ### Java | Tool | Purpose | When to Use | |------|---------|-------------| | **Checkstyle** | Code style | Enforce coding standards | | **PMD** | Bug detection, code smells | General-purpose | | **SpotBugs** | Bug detection | Bytecode analysis | | **SonarQube** | Comprehensive analysis | Enterprise, dashboards | **Recommended combo:** Checkstyle (style) + SpotBugs (bugs) + SonarQube (comprehensive) --- ## Configuration Patterns ### ESLint Configuration (JavaScript) ```javascript // .eslintrc.js module.exports = { extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:security/recommended' ], rules: { // Error: Block merge 'no-console': 'error', 'no-debugger': 'error', '@typescript-eslint/no-explicit-any': 'error', // Warning: Allow merge, but warn 'complexity': ['warn', 10], 'max-lines': ['warn', 500], // Off: Too noisy 'no-unused-vars': 'off', // TypeScript handles this } }; ``` **Run in CI:** ```bash eslint src/ --max-warnings 0 # Fail if any warnings ``` --- ### Pylint Configuration (Python) ```ini # .pylintrc [MESSAGES CONTROL] disable= missing-docstring, # Too noisy for small projects too-few-public-methods, # Design choice logging-fstring-interpolation # False positives [DESIGN] max-line-length=100 max-args=7 max-locals=15 [BASIC] good-names=i,j,k,_,id,db,pk ``` **Run in CI:** ```bash pylint src/ --fail-under=8.0 # Minimum score 8.0/10 ``` --- ### SonarQube Quality Gates ```yaml # sonar-project.properties sonar.projectKey=my-project sonar.sources=src sonar.tests=tests # Quality gate thresholds sonar.qualitygate.wait=true sonar.coverage.exclusions=**/*_test.py,**/migrations/** # Fail conditions sonar.qualitygate.timeout=300 ``` **Quality Gate Criteria:** - **Blocker/Critical issues:** 0 (block merge) - **Major issues:** < 5 (block merge) - **Code coverage:** > 80% (warn if lower) - **Duplicated lines:** < 3% - **Maintainability rating:** A or B --- ## CI/CD Integration ### GitHub Actions (Python) ```yaml # .github/workflows/static-analysis.yml name: Static Analysis on: [pull_request] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | pip install pylint flake8 mypy bandit black - name: Check formatting run: black --check src/ - name: Run Flake8 run: flake8 src/ --max-line-length=100 - name: Run Pylint run: pylint src/ --fail-under=8.0 - name: Run mypy run: mypy src/ --strict - name: Run Bandit (security) run: bandit -r src/ -ll # Only high severity ``` --- ### GitHub Actions (JavaScript) ```yaml # .github/workflows/static-analysis.yml name: Static Analysis on: [pull_request] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: npm ci - name: Check formatting run: npm run format:check # prettier --check - name: Run ESLint run: npm run lint # eslint --max-warnings 0 - name: Run TypeScript run: npm run typecheck # tsc --noEmit ``` --- ## Managing False Positives **Strategy: Suppress selectively, document why** ### Inline Suppression (ESLint) ```javascript // eslint-disable-next-line no-console console.log("Debugging production issue"); // TODO: Remove after fix // Better: Explain WHY // eslint-disable-next-line @typescript-eslint/no-explicit-any const legacyData: any = externalLibrary.getData(); // Library has no types ``` --- ### File-Level Suppression (Pylint) ```python # pylint: disable=too-many-arguments def complex_function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8): """Legacy API - cannot change signature for backward compatibility.""" pass ``` --- ### Configuration Suppression ```ini # .pylintrc [MESSAGES CONTROL] disable= fixme, # Allow TODO comments missing-docstring # Too noisy for this codebase ``` **Rule:** Every suppression needs a comment explaining WHY. --- ## Security-Focused Static Analysis ### Bandit (Python Security) ```yaml # .bandit.yml exclude_dirs: - /tests - /migrations tests: - B201 # Flask debug mode - B601 # Parameterized shell calls - B602 # Shell injection - B608 # SQL injection ``` **Run:** ```bash bandit -r src/ -ll -x tests/ # Only high/medium severity ``` --- ### ESLint Security Plugin (JavaScript) ```javascript // .eslintrc.js module.exports = { plugins: ['security'], extends: ['plugin:security/recommended'], rules: { 'security/detect-object-injection': 'error', 'security/detect-non-literal-regexp': 'warn', 'security/detect-unsafe-regex': 'error' } }; ``` --- ## Code Quality Metrics ### Complexity Analysis **Cyclomatic complexity:** Measures decision paths through code ```python # Simple function: Complexity = 1 def add(a, b): return a + b # Complex function: Complexity = 5 (if/elif/else = 4 paths + 1 base) def process_order(order): if order.status == "pending": return validate(order) elif order.status == "confirmed": return ship(order) elif order.status == "cancelled": return refund(order) else: return reject(order) ``` **Threshold:** - **< 10:** Acceptable - **10-20:** Consider refactoring - **> 20:** Must refactor (untestable) **Configure:** ```ini # Pylint [DESIGN] max-complexity=10 # ESLint complexity: ['warn', 10] ``` --- ### Duplication Detection **SonarQube duplication threshold:** < 3% **Find duplicates (Python):** ```bash pylint src/ --disable=all --enable=duplicate-code ``` **Find duplicates (JavaScript):** ```bash jscpd src/ # JavaScript Copy/Paste Detector ``` --- ## Anti-Patterns Catalog ### ❌ Suppressing All Warnings **Symptom:** Config disables most rules ```javascript // ❌ BAD module.exports = { rules: { 'no-console': 'off', 'no-debugger': 'off', '@typescript-eslint/no-explicit-any': 'off', // ... 50 more disabled rules } }; ``` **Why bad:** Static analysis becomes useless **Fix:** Address root causes, suppress selectively --- ###❌ No Quality Gates **Symptom:** Static analysis runs but doesn't block merges ```yaml # ❌ BAD: Linting failures don't block merge - name: Run ESLint run: eslint src/ || true # Always succeeds! ``` **Fix:** Fail CI on critical issues ```yaml # ✅ GOOD - name: Run ESLint run: eslint src/ --max-warnings 0 ``` --- ### ❌ Ignoring Security Warnings **Symptom:** Security findings marked as false positives without investigation ```python # ❌ BAD cursor.execute(f"SELECT * FROM users WHERE id = {user_id}") # nosec ``` **Why bad:** Real SQL injection vulnerability ignored **Fix:** Fix the issue, don't suppress ```python # ✅ GOOD cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) ``` --- ### ❌ Running Static Analysis Only on Main Branch **Symptom:** Issues discovered after merge **Fix:** Run on every PR ```yaml on: [pull_request] # Not just 'push' to main ``` --- ## Quality Dashboard Setup ### SonarQube Dashboard **Key metrics to track:** 1. **Bugs:** Code issues likely to cause failures 2. **Vulnerabilities:** Security issues 3. **Code Smells:** Maintainability issues 4. **Coverage:** Test coverage % 5. **Duplications:** Duplicated code blocks **Quality Gate Example:** - Bugs (Blocker/Critical): **0** - Vulnerabilities (Blocker/Critical): **0** - Code Smells (Blocker/Critical): **< 5** - Coverage on new code: **> 80%** - Duplicated lines on new code: **< 3%** --- ## Gradual Adoption Strategy **For legacy codebases with thousands of issues:** ### Phase 1: Baseline (Week 1) ```bash # Run analysis, capture current state pylint src/ > baseline.txt # Configure to only fail on NEW issues # (Track baseline, don't enforce on old code) ``` --- ### Phase 2: Block New Issues (Week 2) ```yaml # Block PRs that introduce NEW issues - name: Run incremental lint run: | pylint $(git diff --name-only origin/main...HEAD | grep '\.py$') --fail-under=8.0 ``` --- ### Phase 3: Fix High-Priority Old Issues (Weeks 3-8) - Security vulnerabilities first - Bugs second - Code smells third --- ### Phase 4: Full Enforcement (Week 9+) ```yaml # Enforce on entire codebase - name: Run lint run: pylint src/ --fail-under=8.0 ``` --- ## Bottom Line **Static analysis catches bugs and security issues before code review. Automate it in CI/CD with quality gates.** - Choose tools for your language: ESLint (JS), Pylint (Python), Checkstyle (Java) - Configure thresholds: Block critical issues, warn on moderate, ignore noise - Run on every PR, fail CI on violations - Manage false positives selectively with documented suppressions - Track quality metrics: complexity, duplication, coverage **If static analysis isn't blocking merges, you're just generating reports nobody reads. Use quality gates.**