14 KiB
description
| description |
|---|
| Review Sinatra code for security issues, performance problems, route conflicts, and framework best practices |
Sinatra Review Command
Performs comprehensive code review of Sinatra applications, identifying security vulnerabilities, performance issues, routing conflicts, and deviations from best practices.
Arguments
- $1: path (optional) - Path to review (defaults to current directory)
Usage Examples
# Review current directory
/sinatra-review
# Review specific directory
/sinatra-review /path/to/sinatra-app
# Review specific file
/sinatra-review app/controllers/users_controller.rb
Workflow
Step 1: Scan and Identify Application Files
Discovery Phase:
- Locate
config.ruto identify Rack application - Find Sinatra application files (controllers, routes)
- Identify application structure (classic vs modular)
- Scan for middleware configuration
- Locate view templates and helpers
- Find configuration files
- Identify database and model files
File Patterns to Search:
# Application files
*.rb files inheriting from Sinatra::Base
config.ru
app.rb (classic style)
app/controllers/*.rb
lib/**/*.rb
# View templates
views/**/*.erb
views/**/*.haml
views/**/*.slim
# Configuration
config/*.rb
Gemfile
.env files
Step 2: Analyze Route Definitions
Route Conflict Detection:
Check for:
- Duplicate routes with same path and HTTP method
- Overlapping routes where order matters (specific before generic)
- Missing route constraints leading to ambiguous matching
- Wildcard route conflicts
Examples of Issues:
# ISSUE: Route order conflict
get '/users/new' do
# Never reached because of wildcard below
end
get '/users/:id' do
# This catches /users/new
end
# FIX: Specific routes before wildcards
get '/users/new' do
# Now reached first
end
get '/users/:id' do
# Only catches other IDs
end
# ISSUE: Duplicate routes
get '/api/users' do
# First definition
end
get '/api/users' do
# Overwrites first - only this runs
end
# ISSUE: Missing validation
get '/users/:id' do
user = User.find(params[:id]) # What if id is not numeric?
end
# FIX: Add validation
get '/users/:id', id: /\d+/ do
user = User.find(params[:id])
end
Route Analysis Report:
Route Analysis:
Total routes: 25
GET: 15, POST: 5, PUT: 3, DELETE: 2
⚠ Warnings:
- Route order issue in app/controllers/users_controller.rb:15
GET /users/:id should be after GET /users/new
- Missing parameter validation in app/controllers/posts_controller.rb:32
Route GET /posts/:id should validate :id is numeric
Step 3: Security Analysis
Security Checklist:
1. CSRF Protection:
# CHECK: Is CSRF protection enabled?
use Rack::Protection
# or
use Rack::Protection::AuthenticityToken
# ISSUE: Missing CSRF for POST/PUT/DELETE
post '/users' do
User.create(params[:user]) # Vulnerable to CSRF
end
# FIX: Ensure Rack::Protection is enabled
2. XSS Prevention:
# CHECK: Are templates auto-escaping HTML?
# ERB: Use <%= %> (escapes) not <%== %> (raw)
# ISSUE: Raw user input in template
<div><%== @user.bio %></div>
# FIX: Escape user input
<div><%= @user.bio %></div>
# CHECK: JSON responses properly encoded
# ISSUE: Manual JSON creation
get '/api/users' do
"{ \"name\": \"#{user.name}\" }" # XSS if name contains quotes
end
# FIX: Use JSON library
get '/api/users' do
json({ name: user.name })
end
3. SQL Injection:
# ISSUE: String interpolation in queries
DB["SELECT * FROM users WHERE email = '#{params[:email]}'"]
# FIX: Use parameterized queries
DB["SELECT * FROM users WHERE email = ?", params[:email]]
# ISSUE: Unsafe ActiveRecord
User.where("email = '#{params[:email]}'")
# FIX: Use hash conditions
User.where(email: params[:email])
4. Authentication & Authorization:
# CHECK: Protected routes have authentication
# ISSUE: Admin route without auth check
delete '/users/:id' do
User.find(params[:id]).destroy # No auth check!
end
# FIX: Add authentication
before '/admin/*' do
halt 401 unless current_user&.admin?
end
# CHECK: Session security
# ISSUE: Weak session configuration
use Rack::Session::Cookie, secret: 'easy'
# FIX: Strong secret and secure flags
use Rack::Session::Cookie,
secret: ENV['SESSION_SECRET'], # Long random string
same_site: :strict,
httponly: true,
secure: production?
5. Mass Assignment:
# ISSUE: Accepting all params
User.create(params)
# FIX: Whitelist allowed attributes
def user_params
params.slice(:name, :email, :bio)
end
User.create(user_params)
6. File Upload Security:
# ISSUE: Unrestricted file uploads
post '/upload' do
File.write("uploads/#{params[:file][:filename]}", params[:file][:tempfile].read)
end
# FIX: Validate file type and sanitize filename
post '/upload' do
file = params[:file]
# Validate content type
halt 400 unless ['image/jpeg', 'image/png'].include?(file[:type])
# Sanitize filename
filename = File.basename(file[:filename]).gsub(/[^a-zA-Z0-9\._-]/, '')
# Save with random name
secure_name = "#{SecureRandom.hex}-#{filename}"
File.write("uploads/#{secure_name}", file[:tempfile].read)
end
7. Information Disclosure:
# ISSUE: Detailed error messages in production
configure :production do
set :show_exceptions, true # Exposes stack traces
end
# FIX: Hide errors in production
configure :production do
set :show_exceptions, false
set :dump_errors, false
end
error do
log_error(env['sinatra.error'])
json({ error: 'Internal server error' }, 500)
end
Security Report:
Security Analysis:
✓ CSRF protection enabled (Rack::Protection)
✓ Session configured securely
⚠ Potential Issues:
- SQL injection risk in app/models/user.rb:45
- Raw HTML output in views/profile.erb:12
- Missing authentication check in app/controllers/admin_controller.rb:23
- Weak session secret detected
Critical: 1
High: 2
Medium: 3
Low: 2
Step 4: Review Middleware Configuration
Middleware Analysis:
Check for:
- Missing essential middleware (Protection, CommonLogger)
- Incorrect ordering (e.g., session after auth)
- Performance issues (e.g., no compression)
- Security middleware properly configured
Common Issues:
# ISSUE: Missing compression
# FIX: Add Rack::Deflater
use Rack::Deflater
# ISSUE: Session middleware after authentication
use TokenAuth
use Rack::Session::Cookie # Session needed by auth!
# FIX: Session before authentication
use Rack::Session::Cookie
use TokenAuth
# ISSUE: No security headers
# FIX: Add Rack::Protection
use Rack::Protection, except: [:session_hijacking]
# ISSUE: Static file serving after application
run MyApp
use Rack::Static # Never reached!
# FIX: Static before application
use Rack::Static, urls: ['/css', '/js'], root: 'public'
run MyApp
Middleware Report:
Middleware Configuration:
✓ Rack::CommonLogger (logging)
✓ Rack::Session::Cookie (sessions)
✓ Rack::Protection (security)
⚠ Warnings:
- Missing Rack::Deflater (compression)
- Middleware order issue: Session should be before CustomAuth
- Consider adding Rack::Attack for rate limiting
Step 5: Performance Assessment
Performance Patterns to Check:
1. Database Query Optimization:
# ISSUE: N+1 queries
get '/users' do
users = User.all
users.map { |u| { name: u.name, posts: u.posts.count } }
# Queries DB for each user's posts
end
# FIX: Eager load or use counter cache
get '/users' do
users = User.eager(:posts).all
users.map { |u| { name: u.name, posts: u.posts.count } }
end
# ISSUE: Loading entire collection
get '/users' do
json User.all.map(&:to_hash) # Load all users in memory
end
# FIX: Paginate
get '/users' do
page = params[:page]&.to_i || 1
per_page = 50
users = User.limit(per_page).offset((page - 1) * per_page)
json users.map(&:to_hash)
end
2. Caching Opportunities:
# ISSUE: Expensive operation on every request
get '/stats' do
json calculate_expensive_stats # Takes 2 seconds
end
# FIX: Add caching
get '/stats' do
stats = cache.fetch('stats', expires_in: 300) do
calculate_expensive_stats
end
json stats
end
# ISSUE: No HTTP caching headers
get '/public/data' do
json PublicData.all
end
# FIX: Add cache control
get '/public/data' do
cache_control :public, max_age: 3600
json PublicData.all
end
3. Response Optimization:
# ISSUE: Rendering large response synchronously
get '/large-export' do
csv = generate_large_csv # Blocks for 30 seconds
send_file csv
end
# FIX: Stream or queue as background job
get '/large-export' do
stream do |out|
CSV.generate(out) do |csv|
User.find_each do |user|
csv << user.to_csv_row
end
end
end
end
Performance Report:
Performance Analysis:
⚠ Issues Detected:
- Potential N+1 query in app/controllers/users_controller.rb:42
- Missing pagination in GET /api/posts (returns all records)
- No caching headers on GET /api/public/data
- Expensive operation in GET /stats without caching
Recommendations:
- Add database query optimization (eager loading)
- Implement pagination for collection endpoints
- Add HTTP caching headers for static content
- Consider Redis caching for expensive operations
Step 6: Error Handling Review
Error Handling Patterns:
# ISSUE: No error handlers defined
get '/users/:id' do
User.find(params[:id]) # Raises if not found, shows stack trace
end
# FIX: Add error handlers
error ActiveRecord::RecordNotFound do
json({ error: 'Not found' }, 404)
end
error 404 do
json({ error: 'Endpoint not found' }, 404)
end
error 500 do
json({ error: 'Internal server error' }, 500)
end
# ISSUE: Not handling exceptions in routes
post '/users' do
User.create!(params) # Raises on validation error
end
# FIX: Handle exceptions
post '/users' do
user = User.create(params)
if user.persisted?
json(user.to_hash, 201)
else
json({ errors: user.errors }, 422)
end
end
Step 7: Testing Coverage
Test Analysis:
Check for:
- Test files exist
- Route coverage
- Error case testing
- Integration vs unit tests
- Test quality and patterns
Report:
Testing Analysis:
Framework: RSpec
Total specs: 45
Coverage: 78%
⚠ Missing Tests:
- No tests for POST /api/users
- Error cases not tested in app/controllers/posts_controller.rb
- Missing integration tests for authentication flow
Recommendations:
- Add tests for all POST/PUT/DELETE routes
- Test error scenarios (404, 422, 500)
- Increase coverage to 90%+
Step 8: Generate Comprehensive Report
Final Report Structure:
================================================================================
SINATRA CODE REVIEW REPORT
================================================================================
Project: my-sinatra-app
Path: /path/to/app
Date: 2024-01-15
Reviewer: Sinatra Review Tool
--------------------------------------------------------------------------------
SUMMARY
--------------------------------------------------------------------------------
Total Issues: 15
Critical: 2
High: 4
Medium: 6
Low: 3
Categories:
Security: 5 issues
Performance: 4 issues
Best Practices: 6 issues
--------------------------------------------------------------------------------
CRITICAL ISSUES
--------------------------------------------------------------------------------
1. SQL Injection Vulnerability
Location: app/models/user.rb:45
Severity: Critical
Issue:
DB["SELECT * FROM users WHERE email = '#{email}'"]
Fix:
DB["SELECT * FROM users WHERE email = ?", email]
Impact: Attacker can execute arbitrary SQL queries
2. Missing Authentication on Admin Route
Location: app/controllers/admin_controller.rb:23
Severity: Critical
Issue:
delete '/users/:id' do
User.find(params[:id]).destroy
end
Fix:
before '/admin/*' do
authenticate_admin!
end
Impact: Unauthorized users can delete records
--------------------------------------------------------------------------------
HIGH PRIORITY ISSUES
--------------------------------------------------------------------------------
[List high priority issues...]
--------------------------------------------------------------------------------
RECOMMENDATIONS
--------------------------------------------------------------------------------
Security:
- Enable Rack::Protection::AuthenticityToken for CSRF
- Rotate session secret to strong random value
- Implement rate limiting with Rack::Attack
- Add Content-Security-Policy headers
Performance:
- Add Rack::Deflater for response compression
- Implement caching strategy (Redis or Memcached)
- Add pagination to collection endpoints
- Optimize database queries (N+1 issues)
Testing:
- Increase test coverage to 90%+
- Add integration tests for critical flows
- Test error scenarios
- Add security-focused tests
Best Practices:
- Extract business logic to service objects
- Use helpers for repeated code
- Implement proper error handling
- Add API documentation
--------------------------------------------------------------------------------
DETAILED FINDINGS
--------------------------------------------------------------------------------
[Full list of all issues with locations, descriptions, and fixes]
================================================================================
END REPORT
================================================================================
Review Categories
Security
- CSRF protection
- XSS prevention
- SQL injection
- Authentication/Authorization
- Session security
- Mass assignment
- File upload security
- Information disclosure
- Secure headers
Performance
- Database query optimization
- N+1 queries
- Caching opportunities
- Response optimization
- Static asset handling
- Connection pooling
Best Practices
- Route organization
- Error handling
- Code organization
- Helper usage
- Configuration management
- Logging
- Documentation
Testing
- Test coverage
- Test quality
- Missing tests
- Test organization
Output Format
- Console output with colored severity indicators
- Detailed report with file locations and line numbers
- Suggested fixes with code examples
- Priority-sorted issue list
- Summary statistics
Error Handling
- Handle non-Sinatra Ruby applications gracefully
- Report when application structure cannot be determined
- Skip non-readable files
- Handle parse errors in Ruby files