Prerelease cleanup (#46)

* feat: Add const_bound_vars tracking to prevent false positives in ownership checks

* feat: Introduce field interner and typed bounded vars for enhanced type tracking

* feat: Add typed_call_receivers and typed_bounded_dto_fields for enhanced type tracking

* feat: Centralize method name extraction with bare_method_name helper

* feat: Implement Phase-6 hierarchy fan-out for runtime virtual dispatch

* feat: Enhance C++ taint tracking with additional container operations and inline method resolution

* feat: Introduce field-sensitive points-to analysis for enhanced resource tracking

* feat: Implement Pointer-Phase 6 subscript handling for enhanced container analysis

* test: Add comprehensive tests for JavaScript control flow constructs and lattice operations

* docs: Update advanced analysis documentation with field-sensitive points-to and hierarchy fan-out details

* test: Add comprehensive tests for lattice algebra laws and SSA edge cases

* feat: Add destructured session user handling and safe user ID access patterns

* feat: Implement row-population reverse-walk for enhanced authorization checks

* feat: Enhance authorization checks with local alias chain for self-actor types

* feat: Introduce ActiveRecord query safety checks and enhance snippet extraction

* feat: Implement chained method call inner-gate rebinding for SSRF prevention

* feat: Add observability and error modules, enhance debug functionality, and implement theme context

* feat: Remove Auth Analysis page and update navigation to redirect to Explorer

* feat: Optimize SSA lowering by sharing results between taint engine and artifact extractor

* feat: Optimize SSA lowering by sharing results between taint engine and artifact extractor

* feat: Reset path-safe-suppressed spans before lowering to maintain analysis integrity

* fix(ssa): ungate debug_assert_bfs_ordering for release-tests build

The helper at src/ssa/lower.rs was gated `#[cfg(debug_assertions)]` while
the unit test at the bottom of the file was gated only `#[cfg(test)]`.
Since `cfg(test)` is set in release builds with `--tests` but
`cfg(debug_assertions)` is not, `cargo build --release --tests` failed
with E0425. Removing the gate fixes the build; the body is `debug_assert!`
only, so the helper is free in release. Also drop the gate at the call
site to avoid a `dead_code` warning when the lib is built without
`--tests`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(closure-capture): flip JS/TS fixtures to required-finding

The JS and TS closure-capture fixtures pinned the old broken behaviour
via `forbidden_findings: [{ "id_prefix": "taint-" }]`. The engine now
correctly traces taint through the closure boundary (env source captured
by an arrow function, sunk via `child_process.exec` inside the body), so
the formerly-forbidden finding is a true positive.

Match the Python sibling's shape — `required_findings` with
`id_prefix` + `min_count` plus a small `noise_budget` — and rewrite the
companion READMEs and the phase8_fragility_tests doc-comments from
"known gap" to "regression guard".

Verified:
- cargo test --release --test phase8_fragility_tests → 8/8 pass
- cargo test --release --lib bfs_assertion → pass
- corpus benchmark F1 = 0.9976 (TP=205, FP=1, FN=0) — unchanged

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: Add OWASP mapping and baseline mutation hooks for enhanced security analysis

* feat: Introduce health module and enhance health score computation with calibration tests

* feat: Add expectations configuration and cleanup .gitignore for log files

* feat: Implement theme selection and enhance settings panel for triage sync

* feat: Suppress false positives for strcpy calls with literal sources in AST

* feat: Update analyse_function_ssa to return body CFG for accurate analysis

* feat: Add bug report and feature request templates for improved issue tracking

* feat: removed dev scripts

* feat: update README.md for clarity and consistency in fixture descriptions

* feat: removed dev docs

* feat: clean up error handling and UI elements for improved user experience

* feat: adjust button sizes in HeaderBar for better UI consistency

* feat: enhance taint analysis with additional context for sanitizer and taint findings

* cargo fmt

* prettier

* refactor: simplify conditional checks and improve code readability in AST and screenshot capture scripts

* feat: add script to frame PNG screenshots with brand gradient

* feat: add fuzzing support with new targets and CI workflows

* refactor: streamline match expressions and improve formatting in CLI and output handling

* feat: enhance configuration display with detailed output options

* feat: stage demo configuration for improved CLI screenshot output

* feat: expose merge_configs function for user-configurable settings

* refactor: simplify code structure and improve readability in config handling

* refactor: improve descriptions for vulnerability patterns in various languages

* feat: update MIT License section with additional usage details and copyright information

* feat: update screenshots

* refactor: update build process and paths for frontend assets

* feat: add cross-file taint fuzzing target and supporting dictionary

* refactor: clean up formatting and comments in fuzz configuration and example files

* refactor: remove outdated comments and clean up CI configuration files

* chore: update changelog dates and improve formatting in documentation

* refactor: update Cargo.toml and CI configuration for improved packaging and build process

* refactor: enhance quote-stripping logic to prevent panics and add regression tests

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eli Peter 2026-04-29 00:58:38 -04:00 committed by GitHub
parent 79c29b394d
commit 82f18184b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
348 changed files with 48731 additions and 2925 deletions

View file

@ -32,6 +32,22 @@ impl Commands {
pub fn is_serve(&self) -> bool {
matches!(self, Commands::Serve { .. })
}
/// Pure read-only / informational commands that should run without the
/// "note: Using …" config preamble or the trailing "Finished in …"
/// timing line. These commands' output is often piped or grepped; the
/// surrounding chrome is noise.
pub fn is_informational(&self) -> bool {
match self {
Commands::Scan { explain_engine, .. } => *explain_engine,
Commands::List { .. } => true,
Commands::Config { action } => {
matches!(action, ConfigAction::Show { .. } | ConfigAction::Path)
}
Commands::Index { action } => matches!(action, IndexAction::Status { .. }),
_ => false,
}
}
}
/// Output format for scan results.
@ -167,11 +183,11 @@ pub enum Commands {
path: String,
/// Index mode: auto (default), off (no index), rebuild (force rebuild)
#[arg(long, value_enum, default_value_t = IndexMode::Auto)]
#[arg(long, value_enum, default_value_t = IndexMode::Auto, help_heading = "Analysis")]
index: IndexMode,
/// Output format (defaults to config's default_format, or "console")
#[arg(short, long, value_enum)]
#[arg(short, long, value_enum, help_heading = "Output")]
format: Option<OutputFormat>,
/// Severity filter expression: HIGH, HIGH,MEDIUM, or >=MEDIUM
@ -179,30 +195,30 @@ pub enum Commands {
/// Filters findings AFTER all severity normalization (e.g. nonprod
/// downgrades). Only findings matching the expression are emitted.
/// Case-insensitive. Shell-quote expressions containing ">".
#[arg(long)]
#[arg(long, help_heading = "Output")]
severity: Option<String>,
/// Analysis mode: full (default), ast, cfg, taint
#[arg(long, value_enum, default_value_t = ScanMode::Full)]
#[arg(long, value_enum, default_value_t = ScanMode::Full, help_heading = "Analysis")]
mode: ScanMode,
/// Named scan profile to apply (e.g. quick, full, ci, taint_only, conservative_large_repo)
///
/// Profiles override scan-related config settings. CLI flags still
/// take precedence over profile values.
#[arg(long)]
#[arg(long, help_heading = "Analysis")]
profile: Option<String>,
/// Engine-depth shortcut: fast, balanced, or deep. Sets the full
/// stack of analysis toggles at once; individual engine flags still
/// override this after application.
#[arg(long, value_enum)]
#[arg(long, value_enum, help_heading = "Analysis")]
engine_profile: Option<EngineProfile>,
/// Print the effective engine configuration and exit without
/// scanning. Useful for understanding how CLI flags and config
/// values resolve together.
#[arg(long)]
#[arg(long, help_heading = "Analysis")]
explain_engine: bool,
/// Scan all targets (alias for --mode full)
@ -213,57 +229,57 @@ pub enum Commands {
///
/// By default, findings in non-production paths are downgraded by one
/// severity tier. This flag preserves original severity.
#[arg(long, alias = "include-nonprod")]
#[arg(long, alias = "include-nonprod", help_heading = "Output")]
keep_nonprod_severity: bool,
/// Suppress all human-readable status output
#[arg(long)]
#[arg(long, help_heading = "Output")]
quiet: bool,
/// Exit with code 1 if any finding meets or exceeds this severity
///
/// Useful for CI gating. Example: --fail-on HIGH
#[arg(long)]
#[arg(long, help_heading = "Output")]
fail_on: Option<String>,
/// Disable state-model analysis (resource lifecycle, auth state)
#[arg(long)]
#[arg(long, help_heading = "Analysis")]
no_state: bool,
/// Disable attack-surface ranking (findings are sorted by exploitability by default)
#[arg(long)]
#[arg(long, help_heading = "Output")]
no_rank: bool,
/// Show inline-suppressed findings (dimmed, tagged [SUPPRESSED])
#[arg(long)]
#[arg(long, help_heading = "Output")]
show_suppressed: bool,
/// Show all findings: disables category filtering, rollups, and LOW budgets
#[arg(long = "all")]
#[arg(long = "all", help_heading = "Output")]
show_all: bool,
/// Include Quality findings (excluded by default)
#[arg(long)]
#[arg(long, help_heading = "Output")]
include_quality: bool,
/// Maximum total LOW findings to show
#[arg(long, default_value_t = 20)]
#[arg(long, default_value_t = 20, help_heading = "Output")]
max_low: u32,
/// Maximum LOW findings per file
#[arg(long, default_value_t = 1)]
#[arg(long, default_value_t = 1, help_heading = "Output")]
max_low_per_file: u32,
/// Maximum LOW findings per rule
#[arg(long, default_value_t = 10)]
#[arg(long, default_value_t = 10, help_heading = "Output")]
max_low_per_rule: u32,
/// Number of example locations in rollup findings
#[arg(long, default_value_t = 5)]
#[arg(long, default_value_t = 5, help_heading = "Output")]
rollup_examples: u32,
/// Show all instances for a specific rule (bypasses rollup for that rule)
#[arg(long)]
#[arg(long, help_heading = "Output")]
show_instances: Option<String>,
/// Minimum attack-surface score to include in output
@ -271,89 +287,97 @@ pub enum Commands {
/// Findings with a rank score below this threshold are suppressed.
/// Requires ranking to be enabled (has no effect with --no-rank).
/// Example: --min-score 50
#[arg(long)]
#[arg(long, help_heading = "Output")]
min_score: Option<u32>,
/// Minimum confidence level to include in output
///
/// Values: low, medium, high. Findings below this level are dropped.
/// JSON/SARIF include all unless filtered.
#[arg(long)]
#[arg(long, help_heading = "Output")]
min_confidence: Option<String>,
/// Drop findings emitted from capped / widened / bailed analysis
///
/// Suppresses any finding whose engine provenance notes indicate
/// over-reporting (predicate/path widening) or analysis bail
/// (SSA lowering failure, parse timeout). Under-report notes
/// where the emitted finding is still a real flow but the
/// result set is a lower bound are kept.
/// (SSA lowering failure, parse timeout). Under-report notes
/// (where the emitted finding is still a real flow but the
/// result set is a lower bound) are kept.
///
/// Intended for strict CI gates where a finding from non-converged
/// analysis is worse than no finding. Applied after ranking and
/// before the `max_results` truncation.
#[arg(long)]
#[arg(long, help_heading = "Output")]
require_converged: bool,
// ── Analysis engine toggles (override [analysis.engine] config) ───
/// Enable path-constraint solving (default: on)
#[arg(long, overrides_with = "no_constraint_solving")]
#[arg(
long,
overrides_with = "no_constraint_solving",
help_heading = "Engine"
)]
constraint_solving: bool,
/// Disable path-constraint solving
#[arg(long, overrides_with = "constraint_solving")]
#[arg(long, overrides_with = "constraint_solving", help_heading = "Engine")]
no_constraint_solving: bool,
/// Enable abstract interpretation (default: on)
#[arg(long, overrides_with = "no_abstract_interp")]
#[arg(long, overrides_with = "no_abstract_interp", help_heading = "Engine")]
abstract_interp: bool,
/// Disable abstract interpretation
#[arg(long, overrides_with = "abstract_interp")]
#[arg(long, overrides_with = "abstract_interp", help_heading = "Engine")]
no_abstract_interp: bool,
/// Enable k=1 context-sensitive callee inlining (default: on)
#[arg(long, overrides_with = "no_context_sensitive")]
#[arg(long, overrides_with = "no_context_sensitive", help_heading = "Engine")]
context_sensitive: bool,
/// Disable context-sensitive callee inlining
#[arg(long, overrides_with = "context_sensitive")]
#[arg(long, overrides_with = "context_sensitive", help_heading = "Engine")]
no_context_sensitive: bool,
/// Enable the symex pipeline (default: on)
#[arg(long, overrides_with = "no_symex")]
#[arg(long, overrides_with = "no_symex", help_heading = "Symex")]
symex: bool,
/// Disable the symex pipeline entirely
#[arg(long, overrides_with = "symex")]
#[arg(long, overrides_with = "symex", help_heading = "Symex")]
no_symex: bool,
/// Enable cross-file symbolic body execution (default: on)
#[arg(long, overrides_with = "no_cross_file_symex")]
#[arg(long, overrides_with = "no_cross_file_symex", help_heading = "Symex")]
cross_file_symex: bool,
/// Disable cross-file symbolic body execution
#[arg(long, overrides_with = "cross_file_symex")]
#[arg(long, overrides_with = "cross_file_symex", help_heading = "Symex")]
no_cross_file_symex: bool,
/// Enable interprocedural symex frame stack (default: on)
#[arg(long, overrides_with = "no_symex_interproc")]
#[arg(long, overrides_with = "no_symex_interproc", help_heading = "Symex")]
symex_interproc: bool,
/// Disable interprocedural symex
#[arg(long, overrides_with = "symex_interproc")]
#[arg(long, overrides_with = "symex_interproc", help_heading = "Symex")]
no_symex_interproc: bool,
/// Enable SMT solver backend when nyx is built with the `smt` feature (default: on)
#[arg(long, overrides_with = "no_smt")]
#[arg(long, overrides_with = "no_smt", help_heading = "Symex")]
smt: bool,
/// Disable SMT solver backend
#[arg(long, overrides_with = "smt")]
#[arg(long, overrides_with = "smt", help_heading = "Symex")]
no_smt: bool,
/// Enable demand-driven backwards analysis (default: off)
#[arg(long, overrides_with = "no_backwards_analysis")]
#[arg(
long,
overrides_with = "no_backwards_analysis",
help_heading = "Engine"
)]
backwards_analysis: bool,
/// Disable demand-driven backwards analysis
#[arg(long, overrides_with = "backwards_analysis")]
#[arg(long, overrides_with = "backwards_analysis", help_heading = "Engine")]
no_backwards_analysis: bool,
/// Override per-file tree-sitter parse timeout (ms). 0 disables the cap.
#[arg(long)]
#[arg(long, help_heading = "Limits")]
parse_timeout_ms: Option<u64>,
/// Maximum taint origins retained per lattice value (default: 32).
@ -363,7 +387,7 @@ pub enum Commands {
/// `OriginsTruncated` engine note is recorded on affected findings.
/// Raise for very wide codebases where truncation is observed;
/// lower only when lattice width is a measured bottleneck.
#[arg(long)]
#[arg(long, help_heading = "Limits")]
max_origins: Option<u32>,
/// Maximum abstract heap objects retained per points-to set (default: 32).
@ -373,7 +397,7 @@ pub enum Commands {
/// `PointsToTruncated` engine note is recorded on affected findings.
/// Raise for factory-heavy codebases where truncation is observed;
/// lower only when points-to width is a measured bottleneck.
#[arg(long)]
#[arg(long, help_heading = "Limits")]
max_pointsto: Option<u32>,
// ── Deprecated aliases (hidden) ─────────────────────────────────
@ -449,8 +473,15 @@ pub enum Commands {
#[derive(Subcommand)]
pub enum ConfigAction {
/// Print effective merged configuration as TOML
Show,
/// Print configuration as TOML. By default shows only the values
/// that differ from built-in defaults. Pass `--all` for the full
/// effective configuration.
Show {
/// Print the full effective configuration instead of just
/// the user's overrides.
#[arg(long)]
all: bool,
},
/// Print configuration directory path
Path,