fallow 3.36.0 → 3.38.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/README.md +1 -1
- package/capabilities.json +112 -10
- package/issue-registry.json +38 -4
- package/package.json +14 -11
- package/rule-pack-schema.json +264 -0
- package/schema.json +40 -1
- package/skills/fallow/SKILL.md +3 -3
- package/skills/fallow/references/cli-reference.md +80 -12
- package/skills/fallow/references/gotchas.md +2 -0
- package/skills/fallow/references/issue-types.md +1 -0
- package/skills/fallow/references/mcp.md +3 -3
- package/skills/fallow/references/patterns.md +1 -1
- package/types/output-contract.d.ts +467 -30
- package/scripts/lazy-verify.test.js +0 -564
- package/scripts/platform-package.test.js +0 -26
- package/scripts/run-binary.test.js +0 -293
- package/scripts/sentinel-path.test.js +0 -240
- package/scripts/verify-binary.test.js +0 -809
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ npx fallow fix --dry-run # Preview automatic cleanup
|
|
|
28
28
|
|
|
29
29
|
## Output and exit codes
|
|
30
30
|
|
|
31
|
-
Add `--format json --quiet` to any command for one typed JSON document on stdout. Exit code 1 means findings, not failure; 0
|
|
31
|
+
Add `--format json --quiet` to any command for one typed JSON document on stdout. Exit code 1 means findings, not failure; 0 means no enforced gate failed (or an audit pass or warn verdict). Bare `fallow` in a machine format exits 0 on findings unless you pass `--fail-on-issues`; 2 is a validation or runtime error, reported as a JSON error envelope rather than a stack trace. License, coverage setup, network, and security-gate workflows use additional documented codes; read `fallow schema.exit_codes` instead of suppressing the process status.
|
|
32
32
|
|
|
33
33
|
Parsing the output in TypeScript? Import the typed shapes, version-pinned to the CLI you install:
|
|
34
34
|
|
package/capabilities.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fallow",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.38.0",
|
|
4
4
|
"manifest_version": "1",
|
|
5
5
|
"description": "Codebase analyzer for TypeScript/JavaScript: unused code, circular dependencies, code duplication, complexity hotspots, and architecture boundary violations",
|
|
6
6
|
"global_flags": [
|
|
@@ -67,6 +67,26 @@
|
|
|
67
67
|
"false"
|
|
68
68
|
]
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
"name": "--lean",
|
|
72
|
+
"type": "bool",
|
|
73
|
+
"required": false,
|
|
74
|
+
"description": "Trim JSON for agent context: leave out empty arrays and zero dead-code summary counts, group workspace diagnostics, cap health tables, and move repeated action text to `_meta.actions`. Requires JSON output. Applies to dead-code, health and the combined report; other commands reject it. Run without `--lean` for the full diagnostic list and the complete tables",
|
|
75
|
+
"possible_values": [
|
|
76
|
+
"true",
|
|
77
|
+
"false"
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "--full-tables",
|
|
82
|
+
"type": "bool",
|
|
83
|
+
"required": false,
|
|
84
|
+
"description": "With `--lean`, keep every row of the health tables (`hotspots`, `file_scores`, `large_functions`)",
|
|
85
|
+
"possible_values": [
|
|
86
|
+
"true",
|
|
87
|
+
"false"
|
|
88
|
+
]
|
|
89
|
+
},
|
|
70
90
|
{
|
|
71
91
|
"name": "--quiet",
|
|
72
92
|
"type": "bool",
|
|
@@ -1289,6 +1309,26 @@
|
|
|
1289
1309
|
"false"
|
|
1290
1310
|
]
|
|
1291
1311
|
},
|
|
1312
|
+
{
|
|
1313
|
+
"name": "--resume",
|
|
1314
|
+
"type": "bool",
|
|
1315
|
+
"required": false,
|
|
1316
|
+
"description": "Continue an interrupted or partial run: reuse the killed and confirmed survived mutants in its journal and run only the others. A journal of other inputs exits 2",
|
|
1317
|
+
"possible_values": [
|
|
1318
|
+
"true",
|
|
1319
|
+
"false"
|
|
1320
|
+
]
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
"name": "--kill-matrix",
|
|
1324
|
+
"type": "bool",
|
|
1325
|
+
"required": false,
|
|
1326
|
+
"description": "Collect all killing tests and report redundant-test candidates for individual review. Run every covering test without stopping at a failure",
|
|
1327
|
+
"possible_values": [
|
|
1328
|
+
"true",
|
|
1329
|
+
"false"
|
|
1330
|
+
]
|
|
1331
|
+
},
|
|
1292
1332
|
{
|
|
1293
1333
|
"name": "paths",
|
|
1294
1334
|
"type": "string",
|
|
@@ -1332,9 +1372,30 @@
|
|
|
1332
1372
|
"true",
|
|
1333
1373
|
"false"
|
|
1334
1374
|
]
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
"name": "--cloud",
|
|
1378
|
+
"type": "bool",
|
|
1379
|
+
"required": false,
|
|
1380
|
+
"description": "OPT-IN: attach Fallow Cloud production evidence for a `--file` target as the `cloud` evidence section: calls, errors, CPU and never-run branches per function. The API key is $FALLOW_API_KEY, else the key that `fallow cloud login` stored. A missing key, a plan gate or an unreachable cloud is a section status, never a failed run",
|
|
1381
|
+
"possible_values": [
|
|
1382
|
+
"true",
|
|
1383
|
+
"false"
|
|
1384
|
+
]
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
"name": "--repo",
|
|
1388
|
+
"type": "string",
|
|
1389
|
+
"required": false,
|
|
1390
|
+
"description": "Fallow Cloud repository for `--cloud`. Precedence: this flag > $FALLOW_REPO > the `origin` git remote"
|
|
1335
1391
|
}
|
|
1336
1392
|
]
|
|
1337
1393
|
},
|
|
1394
|
+
{
|
|
1395
|
+
"name": "cloud",
|
|
1396
|
+
"description": "Connect this machine to Fallow Cloud",
|
|
1397
|
+
"flags": []
|
|
1398
|
+
},
|
|
1338
1399
|
{
|
|
1339
1400
|
"name": "trace",
|
|
1340
1401
|
"description": "Trace a symbol's call chain, or the shortest import path between two modules (best-effort, syntactic; OFF the ranked path)",
|
|
@@ -1841,6 +1902,12 @@
|
|
|
1841
1902
|
"required": false,
|
|
1842
1903
|
"description": "Maximum CRAP score threshold (overrides config, default 30.0). Functions meeting or exceeding this score are reported alongside complexity findings. Pair with `--coverage` for accurate scoring"
|
|
1843
1904
|
},
|
|
1905
|
+
{
|
|
1906
|
+
"name": "--max-file-lines",
|
|
1907
|
+
"type": "string",
|
|
1908
|
+
"required": false,
|
|
1909
|
+
"description": "Maximum physical lines per file (overrides config `health.maxFileLines`, default 0 = off). A longer file is reported as a complexity finding with `exceeded: \"file_lines\"`"
|
|
1910
|
+
},
|
|
1844
1911
|
{
|
|
1845
1912
|
"name": "--top",
|
|
1846
1913
|
"type": "string",
|
|
@@ -4536,9 +4603,11 @@
|
|
|
4536
4603
|
"sarif_rule_ids": [
|
|
4537
4604
|
"fallow/thin-wrapper"
|
|
4538
4605
|
],
|
|
4539
|
-
"codeclimate_check_names":
|
|
4606
|
+
"codeclimate_check_names": [
|
|
4607
|
+
"fallow/thin-wrapper"
|
|
4608
|
+
],
|
|
4540
4609
|
"ts_alias": null,
|
|
4541
|
-
"counts_in_total":
|
|
4610
|
+
"counts_in_total": true,
|
|
4542
4611
|
"fixable": false,
|
|
4543
4612
|
"suppressible": true,
|
|
4544
4613
|
"suppress_comment": "// fallow-ignore-next-line thin-wrapper",
|
|
@@ -4570,9 +4639,11 @@
|
|
|
4570
4639
|
"sarif_rule_ids": [
|
|
4571
4640
|
"fallow/duplicate-prop-shape"
|
|
4572
4641
|
],
|
|
4573
|
-
"codeclimate_check_names":
|
|
4642
|
+
"codeclimate_check_names": [
|
|
4643
|
+
"fallow/duplicate-prop-shape"
|
|
4644
|
+
],
|
|
4574
4645
|
"ts_alias": null,
|
|
4575
|
-
"counts_in_total":
|
|
4646
|
+
"counts_in_total": true,
|
|
4576
4647
|
"fixable": false,
|
|
4577
4648
|
"suppressible": true,
|
|
4578
4649
|
"suppress_comment": "// fallow-ignore-next-line duplicate-prop-shape",
|
|
@@ -4780,6 +4851,36 @@
|
|
|
4780
4851
|
"license_note": null,
|
|
4781
4852
|
"docs_url": "https://fallow.tools/docs/explanations/health/#crap-score"
|
|
4782
4853
|
},
|
|
4854
|
+
{
|
|
4855
|
+
"id": "long-file",
|
|
4856
|
+
"rule_id": "fallow/long-file",
|
|
4857
|
+
"command": "health",
|
|
4858
|
+
"category": "Health",
|
|
4859
|
+
"description": "File has more lines than the file-length threshold",
|
|
4860
|
+
"label": null,
|
|
4861
|
+
"config_key": null,
|
|
4862
|
+
"registry_index": null,
|
|
4863
|
+
"aliases": [],
|
|
4864
|
+
"lsp": false,
|
|
4865
|
+
"filter_flag": "--complexity",
|
|
4866
|
+
"result_key": null,
|
|
4867
|
+
"summary_label": null,
|
|
4868
|
+
"summary_docs_anchor": null,
|
|
4869
|
+
"sarif_rule_ids": null,
|
|
4870
|
+
"codeclimate_check_names": null,
|
|
4871
|
+
"ts_alias": null,
|
|
4872
|
+
"counts_in_total": false,
|
|
4873
|
+
"fixable": false,
|
|
4874
|
+
"suppressible": true,
|
|
4875
|
+
"suppress_comment": "// fallow-ignore-file complexity",
|
|
4876
|
+
"default_severity": null,
|
|
4877
|
+
"opt_in": null,
|
|
4878
|
+
"frameworks": [],
|
|
4879
|
+
"note": null,
|
|
4880
|
+
"license": "free",
|
|
4881
|
+
"license_note": null,
|
|
4882
|
+
"docs_url": "https://fallow.tools/docs/explanations/health/#file-length"
|
|
4883
|
+
},
|
|
4783
4884
|
{
|
|
4784
4885
|
"id": "refactoring-target",
|
|
4785
4886
|
"rule_id": "fallow/refactoring-target",
|
|
@@ -6995,8 +7096,8 @@
|
|
|
6995
7096
|
"github-summary"
|
|
6996
7097
|
],
|
|
6997
7098
|
"exit_codes": {
|
|
6998
|
-
"0": "Success
|
|
6999
|
-
"1": "
|
|
7099
|
+
"0": "Success: no enforced gate failed. Bare fallow in a machine format (json, sarif, codeclimate, the GitHub formats, the comment and review formats) does not enforce findings without --fail-on-issues, so it exits 0 on findings. Read gate_outcomes: status \"fail\" with enforced false is a failing gate that did not set the exit code",
|
|
7100
|
+
"1": "An enforced gate failed, for example error-severity findings (per rules config, or --fail-on-issues promotes warn to error). This is an analysis result, not a tool failure",
|
|
7000
7101
|
"2": "Error (invalid config, invalid input, etc.). When --format json is active, errors are emitted as structured JSON on stdout: {\"error\": true, \"message\": \"...\", \"exit_code\": 2}",
|
|
7001
7102
|
"3": "Requested resource unavailable: config --path found no config, or a license is missing, invalid, or beyond its offline hard-fail window",
|
|
7002
7103
|
"4": "Runtime coverage sidecar is unavailable, unverifiable, protocol-incompatible, or terminated unexpectedly",
|
|
@@ -7034,7 +7135,7 @@
|
|
|
7034
7135
|
"FALLOW_MAX_FILE_SIZE": "Per-file size ceiling in megabytes for source discovery (default 5; 0 = no limit). CLI --max-file-size flag overrides this.",
|
|
7035
7136
|
"FALLOW_TYPE_AWARE": "Enable or disable TypeScript semantic (type-aware) analysis for the run (true/false/1/0/yes/no/on/off). Precedence: --type-aware/--no-type-aware CLI flags, then FALLOW_TYPE_AWARE, then the audit.typeAware config field, then typeAware.enabled.",
|
|
7036
7137
|
"FALLOW_TYPE_AWARE_TIMEOUT_SECS": "Wall clock in seconds allowed for one TypeScript semantic sidecar request (default 120; unset, 0, or a non-numeric value keeps the default). Raise it for very large TypeScript programs, where a semantic query scans the whole program.",
|
|
7037
|
-
"FALLOW_TYPE_AWARE_BACKEND": "Experimental. Type-checker backend for the TypeScript semantic sidecar: typescript-go (default) or tsrs. The tsrs backend needs
|
|
7138
|
+
"FALLOW_TYPE_AWARE_BACKEND": "Experimental. Type-checker backend for the TypeScript semantic sidecar: typescript-go (default) or tsrs. The tsrs backend needs a tsrs npm package in the supported range of the type-aware protocol manifest, where fallow-type-aware can resolve it. An unknown value makes the type-aware pass unavailable.",
|
|
7038
7139
|
"FALLOW_TYPE_AWARE_BIN": "Trusted executable override for the TypeScript semantic refinement sidecar used by dead-code --type-aware. Relative paths resolve from the caller's working directory before --root is applied; project node_modules and PATH are intentionally not searched. Default: sibling of the active Fallow executable.",
|
|
7039
7140
|
"FALLOW_AUDIT_BASE": "Pins the fallow audit comparison base ref when no --base/--changed-since is passed (e.g. upstream/main).",
|
|
7040
7141
|
"FALLOW_AUDIT_CACHE_MAX_AGE_DAYS": "GC threshold in days for reusable audit base-snapshot caches (default 30; 0 disables the sweep).",
|
|
@@ -7046,9 +7147,10 @@
|
|
|
7046
7147
|
"FALLOW_COV_BIN": "Explicit path override for the fallow-cov runtime-coverage sidecar binary.",
|
|
7047
7148
|
"FALLOW_COV_BINARY_PATH": "Secondary explicit path override for the fallow-cov sidecar, checked after FALLOW_COV_BIN (air-gapped installs, distro-packaged sidecars, shared Docker images).",
|
|
7048
7149
|
"FALLOW_RUNTIME_COVERAGE_SOURCE": "Set to cloud to select cloud runtime coverage in fallow coverage analyze without passing --cloud.",
|
|
7049
|
-
"FALLOW_REPO": "owner/repo fallback for fallow coverage analyze --cloud when --repo is not passed (otherwise parsed from the git origin remote).",
|
|
7150
|
+
"FALLOW_REPO": "owner/repo fallback for fallow coverage analyze --cloud and fallow inspect --cloud when --repo is not passed (otherwise parsed from the git origin remote).",
|
|
7050
7151
|
"FALLOW_API_URL": "Base URL override for Fallow Cloud API calls (license refresh, trial, coverage uploads).",
|
|
7051
|
-
"FALLOW_API_KEY": "Fallow Cloud bearer token for coverage upload commands, and the fallback bearer for fallow license refresh when the stored license JWT is missing or too stale.",
|
|
7152
|
+
"FALLOW_API_KEY": "Fallow Cloud bearer token for coverage upload and cloud read commands (wins over the key that fallow cloud login stored), and the fallback bearer for fallow license refresh when the stored license JWT is missing or too stale.",
|
|
7153
|
+
"FALLOW_CREDENTIAL_STORE": "Credential store for the key that fallow cloud login writes: auto (default: OS keychain, else ~/.config/fallow/credentials), file (credentials file only) or none (no stored key is read or written).",
|
|
7052
7154
|
"FALLOW_CA_BUNDLE": "Path to a PEM certificate bundle for Fallow Cloud and provider HTTP calls (replaces the default WebPKI roots).",
|
|
7053
7155
|
"FALLOW_UPDATE_CHECK": "Set to off/0/false to disable the human-TTY upgrade nudge and its background version check.",
|
|
7054
7156
|
"FALLOW_CLAUDE_CODE_HINT": "Set to off/0/false/no/disabled to suppress the one-line Claude Code plugin hint on stderr. Fallow writes the hint only inside a Claude Code session (CLAUDECODE or CLAUDE_CODE_CHILD_SESSION), for human output without --quiet, outside CI, and when no Fallow plugin or skill is set up for the project. Default on.",
|
package/issue-registry.json
CHANGED
|
@@ -1939,9 +1939,11 @@
|
|
|
1939
1939
|
"sarif_rule_ids": [
|
|
1940
1940
|
"fallow/thin-wrapper"
|
|
1941
1941
|
],
|
|
1942
|
-
"codeclimate_check_names":
|
|
1942
|
+
"codeclimate_check_names": [
|
|
1943
|
+
"fallow/thin-wrapper"
|
|
1944
|
+
],
|
|
1943
1945
|
"ts_alias": null,
|
|
1944
|
-
"counts_in_total":
|
|
1946
|
+
"counts_in_total": true,
|
|
1945
1947
|
"fixable": false,
|
|
1946
1948
|
"suppressible": true,
|
|
1947
1949
|
"suppress_comment": "// fallow-ignore-next-line thin-wrapper",
|
|
@@ -1973,9 +1975,11 @@
|
|
|
1973
1975
|
"sarif_rule_ids": [
|
|
1974
1976
|
"fallow/duplicate-prop-shape"
|
|
1975
1977
|
],
|
|
1976
|
-
"codeclimate_check_names":
|
|
1978
|
+
"codeclimate_check_names": [
|
|
1979
|
+
"fallow/duplicate-prop-shape"
|
|
1980
|
+
],
|
|
1977
1981
|
"ts_alias": null,
|
|
1978
|
-
"counts_in_total":
|
|
1982
|
+
"counts_in_total": true,
|
|
1979
1983
|
"fixable": false,
|
|
1980
1984
|
"suppressible": true,
|
|
1981
1985
|
"suppress_comment": "// fallow-ignore-next-line duplicate-prop-shape",
|
|
@@ -3157,6 +3161,36 @@
|
|
|
3157
3161
|
"license_note": null,
|
|
3158
3162
|
"docs_url": "https://fallow.tools/docs/cli/security/"
|
|
3159
3163
|
},
|
|
3164
|
+
{
|
|
3165
|
+
"id": "long-file",
|
|
3166
|
+
"rule_id": "fallow/long-file",
|
|
3167
|
+
"command": "health",
|
|
3168
|
+
"category": "Health",
|
|
3169
|
+
"description": "File has more lines than the file-length threshold",
|
|
3170
|
+
"label": null,
|
|
3171
|
+
"config_key": null,
|
|
3172
|
+
"registry_index": null,
|
|
3173
|
+
"aliases": [],
|
|
3174
|
+
"lsp": false,
|
|
3175
|
+
"filter_flag": "--complexity",
|
|
3176
|
+
"result_key": null,
|
|
3177
|
+
"summary_label": null,
|
|
3178
|
+
"summary_docs_anchor": null,
|
|
3179
|
+
"sarif_rule_ids": null,
|
|
3180
|
+
"codeclimate_check_names": null,
|
|
3181
|
+
"ts_alias": null,
|
|
3182
|
+
"counts_in_total": false,
|
|
3183
|
+
"fixable": false,
|
|
3184
|
+
"suppressible": true,
|
|
3185
|
+
"suppress_comment": "// fallow-ignore-file complexity",
|
|
3186
|
+
"default_severity": null,
|
|
3187
|
+
"opt_in": null,
|
|
3188
|
+
"frameworks": [],
|
|
3189
|
+
"note": null,
|
|
3190
|
+
"license": "free",
|
|
3191
|
+
"license_note": null,
|
|
3192
|
+
"docs_url": "https://fallow.tools/docs/explanations/health/#file-length"
|
|
3193
|
+
},
|
|
3160
3194
|
{
|
|
3161
3195
|
"id": "mass-assignment",
|
|
3162
3196
|
"rule_id": "security/mass-assignment",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fallow",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.38.0",
|
|
4
4
|
"mcpName": "io.github.fallow-rs/fallow",
|
|
5
5
|
"description": "Codebase intelligence for TypeScript and JavaScript: health, complexity, duplication, architecture, styling drift, and unused code from one graph. CLI, LSP, and MCP server. Zero config for over 100 frameworks.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"./scripts/*": "./scripts/*",
|
|
55
55
|
"./skills/*": "./skills/*",
|
|
56
56
|
"./schema.json": "./schema.json",
|
|
57
|
+
"./rule-pack-schema.json": "./rule-pack-schema.json",
|
|
57
58
|
"./capabilities.json": "./capabilities.json",
|
|
58
59
|
"./issue-registry.json": "./issue-registry.json"
|
|
59
60
|
},
|
|
@@ -67,11 +68,13 @@
|
|
|
67
68
|
"files": [
|
|
68
69
|
"bin",
|
|
69
70
|
"scripts",
|
|
71
|
+
"!scripts/*.test.js",
|
|
70
72
|
"skills",
|
|
71
73
|
"!skills/_artifacts",
|
|
72
74
|
"types",
|
|
73
75
|
"README.md",
|
|
74
76
|
"schema.json",
|
|
77
|
+
"rule-pack-schema.json",
|
|
75
78
|
"capabilities.json",
|
|
76
79
|
"issue-registry.json"
|
|
77
80
|
],
|
|
@@ -86,17 +89,17 @@
|
|
|
86
89
|
"detect-libc": "2.1.2"
|
|
87
90
|
},
|
|
88
91
|
"devDependencies": {
|
|
89
|
-
"@tanstack/intent": "0.5.
|
|
92
|
+
"@tanstack/intent": "0.5.6"
|
|
90
93
|
},
|
|
91
94
|
"optionalDependencies": {
|
|
92
|
-
"@fallow-cli/darwin-arm64": "3.
|
|
93
|
-
"@fallow-cli/darwin-x64": "3.
|
|
94
|
-
"@fallow-cli/linux-x64-gnu": "3.
|
|
95
|
-
"@fallow-cli/linux-arm64-gnu": "3.
|
|
96
|
-
"@fallow-cli/linux-x64-musl": "3.
|
|
97
|
-
"@fallow-cli/linux-arm64-musl": "3.
|
|
98
|
-
"@fallow-cli/win32-arm64-msvc": "3.
|
|
99
|
-
"@fallow-cli/win32-x64-msvc": "3.
|
|
100
|
-
"fallow-type-aware": "3.
|
|
95
|
+
"@fallow-cli/darwin-arm64": "3.38.0",
|
|
96
|
+
"@fallow-cli/darwin-x64": "3.38.0",
|
|
97
|
+
"@fallow-cli/linux-x64-gnu": "3.38.0",
|
|
98
|
+
"@fallow-cli/linux-arm64-gnu": "3.38.0",
|
|
99
|
+
"@fallow-cli/linux-x64-musl": "3.38.0",
|
|
100
|
+
"@fallow-cli/linux-arm64-musl": "3.38.0",
|
|
101
|
+
"@fallow-cli/win32-arm64-msvc": "3.38.0",
|
|
102
|
+
"@fallow-cli/win32-x64-msvc": "3.38.0",
|
|
103
|
+
"fallow-type-aware": "3.38.0"
|
|
101
104
|
}
|
|
102
105
|
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "RulePackDef",
|
|
4
|
+
"description": "A declarative rule pack loaded from a standalone JSON or JSONC file listed\nin the `rulePacks` config key.\n\nRule packs are pure data: loading a pack never executes project code. They\nencode project-specific policy (banned calls, banned imports, and\ncatalogue-backed banned effects) evaluated over fallow's static extraction\ndata, reporting as `policy-violation`\nfindings.\n\n```jsonc\n{\n \"$schema\": \"https://raw.githubusercontent.com/fallow-rs/fallow/main/rule-pack-schema.json\",\n \"version\": 1,\n \"name\": \"team-policy\",\n \"description\": \"House rules for the platform team\",\n \"rules\": [\n {\n \"id\": \"no-child-process\",\n \"kind\": \"banned-call\",\n \"callees\": [\"child_process.*\"],\n \"message\": \"Use the sandboxed runner instead.\",\n \"severity\": \"error\"\n },\n {\n \"id\": \"no-network\",\n \"kind\": \"banned-effect\",\n \"effects\": [\"network\"],\n \"message\": \"Keep this package side-effect free.\"\n },\n {\n \"id\": \"no-moment\",\n \"kind\": \"banned-import\",\n \"specifiers\": [\"moment\"],\n \"message\": \"Use date-fns.\"\n }\n ]\n}\n```",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"version": {
|
|
8
|
+
"description": "Pack format version. Must be `1`; the field exists so future rule\nkinds can be added without breaking older fallow builds silently.",
|
|
9
|
+
"type": "integer",
|
|
10
|
+
"format": "uint32",
|
|
11
|
+
"minimum": 0
|
|
12
|
+
},
|
|
13
|
+
"name": {
|
|
14
|
+
"description": "Pack name, unique across all loaded packs. Must use only ASCII\nletters, digits, `.`, `_`, and `-` so `\"<pack>/<id>\"` is unambiguous in\noutput, baselines, and scoped suppression comments.",
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"description": {
|
|
18
|
+
"description": "Optional human description of the pack's intent.",
|
|
19
|
+
"type": [
|
|
20
|
+
"string",
|
|
21
|
+
"null"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"rules": {
|
|
25
|
+
"description": "The policy rules this pack enforces. Must be non-empty: an empty pack\nwould silently enforce nothing.",
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": {
|
|
28
|
+
"$ref": "#/$defs/RulePackRule"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"required": [
|
|
34
|
+
"version",
|
|
35
|
+
"name",
|
|
36
|
+
"rules"
|
|
37
|
+
],
|
|
38
|
+
"$defs": {
|
|
39
|
+
"RulePackRule": {
|
|
40
|
+
"description": "One declarative policy rule inside a rule pack.\n\n`callees` applies only to `banned-call` rules; `specifiers` and\n`ignoreTypeOnly` apply only to `banned-import` rules; `effects` applies\nonly to `banned-effect` rules; `exports` applies only to `banned-export`\nrules. `allowedFiles` and `proofKinds` apply only to `gdp-proof-producer`\nrules. `zones` can scope any rule kind to files classified into one of the\nnamed boundary zones. Setting a field on the wrong kind is a load error\n(fail loud, never silently ignore policy).",
|
|
41
|
+
"type": "object",
|
|
42
|
+
"properties": {
|
|
43
|
+
"id": {
|
|
44
|
+
"description": "Rule id, unique within the pack. Must use only ASCII letters, digits,\n`.`, `_`, and `-` so `\"<pack>/<id>\"` is unambiguous in output,\nbaselines, and scoped suppression comments.",
|
|
45
|
+
"type": "string"
|
|
46
|
+
},
|
|
47
|
+
"kind": {
|
|
48
|
+
"description": "Which check this rule performs.",
|
|
49
|
+
"$ref": "#/$defs/RulePackRuleKind"
|
|
50
|
+
},
|
|
51
|
+
"callees": {
|
|
52
|
+
"description": "Callee patterns to ban (`banned-call` only). Matching is segment-aware\nand import-resolved, identical to `boundaries.calls.forbidden`:\n`child_process.*` covers `import { exec } from \"node:child_process\"`,\nthe bare specifier, and namespace/default imports; `fetch` matches only\nthe global `fetch`; a leading `*.member` matches any object.",
|
|
53
|
+
"type": "array",
|
|
54
|
+
"items": {
|
|
55
|
+
"type": "string"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"specifiers": {
|
|
59
|
+
"description": "Import specifiers to ban (`banned-import` only). Matched segment-aware\nagainst the RAW specifier: `moment` covers `moment` and\n`moment/locale/nl` but not `moment-timezone`. A trailing `/*` form,\nsuch as `@org/ui/*`, matches subpaths only (`@org/ui/internal`) and\nnot the package root (`@org/ui`). Aliased or rewritten specifiers\n(e.g. `npm:moment`) are not matched.",
|
|
60
|
+
"type": "array",
|
|
61
|
+
"items": {
|
|
62
|
+
"type": "string"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"effects": {
|
|
66
|
+
"description": "Effect classes to ban (`banned-effect` only). Effects are derived from\n`security_matchers.toml` catalogue rows and matched against captured\ncall sites after import-resolution canonicalization.",
|
|
67
|
+
"type": "array",
|
|
68
|
+
"items": {
|
|
69
|
+
"$ref": "#/$defs/EffectKind"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"exports": {
|
|
73
|
+
"description": "Export names to ban (`banned-export` only). `\"default\"` matches the\ndefault export; any other entry matches an exported name exactly; a\nsingle trailing `*` makes it a prefix match (`internal*`). No other\nglob syntax is supported. Re-exports are out of scope for this rule.",
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": {
|
|
76
|
+
"type": "string"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"allowedFiles": {
|
|
80
|
+
"description": "Project-root-relative globs allowed to call `@gdp-ts/core.defineProof`\n(`gdp-proof-producer` only). At least one pattern is required.\nA single `*` stays within one path segment; use `**` to match across directories.",
|
|
81
|
+
"type": "array",
|
|
82
|
+
"items": {
|
|
83
|
+
"type": "string"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"proofKinds": {
|
|
87
|
+
"description": "Exact literal proof labels checked by a `gdp-proof-producer` rule.\nEmpty or absent checks every recognized factory call, including calls\nwith dynamic labels. A nonempty list checks only static string labels.",
|
|
88
|
+
"type": "array",
|
|
89
|
+
"items": {
|
|
90
|
+
"type": "string"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"ignoreTypeOnly": {
|
|
94
|
+
"description": "When `true`, type-only imports (`import type ...` and type-only\nre-exports) are ignored by `banned-import`; type-only exports are\nignored by `banned-export`. Defaults to `false`: type-only sites are\nflagged too.",
|
|
95
|
+
"type": "boolean"
|
|
96
|
+
},
|
|
97
|
+
"files": {
|
|
98
|
+
"description": "Optional include globs (project-root-relative). Empty or absent means\nthe rule applies to every analyzed file.\nA single `*` stays within one path segment; use `**` to match across directories.",
|
|
99
|
+
"type": "array",
|
|
100
|
+
"items": {
|
|
101
|
+
"type": "string"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"exclude": {
|
|
105
|
+
"description": "Optional exclude globs (project-root-relative), applied after `files`.\nA single `*` stays within one path segment; use `**` to match across directories.",
|
|
106
|
+
"type": "array",
|
|
107
|
+
"items": {
|
|
108
|
+
"type": "string"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"zones": {
|
|
112
|
+
"description": "Optional boundary zones this rule applies to. Empty or absent means the\nrule applies regardless of zone; non-empty values require matching\nconfigured boundaries and combine with `files`/`exclude` as AND.",
|
|
113
|
+
"type": "array",
|
|
114
|
+
"items": {
|
|
115
|
+
"type": "string"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"message": {
|
|
119
|
+
"description": "Author-provided message naming the sanctioned alternative. Rendered\nnext to each finding.",
|
|
120
|
+
"type": [
|
|
121
|
+
"string",
|
|
122
|
+
"null"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"severity": {
|
|
126
|
+
"description": "Per-rule severity overriding the `rules.\"policy-violation\"` master.\n`off` disables this rule. When the master itself is `off`, the whole\nevaluator is disabled and per-rule severity cannot resurrect it.",
|
|
127
|
+
"anyOf": [
|
|
128
|
+
{
|
|
129
|
+
"$ref": "#/$defs/Severity"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"type": "null"
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"additionalProperties": false,
|
|
138
|
+
"required": [
|
|
139
|
+
"id",
|
|
140
|
+
"kind"
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
"RulePackRuleKind": {
|
|
144
|
+
"description": "Which check a rule-pack rule performs.",
|
|
145
|
+
"oneOf": [
|
|
146
|
+
{
|
|
147
|
+
"description": "Ban call sites whose callee path matches one of `callees`.",
|
|
148
|
+
"type": "string",
|
|
149
|
+
"const": "banned-call"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"description": "Ban imports and re-exports whose raw specifier matches one of\n`specifiers`.",
|
|
153
|
+
"type": "string",
|
|
154
|
+
"const": "banned-import"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"description": "Ban call sites whose catalogue-derived effect matches one of `effects`.",
|
|
158
|
+
"type": "string",
|
|
159
|
+
"const": "banned-effect"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"description": "Ban exported names that match one of `exports`.",
|
|
163
|
+
"type": "string",
|
|
164
|
+
"const": "banned-export"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"description": "Restrict gdp-ts proof factory calls to explicitly allowed modules.",
|
|
168
|
+
"type": "string",
|
|
169
|
+
"const": "gdp-proof-producer"
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
"EffectKind": {
|
|
174
|
+
"description": "Internal side-effect taxonomy derived from security catalogue rows.",
|
|
175
|
+
"oneOf": [
|
|
176
|
+
{
|
|
177
|
+
"description": "No observable side effect.",
|
|
178
|
+
"type": "string",
|
|
179
|
+
"const": "pure"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"description": "Structured-data read/query evaluation (XML external entities, XPath).",
|
|
183
|
+
"type": "string",
|
|
184
|
+
"const": "read"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"description": "In-memory state mutation (mass assignment, prototype pollution).",
|
|
188
|
+
"type": "string",
|
|
189
|
+
"const": "write"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"description": "Network I/O (HTTP clients, request-forgery sinks).",
|
|
193
|
+
"type": "string",
|
|
194
|
+
"const": "network"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"description": "Filesystem access (path traversal, file permission changes).",
|
|
198
|
+
"type": "string",
|
|
199
|
+
"const": "storage"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"description": "In-process code evaluation (`eval`, `Function`, string timers).",
|
|
203
|
+
"type": "string",
|
|
204
|
+
"const": "process"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"description": "OS shell command execution.",
|
|
208
|
+
"type": "string",
|
|
209
|
+
"const": "shell"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"description": "Cryptographic primitives (weak algorithm or key usage).",
|
|
213
|
+
"type": "string",
|
|
214
|
+
"const": "crypto"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"description": "Random-number generation in security-sensitive contexts.",
|
|
218
|
+
"type": "string",
|
|
219
|
+
"const": "randomness"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"description": "DOM injection (`innerHTML`-style XSS sinks).",
|
|
223
|
+
"type": "string",
|
|
224
|
+
"const": "dom"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"description": "Database query execution (SQL/NoSQL injection sinks).",
|
|
228
|
+
"type": "string",
|
|
229
|
+
"const": "database"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"description": "Callback invoked by a framework rather than a direct effect.",
|
|
233
|
+
"type": "string",
|
|
234
|
+
"const": "framework-callback"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"description": "Effect the catalogue cannot classify.",
|
|
238
|
+
"type": "string",
|
|
239
|
+
"const": "unknown"
|
|
240
|
+
}
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
"Severity": {
|
|
244
|
+
"description": "Severity level for rules.\n\nControls whether an issue type sets a non-zero exit code (`error`), is\nreported without an effect on the exit code (`warn`), or is suppressed\nentirely (`off`). `--fail-on-issues` promotes `warn` to `error`. The\ndead-code count gate of the GitHub Action counts `warn` findings unless its\n`fail-on-issues` input is `false`.",
|
|
245
|
+
"oneOf": [
|
|
246
|
+
{
|
|
247
|
+
"description": "Report and set a non-zero exit code.",
|
|
248
|
+
"type": "string",
|
|
249
|
+
"const": "error"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"description": "Report without an effect on the exit code.",
|
|
253
|
+
"type": "string",
|
|
254
|
+
"const": "warn"
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"description": "Don't detect or report.",
|
|
258
|
+
"type": "string",
|
|
259
|
+
"const": "off"
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|