fallow 2.86.0 → 2.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "2.86.0",
3
+ "version": "2.87.0",
4
4
  "description": "Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, 96 framework plugins.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -83,13 +83,13 @@
83
83
  "@tanstack/intent": "0.0.41"
84
84
  },
85
85
  "optionalDependencies": {
86
- "@fallow-cli/darwin-arm64": "2.86.0",
87
- "@fallow-cli/darwin-x64": "2.86.0",
88
- "@fallow-cli/linux-x64-gnu": "2.86.0",
89
- "@fallow-cli/linux-arm64-gnu": "2.86.0",
90
- "@fallow-cli/linux-x64-musl": "2.86.0",
91
- "@fallow-cli/linux-arm64-musl": "2.86.0",
92
- "@fallow-cli/win32-arm64-msvc": "2.86.0",
93
- "@fallow-cli/win32-x64-msvc": "2.86.0"
86
+ "@fallow-cli/darwin-arm64": "2.87.0",
87
+ "@fallow-cli/darwin-x64": "2.87.0",
88
+ "@fallow-cli/linux-x64-gnu": "2.87.0",
89
+ "@fallow-cli/linux-arm64-gnu": "2.87.0",
90
+ "@fallow-cli/linux-x64-musl": "2.87.0",
91
+ "@fallow-cli/linux-arm64-musl": "2.87.0",
92
+ "@fallow-cli/win32-arm64-msvc": "2.87.0",
93
+ "@fallow-cli/win32-x64-msvc": "2.87.0"
94
94
  }
95
95
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: fallow
3
- description: Codebase intelligence for JavaScript and TypeScript. Free static layer reports quality, changed-code risk, cleanup opportunities (unused files, exports, types, dependencies), code duplication, circular dependencies, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same health report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode. 114 framework plugins, zero configuration, sub-second static analysis. Use when asked to analyze code health, audit PR risk, find cleanup opportunities or unused code, detect duplicates, check circular dependencies, audit complexity, check architecture boundaries, detect feature flags, surface security candidates, clean up the codebase, auto-fix issues, merge runtime coverage, or run fallow.
3
+ description: Codebase intelligence for JavaScript and TypeScript. Free static layer reports quality, changed-code risk, cleanup opportunities (unused files, exports, types, dependencies), code duplication, circular dependencies, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same health report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode. 118 framework plugins, zero configuration, sub-second static analysis. Use when asked to analyze code health, audit PR risk, find cleanup opportunities or unused code, detect duplicates, check circular dependencies, audit complexity, check architecture boundaries, detect feature flags, surface security candidates, clean up the codebase, auto-fix issues, merge runtime coverage, or run fallow.
4
4
  license: MIT
5
5
  metadata:
6
6
  author: Bart Waardenburg
@@ -10,7 +10,7 @@ metadata:
10
10
 
11
11
  # Fallow: codebase intelligence for JavaScript and TypeScript
12
12
 
13
- Codebase intelligence for JavaScript and TypeScript. The free static layer reports quality, changed-code risk, cleanup opportunities, circular dependencies, code duplication, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same `fallow health` report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode. 114 framework plugins, zero configuration, sub-second static analysis.
13
+ Codebase intelligence for JavaScript and TypeScript. The free static layer reports quality, changed-code risk, cleanup opportunities, circular dependencies, code duplication, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same `fallow health` report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode. 118 framework plugins, zero configuration, sub-second static analysis.
14
14
 
15
15
  ## When to Use
16
16
 
@@ -30,7 +30,7 @@ Codebase intelligence for JavaScript and TypeScript. The free static layer repor
30
30
  - Runtime error analysis or debugging
31
31
  - Type checking (use `tsc` for that)
32
32
  - Linting style or formatting issues (use ESLint, Biome, Prettier)
33
- - Security vulnerability scanning
33
+ - Verified security vulnerability scanning or SAST. `fallow security` surfaces local, deterministic security *candidates* for a downstream agent to verify; it does not prove exploitability. Use Snyk, CodeQL, or Semgrep for verified scanning, and an SCA tool for dependency CVEs.
34
34
  - Bundle size analysis
35
35
  - Projects that are not JavaScript or TypeScript
36
36
 
@@ -75,7 +75,7 @@ cargo install fallow-cli # build from source
75
75
  | `health` | Function complexity analysis (also covers Angular templates as synthetic `<template>` findings: external `.html` files via `templateUrl` AND inline `@Component({ template: \`...\` })` literals; suppress external with `<!-- fallow-ignore-file complexity -->` at the top of the `.html` file, suppress inline with `// fallow-ignore-next-line complexity` directly above the `@Component` decorator) | `--complexity`, `--max-cyclomatic`, `--max-cognitive`, `--max-crap`, `--top`, `--sort`, `--file-scores`, `--hotspots`, `--ownership`, `--ownership-emails`, `--targets`, `--effort`, `--score`, `--min-score`, `--since`, `--min-commits`, `--save-snapshot`, `--trend`, `--coverage-gaps`, `--coverage`, `--coverage-root`, `--runtime-coverage`, `--min-invocations-hot`, `--min-observation-volume`, `--low-traffic-threshold`, `--workspace`, `--changed-workspaces`, `--baseline`, `--save-baseline` |
76
76
  | `audit` | Combined dead-code + complexity + duplication for changed files | `--base`, `--gate`, `--production`, `--production-dead-code`, `--production-health`, `--production-dupes`, `--workspace`, `--changed-workspaces`, `--ci`, `--fail-on-issues`, `--explain`, `--explain-skipped`, `--dead-code-baseline`, `--health-baseline`, `--dupes-baseline`, `--max-crap`, `--coverage`, `--coverage-root`, `--include-entry-exports` |
77
77
  | `flags` | Detect feature flag patterns (env vars, SDK calls, config objects) | `--top` |
78
- | `security` | Surface opt-in local security candidates for verification. First rule: `"use client"` file reaches a non-public `process.env` secret source. Findings are candidates, not confirmed vulnerabilities. | `--format human|json|sarif`, `--changed-since`, `--diff-file`, `--workspace`, `--changed-workspaces`, `--ci`, `--fail-on-issues`, `--sarif-file`, `--summary` |
78
+ | `security` | Surface opt-in local security candidates for agent verification (not confirmed vulnerabilities). Two rule families: the graph rule `client-server-leak` (a `"use client"` file reaching a non-public `process.env` secret) and a data-driven `tainted-sink` catalogue across 9 CWE categories (dangerous-html, command-injection, code-injection, sql-injection, ssrf, path-traversal, open-redirect, weak-crypto, unsafe-deserialization). Conservative non-literal trigger; parameterized SQL not flagged. Rules default off; suppress a file with `// fallow-ignore-file security-sink`; scope categories with `security.categories`. | `--format human|json|sarif`, `--changed-since`, `--diff-file`, `--workspace`, `--changed-workspaces`, `--ci`, `--fail-on-issues`, `--sarif-file`, `--summary` |
79
79
  | `explain` | Explain one issue type without running analysis | `<issue-type>`, `--format json` |
80
80
  | `license` | Manage the local license JWT for continuous/cloud runtime monitoring (activate, status, refresh, deactivate) | `activate --trial --email <addr>`, `activate --from-file`, `activate --stdin`, `status`, `refresh`, `deactivate` |
81
81
  | `telemetry` | Manage opt-in, off-by-default product telemetry (never collects code, paths, or names). Agents must not enable it; only the user may | `status`, `enable`, `disable`, `inspect --example` |
@@ -118,6 +118,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
118
118
  |------|-------------|
119
119
  | `analyze` | Full dead code analysis (unused files/exports/types/dependencies/members + circular dependencies + re-export cycles (barrel files that form a structural loop, silently breaking re-exports) + boundary violations + stale suppressions). Private type leaks are an opt-in API hygiene check via `issue_types: ["private-type-leaks"]`. Set `boundary_violations: true` as a convenience alias for `issue_types: ["boundary-violations"]`. Set `group_by` to `"owner"`, `"directory"`, `"package"`, or `"section"` to partition results. The `section` mode reads GitLab CODEOWNERS `[Section]` headers and emits `owners` metadata per group |
120
120
  | `check_changed` | Incremental analysis of files changed since a git ref |
121
+ | `security_candidates` | Unverified local security candidates, not confirmed vulnerabilities (`fallow security --format json`). Read `security_findings[]` for category, CWE, evidence, and trace; verify trace and evidence before editing code. Supports `root`, `config`, `workspace`, `changed_since`, `changed_workspaces`, `no_cache`, and `threads`; inherits `FALLOW_DIFF_FILE` from the server environment for line-level diff scoping; raise `FALLOW_TIMEOUT_SECS` for large repos. |
121
122
  | `find_dupes` | Code duplication detection. Set `changed_since` to scope to changed files since a git ref. Set `min_occurrences` (≥ 2, default 2) to hide pair-only clones and focus on widespread copy-paste; JSON gains `stats.clone_groups_below_min_occurrences` when the filter hides anything. Each `clone_groups[]` entry carries a stable `fingerprint`, usually `dup:<8hex>` and widened only on rare report collisions; pass it to `trace_clone` to deep-dive that group |
122
123
  | `fix_preview` | Dry-run auto-fix preview |
123
124
  | `fix_apply` | Apply auto-fixes (destructive) |
@@ -234,7 +235,7 @@ fallow list --entry-points --format json --quiet
234
235
  fallow list --plugins --format json --quiet
235
236
  ```
236
237
 
237
- Shows detected entry points and active framework plugins (114 built-in: Next.js, Vite, Ember, Wuchale, Jest, Storybook, Tailwind, PandaCSS, Contentlayer, tap, tsd, etc.).
238
+ Shows detected entry points and active framework plugins (118 built-in: Next.js, Vite, Ember, Wuchale, Jest, Storybook, Tailwind, PandaCSS, Contentlayer, tap, tsd, etc.).
238
239
 
239
240
  ### Production-only analysis
240
241
 
@@ -339,7 +340,7 @@ When `--format json` is active and exit code is 2, errors are emitted as JSON on
339
340
 
340
341
  ## Configuration
341
342
 
342
- Fallow reads config from project root: `.fallowrc.json` > `.fallowrc.jsonc` > `fallow.toml` > `.fallow.toml`. Both `.fallowrc.json` and `.fallowrc.jsonc` accept JSON-with-comments syntax (same parser); the `.jsonc` extension lets editors auto-detect JSONC syntax highlighting. Most projects work with zero configuration thanks to 114 auto-detecting framework plugins.
343
+ Fallow reads config from project root: `.fallowrc.json` > `.fallowrc.jsonc` > `fallow.toml` > `.fallow.toml`. Both `.fallowrc.json` and `.fallowrc.jsonc` accept JSON-with-comments syntax (same parser); the `.jsonc` extension lets editors auto-detect JSONC syntax highlighting. Most projects work with zero configuration thanks to 118 auto-detecting framework plugins.
343
344
 
344
345
  ```jsonc
345
346
  {
@@ -388,7 +389,7 @@ export const deprecatedHelper = () => {};
388
389
  ## Key Gotchas
389
390
 
390
391
  - **`fix --yes` is required** in non-TTY (agent) environments. Without it, `fix` exits with code 2
391
- - **Zero config by default.** 114 framework plugins auto-detect, including Wuchale config, Contentlayer content roots, tap and tsd test entry points. Don't create config unless customization is needed
392
+ - **Zero config by default.** 118 framework plugins auto-detect, including Wuchale config, Contentlayer content roots, tap and tsd test entry points. Don't create config unless customization is needed
392
393
  - **Syntactic analysis only.** No TypeScript compiler, so fully dynamic `import(variable)` is not resolved
393
394
  - **Function overloads are deduplicated.** TypeScript function overload signatures are merged into a single export (not reported as separate unused exports)
394
395
  - **Re-export chains are resolved.** Exports through barrel files are tracked, not falsely flagged
@@ -485,7 +485,7 @@ fallow health --format json --quiet --trend
485
485
  {
486
486
  "kind": "health",
487
487
  "schema_version": 7,
488
- "version": "2.86.0",
488
+ "version": "2.87.0",
489
489
  "elapsed_ms": 32,
490
490
  "summary": {
491
491
  "files_analyzed": 482,
@@ -875,7 +875,7 @@ fallow audit \
875
875
  {
876
876
  "kind": "audit",
877
877
  "schema_version": 7,
878
- "version": "2.86.0",
878
+ "version": "2.87.0",
879
879
  "command": "audit",
880
880
  "verdict": "fail",
881
881
  "changed_files_count": 12,
@@ -948,7 +948,7 @@ fallow flags --format json --quiet --workspace my-package
948
948
  ```json
949
949
  {
950
950
  "schema_version": 7,
951
- "version": "2.86.0",
951
+ "version": "2.87.0",
952
952
  "elapsed_ms": 116,
953
953
  "feature_flags": [],
954
954
  "total_flags": 0
@@ -963,6 +963,22 @@ Surfaces local security candidates for agent or human verification. The first ru
963
963
 
964
964
  Findings are not confirmed vulnerabilities. Use the structural trace to verify whether the value can actually reach client-bundled code. Public env conventions (`NODE_ENV`, `NEXT_PUBLIC_*`, `VITE_*`, `NUXT_PUBLIC_*`, `REACT_APP_*`, `PUBLIC_*`, `GATSBY_*`, `EXPO_PUBLIC_*`, `STORYBOOK_*`) are excluded.
965
965
 
966
+ The second rule family is a data-driven `tainted-sink` catalogue: syntactic dangerous-sink candidates across 9 CWE categories. A candidate fires only when the relevant argument is non-literal, so a fully-literal value (`el.innerHTML = "<b>x</b>"`, `child_process.exec("ls")`) never fires; fallow prefers false-negatives over false-positives.
967
+
968
+ | Category | CWE | Sink |
969
+ |----------|-----|------|
970
+ | `dangerous-html` | 79 | `innerHTML` / `outerHTML` / `insertAdjacentHTML` / `dangerouslySetInnerHTML` |
971
+ | `command-injection` | 78 | `child_process` `exec` / `execSync` / `spawn` / `spawnSync` (provenance-gated to `node:child_process`) |
972
+ | `code-injection` | 94 | `eval` / `vm.runInNewContext` |
973
+ | `sql-injection` | 89 | string concat or interpolated template into `.query()` / `.execute()`, and `sql.raw(...)`. Parameterized `` sql`${x}` `` and the object form `.execute({ sql, args })` are NOT flagged |
974
+ | `ssrf` | 918 | `fetch` / `axios` / `http(s).request` |
975
+ | `path-traversal` | 22 | `fs.*` / `path.join` / `path.resolve` |
976
+ | `open-redirect` | 601 | `res.redirect` |
977
+ | `weak-crypto` | 327 | runtime-selectable hash / cipher algorithm |
978
+ | `unsafe-deserialization` | 502 | `js-yaml` `load` / `node-serialize` |
979
+
980
+ Build-config and test files are excluded from candidate generation. Both rule families default to `off` and are surfaced only by `fallow security`, never under bare `fallow` or the `audit` gate. Scope which catalogue categories run with `security.categories` include / exclude lists in config.
981
+
966
982
  ### Flags
967
983
 
968
984
  | Flag | Type | Default | Description |
@@ -993,11 +1009,12 @@ git diff --unified=0 origin/main...HEAD | fallow security --diff-file -
993
1009
  "kind": "security",
994
1010
  "schema_version": "1",
995
1011
  "security_findings": [],
996
- "unresolved_edge_files": 0
1012
+ "unresolved_edge_files": 0,
1013
+ "unresolved_callee_sites": 0
997
1014
  }
998
1015
  ```
999
1016
 
1000
- Each finding includes `kind`, `path`, `line`, `col`, `evidence`, `trace`, and `actions`. Suppress a verified false positive with `// fallow-ignore-file security-client-server-leak`.
1017
+ Each finding includes `kind`, `path`, `line`, `col`, `evidence`, `trace`, and `actions`. `tainted-sink` findings additionally carry `category` (the catalogue id, e.g. `"dangerous-html"`) and `cwe`; `client-server-leak` findings omit both. `unresolved_edge_files` (client-server-leak) and `unresolved_callee_sites` (tainted-sink) are in-band blind-spot counters: a zero finding count with a non-zero counter is not a clean bill. Suppress a verified false positive with `// fallow-ignore-file security-client-server-leak` (client-server-leak) or `// fallow-ignore-file security-sink` (any tainted-sink category).
1001
1018
 
1002
1019
  ---
1003
1020
 
@@ -1470,7 +1487,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
1470
1487
  {
1471
1488
  "kind": "dead-code",
1472
1489
  "schema_version": 7,
1473
- "version": "2.86.0",
1490
+ "version": "2.87.0",
1474
1491
  "elapsed_ms": 45,
1475
1492
  "total_issues": 12,
1476
1493
  "entry_points": {
@@ -1630,7 +1647,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
1630
1647
  {
1631
1648
  "kind": "dupes",
1632
1649
  "schema_version": 7,
1633
- "version": "2.86.0",
1650
+ "version": "2.87.0",
1634
1651
  "elapsed_ms": 82,
1635
1652
  "total_clones": 15,
1636
1653
  "total_lines_duplicated": 230,
@@ -1674,11 +1691,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1674
1691
  {
1675
1692
  "kind": "combined",
1676
1693
  "schema_version": 7,
1677
- "version": "2.86.0",
1694
+ "version": "2.87.0",
1678
1695
  "elapsed_ms": 159,
1679
1696
  "check": {
1680
1697
  "schema_version": 7,
1681
- "version": "2.86.0",
1698
+ "version": "2.87.0",
1682
1699
  "elapsed_ms": 45,
1683
1700
  "total_issues": 12,
1684
1701
  "unused_files": [],
@@ -23,7 +23,7 @@ Always preview with `--dry-run` before applying. This is a destructive operation
23
23
 
24
24
  ## Don't Create Config Unless Needed
25
25
 
26
- Fallow works with zero configuration for most projects thanks to 114 auto-detecting framework plugins. Creating an unnecessary config file can mask issues or override detection behavior.
26
+ Fallow works with zero configuration for most projects thanks to 118 auto-detecting framework plugins. Creating an unnecessary config file can mask issues or override detection behavior.
27
27
 
28
28
  ```bash
29
29
  # WRONG: creating config for a standard Next.js project
@@ -627,7 +627,7 @@ Focus on findings that are BOTH dead code and duplicated:
627
627
 
628
628
  ## Custom Plugin Setup
629
629
 
630
- For frameworks not covered by the 114 built-in plugins.
630
+ For frameworks not covered by the 118 built-in plugins.
631
631
 
632
632
  ### Option 1: Inline framework config
633
633
 
@@ -4756,6 +4756,17 @@ col: number
4756
4756
  * Agent/human-readable evidence (e.g. the named env var the chain reaches).
4757
4757
  */
4758
4758
  evidence: string
4759
+ /**
4760
+ * Whether the sink argument was associated with a known untrusted source by
4761
+ * the intra-module source-to-sink back-trace (issue #859): a local binding
4762
+ * referenced in the argument was sourced from a catalogue source path
4763
+ * (`req.query`, `process.argv`, message-event `data`, etc.). `true` ranks
4764
+ * the candidate higher and annotates the evidence; `false` does NOT
4765
+ * suppress the finding (the association is conservative, never a proof, and
4766
+ * fallow prefers false-negatives over false-positives). Always `false` for
4767
+ * `ClientServerLeak`. Skipped from JSON when `false` for output stability.
4768
+ */
4769
+ source_backed?: boolean
4759
4770
  /**
4760
4771
  * Structural import-hop trace from the client boundary to the secret source.
4761
4772
  * The hop count is the uncalibrated signal; fallow does not prove the path
@@ -4769,6 +4780,13 @@ trace: TraceHop[]
4769
4780
  * verification is the agent's job, not fallow's.
4770
4781
  */
4771
4782
  actions: IssueAction[]
4783
+ /**
4784
+ * Graph-derived reachability ranking signal (issue #860). `None` until the
4785
+ * post-detection ranking pass fills it; additive on the wire (skipped when
4786
+ * absent). Drives the order findings are emitted in: candidates reachable
4787
+ * from a runtime entry point with a wider blast radius sort first.
4788
+ */
4789
+ reachability?: (SecurityReachability | null)
4772
4790
  }
4773
4791
  /**
4774
4792
  * One hop in a security finding's structural trace. Stored as an absolute path
@@ -4792,6 +4810,37 @@ line: number
4792
4810
  col: number
4793
4811
  role: TraceHopRole
4794
4812
  }
4813
+ /**
4814
+ * Graph-derived reachability ranking signal for a security candidate. Computed
4815
+ * from the EXISTING module graph (runtime reachability + reverse-dep fan-in)
4816
+ * after detection, never proven exploitable. Used to surface candidates that
4817
+ * sit on a request/runtime-reachable surface above isolated helpers or scripts.
4818
+ *
4819
+ * This is a relative-ordering signal, NOT a `confidence` or `signal_strength`
4820
+ * score: fallow does not prove the path is exploitable.
4821
+ */
4822
+ export interface SecurityReachability {
4823
+ /**
4824
+ * Whether the anchor module is reachable from a runtime/application entry
4825
+ * point (route handlers, server entry, framework runtime roots), the
4826
+ * closest graph proxy for an external/request input surface. Code reachable
4827
+ * only from test entry points does not count.
4828
+ */
4829
+ reachable_from_entry: boolean
4830
+ /**
4831
+ * Number of distinct modules that transitively depend on the anchor module
4832
+ * (fan-in via the graph's reverse-dependency index). A higher value means a
4833
+ * wider surface: more call sites could route untrusted input into the sink.
4834
+ */
4835
+ blast_radius: number
4836
+ /**
4837
+ * Whether the anchor module participates in an architecture-boundary
4838
+ * violation found in the same run (as the importing or imported file).
4839
+ * Optional pairing: a candidate that also crosses a declared boundary is a
4840
+ * stronger review target.
4841
+ */
4842
+ crosses_boundary: boolean
4843
+ }
4795
4844
  /**
4796
4845
  * Bare `fallow --format json` envelope.
4797
4846
  */