Overview
Static code analysis examines source code without executing the program to identify potential defects, security vulnerabilities, code smells, and violations of coding standards. The analysis operates on the abstract syntax tree (AST) or intermediate representations of code, applying pattern matching, data flow analysis, and control flow analysis to detect issues that might escape runtime testing.
The practice emerged in the 1970s with tools like Lint for C, which found suspicious code constructs that compilers would accept but likely contained errors. Modern static analysis tools have expanded beyond simple pattern matching to include sophisticated techniques like taint analysis for security vulnerabilities, symbolic execution for logic errors, and machine learning-based anomaly detection.
Static analysis differs from dynamic analysis (testing) in that it examines all possible code paths without executing the program. This characteristic makes it particularly effective for finding issues in rarely-executed error handling code, security vulnerabilities in edge cases, and inconsistencies across large codebases. The analysis occurs at various stages: during editing (IDE integration), before commits (pre-commit hooks), during code review (pull request checks), or as part of continuous integration pipelines.
# Code that static analysis can check without execution
def transfer_funds(from_account, to_account, amount)
# Detects: Unused variable 'transaction_id'
transaction_id = generate_id
# Detects: Potential nil reference if 'from_account' is nil
from_account.balance -= amount
# Detects: SQL injection vulnerability
execute("SELECT * FROM accounts WHERE id = #{to_account.id}")
end
The analysis provides immediate feedback during development rather than waiting for runtime failures or security incidents. This shift-left approach to quality assurance reduces the cost of fixing defects by catching them early in the development cycle.
Key Principles
Static analysis operates through several fundamental mechanisms that examine code structure, semantics, and patterns. The analysis begins with parsing source code into an abstract syntax tree, which represents the syntactic structure of the program in a tree format where each node denotes a language construct. This AST becomes the foundation for all subsequent analysis passes.
Lexical Analysis examines individual tokens and patterns in the source code without understanding program semantics. This level detects formatting inconsistencies, naming convention violations, and suspicious patterns like duplicated code or commented-out sections. Lexical analysis requires no understanding of program flow or data relationships.
Syntax Analysis verifies that code conforms to language grammar rules and coding standards. This analysis identifies deprecated APIs, incorrect method signatures, missing error handling, and violations of established style guides. The analysis operates on the structure of code rather than its runtime behavior.
Data Flow Analysis tracks how data moves through the program by examining assignments, method calls, and variable usage patterns. The analyzer builds a graph representing possible data transformations and identifies issues like uninitialized variables, unused assignments, potential null pointer dereferences, and information leakage through insecure data channels. Control flow analysis works in tandem by examining the order of statement execution, identifying unreachable code, infinite loops, missing return statements, and complex conditional logic.
Type Analysis examines type compatibility and conversions, detecting type mismatches that might cause runtime errors, unsafe type casting, and implicit conversions that could lose precision or introduce bugs. Ruby's dynamic nature requires static analyzers to infer types through pattern analysis and method signatures rather than explicit declarations.
Taint Analysis tracks potentially malicious or untrusted data as it flows through the application. The analyzer marks data from untrusted sources (user input, external APIs, file systems) as "tainted" and traces its propagation through the codebase. When tainted data reaches a sensitive operation (database query, system command, template rendering) without proper sanitization, the analyzer flags a potential security vulnerability.
# Taint analysis example
def search_users(query)
# 'query' is marked as tainted (user input)
sanitized = sanitize_sql(query) # Removes taint
# Safe: uses sanitized data
User.where("name LIKE ?", sanitized)
# Unsafe: uses tainted data directly
User.where("name LIKE '#{query}'") # Analyzer flags this
end
Pattern Matching identifies known problematic code constructs by comparing code against a database of anti-patterns, security vulnerabilities, and bug patterns. This includes detection of SQL injection patterns, cross-site scripting vulnerabilities, race conditions, resource leaks, and common programming mistakes specific to the language or framework.
The analysis produces findings with severity classifications (error, warning, information), precise source locations, descriptions of the issue, and often suggested fixes. False positives occur when the analyzer flags correct code as problematic, typically due to limitations in understanding complex program semantics or intentional use of advanced language features. False negatives occur when the analyzer misses actual defects, usually in dynamically-evaluated code or patterns not covered by the analyzer's rules.
Ruby Implementation
Ruby static analysis tools operate by parsing Ruby source code into an AST using the parser gem or Ruby's built-in Ripper library. The tools then apply various checks against this AST, examining node patterns, method calls, variable usage, and code structure.
RuboCop serves as the primary static analyzer for Ruby code, enforcing both syntactic rules and semantic patterns. The tool operates through a cop-based architecture where each cop (checker) examines specific aspects of code. Cops can auto-correct violations, generate offense reports, and integrate with editors and CI systems.
# .rubocop.yml configuration
AllCops:
NewCops: enable
TargetRubyVersion: 3.2
Style/StringLiterals:
EnforcedStyle: double_quotes
Metrics/MethodLength:
Max: 20
Exclude:
- 'db/migrate/*'
Naming/VariableName:
EnforcedStyle: snake_case
The tool provides extensive configuration options for enabling, disabling, or modifying cop behavior. Custom cops can be created to enforce organization-specific rules:
# Custom cop for enforcing service object naming
module CustomCops
class ServiceObjectNaming < RuboCop::Cop::Base
MSG = "Service objects must end with 'Service'"
def on_class(node)
class_name = node.identifier.source
return if class_name.end_with?('Service')
return unless inherits_from_base_service?(node)
add_offense(node.identifier)
end
private
def inherits_from_base_service?(node)
return false unless node.parent_class
node.parent_class.source == 'BaseService'
end
end
end
Reek focuses specifically on code smells, detecting issues like long parameter lists, complex conditionals, duplicate code, and poor abstraction. Unlike RuboCop's focus on style and correctness, Reek examines design quality:
# Reek detects code smells
class UserProcessor
# Smell: Too many instance variables
def initialize(user, validator, notifier, logger, cache)
@user = user
@validator = validator
@notifier = notifier
@logger = logger
@cache = cache
end
# Smell: Long method
# Smell: Feature envy (using methods from user extensively)
def process
return false unless @validator.valid?(@user)
@user.status = 'active'
@user.processed_at = Time.now
@user.save!
@notifier.send_welcome(@user)
@logger.info("Processed user #{@user.id}")
@cache.delete("pending_users")
true
end
end
Brakeman specializes in security analysis for Rails applications, detecting vulnerabilities like SQL injection, cross-site scripting, command injection, and insecure configurations:
# Brakeman detects security issues
class ArticlesController < ApplicationController
def search
# SQL injection vulnerability
@articles = Article.where("title LIKE '%#{params[:query]}%'")
# Cross-site scripting vulnerability
@message = params[:message].html_safe
# Mass assignment vulnerability
@user = User.new(params[:user])
end
def secure_search
# Safe parameterized query
@articles = Article.where("title LIKE ?", "%#{params[:query]}%")
# Escaped output
@message = sanitize(params[:message])
# Strong parameters
@user = User.new(user_params)
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
Ruby-specific analysis must account for metaprogramming, dynamic method definitions, and runtime code evaluation. Analyzers use heuristics and pattern matching to handle these dynamic features:
# Challenges for static analysis
class DynamicModel
# Dynamic method definition
[:name, :email, :phone].each do |attr|
define_method(attr) do
instance_variable_get("@#{attr}")
end
define_method("#{attr}=") do |value|
instance_variable_set("@#{attr}", value)
end
end
# Runtime code evaluation
def execute_code(code)
eval(code) # Analyzer flags security risk
end
# send usage can bypass access control
def invoke_method(method_name)
send(method_name) # Analyzer may warn about dynamic dispatch
end
end
Implementation Approaches
Static analysis integrates into development workflows at multiple points, each offering different trade-offs between feedback speed, thoroughness, and developer disruption.
IDE Integration provides real-time feedback as developers write code. Modern editors like RubyMine, VS Code with Ruby LSP, and Vim with ALE display static analysis warnings inline with syntax highlighting. This immediate feedback loop catches issues at the earliest possible moment:
# VS Code settings.json for Ruby analysis
{
"ruby.lint": {
"rubocop": true,
"reek": true
},
"ruby.format": "rubocop",
"editor.formatOnSave": true,
"ruby.intellisense": "rubyLocate"
}
The approach minimizes context switching since developers see issues without leaving their editor. However, IDE integration typically runs lighter analysis to maintain editor responsiveness, potentially missing deeper issues that require more computation time.
Pre-commit Hooks run analysis before changes enter version control. Git hooks execute static analysis tools and block commits that contain violations, ensuring only clean code reaches the repository:
# .git/hooks/pre-commit
#!/usr/bin/env ruby
# Get list of Ruby files changed in this commit
changed_files = `git diff --cached --name-only --diff-filter=ACM`
.split("\n")
.select { |file| file.end_with?('.rb') }
exit 0 if changed_files.empty?
puts "Running static analysis on changed files..."
# Run RuboCop on changed files
system("bundle exec rubocop #{changed_files.join(' ')}")
rubocop_result = $?.exitstatus
# Run Reek on changed files
system("bundle exec reek #{changed_files.join(' ')}")
reek_result = $?.exitstatus
# Exit with failure if any analyzer failed
exit 1 if rubocop_result != 0 || reek_result != 0
Pre-commit analysis prevents problematic code from entering the repository but can slow down the commit process. Developers may disable hooks when rushing, bypassing the safety mechanism. Tools like Overcommit provide a framework for managing Git hooks with better developer experience.
Pull Request Analysis runs comprehensive checks on proposed changes before merging. CI systems execute full analysis suites, post results as PR comments, and block merges based on quality gates:
# .github/workflows/static_analysis.yml
name: Static Analysis
on: [pull_request]
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2
bundler-cache: true
- name: Run RuboCop
run: bundle exec rubocop --format json --out rubocop-results.json
- name: Run Brakeman
run: bundle exec brakeman -o brakeman-results.json --no-pager
- name: Run Reek
run: bundle exec reek --format json > reek-results.json
- name: Upload results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: combined-results.sarif
This approach provides thorough analysis without disrupting individual developer workflows. The analysis runs in parallel with human code review, catching issues before they reach production. PR-based analysis allows for stricter rules than pre-commit hooks since failures don't interrupt local development.
Continuous Monitoring tracks code quality metrics over time, identifying trends and hotspots. Tools like Code Climate, SonarQube, and Coveralls aggregate analysis results across commits and branches:
# config/quality_gates.yml
maintainability:
threshold: 'B'
block_on_failure: true
security:
max_vulnerabilities:
critical: 0
high: 2
medium: 10
coverage:
minimum: 85
allow_coverage_decrease: false
complexity:
max_method_complexity: 10
max_class_complexity: 50
Continuous monitoring provides visibility into code quality evolution and helps teams prioritize technical debt. Historical data reveals which areas of the codebase accumulate issues most frequently, guiding refactoring efforts.
Incremental Analysis examines only changed code rather than the entire codebase, reducing analysis time for large projects. This approach requires careful cache management to ensure accuracy:
# Rakefile for incremental analysis
namespace :analyze do
desc 'Run analysis on changed files since main branch'
task :incremental do
# Find files changed compared to main branch
changed_files = `git diff --name-only origin/main...HEAD`
.split("\n")
.select { |f| f.end_with?('.rb') }
if changed_files.any?
puts "Analyzing #{changed_files.size} changed files..."
system("rubocop #{changed_files.join(' ')}")
else
puts "No Ruby files changed"
end
end
end
Tools & Ecosystem
The Ruby ecosystem provides specialized static analysis tools targeting different aspects of code quality, security, and maintainability.
RuboCop serves as the most comprehensive style and quality checker for Ruby. The tool includes over 400 cops organized into departments (Style, Layout, Lint, Metrics, Naming, Security). Extensions add framework-specific rules:
| Extension | Purpose | Key Features |
|---|---|---|
| rubocop-rails | Rails conventions | ActiveRecord patterns, controller checks, view helpers |
| rubocop-rspec | RSpec best practices | Spec organization, expectation styles, test structure |
| rubocop-performance | Performance optimization | N+1 queries, inefficient iterations, object allocations |
| rubocop-thread_safety | Concurrency safety | Thread-unsafe operations, race conditions, shared state |
RuboCop's auto-correction capability fixes many violations automatically, though complex issues require manual intervention. The tool supports multiple output formats (JSON, JUnit, HTML) for integration with various CI systems and reporting tools.
Reek identifies code smells through heuristic analysis. The tool detects design issues that don't violate syntax rules but indicate potential maintenance problems:
| Smell Category | Detection | Impact |
|---|---|---|
| Uncommunicative Name | Short or unclear identifiers | Reduced readability |
| Long Parameter List | Methods with 4+ parameters | High coupling, testing difficulty |
| Data Clump | Same parameters appearing together | Missing abstraction |
| Feature Envy | Methods using another class extensively | Misplaced responsibility |
| Utility Function | Public methods not using instance state | Poor encapsulation |
Reek operates with lower precision than RuboCop, producing more false positives since code smell detection involves subjective judgment about design quality.
Brakeman specializes in security vulnerability detection for Rails applications. The scanner identifies common web application security issues without requiring a running application:
# Running Brakeman with options
bundle exec brakeman \
--confidence-level 2 \
--ignore-config config/brakeman.ignore \
--output brakeman-report.html \
--no-exit-on-warn
Brakeman detects vulnerabilities including SQL injection, cross-site scripting, command injection, unsafe redirects, mass assignment, and insecure dependencies. The tool produces confidence ratings (high, medium, low) for each finding based on analysis certainty.
Bundler Audit scans Gemfile.lock against a database of known vulnerable gem versions. The tool integrates into CI pipelines to catch security vulnerabilities in dependencies:
# Running bundle-audit
bundle audit check --update # Update vulnerability database
bundle audit check --ignore CVE-2024-1234 # Ignore specific CVE
Fasterer suggests performance improvements by detecting inefficient Ruby patterns and suggesting faster alternatives:
# Fasterer detects performance issues
array.shuffle.first # Suggests: array.sample
array.select { |e| condition }.size # Suggests: array.count { |e| condition }
hash.keys.each { |k| process(hash[k]) } # Suggests: hash.each { |k, v| process(v) }
Debride finds unused methods through static analysis of method definitions and calls. The tool helps identify dead code that can be safely removed:
# debride output
path/to/file.rb:
unused_method_1 # Defined but never called
unused_method_2 # Defined but never called
Integration frameworks like Pronto aggregate results from multiple analyzers and present them as unified code review comments on pull requests. This centralized approach reduces noise by deduplicating findings and provides a single interface for multiple analysis tools.
Security Implications
Static analysis identifies security vulnerabilities before code execution, catching issues that testing might miss. Security-focused analysis examines how untrusted data flows through applications, detecting patterns that enable attacks.
SQL Injection Detection identifies database queries constructed through string interpolation rather than parameterized statements. Analyzers trace user input from controllers or API endpoints to database queries, flagging any path where tainted data enters a query without proper escaping:
# Insecure patterns detected by analysis
class UserController
def search
# Direct interpolation - High severity
query = "SELECT * FROM users WHERE name = '#{params[:name]}'"
# String concatenation - High severity
query = "SELECT * FROM users WHERE " + build_where_clause(params)
# Conditional query building - Medium severity
User.where("status = '#{params[:status]}'") if params[:status]
end
def secure_search
# Parameterized query - Safe
User.where("name = ?", params[:name])
# Hash conditions - Safe
User.where(name: params[:name])
# Arel - Safe
User.where(User.arel_table[:name].eq(params[:name]))
end
end
Cross-Site Scripting (XSS) Prevention detects unsafe rendering of user-provided content. Analyzers flag calls to html_safe, raw, or render with user input without proper sanitization:
# XSS vulnerabilities detected
class CommentsController
def show
# Unsafe: marks user input as safe HTML
@comment_text = params[:comment].html_safe
# Unsafe: raw bypasses escaping
@formatted = raw(markdown_to_html(params[:content]))
# Unsafe: dynamic rendering with user input
render inline: params[:template]
end
def secure_show
# Safe: automatically escaped by default
@comment_text = params[:comment]
# Safe: sanitize removes dangerous HTML
@formatted = sanitize(markdown_to_html(params[:content]))
# Safe: render predefined template
render :show
end
end
Command Injection Detection identifies system calls constructed from user input. Analyzers flag uses of system, backticks, exec, and open with tainted data:
# Command injection vulnerabilities
def process_file(filename)
# Unsafe: shell interpolation
system("convert #{filename} output.pdf")
# Unsafe: backtick execution
result = `cat #{filename}`
# Unsafe: pipe open
IO.popen("process_data #{params[:input]}")
end
def secure_process_file(filename)
# Safe: array form avoids shell interpolation
system("convert", filename, "output.pdf")
# Safe: explicit array
result = IO.popen(["cat", filename]).read
# Safe: input validation
raise ArgumentError unless filename.match?(/\A[\w.-]+\z/)
system("convert #{filename} output.pdf")
end
Path Traversal Prevention detects file operations using unsanitized user input that could access files outside intended directories:
# Path traversal vulnerabilities
def download_file
# Unsafe: allows ../../../etc/passwd
send_file("/uploads/#{params[:filename]}")
# Unsafe: join doesn't prevent traversal
path = File.join("/uploads", params[:path])
send_file(path)
end
def secure_download_file
# Safe: validates against whitelist
allowed_files = ["document.pdf", "image.png"]
raise SecurityError unless allowed_files.include?(params[:filename])
send_file("/uploads/#{params[:filename]}")
# Safe: expand_path and check prefix
base = File.expand_path("/uploads")
path = File.expand_path(File.join(base, params[:filename]))
raise SecurityError unless path.start_with?(base)
send_file(path)
end
Mass Assignment Protection identifies controller actions that pass user parameters directly to model constructors or update methods:
# Mass assignment vulnerabilities
def create
# Unsafe: all parameters passed through
@user = User.create(params[:user])
# Unsafe: permit! allows everything
@user = User.create(params.require(:user).permit!)
end
def secure_create
# Safe: strong parameters whitelist
@user = User.create(user_params)
end
private
def user_params
params.require(:user).permit(:name, :email)
end
Security analyzers also detect insecure cryptographic practices, weak random number generation, hardcoded secrets, and insecure session configuration. The analysis provides remediation guidance alongside vulnerability reports.
Common Pitfalls
Static analysis tools require careful configuration and interpretation to provide value without creating excessive noise or developer friction.
Ignoring All Warnings defeats the purpose of static analysis. Teams that suppress all warnings or disable analyzers due to initial overwhelming output lose the security and quality benefits. The correct approach involves progressively addressing violations:
# Bad: Blanket disable
# .rubocop.yml
AllCops:
Enabled: false
# Good: Targeted configuration with plan to improve
Metrics/MethodLength:
Max: 30 # Current state
# TODO: Reduce to 20 over next quarter
Layout/LineLength:
Exclude:
- 'db/migrate/*.rb' # Specific exclusion with reason
Effective analysis requires establishing baseline configurations that reflect current code quality, then progressively tightening rules as the codebase improves.
Configuration Drift occurs when teams copy analysis configurations between projects without adaptation. Each project's context determines appropriate rules:
# Anti-pattern: Same config everywhere
# Project A: API service
# Project B: Background jobs
# Project C: Admin interface
# All use identical RuboCop config
# Better: Context-specific rules
# API service emphasizes security and performance
Security/YAMLLoad:
Enabled: true
Performance/UnfreezeString:
Enabled: true
# Background jobs emphasize reliability and monitoring
Lint/SuppressedException:
Enabled: true
AllowComments: false
False Positive Fatigue happens when developers encounter too many incorrect warnings. This erodes trust in analysis tools and leads to ignoring legitimate issues. Address false positives through better configuration rather than blanket suppression:
# Problem: Analyzer incorrectly flags valid code
def calculate_checksum(data)
# Reek: Unused variable 'checksum'
# But it's actually used in rescue clause
checksum = 0
data.each do |byte|
checksum = (checksum + byte) & 0xFF
end
rescue
logger.error("Checksum calculation failed: #{checksum}")
end
# Solution: Inline suppression with explanation
def calculate_checksum(data)
checksum = 0 # reek:UnusedVariable (used in rescue)
data.each do |byte|
checksum = (checksum + byte) & 0xFF
end
rescue
logger.error("Checksum calculation failed: #{checksum}")
end
Ignoring Context applies rules mechanically without considering their purpose. Static analysis provides starting points for discussion, not absolute mandates:
# Metrics/CyclomaticComplexity: Reports complexity of 12 (max 10)
def process_payment(payment, options = {})
return false unless payment.valid?
return false unless sufficient_funds?(payment)
return false if payment.duplicate?
if options[:priority]
process_priority_payment(payment)
elsif payment.recurring?
process_recurring_payment(payment)
elsif payment.international?
process_international_payment(payment)
else
process_standard_payment(payment)
end
notify_payment_complete(payment)
true
end
# Blindly reducing complexity can worsen code
# Extract methods just to satisfy metric
def process_payment(payment, options = {})
return false unless valid_payment?(payment)
route_payment(payment, options)
notify_payment_complete(payment)
true
end
The complexity metric correctly identifies code that merits review, but the solution depends on whether the complexity reflects essential business logic or poor design.
Performance Cost Neglect runs expensive analysis too frequently. Comprehensive security scans or deep program analysis can take minutes on large codebases:
# Anti-pattern: Run everything on every save
# .vscode/settings.json
{
"ruby.lint": {
"rubocop": true,
"reek": true,
"brakeman": true, # Too slow for real-time
"bundler-audit": true # Network calls on every save
}
}
# Better: Tier analysis by speed
# Real-time: Fast checks only
# Pre-commit: Medium depth
# CI: Comprehensive analysis
Dependency on Single Tool limits detection scope. Different analyzers find different issues:
# Incomplete: RuboCop only
# Misses: Security vulnerabilities, code smells, performance issues
# Comprehensive: Multiple tools
- rubocop: Style, syntax, basic security
- reek: Design smells
- brakeman: Security vulnerabilities
- fasterer: Performance patterns
- bundle-audit: Dependency vulnerabilities
Effective static analysis requires orchestrating multiple tools, each specialized for different detection capabilities.
Reference
Analysis Tool Comparison
| Tool | Primary Focus | Language Support | Auto-fix | Configuration Complexity |
|---|---|---|---|---|
| RuboCop | Style and correctness | Ruby | Extensive | Medium |
| Reek | Code smells | Ruby | None | Low |
| Brakeman | Security | Ruby/Rails | None | Low |
| Bundler Audit | Dependencies | Gemfile | None | Minimal |
| Fasterer | Performance | Ruby | None | Minimal |
| Debride | Dead code | Ruby | None | Minimal |
Common Vulnerability Categories
| Vulnerability | Detection Method | Severity | Auto-fix Available |
|---|---|---|---|
| SQL Injection | Data flow analysis | Critical | No |
| XSS | Output encoding check | High | No |
| Command Injection | System call analysis | Critical | No |
| Path Traversal | File operation analysis | High | No |
| Mass Assignment | Parameter analysis | Medium | No |
| Weak Crypto | API pattern matching | Medium | Sometimes |
| CSRF | Protection verification | High | No |
| Insecure Cookies | Configuration check | Medium | No |
Integration Points
| Integration | Feedback Speed | Thoroughness | Developer Impact |
|---|---|---|---|
| IDE | Real-time | Light | Minimal |
| Pre-commit | Seconds | Medium | Medium |
| Pull Request | Minutes | Comprehensive | Low |
| Continuous | Varies | Comprehensive | None |
RuboCop Department Overview
| Department | Purpose | Example Cops |
|---|---|---|
| Style | Code style conventions | StringLiterals, TrailingComma, HashSyntax |
| Layout | Code formatting | LineLength, IndentationWidth, EmptyLines |
| Lint | Error-prone patterns | UnusedVariable, UselessAssignment, Void |
| Metrics | Complexity measures | MethodLength, CyclomaticComplexity, ClassLength |
| Naming | Identifier conventions | MethodName, VariableName, ClassAndModuleCamelCase |
| Security | Security vulnerabilities | YAMLLoad, JSONLoad, Eval |
Analysis Metrics
| Metric | Measures | Threshold Guidance |
|---|---|---|
| Cyclomatic Complexity | Decision paths | Methods: 10, Classes: 50 |
| Method Length | Lines per method | 20 lines |
| Class Length | Lines per class | 100 lines |
| Parameter Count | Method parameters | 4 parameters |
| ABC Metric | Assignments, branches, calls | 15 |
| Perceived Complexity | Nested control flow | 8 |
Configuration Template
# .rubocop.yml - Starter configuration
AllCops:
NewCops: enable
TargetRubyVersion: 3.2
Exclude:
- 'vendor/**/*'
- 'db/schema.rb'
- 'bin/**/*'
- 'node_modules/**/*'
Style/Documentation:
Enabled: false
Metrics/MethodLength:
Max: 20
CountComments: false
Metrics/BlockLength:
Exclude:
- 'spec/**/*'
- 'config/routes.rb'
Layout/LineLength:
Max: 120
AllowedPatterns:
- '\s+# '
Naming/VariableNumber:
EnforcedStyle: normalcase
Brakeman Scan Options
| Option | Purpose | Usage |
|---|---|---|
| --confidence-level | Filter by confidence | 1 (high only), 2 (high/medium), 3 (all) |
| --ignore-config | Suppression file | Path to brakeman.ignore |
| --quiet | Reduce output | Flag for CI environments |
| --format | Output format | json, html, tabs, csv |
| --skip-files | Exclude files | Comma-separated patterns |