Ragex. Analysis. BusinessLogic
(Ragex v0.14.1)
View Source
Business logic analysis using Metastatic analyzers.
Provides unified access to 33 language-agnostic business logic analyzers that detect common anti-patterns, security vulnerabilities, and issues across multiple languages.
Semantic Analysis with OpKind
Many analyzers leverage Metastatic's OpKind semantic metadata system for accurate detection. OpKind tags function calls with their semantic meaning:
- Domain:
:db,:http,:auth,:cache,:queue,:file,:external_api - Operation:
:retrieve,:create,:update,:delete,:query, etc. - Framework:
:ecto,:django,:activerecord,:requests, etc.
Location Information
Note: Business logic analyzers operate at the MetaAST (M2) abstraction level, which intentionally abstracts away language-specific details like line numbers. This is what makes them language-agnostic. As a result, precise line/column location information is typically not available. Issues will include file paths and function context when available.
Analyzers
Tier 1: Pure MetaAST (Language-Agnostic)
- CallbackHell - Detects deeply nested conditionals (M2.1 Core)
- MissingErrorHandling - Pattern matching without error case (M2.2 Extended)
- SilentErrorCase - Conditionals with only success path (M2.1 Core)
- SwallowingException - Exception handling without logging (M2.2 Extended)
- HardcodedValue - Hardcoded URLs/IPs in literals (M2.1 Core)
- NPlusOneQuery - DB queries in collection operations (M2.2 Extended)
- InefficientFilter - Fetch-all then filter pattern (M2.2 Extended)
- UnmanagedTask - Unsupervised async operations (M2.2 Extended)
- TelemetryInRecursiveFunction - Metrics in recursive functions (M2.1 Core)
Tier 2: Function Name Heuristics
- MissingTelemetryForExternalHttp - HTTP calls without telemetry
- SyncOverAsync - Blocking operations in async contexts
- DirectStructUpdate - Struct updates bypassing validation
- MissingHandleAsync - Unmonitored async operations
Tier 3: Naming Conventions
- BlockingInPlug - Blocking I/O in middleware
- MissingTelemetryInAuthPlug - Auth checks without audit logging
- MissingTelemetryInLiveviewMount - Component lifecycle without metrics
- MissingTelemetryInObanWorker - Background jobs without telemetry
Tier 4: Content Analysis
- MissingPreload - Database queries without eager loading
- InlineJavascript - Inline scripts in strings (XSS risk)
- MissingThrottle - Expensive operations without rate limiting
Tier 5: Security (CWE-based)
- SQLInjection - SQL query string concatenation (CWE-89)
- XSSVulnerability - Cross-site scripting risks (CWE-79)
- SSRFVulnerability - Server-side request forgery (CWE-918)
- PathTraversal - Directory traversal attacks (CWE-22)
- InsecureDirectObjectReference - IDOR vulnerabilities (CWE-639)
- MissingAuthentication - Unprotected endpoints (CWE-306)
- MissingAuthorization - Missing access control (CWE-862)
- IncorrectAuthorization - Flawed access control (CWE-863)
- MissingCSRFProtection - CSRF vulnerabilities (CWE-352)
- SensitiveDataExposure - Data leaks in logs/responses (CWE-200)
- UnrestrictedFileUpload - Unsafe file uploads (CWE-434)
- ImproperInputValidation - Input validation issues (CWE-20)
Tier 6: Race Conditions
- TOCTOU - Time-of-check-time-of-use vulnerabilities (CWE-367)
Tier 7: Refactoring
- ImperativeStatusHandling - Imperative status/state management (suggests FSM)
Usage
alias Ragex.Analysis.BusinessLogic
# Analyze single file
{:ok, result} = BusinessLogic.analyze_file("lib/my_module.ex")
# Check for issues
result.has_issues? # => true/false
result.total_issues # => 5
result.critical_count # => 1
# Analyze directory
{:ok, results} = BusinessLogic.analyze_directory("lib/")
# Run specific analyzers
{:ok, result} = BusinessLogic.analyze_file("lib/my_module.ex",
analyzers: [:callback_hell, :missing_error_handling])
# Filter by severity
{:ok, results} = BusinessLogic.analyze_directory("lib/",
min_severity: :high)
# Generate report
report = BusinessLogic.audit_report(results)
Summary
Functions
Analyzes all files in a directory for business logic issues.
Analyzes a single file for business logic issues.
Generates a comprehensive business logic audit report.
Returns the list of available business logic analyzers.
Returns the recommendation for a specific analyzer.
Types
@type analysis_result() :: %{ file: String.t(), language: atom(), issues: [issue()], has_issues?: boolean(), total_issues: non_neg_integer(), critical_count: non_neg_integer(), high_count: non_neg_integer(), medium_count: non_neg_integer(), low_count: non_neg_integer(), info_count: non_neg_integer(), by_analyzer: %{required(atom()) => non_neg_integer()}, timestamp: DateTime.t() }
@type directory_result() :: %{ total_files: non_neg_integer(), files_with_issues: non_neg_integer(), total_issues: non_neg_integer(), by_severity: %{required(atom()) => non_neg_integer()}, by_analyzer: %{required(atom()) => non_neg_integer()}, results: [analysis_result()], summary: String.t() }
@type location() :: %{ line: non_neg_integer() | nil, column: non_neg_integer() | nil, function: String.t() | nil }
Functions
@spec analyze_directory( String.t(), keyword() ) :: {:ok, directory_result()} | {:error, term()}
Analyzes all files in a directory for business logic issues.
Options
:recursive- Recursively analyze subdirectories (default: true):parallel- Use parallel processing (default: true):max_concurrency- Maximum concurrent analyses (default: System.schedulers_online())- Plus all options from
analyze_file/2
Examples
{:ok, results} = BusinessLogic.analyze_directory("lib/")
total_issues = results.total_issues
@spec analyze_file( String.t(), keyword() ) :: {:ok, analysis_result()} | {:error, term()}
Analyzes a single file for business logic issues.
Options
:analyzers- List of analyzer names to run (default: all):language- Explicit language (default: auto-detect):min_severity- Minimum severity to report (default: :info):config- Configuration map for analyzers
Examples
{:ok, result} = BusinessLogic.analyze_file("lib/my_module.ex")
result.has_issues? # => false
{:ok, result} = BusinessLogic.analyze_file("lib/my_module.ex",
analyzers: [:callback_hell, :missing_error_handling],
min_severity: :high)
@spec audit_report([analysis_result()]) :: map()
Generates a comprehensive business logic audit report.
Returns a formatted map with:
- Summary statistics
- Issues grouped by severity
- Issues grouped by analyzer
- Recommendations
Examples
{:ok, results} = BusinessLogic.analyze_directory("lib/")
report = BusinessLogic.audit_report(results.results)
IO.puts(report.summary)
@spec available_analyzers() :: [atom()]
Returns the list of available business logic analyzers.
Examples
iex> Ragex.Analysis.BusinessLogic.available_analyzers()
[:callback_hell, :missing_error_handling, ...]
Returns the recommendation for a specific analyzer.
For security analyzers, includes CWE reference numbers.
Examples
iex> Ragex.Analysis.BusinessLogic.recommendation(:sql_injection)
"CWE-89: Use parameterized queries or Ecto's query DSL..."