code-auditor-mcp 4.0.4 → 4.1.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +96 -0
- package/README.md +5 -5
- package/configs/hhra-compat.json +2 -2
- package/dist/analyzers/applicability.d.ts +25 -2
- package/dist/analyzers/applicability.d.ts.map +1 -1
- package/dist/analyzers/applicability.js +44 -50
- package/dist/analyzers/applicability.js.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts +18 -49
- package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.js +22 -240
- package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.d.ts +2 -14
- package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.js +0 -104
- package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
- package/dist/analyzers/orgFilterTiers.d.ts +89 -0
- package/dist/analyzers/orgFilterTiers.d.ts.map +1 -0
- package/dist/analyzers/orgFilterTiers.js +96 -0
- package/dist/analyzers/orgFilterTiers.js.map +1 -0
- package/dist/analyzers/ruleRegistry.d.ts +15 -0
- package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
- package/dist/analyzers/ruleRegistry.js +139 -185
- package/dist/analyzers/ruleRegistry.js.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +39 -0
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +62 -41
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +2 -2
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +2 -2
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSecurityAnalyzer.d.ts +86 -0
- package/dist/analyzers/universal/UniversalSecurityAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/universal/UniversalSecurityAnalyzer.js +606 -0
- package/dist/analyzers/universal/UniversalSecurityAnalyzer.js.map +1 -0
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts +14 -0
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.js +35 -18
- package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
- package/dist/analyzers/universal/schema/migrations.d.ts +14 -1
- package/dist/analyzers/universal/schema/migrations.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/migrations.js +58 -14
- package/dist/analyzers/universal/schema/migrations.js.map +1 -1
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +70 -13
- package/dist/auditRunner.js.map +1 -1
- package/dist/churn/churnExtractor.js +5 -5
- package/dist/churn/churnExtractor.js.map +1 -1
- package/dist/cli.js +21 -9
- package/dist/cli.js.map +1 -1
- package/dist/codeIndexDB.d.ts +6 -0
- package/dist/codeIndexDB.d.ts.map +1 -1
- package/dist/codeIndexDB.js +33 -1
- package/dist/codeIndexDB.js.map +1 -1
- package/dist/config/configGeneratePath.d.ts +19 -0
- package/dist/config/configGeneratePath.d.ts.map +1 -0
- package/dist/config/configGeneratePath.js +29 -0
- package/dist/config/configGeneratePath.js.map +1 -0
- package/dist/config/configLoader.d.ts +36 -4
- package/dist/config/configLoader.d.ts.map +1 -1
- package/dist/config/configLoader.js +136 -15
- package/dist/config/configLoader.js.map +1 -1
- package/dist/config/lintConfigReader.d.ts +4 -0
- package/dist/config/lintConfigReader.d.ts.map +1 -1
- package/dist/config/lintConfigReader.js +35 -36
- package/dist/config/lintConfigReader.js.map +1 -1
- package/dist/config/staticObjectExtract.d.ts +35 -0
- package/dist/config/staticObjectExtract.d.ts.map +1 -0
- package/dist/config/staticObjectExtract.js +312 -0
- package/dist/config/staticObjectExtract.js.map +1 -0
- package/dist/constants.d.ts +1 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -2
- package/dist/constants.js.map +1 -1
- package/dist/daemon/core.js +1 -1
- package/dist/daemon/core.js.map +1 -1
- package/dist/daemon/main.js +1 -1
- package/dist/daemon/main.js.map +1 -1
- package/dist/dataPaths.d.ts.map +1 -1
- package/dist/dataPaths.js +11 -2
- package/dist/dataPaths.js.map +1 -1
- package/dist/generators/BaseConfigGenerator.d.ts +0 -4
- package/dist/generators/BaseConfigGenerator.d.ts.map +1 -1
- package/dist/generators/BaseConfigGenerator.js +1 -7
- package/dist/generators/BaseConfigGenerator.js.map +1 -1
- package/dist/installConfig.d.ts +3 -1
- package/dist/installConfig.d.ts.map +1 -1
- package/dist/installConfig.js +15 -2
- package/dist/installConfig.js.map +1 -1
- package/dist/installer.d.ts +10 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +14 -2
- package/dist/installer.js.map +1 -1
- package/dist/languages/LanguageOrchestrator.js +6 -6
- package/dist/languages/LanguageOrchestrator.js.map +1 -1
- package/dist/languages/RuntimeManager.js +13 -10
- package/dist/languages/RuntimeManager.js.map +1 -1
- package/dist/mcp-tools-shared.d.ts.map +1 -1
- package/dist/mcp-tools-shared.js +7 -2
- package/dist/mcp-tools-shared.js.map +1 -1
- package/dist/mcp-ui-simple.d.ts +5 -1
- package/dist/mcp-ui-simple.d.ts.map +1 -1
- package/dist/mcp-ui-simple.js +81 -29
- package/dist/mcp-ui-simple.js.map +1 -1
- package/dist/mcp.js +19 -4
- package/dist/mcp.js.map +1 -1
- package/dist/mcpAuditJobs.d.ts.map +1 -1
- package/dist/mcpAuditJobs.js +1 -0
- package/dist/mcpAuditJobs.js.map +1 -1
- package/dist/nextFileIncremental.js +1 -1
- package/dist/nextFileIncremental.js.map +1 -1
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +13 -2
- package/dist/pipeline.js.map +1 -1
- package/dist/pipelineAdapters.d.ts +15 -0
- package/dist/pipelineAdapters.d.ts.map +1 -1
- package/dist/pipelineAdapters.js +140 -6
- package/dist/pipelineAdapters.js.map +1 -1
- package/dist/reporting/htmlReportGenerator.js +2 -2
- package/dist/reporting/htmlReportGenerator.js.map +1 -1
- package/dist/ruleAliases.d.ts.map +1 -1
- package/dist/ruleAliases.js +45 -0
- package/dist/ruleAliases.js.map +1 -1
- package/dist/styles/tailwindConfigLoader.d.ts +4 -0
- package/dist/styles/tailwindConfigLoader.d.ts.map +1 -1
- package/dist/styles/tailwindConfigLoader.js +54 -36
- package/dist/styles/tailwindConfigLoader.js.map +1 -1
- package/dist/types.d.ts +55 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -1
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/examples/.auditrc.example.json +2 -2
- package/examples/.auditrc.json +3 -3
- package/examples/nextjs.auditrc.json +1 -1
- package/examples/node-api.auditrc.json +1 -1
- package/examples/react.auditrc.json +2 -2
- package/examples/tolerant-solid.auditrc.json +1 -1
- package/package.json +2 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/scripts/hook-common.sh +27 -27
- package/plugin/skills/code-auditor/SKILL.md +1 -1
- package/server.json +2 -2
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "code-auditor",
|
|
11
11
|
"source": "./plugin",
|
|
12
12
|
"description": "Diff-scoped code quality auditing on every edit. Indexes your codebase, enforces invariants, and feeds violations back to the agent so fixes happen inline.",
|
|
13
|
-
"version": "4.0
|
|
13
|
+
"version": "4.1.0",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Ben Hammond"
|
|
16
16
|
},
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,102 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the Code Auditor MCP project.
|
|
4
4
|
|
|
5
|
+
## [4.1.0] — 2026-09-23
|
|
6
|
+
|
|
7
|
+
### Severity becomes a three-tier urgency ladder, not a permission knob
|
|
8
|
+
|
|
9
|
+
The `warning`/`suggestion` vocabulary that leaked from the old linter semantics
|
|
10
|
+
is gone. Every finding is now `critical`, `severe`, or `high` — three defect
|
|
11
|
+
tiers with nothing below `high` — and the agent gate blocks **all three**. The
|
|
12
|
+
old per-rule severity knobs (`gateSeverities`, `DEFAULT_BLOCKING_SEVERITIES`,
|
|
13
|
+
`severityOverrides`, and path-profile severity capping) are deleted: a team that
|
|
14
|
+
disagrees with a level scopes the finding out of the gate (`excludeFromGate`) or
|
|
15
|
+
edits the rule, it never re-labels severity.
|
|
16
|
+
|
|
17
|
+
- **102 live severity rules** re-assigned on the urgency axis — 11 `critical`, 37
|
|
18
|
+
`severe`, 54 `high` — one row per rule with rationale in
|
|
19
|
+
`specs/severity-assignment-ledger.md`, plus 4 off-ladder diagnostics.
|
|
20
|
+
- `--fail-on` and `excludeFromGate` remain — they are *scope* controls, not level
|
|
21
|
+
controls.
|
|
22
|
+
- Stale `warning`/`suggestion` literals swept from the shipped configs, README,
|
|
23
|
+
CONTRIBUTING, and the 78 corpus `expected.json` fixtures; a new
|
|
24
|
+
`examplesValidate.spec.ts` loads every shipped example through `loadConfig`, so
|
|
25
|
+
a stale value regresses to a red test rather than silently shipping.
|
|
26
|
+
|
|
27
|
+
### Ten rules that could never fire are removed, not kept as standing no-ops
|
|
28
|
+
|
|
29
|
+
A rule with no reachable emission site is a finding about the analyzer, not a
|
|
30
|
+
rule to assign severity to. Six `api-contract` rules, the schema `file-error`,
|
|
31
|
+
and three schema-validator aliases (`field-mismatch`, `constraint-mismatch`,
|
|
32
|
+
`version-mismatch`) had exactly that shape — a legacy alias or a predicate
|
|
33
|
+
reading a field no extractor ever populated — so they were deleted outright
|
|
34
|
+
(registry entry, emitter, and ledger row). The ten IDs are tombstoned in
|
|
35
|
+
`ruleAliases.ts` so a stale reference reports *why* each was removed. The
|
|
36
|
+
`cannot-fire` class drops 10 → 0; `APIContractAnalyzer` is now a no-op returning
|
|
37
|
+
`[]`, pending real endpoint/call extraction.
|
|
38
|
+
|
|
39
|
+
### `missing-org-filter` fires where it should: hhra-org 0 → 9
|
|
40
|
+
|
|
41
|
+
The rule was *applicable* on a DDL-declared multi-tenant corpus (hhra-org) yet
|
|
42
|
+
*fired zero findings* — a false `clean` on a real tenant-isolation leak. Firing
|
|
43
|
+
and applicability had drifted to two different tenancy predicates. Both now
|
|
44
|
+
derive from a single `buildOrgFilterTierSet`, and the rule moved to Stage 4,
|
|
45
|
+
where the DDL-discovered tenant columns live. hhra-org now reports 9
|
|
46
|
+
`missing-org-filter` findings (was 0), and the exact `organization_id = $n`
|
|
47
|
+
positional shape is pinned in a fixture so the long-form column case can't go
|
|
48
|
+
vacuous again. Severity stays `critical` — no provenance tier (recorded, not
|
|
49
|
+
assumed).
|
|
50
|
+
|
|
51
|
+
### `unescaped-html-interpolation` stops trusting what a string *looks* like
|
|
52
|
+
|
|
53
|
+
The rule used to fire on any template literal whose text contained an HTML tag —
|
|
54
|
+
which flagged a react-analyzer violation *message* as stored XSS and missed 8
|
|
55
|
+
real sinks. It now computes flow: `computeHtmlSinkTemplates` backward-propagates
|
|
56
|
+
from genuine HTML sinks to find which template values actually reach one. The
|
|
57
|
+
sink set is completed to include `setHTMLUnsafe`, Vue `v-html`, the jQuery/Hono
|
|
58
|
+
`.html(x)` setter, and React `dangerouslySetInnerHTML`. The old text trigger's 77
|
|
59
|
+
false positives across corpora are gone; the one real delta is `endless-guessing`
|
|
60
|
+
0 → 3 (a Hono `c.html(…)` sink).
|
|
61
|
+
|
|
62
|
+
### The self-audit gate actually enforces all three tiers now
|
|
63
|
+
|
|
64
|
+
`verify:self`'s blocking predicate had drifted to `critical | severe` — a
|
|
65
|
+
two-tier narrowing that let `high` findings through the ratchet (itself a second
|
|
66
|
+
bug on top of the earlier `'warning'` fix). It now matches `BLOCKING_SEVERITIES`
|
|
67
|
+
(`critical | severe | high`). Re-running surfaced 7 in-scope findings, resolved
|
|
68
|
+
as 4 fixes (including splitting `computeHtmlSinkTemplates`' fused visitor into
|
|
69
|
+
three single-purpose phases) and 3 correct-by-design `(file, rule)` scoped
|
|
70
|
+
exemptions with written rationale — excluded *by scope*, never by re-labelling
|
|
71
|
+
severity. The exemptions are now also self-policing: `verify:self` fails on any
|
|
72
|
+
exemption whose `(file, rule)` pair no longer fires, so a suppression can't
|
|
73
|
+
outlive the finding it suppressed (the `SKIP_RULES` failure mode).
|
|
74
|
+
|
|
75
|
+
### Gate-liveness tests (Spec 62 R9)
|
|
76
|
+
|
|
77
|
+
A gate that "passes" because it checks nothing is the same defect shape as
|
|
78
|
+
`missing-org-filter` — a clean result from a check that isn't there. New
|
|
79
|
+
`gate-liveness.test.ts` proves each gate's failure branch is live: `verify:self`'s
|
|
80
|
+
predicate (extracted to `verify-self-core.mjs`), `verify:disk-space`,
|
|
81
|
+
`verify:gate-budget`, and `assert_compatible` each exit non-zero against their
|
|
82
|
+
own trigger, so a gate can no longer silently pass by checking nothing.
|
|
83
|
+
|
|
84
|
+
### Registry ↔ ledger reconciliation
|
|
85
|
+
|
|
86
|
+
The rule registry and the authenticity/severity ledgers are now reconciled
|
|
87
|
+
bidirectionally — registry ids with no ledger row, ledger rows with no registry
|
|
88
|
+
id, and the two unregistered-live emit sites are pinned by a membership test so
|
|
89
|
+
the two books can't drift apart.
|
|
90
|
+
|
|
91
|
+
### Release-rail changes
|
|
92
|
+
|
|
93
|
+
- **`bench` removed from `verify:close`** — it is a measurement, not a gate. The
|
|
94
|
+
close gate is now `verify:disk-space && verify:types && verify:dist-fresh &&
|
|
95
|
+
test && test:integration && verify:gate-budget && verify:clean-install &&
|
|
96
|
+
verify:dist && verify:self`.
|
|
97
|
+
- `verify:gate-budget` and `verify:disk-space` gained env overrides
|
|
98
|
+
(`VERIFY_GATE_BUDGET_MS`, `VERIFY_MIN_FREE_BYTES`) so their failure branches are
|
|
99
|
+
testable without a genuinely slow rule or a genuinely full disk.
|
|
100
|
+
|
|
5
101
|
## [4.0.4] — 2026-09-20
|
|
6
102
|
|
|
7
103
|
### Go analysis now works everywhere, not just Intel Macs
|
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ Code Auditor's built-in rules fall into two categories:
|
|
|
92
92
|
| **Deterministic** | Structural fact — an engineer would act on every finding | `single-responsibility` (300-line functions), `solid/method-complexity` (cyclomatic complexity > 20), `solid/class-size` (40+ method classes), `dependency-inversion` (concrete imports where an interface exists) |
|
|
93
93
|
| **Advisory** | Heuristic signal — may be wrong depending on domain | `sql-injection-risk` (AST-level string-pattern matching without type info), `missing-org-filter` (domain-specific — assumes SaaS tenant isolation), `unknown-table` (requires user-provided schema), `dry/duplicate` (token-identical blocks) |
|
|
94
94
|
|
|
95
|
-
Deterministic rules ship at `critical` or `
|
|
95
|
+
Deterministic rules ship at `critical` or `severe`. Advisory rules ship at `severe` or `high`. Rules proven near-zero precision on a real corpus are **disabled by default** (`off`) — users opt in when the rule matches their domain.
|
|
96
96
|
|
|
97
97
|
### Recalibration
|
|
98
98
|
|
|
@@ -103,9 +103,9 @@ Every disabled rule documents what corpus it *would* be useful on. Users can res
|
|
|
103
103
|
```json
|
|
104
104
|
{
|
|
105
105
|
"severityOverrides": {
|
|
106
|
-
"sql-injection-risk": "
|
|
107
|
-
"missing-org-filter": "
|
|
108
|
-
"loop-query": "
|
|
106
|
+
"sql-injection-risk": "critical",
|
|
107
|
+
"missing-org-filter": "severe",
|
|
108
|
+
"loop-query": "severe"
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
```
|
|
@@ -195,7 +195,7 @@ code-audit search "mechanism:inline css:color" # inline color declarati
|
|
|
195
195
|
code-audit search "token:--color-primary" # bypassing a design token
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
-
**The React analyzer** also gains raw-element detection: if your project has a `Button` wrapper, raw `<button>` usages outside `Button`'s definition become
|
|
198
|
+
**The React analyzer** also gains raw-element detection: if your project has a `Button` wrapper, raw `<button>` usages outside `Button`'s definition become severe findings.
|
|
199
199
|
|
|
200
200
|
## License
|
|
201
201
|
|
package/configs/hhra-compat.json
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
|
|
26
26
|
"enabledAnalyzers": [
|
|
27
|
-
"
|
|
27
|
+
"react",
|
|
28
28
|
"security",
|
|
29
29
|
"solid",
|
|
30
30
|
"dry",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"outputFormats": ["html", "json"],
|
|
139
139
|
"outputDirectory": "./audit-reports",
|
|
140
140
|
|
|
141
|
-
"minSeverity": "
|
|
141
|
+
"minSeverity": "high",
|
|
142
142
|
"failOnCritical": false,
|
|
143
143
|
"verbose": false,
|
|
144
144
|
"showProgress": true,
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
* UniversalSchemaAnalyzer.js → makeVisitorStatus), so a static analyzer import
|
|
14
14
|
* here would create a pipeline↔analyzer cycle. The pipeline-side convention is
|
|
15
15
|
* to reach analyzers only through dynamic import() (see pipelineAdapters.ts).
|
|
16
|
+
*
|
|
17
|
+
* The one exception is {@link orgFilterTiers}: a pure, dependency-free module
|
|
18
|
+
* that is the single source of truth for tenant-scoping tiers. Both this
|
|
19
|
+
* applicability predicate and the Stage-4 missing-org-filter reducer derive
|
|
20
|
+
* from it, so firing and applicability can never read different tier sets.
|
|
16
21
|
*/
|
|
17
22
|
export interface RuleApplicability {
|
|
18
23
|
applicable: boolean;
|
|
@@ -85,11 +90,12 @@ export interface UnreadStyleSourceInfo {
|
|
|
85
90
|
*
|
|
86
91
|
* @param ruleId The registry rule id.
|
|
87
92
|
* @param dataAccessConfig The namespaced data-access config (may be undefined).
|
|
88
|
-
* @param
|
|
93
|
+
* @param ddlTableColumns Aggregated DDL-declared per-table columns from the
|
|
94
|
+
* schema reducer (`Record<table, columns>`), folded corpus-wide.
|
|
89
95
|
* @returns The rule's applicability verdict, or null when the rule declares no
|
|
90
96
|
* applicability predicate and runs unconditionally.
|
|
91
97
|
*/
|
|
92
|
-
export declare function evaluateRuleApplicability(ruleId: string, dataAccessConfig: Record<string, unknown> | undefined,
|
|
98
|
+
export declare function evaluateRuleApplicability(ruleId: string, dataAccessConfig: Record<string, unknown> | undefined, ddlTableColumns: Record<string, string[]> | undefined): RuleApplicability | null;
|
|
93
99
|
/**
|
|
94
100
|
* Spec 44 bucket 2 — rules that are structurally unreachable: their predicate
|
|
95
101
|
* reads a field no extractor populates (or they are a legacy alias with no
|
|
@@ -101,6 +107,23 @@ export declare function evaluateRuleApplicability(ruleId: string, dataAccessConf
|
|
|
101
107
|
* Each reason names the specific extractor and the specific field (or absence
|
|
102
108
|
* of an emission site) so a reader can tell *why* it cannot fire. Remove an id
|
|
103
109
|
* here when its extraction begins emitting it.
|
|
110
|
+
*
|
|
111
|
+
* As of 4.1.0 this map is empty: the ten `cannot-fire` rules (the six
|
|
112
|
+
* api-contract rules, `file-error`, and the three schema-validator aliases)
|
|
113
|
+
* were removed outright — registry entry, emission site, and ledger row — rather
|
|
114
|
+
* than kept as standing findings. The `cannot-fire` verdict remains part of the
|
|
115
|
+
* applicability vocabulary for when a future rule is genuinely unreachable, but
|
|
116
|
+
* no such rule currently exists.
|
|
117
|
+
*
|
|
118
|
+
* This map is NOT the only producer of the `cannot-fire` state: the static-config
|
|
119
|
+
* extractors (`lintConfigReader.ts`, `tailwindConfigLoader.ts`, and the
|
|
120
|
+
* styles-source visitor in `pipelineAdapters.ts`) emit a `CoverageDiagnostic`
|
|
121
|
+
* with `kind: 'cannot-fire'` when a project config cannot be read statically
|
|
122
|
+
* (Spec 61 R3.4). That diagnostic route is independent of this map, so emptying
|
|
123
|
+
* this map does not dead the `cannot-fire` state — the diagnostic route remains
|
|
124
|
+
* live (and is exercised by `spec61-exploits.spec.ts` fixture 8). The
|
|
125
|
+
* unresolvable dynamic-import path emits the sibling `unresolved-dynamic-import`
|
|
126
|
+
* kind, not `cannot-fire`.
|
|
104
127
|
*/
|
|
105
128
|
export declare const CANNOT_FIRE_RULES: ReadonlyMap<string, string>;
|
|
106
129
|
//# sourceMappingURL=applicability.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applicability.d.ts","sourceRoot":"","sources":["../../src/analyzers/applicability.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"applicability.d.ts","sourceRoot":"","sources":["../../src/analyzers/applicability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAQH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,eAAe,GAAG,aAAa,CAAC;CACxC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAAC,MAAM,CAMrD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAWhC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACrD,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,GACpD,iBAAiB,GAAG,IAAI,CAS1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAe,CAAC"}
|
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
* UniversalSchemaAnalyzer.js → makeVisitorStatus), so a static analyzer import
|
|
14
14
|
* here would create a pipeline↔analyzer cycle. The pipeline-side convention is
|
|
15
15
|
* to reach analyzers only through dynamic import() (see pipelineAdapters.ts).
|
|
16
|
+
*
|
|
17
|
+
* The one exception is {@link orgFilterTiers}: a pure, dependency-free module
|
|
18
|
+
* that is the single source of truth for tenant-scoping tiers. Both this
|
|
19
|
+
* applicability predicate and the Stage-4 missing-org-filter reducer derive
|
|
20
|
+
* from it, so firing and applicability can never read different tier sets.
|
|
16
21
|
*/
|
|
22
|
+
import { buildOrgFilterTierSet, hasDeclaredTenancy, } from './orgFilterTiers.js';
|
|
17
23
|
/**
|
|
18
24
|
* Spec 52 R3 — the whole-program rule class. These rules draw a global
|
|
19
25
|
* conclusion ("table X is never read", "table Y is unknown", "no validator is
|
|
@@ -70,13 +76,6 @@ export function scopedWholeProgramApplicability(isScoped, fileCount) {
|
|
|
70
76
|
}
|
|
71
77
|
return map;
|
|
72
78
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Default tenant-scoping column names. The single source of truth is
|
|
75
|
-
* DEFAULT_DATA_ACCESS_CONFIG.orgFilterColumns in UniversalDataAccessAnalyzer.js;
|
|
76
|
-
* this is a local copy because importing that module here would create the cycle
|
|
77
|
-
* described above. Keep in sync with that constant.
|
|
78
|
-
*/
|
|
79
|
-
const DEFAULT_ORG_FILTER_COLUMNS = ['org_id', 'tenant_id', 'organization_id', 'workspace_id'];
|
|
80
79
|
/**
|
|
81
80
|
* Evaluate whether a rule is applicable to the current codebase, given inputs
|
|
82
81
|
* the pipeline has already computed.
|
|
@@ -87,13 +86,14 @@ const DEFAULT_ORG_FILTER_COLUMNS = ['org_id', 'tenant_id', 'organization_id', 'w
|
|
|
87
86
|
*
|
|
88
87
|
* @param ruleId The registry rule id.
|
|
89
88
|
* @param dataAccessConfig The namespaced data-access config (may be undefined).
|
|
90
|
-
* @param
|
|
89
|
+
* @param ddlTableColumns Aggregated DDL-declared per-table columns from the
|
|
90
|
+
* schema reducer (`Record<table, columns>`), folded corpus-wide.
|
|
91
91
|
* @returns The rule's applicability verdict, or null when the rule declares no
|
|
92
92
|
* applicability predicate and runs unconditionally.
|
|
93
93
|
*/
|
|
94
|
-
export function evaluateRuleApplicability(ruleId, dataAccessConfig,
|
|
94
|
+
export function evaluateRuleApplicability(ruleId, dataAccessConfig, ddlTableColumns) {
|
|
95
95
|
if (ruleId === 'missing-org-filter') {
|
|
96
|
-
return evaluateMissingOrgFilterApplicability(dataAccessConfig,
|
|
96
|
+
return evaluateMissingOrgFilterApplicability(dataAccessConfig, ddlTableColumns);
|
|
97
97
|
}
|
|
98
98
|
const cannotFireReason = CANNOT_FIRE_RULES.get(ruleId);
|
|
99
99
|
if (cannotFireReason !== undefined) {
|
|
@@ -112,50 +112,44 @@ export function evaluateRuleApplicability(ruleId, dataAccessConfig, ddlColumns)
|
|
|
112
112
|
* Each reason names the specific extractor and the specific field (or absence
|
|
113
113
|
* of an emission site) so a reader can tell *why* it cannot fire. Remove an id
|
|
114
114
|
* here when its extraction begins emitting it.
|
|
115
|
+
*
|
|
116
|
+
* As of 4.1.0 this map is empty: the ten `cannot-fire` rules (the six
|
|
117
|
+
* api-contract rules, `file-error`, and the three schema-validator aliases)
|
|
118
|
+
* were removed outright — registry entry, emission site, and ledger row — rather
|
|
119
|
+
* than kept as standing findings. The `cannot-fire` verdict remains part of the
|
|
120
|
+
* applicability vocabulary for when a future rule is genuinely unreachable, but
|
|
121
|
+
* no such rule currently exists.
|
|
122
|
+
*
|
|
123
|
+
* This map is NOT the only producer of the `cannot-fire` state: the static-config
|
|
124
|
+
* extractors (`lintConfigReader.ts`, `tailwindConfigLoader.ts`, and the
|
|
125
|
+
* styles-source visitor in `pipelineAdapters.ts`) emit a `CoverageDiagnostic`
|
|
126
|
+
* with `kind: 'cannot-fire'` when a project config cannot be read statically
|
|
127
|
+
* (Spec 61 R3.4). That diagnostic route is independent of this map, so emptying
|
|
128
|
+
* this map does not dead the `cannot-fire` state — the diagnostic route remains
|
|
129
|
+
* live (and is exercised by `spec61-exploits.spec.ts` fixture 8). The
|
|
130
|
+
* unresolvable dynamic-import path emits the sibling `unresolved-dynamic-import`
|
|
131
|
+
* kind, not `cannot-fire`.
|
|
115
132
|
*/
|
|
116
|
-
export const CANNOT_FIRE_RULES = new Map([
|
|
117
|
-
// api-contract — reads response/auth metadata that extractEndpoints /
|
|
118
|
-
// extractAPICalls never populate, or has no emission site at all.
|
|
119
|
-
['api-type-mismatch', 'cannot fire — extractEndpoints/extractAPICalls never populate responseSchema/expectedResponseType/deprecated, the fields this rule reads'],
|
|
120
|
-
['missing-endpoint', 'cannot fire — gated: extractMethodFrom*/extractPathFromGo derive method and URL from function names (name proxy), so any finding is fabricated'],
|
|
121
|
-
['api-extra-field', 'cannot fire — no emission site: the analyzer has no code that produces this rule'],
|
|
122
|
-
['api-missing-field', 'cannot fire — no emission site: the analyzer has no code that produces this rule'],
|
|
123
|
-
['method-mismatch', 'cannot fire — gated: extractMethodFrom* derives the verb from function names (name proxy), so any finding is fabricated'],
|
|
124
|
-
['auth-mismatch', 'cannot fire — extractEndpoints never sets `authentication`, the field this rule reads'],
|
|
125
|
-
// schema — file errors are routed to state.errors, never a file-error violation.
|
|
126
|
-
['file-error', 'cannot fire — schema file errors are routed to state.errors, never emitted as a `file-error` violation'],
|
|
127
|
-
// schema-validator — legacy alias or reads constraints/version the extractor never assigns.
|
|
128
|
-
['field-mismatch', 'cannot fire — legacy alias: the validator emits `schema-field-mismatch`, never `field-mismatch`'],
|
|
129
|
-
['constraint-mismatch', 'cannot fire — extractSchemas never assigns `constraints` on fields, the input this rule reads'],
|
|
130
|
-
['version-mismatch', 'cannot fire — extractSchemas never assigns `version` on schemas, the input this rule reads'],
|
|
131
|
-
]);
|
|
133
|
+
export const CANNOT_FIRE_RULES = new Map([]);
|
|
132
134
|
/**
|
|
133
|
-
* Spec 39/42 R3 — `missing-org-filter` is applicable when
|
|
134
|
-
*
|
|
135
|
-
*
|
|
135
|
+
* Spec 39/42 R3 + Spec 62 Amendment B — `missing-org-filter` is applicable when
|
|
136
|
+
* the project declares tenancy in any tier. Applicability and firing read the
|
|
137
|
+
* SAME tier set, built once by {@link buildOrgFilterTierSet}:
|
|
138
|
+
*
|
|
139
|
+
* Tier 1 (config-primary) — `orgFilterTables`, the explicit tenant-table list.
|
|
140
|
+
* Tier 2 (schema-inference) — a configured schema table carrying a
|
|
141
|
+
* tenant-scoping column (org_id/tenant_id/organization_id/workspace_id).
|
|
142
|
+
* Tier 3 (DDL-discovery) — a table whose DDL columns carry a tenant-scoping
|
|
143
|
+
* column. This tier was the Amendment B defect: applicability read it (3
|
|
144
|
+
* tiers) while the firing predicate read only Tiers 1–2, so a DDL-declared
|
|
145
|
+
* multi-tenant codebase un-suppressed the rule without ever making it fire —
|
|
146
|
+
* reporting `clean` on a real leak. Both consumers now derive from one
|
|
147
|
+
* function, so they cannot drift.
|
|
136
148
|
*/
|
|
137
|
-
function evaluateMissingOrgFilterApplicability(dataAccessConfig,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (orgFilterTables.length > 0)
|
|
141
|
-
return { applicable: true };
|
|
142
|
-
const orgFilterColumns = dataAccessConfig?.orgFilterColumns ?? DEFAULT_ORG_FILTER_COLUMNS;
|
|
143
|
-
const schemas = dataAccessConfig?.schemas ?? [];
|
|
144
|
-
const tenantColumns = new Set(orgFilterColumns.map((c) => String(c).toLowerCase()));
|
|
145
|
-
// Tier 2 — a configured schema declares a table carrying a tenant-scoping column.
|
|
146
|
-
for (const schema of schemas) {
|
|
147
|
-
for (const table of schema.tables ?? []) {
|
|
148
|
-
for (const column of table.columns ?? []) {
|
|
149
|
-
if (tenantColumns.has(String(column.name).toLowerCase())) {
|
|
150
|
-
return { applicable: true };
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
// Tier 3 — the table catalog (DDL-derived columns) carries a tenant-scoping column.
|
|
156
|
-
if (ddlColumns?.some((c) => tenantColumns.has(String(c).toLowerCase()))) {
|
|
149
|
+
function evaluateMissingOrgFilterApplicability(dataAccessConfig, ddlTableColumns) {
|
|
150
|
+
const tierSet = buildOrgFilterTierSet(dataAccessConfig, ddlTableColumns);
|
|
151
|
+
if (hasDeclaredTenancy(tierSet))
|
|
157
152
|
return { applicable: true };
|
|
158
|
-
}
|
|
159
153
|
return {
|
|
160
154
|
applicable: false,
|
|
161
155
|
reason: 'no tenant-scoping column found in table catalog',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applicability.js","sourceRoot":"","sources":["../../src/analyzers/applicability.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"applicability.js","sourceRoot":"","sources":["../../src/analyzers/applicability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,qBAAqB,EACrB,kBAAkB,GAEnB,MAAM,qBAAqB,CAAC;AAe7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA0B;IACxD,iCAAiC;IACjC,iCAAiC;IACjC,qCAAqC;IACrC,eAAe;IACf,uBAAuB;CACxB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAAiB,EACjB,SAAiB;IAEjB,MAAM,GAAG,GAAG,IAAI,GAAG,EAA6B,CAAC;IACjD,IAAI,CAAC,QAAQ;QAAE,OAAO,GAAG,CAAC;IAC1B,KAAK,MAAM,MAAM,IAAI,mBAAmB,EAAE,CAAC;QACzC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE;YACd,UAAU,EAAE,KAAK;YACjB,IAAI,EAAE,eAAe;YACrB,MAAM,EAAE,2DAA2D,SAAS,UAAU;SACvF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAcD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAc,EACd,gBAAqD,EACrD,eAAqD;IAErD,IAAI,MAAM,KAAK,oBAAoB,EAAE,CAAC;QACpC,OAAO,qCAAqC,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvD,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACnC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAgC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;AAE1E;;;;;;;;;;;;;;GAcG;AACH,SAAS,qCAAqC,CAC5C,gBAAqD,EACrD,eAAqD;IAErD,MAAM,OAAO,GAAG,qBAAqB,CAAC,gBAA+C,EAAE,eAAe,CAAC,CAAC;IACxG,IAAI,kBAAkB,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAE7D,OAAO;QACL,UAAU,EAAE,KAAK;QACjB,MAAM,EAAE,iDAAiD;KAC1D,CAAC;AACJ,CAAC"}
|
|
@@ -28,61 +28,30 @@ export interface APICall {
|
|
|
28
28
|
errorHandling?: string[];
|
|
29
29
|
timeout?: number;
|
|
30
30
|
}
|
|
31
|
-
export interface ContractViolation extends Violation {
|
|
32
|
-
rule: 'api-type-mismatch' | 'missing-endpoint' | 'api-extra-field' | 'api-missing-field' | 'method-mismatch' | 'auth-mismatch';
|
|
33
|
-
contractType: 'api-type-mismatch' | 'missing-endpoint' | 'api-extra-field' | 'api-missing-field' | 'method-mismatch' | 'auth-mismatch';
|
|
34
|
-
endpoint?: APIEndpoint;
|
|
35
|
-
call?: APICall;
|
|
36
|
-
expectedType?: string;
|
|
37
|
-
actualType?: string;
|
|
38
|
-
missingFields?: string[];
|
|
39
|
-
extraFields?: string[];
|
|
40
|
-
}
|
|
41
31
|
/**
|
|
42
32
|
* Api contract analyzer.
|
|
33
|
+
*
|
|
34
|
+
* All six api-contract rules were removed in 4.1.0: each was `cannot-fire` (its
|
|
35
|
+
* extractor never populated the fields it read, or its computation was a name
|
|
36
|
+
* proxy). The rules were removed outright rather than kept as standing findings,
|
|
37
|
+
* so this analyzer is a no-op that returns no violations. The endpoint/call
|
|
38
|
+
* extraction below remains for when real contract extraction lands.
|
|
43
39
|
*/
|
|
44
40
|
export declare class APIContractAnalyzer {
|
|
45
|
-
private endpoints;
|
|
46
|
-
private calls;
|
|
47
|
-
/**
|
|
48
|
-
* Analyze API contracts and find violations
|
|
49
|
-
* @param calls
|
|
50
|
-
* @param endpoints
|
|
51
|
-
* @returns
|
|
52
|
-
*/
|
|
53
|
-
analyzeContracts(endpoints: APIEndpoint[], calls: APICall[]): Promise<ContractViolation[]>;
|
|
54
|
-
/**
|
|
55
|
-
* Find API calls that don't have matching endpoints
|
|
56
|
-
*/
|
|
57
|
-
private findUnmatchedCalls;
|
|
58
|
-
/**
|
|
59
|
-
* Validate matched endpoint-call pairs for compatibility
|
|
60
|
-
*/
|
|
61
|
-
private validateMatchedPairs;
|
|
62
|
-
/**
|
|
63
|
-
* Check for usage of deprecated APIs
|
|
64
|
-
*/
|
|
65
|
-
private checkDeprecatedUsage;
|
|
66
|
-
/**
|
|
67
|
-
* Validate authentication requirements
|
|
68
|
-
*/
|
|
69
|
-
private validateAuthentication;
|
|
70
|
-
/**
|
|
71
|
-
* Find matching endpoint for an API call
|
|
72
|
-
*/
|
|
73
|
-
private findMatchingEndpoint;
|
|
74
|
-
/**
|
|
75
|
-
* Check if two API paths match (handling path parameters)
|
|
76
|
-
*/
|
|
77
|
-
private pathsMatch;
|
|
78
|
-
/**
|
|
79
|
-
* Validate type compatibility between endpoint and call
|
|
80
|
-
*/
|
|
81
|
-
private validateTypeCompatibility;
|
|
82
41
|
/**
|
|
83
|
-
*
|
|
42
|
+
* Detect mismatches between a project's declared API endpoints and the calls
|
|
43
|
+
* its clients make against them.
|
|
44
|
+
*
|
|
45
|
+
* A no-op as of 4.1.0: all six api-contract rules this method fed were removed
|
|
46
|
+
* (each was `cannot-fire`), so it always returns an empty list. Kept as the
|
|
47
|
+
* seam real contract extraction will plug into — the endpoint/call extraction
|
|
48
|
+
* below remains for that work.
|
|
49
|
+
*
|
|
50
|
+
* @param _endpoints The API endpoints extracted from the corpus.
|
|
51
|
+
* @param _calls The API calls extracted from the corpus.
|
|
52
|
+
* @returns An empty list (no contract rules are live).
|
|
84
53
|
*/
|
|
85
|
-
|
|
54
|
+
analyzeContracts(_endpoints: APIEndpoint[], _calls: APICall[]): Promise<Violation[]>;
|
|
86
55
|
}
|
|
87
56
|
/**
|
|
88
57
|
* Extract API endpoints from code entities
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"APIContractAnalyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/cross-language/APIContractAnalyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"APIContractAnalyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/cross-language/APIContractAnalyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAmB;IAC9B;;;;;;;;;;;;OAYG;IACG,gBAAgB,CACpB,UAAU,EAAE,WAAW,EAAE,EACzB,MAAM,EAAE,OAAO,EAAE,GAChB,OAAO,CAAC,SAAS,EAAE,CAAC;CAGxB;AAUD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,WAAW,EAAE,CAwB/D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,CAkB1D"}
|