fallow 2.90.0 → 2.91.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.90.0",
3
+ "version": "2.91.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.90.0",
87
- "@fallow-cli/darwin-x64": "2.90.0",
88
- "@fallow-cli/linux-x64-gnu": "2.90.0",
89
- "@fallow-cli/linux-arm64-gnu": "2.90.0",
90
- "@fallow-cli/linux-x64-musl": "2.90.0",
91
- "@fallow-cli/linux-arm64-musl": "2.90.0",
92
- "@fallow-cli/win32-arm64-msvc": "2.90.0",
93
- "@fallow-cli/win32-x64-msvc": "2.90.0"
86
+ "@fallow-cli/darwin-arm64": "2.91.0",
87
+ "@fallow-cli/darwin-x64": "2.91.0",
88
+ "@fallow-cli/linux-x64-gnu": "2.91.0",
89
+ "@fallow-cli/linux-arm64-gnu": "2.91.0",
90
+ "@fallow-cli/linux-x64-musl": "2.91.0",
91
+ "@fallow-cli/linux-arm64-musl": "2.91.0",
92
+ "@fallow-cli/win32-arm64-msvc": "2.91.0",
93
+ "@fallow-cli/win32-x64-msvc": "2.91.0"
94
94
  }
95
95
  }
@@ -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 agent verification (not confirmed vulnerabilities). Rule families include the graph rule `client-server-leak`, a data-driven `tainted-sink` catalogue, and the include-required `hardcoded-secret` category for provider-prefix credentials and high-entropy literals assigned to secret-shaped identifiers. Most catalogue rows require non-literal input; narrowly literal-aware rows flag deterministic unsafe literals. Rules default off; suppress a file with `// fallow-ignore-file security-sink`; scope categories with `security.categories`. `hardcoded-secret` runs only when listed in `security.categories.include`. | `--format human|json|sarif`, `--changed-since`, `--file`, `--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). Rule families include the graph rule `client-server-leak`, a data-driven `tainted-sink` catalogue, and the include-required `hardcoded-secret` category for provider-prefix credentials and high-entropy literals assigned to secret-shaped identifiers. Most catalogue rows require non-literal input; narrowly literal-aware rows flag deterministic unsafe literals. Rules default off; suppress a file with `// fallow-ignore-file security-sink`; scope categories with `security.categories`. `hardcoded-secret` runs only when listed in `security.categories.include`. | `--format human|json|sarif`, `--changed-since`, `--file`, `--diff-file`, `--workspace`, `--changed-workspaces`, `--surface`, `--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,7 +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, trace, optional `reachability`, and blind-spot counters. Each finding also carries an agent-actionable `candidate` (`source_kind`/`sink`/`boundary`), an optional `taint_flow` source-to-sink triple, and a stable `finding_id` (equal to the SARIF fingerprint) for cross-run correlation; there is no `impact` field (deciding exploitability is the agent's job). `reachability.untrusted_source_trace` is module-level import context only and does not prove value flow. Verify trace, reachability context, and evidence before editing code. Supports `root`, `config`, `workspace`, `paths`, `changed_since`, `changed_workspaces`, `no_cache`, and `threads`; `paths` forwards repeated `fallow security --file` filters for finding anchors, trace hops, or untrusted-source reachability trace hops. Inherits `FALLOW_DIFF_FILE` from the server environment for line-level diff scoping; raise `FALLOW_TIMEOUT_SECS` for large repos. |
121
+ | `security_candidates` | Unverified local security candidates, not confirmed vulnerabilities (`fallow security --format json`). Read `security_findings[]` for category, CWE, severity, evidence, trace, optional `reachability`, and blind-spot counters. `severity` is a review-priority tier, not a verified vulnerability verdict. Each finding also carries an agent-actionable `candidate` (`source_kind`/`sink`/`boundary`), an optional `taint_flow` source-to-sink triple, and a stable `finding_id` (equal to the SARIF fingerprint) for cross-run correlation; there is no `impact` field (deciding exploitability is the agent's job). Set `surface: true` to include top-level `attack_surface[]` entries with defensive-boundary prompts for a verifier. `reachability.untrusted_source_trace` is module-level import context only and does not prove value flow; `reachability.taint_confidence` tiers each reachable candidate as `arg-level` (sink argument traces to a same-module source read, strong) or `module-level` (only the module is import-reachable from a source, weak), so tier from this field instead of the evidence text. Verify trace, reachability context, severity, and evidence before editing code. Supports `root`, `config`, `workspace`, `paths`, `changed_since`, `changed_workspaces`, `surface`, `no_cache`, and `threads`; `paths` forwards repeated `fallow security --file` filters for finding anchors, trace hops, or untrusted-source reachability trace hops. See <https://docs.fallow.tools/cli/security-agent-verification> for the verifier packet and verdict recipe. Inherits `FALLOW_DIFF_FILE` from the server environment for line-level diff scoping; raise `FALLOW_TIMEOUT_SECS` for large repos. |
122
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 |
123
123
  | `fix_preview` | Dry-run auto-fix preview |
124
124
  | `fix_apply` | Apply auto-fixes (destructive) |
@@ -43,6 +43,7 @@ Analyzes the project for unused files, exports, dependencies, types, members, an
43
43
  | `-o, --output-file` | path | (none) | Write the report to a file instead of stdout, for any `--format` (no ANSI codes). Progress and a confirmation stay on stderr (suppressed by `--quiet`). Valid with dead-code/dupes/health/security/bare; composes with `--sarif-file`. |
44
44
  | `--legacy-envelope` | bool | `false` | Remove the top-level `kind` field from typed JSON roots for one migration cycle |
45
45
  | `--changed-since` | string | — | Only analyze files changed since a git ref (e.g., `main`, `HEAD~3`) |
46
+ | `--max-file-size` | int (MB) | `5` | Skip source files larger than N megabytes at discovery instead of parsing them (`0` disables). Guards against the OOM a single multi-MB generated/vendored/bundled file causes on large repos. `.d.ts` files are always analyzed. Skipped files appear on stderr and in `--format json` under `workspace_diagnostics` (`kind: "skipped-large-file"`). Also settable via `FALLOW_MAX_FILE_SIZE`. Global flag. |
46
47
  | `--production` | bool | `false` | Exclude test/dev files, only start/build scripts (applies to every analysis) |
47
48
  | `--no-production` | bool | `false` | Force production mode off, overriding a project config's `production: true` (applies to every analysis; conflicts with `--production`) |
48
49
  | `--production-dead-code` | bool | `false` | Per-analysis production mode for dead-code. Bare combined runs and `fallow audit` only. |
@@ -497,7 +498,7 @@ fallow health --format json --quiet --trend
497
498
  {
498
499
  "kind": "health",
499
500
  "schema_version": 7,
500
- "version": "2.90.0",
501
+ "version": "2.91.0",
501
502
  "elapsed_ms": 32,
502
503
  "summary": {
503
504
  "files_analyzed": 482,
@@ -888,7 +889,7 @@ fallow audit \
888
889
  {
889
890
  "kind": "audit",
890
891
  "schema_version": 7,
891
- "version": "2.90.0",
892
+ "version": "2.91.0",
892
893
  "command": "audit",
893
894
  "verdict": "fail",
894
895
  "changed_files_count": 12,
@@ -961,7 +962,7 @@ fallow flags --format json --quiet --workspace my-package
961
962
  ```json
962
963
  {
963
964
  "schema_version": 7,
964
- "version": "2.90.0",
965
+ "version": "2.91.0",
965
966
  "elapsed_ms": 116,
966
967
  "feature_flags": [],
967
968
  "total_flags": 0
@@ -1042,6 +1043,7 @@ Build-config and test files are excluded from candidate generation. Security rul
1042
1043
  | `--file` | path, repeatable | none | Scope output to candidates whose finding anchor or trace hop matches the selected file. The full graph is still analyzed |
1043
1044
  | `--diff-file` | path | none | Scope candidates to added hunks on the client anchor or import trace. Secret-source hops use file-level retention because member-access spans are not yet stored. Use `-` for stdin |
1044
1045
  | `--diff-stdin` | bool | `false` | Read the unified diff from stdin (equivalent to `--diff-file -`) for line-level scoping and the regression gate |
1046
+ | `--surface` | bool | `false` | Include the agent-facing `attack_surface[]` inventory in JSON output |
1045
1047
  | `--gate` | `new` | none | Fail (exit code **8**) only when the change introduces a NEW security-sink candidate in the changed lines, not on the whole candidate backlog. Requires a diff source (`--changed-since`, `--diff-file`, or `--diff-stdin`); a diff the gate cannot compute is a loud exit 2, never a green gate. Human output says `REVIEW REQUIRED` (not `FAIL`); SARIF keeps every result at `level: note` with the verdict in `run.properties.fallowGate`; `--format json` carries an additive `gate` block (`mode` / `verdict` / `new_count`) |
1046
1048
  | `--workspace` | string | none | Scope to selected workspace packages |
1047
1049
  | `--changed-workspaces` | git ref | none | Scope to workspaces changed since a git ref |
@@ -1062,14 +1064,14 @@ git diff --cached --unified=0 | fallow security --gate new --diff-stdin
1062
1064
  ```json
1063
1065
  {
1064
1066
  "kind": "security",
1065
- "schema_version": "1",
1067
+ "schema_version": "2",
1066
1068
  "security_findings": [],
1067
1069
  "unresolved_edge_files": 0,
1068
1070
  "unresolved_callee_sites": 0
1069
1071
  }
1070
1072
  ```
1071
1073
 
1072
- Each finding includes `kind`, `path`, `line`, `col`, `evidence`, `trace`, `actions`, and optional `reachability`. `tainted-sink` findings additionally carry `category` (the catalogue id, e.g. `"dangerous-html"`) and `cwe`; `client-server-leak` findings omit both. `tainted-sink` findings can also include `reachability.untrusted_source_trace` when a module with a known untrusted source imports the sink module; it is ranking and triage context only, not proof that a specific value reaches the sink. `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).
1074
+ Each finding includes `kind`, `path`, `line`, `col`, `evidence`, `trace`, `actions`, `severity`, and optional `reachability`. `severity` is a review-priority tier (`high`, `medium`, or `low`) derived from reachability, boundary, source-backed, and runtime-hot signals; it is not a verified vulnerability verdict and does not change gate or exit semantics. SARIF maps high and medium candidates to `warning`, and low candidates to `note`. `tainted-sink` findings additionally carry `category` (the catalogue id, e.g. `"dangerous-html"`) and `cwe`; `client-server-leak` findings omit both. `tainted-sink` findings can also include `reachability.untrusted_source_trace` when a module with a known untrusted source imports the sink module; it is ranking and triage context only, not proof that a specific value reaches the sink. When set, `reachability.taint_confidence` tiers the association as `"arg-level"` (the sink argument traces to a same-module source read, strong) or `"module-level"` (only the module is import-reachable from a source, weak); tier from this field rather than the evidence text. For arg-level findings the trace's first hop points at the actual source-read line, and module-level source hops carry the role `"module-source"`. `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).
1073
1075
 
1074
1076
  Every finding also carries an agent-actionable `candidate { source_kind, sink, boundary }`, an optional `taint_flow { source, sink, path }`, and a stable `finding_id`:
1075
1077
 
@@ -1077,7 +1079,7 @@ Every finding also carries an agent-actionable `candidate { source_kind, sink, b
1077
1079
  - `candidate.sink`: a self-contained sink (`path`, `line`, `col`, `category`, `cwe`, `callee`), actionable without reading the rest of the finding.
1078
1080
  - `candidate.boundary`: `client_server` (a `"use client"` file in the trace), `cross_module` (the source reaches the sink across import hops), and optional `architecture_zone` (`from`/`to`) when the anchor also crosses a declared architecture boundary.
1079
1081
  - `candidate.network`: present only on `secret-to-network` (#890) candidates. `destination` is the network call's URL when it is a static literal (usually intended auth) or absent when the destination is dynamic (the higher-signal exfil case). Use it to triage exfil from intended auth without re-reading source.
1080
- - There is no `impact` field: deciding exploitability is the verifying agent's job.
1082
+ - There is no `impact` field: deciding exploitability is the verifying agent's job; `severity` is only the review-priority tier.
1081
1083
  - `taint_flow`: present only when an untrusted source is import-reachable to the sink. `path` is the compact `{ intra_module, cross_module_hops }` shape; the full ordered hops stay in `reachability.untrusted_source_trace`.
1082
1084
  - `finding_id`: a stable correlation id, identical across runs for the same rule/path/line and identical to the SARIF `partialFingerprints` value, for tracking a candidate across runs and joining JSON with SARIF.
1083
1085
 
@@ -1554,7 +1556,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
1554
1556
  {
1555
1557
  "kind": "dead-code",
1556
1558
  "schema_version": 7,
1557
- "version": "2.90.0",
1559
+ "version": "2.91.0",
1558
1560
  "elapsed_ms": 45,
1559
1561
  "total_issues": 12,
1560
1562
  "entry_points": {
@@ -1714,7 +1716,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
1714
1716
  {
1715
1717
  "kind": "dupes",
1716
1718
  "schema_version": 7,
1717
- "version": "2.90.0",
1719
+ "version": "2.91.0",
1718
1720
  "elapsed_ms": 82,
1719
1721
  "total_clones": 15,
1720
1722
  "total_lines_duplicated": 230,
@@ -1758,11 +1760,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1758
1760
  {
1759
1761
  "kind": "combined",
1760
1762
  "schema_version": 7,
1761
- "version": "2.90.0",
1763
+ "version": "2.91.0",
1762
1764
  "elapsed_ms": 159,
1763
1765
  "check": {
1764
1766
  "schema_version": 7,
1765
- "version": "2.90.0",
1767
+ "version": "2.91.0",
1766
1768
  "elapsed_ms": 45,
1767
1769
  "total_issues": 12,
1768
1770
  "unused_files": [],
@@ -322,6 +322,12 @@ error: string
322
322
  kind: "malformed-tsconfig"
323
323
  } | {
324
324
  kind: "tsconfig-reference-dir-missing"
325
+ } | {
326
+ /**
327
+ * On-disk size of the skipped file in bytes.
328
+ */
329
+ size_bytes: number
330
+ kind: "skipped-large-file"
325
331
  })
326
332
  /**
327
333
  * Discriminant for [`CloneGroupAction::kind`]. Mirrors the action types
@@ -600,7 +606,7 @@ export type ImpactTrendDirection = ("improving" | "declining" | "stable")
600
606
  * The `fallow security --format json` schema version. Independently versioned
601
607
  * from the main contract, mirroring `ImpactReportSchemaVersion`.
602
608
  */
603
- export type SecuritySchemaVersion = "1"
609
+ export type SecuritySchemaVersion = ("1" | "2")
604
610
  /**
605
611
  * Gate mode for `fallow security --gate <mode>` (issue #886). Tier 2 reserves
606
612
  * the value `newly-reachable`.
@@ -617,14 +623,28 @@ export type SecurityGateVerdict = ("pass" | "fail")
617
623
  * verification, NOT verified vulnerabilities.
618
624
  */
619
625
  export type SecurityFindingKind = ("client-server-leak" | "tainted-sink")
626
+ /**
627
+ * Verification-priority tier for a security candidate. This is ranking, not an
628
+ * exploitability verdict.
629
+ */
630
+ export type SecuritySeverity = ("high" | "medium" | "low")
620
631
  /**
621
632
  * The role a hop plays in a security finding's structural import trace.
622
633
  */
623
- export type TraceHopRole = ("client-boundary" | "untrusted-source" | "intermediate" | "secret-source" | "sink")
634
+ export type TraceHopRole = ("client-boundary" | "untrusted-source" | "module-source" | "intermediate" | "secret-source" | "sink")
624
635
  /**
625
636
  * Dead-code issue kind linked to a security candidate.
626
637
  */
627
638
  export type SecurityDeadCodeKind = ("unused-file" | "unused-export")
639
+ /**
640
+ * How strongly the untrusted-source signal is associated with the sink, a
641
+ * structured discriminator so a consumer can tier candidates without parsing
642
+ * the human `evidence` prose. Present only when
643
+ * [`SecurityReachability::reachable_from_untrusted_source`] is true. Neither
644
+ * value proves exploitability; both are ranking signals (issue #885 doctrine:
645
+ * rank, never gate).
646
+ */
647
+ export type TaintConfidence = ("arg-level" | "module-level")
628
648
  /**
629
649
  * Runtime coverage state for the function enclosing a security sink.
630
650
  * This is production-observation evidence, not an exploitability verdict.
@@ -4960,6 +4980,7 @@ evidence: string
4960
4980
  * `ClientServerLeak`. Skipped from JSON when `false` for output stability.
4961
4981
  */
4962
4982
  source_backed?: boolean
4983
+ severity: SecuritySeverity
4963
4984
  /**
4964
4985
  * Structural import-hop trace from the client boundary to the secret source.
4965
4986
  * The hop count is the uncalibrated signal; fallow does not prove the path
@@ -5071,6 +5092,15 @@ reachable_from_entry: boolean
5071
5092
  * not prove a specific source value reaches the sink argument.
5072
5093
  */
5073
5094
  reachable_from_untrusted_source?: boolean
5095
+ /**
5096
+ * Structured tier of the untrusted-source association: `arg-level` when the
5097
+ * sink argument traces to a same-module source read (strong), `module-level`
5098
+ * when only the module is import-reachable from a source (weak). Present
5099
+ * exactly when `reachable_from_untrusted_source` is true, so a consumer can
5100
+ * separate strong from weak candidates from this field alone without parsing
5101
+ * the `evidence` string. Not an exploitability proof.
5102
+ */
5103
+ taint_confidence?: (TaintConfidence | null)
5074
5104
  /**
5075
5105
  * Number of value-import hops from the untrusted-source module to the sink
5076
5106
  * module when `reachable_from_untrusted_source` is true.
@@ -5099,10 +5129,11 @@ crosses_boundary: boolean
5099
5129
  /**
5100
5130
  * An agent-actionable candidate record on a [`SecurityFinding`]. fallow fills
5101
5131
  * `source_kind`, `sink`, and `boundary`. The exploitability IMPACT is
5102
- * deliberately NOT a field: deciding severity / exploitability is the consuming
5103
- * agent's job, not fallow's, and a perpetually-null `impact` key would only
5104
- * train consumers to ignore it. The agent reads this record, then writes its
5105
- * own impact verdict downstream.
5132
+ * deliberately NOT a field: `severity` on the parent finding is only a
5133
+ * review-priority tier, while deciding exploitability remains the consuming
5134
+ * agent's job. A perpetually-null `impact` key would only train consumers to
5135
+ * ignore it. The agent reads this record, then writes its own impact verdict
5136
+ * downstream.
5106
5137
  */
5107
5138
  export interface SecurityCandidate {
5108
5139
  /**