code-auditor-mcp 3.9.6 → 3.9.9
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 +106 -0
- package/README.md +18 -0
- package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/reactAnalyzer.js +4 -1
- package/dist/analyzers/reactAnalyzer.js.map +1 -1
- package/dist/analyzers/ruleRegistry.d.ts +8 -0
- package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
- package/dist/analyzers/ruleRegistry.js +20 -10
- package/dist/analyzers/ruleRegistry.js.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +23 -20
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
- package/dist/auditRouter.d.ts.map +1 -1
- package/dist/auditRouter.js +6 -1
- package/dist/auditRouter.js.map +1 -1
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +53 -1
- package/dist/auditRunner.js.map +1 -1
- package/dist/cli.js +119 -4
- package/dist/cli.js.map +1 -1
- package/dist/config/defaults.d.ts +1 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +14 -6
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts +22 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +69 -2
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/config/lintConfigReader.d.ts +56 -0
- package/dist/config/lintConfigReader.d.ts.map +1 -0
- package/dist/config/lintConfigReader.js +263 -0
- package/dist/config/lintConfigReader.js.map +1 -0
- package/dist/dataPaths.d.ts +8 -0
- package/dist/dataPaths.d.ts.map +1 -1
- package/dist/dataPaths.js +21 -0
- package/dist/dataPaths.js.map +1 -1
- package/dist/dismissals.d.ts +59 -0
- package/dist/dismissals.d.ts.map +1 -0
- package/dist/dismissals.js +128 -0
- package/dist/dismissals.js.map +1 -0
- package/dist/enforcement/gate.d.ts.map +1 -1
- package/dist/enforcement/gate.js +5 -0
- package/dist/enforcement/gate.js.map +1 -1
- package/dist/installConfig.d.ts +40 -0
- package/dist/installConfig.d.ts.map +1 -0
- package/dist/installConfig.js +84 -0
- package/dist/installConfig.js.map +1 -0
- package/dist/languages/go/analyzer +0 -0
- package/dist/languages/go/analyzer-src/solid.go +14 -6
- package/dist/mcp.js +54 -0
- package/dist/mcp.js.map +1 -1
- package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
- package/dist/reporting/csvReportGenerator.js +1 -0
- package/dist/reporting/csvReportGenerator.js.map +1 -1
- package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
- package/dist/reporting/htmlReportGenerator.js +5 -0
- package/dist/reporting/htmlReportGenerator.js.map +1 -1
- package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
- package/dist/reporting/jsonReportGenerator.js +6 -0
- package/dist/reporting/jsonReportGenerator.js.map +1 -1
- package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
- package/dist/reporting/sarifReportGenerator.js +3 -0
- package/dist/reporting/sarifReportGenerator.js.map +1 -1
- package/dist/structuralSignature.d.ts +41 -0
- package/dist/structuralSignature.d.ts.map +1 -0
- package/dist/structuralSignature.js +93 -0
- package/dist/structuralSignature.js.map +1 -0
- package/dist/telemetry.d.ts +80 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +148 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/code-auditor/SKILL.md +24 -2
- package/server.json +2 -2
package/dist/dataPaths.js
CHANGED
|
@@ -104,6 +104,27 @@ function getFallbackCacheRoot() {
|
|
|
104
104
|
}
|
|
105
105
|
return path.join(os.homedir(), '.cache', 'code-auditor');
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* OS-specific per-user config root for persistent, user-scoped state (the anonymous
|
|
109
|
+
* install ID and the telemetry opt-in). Deliberately NOT the cache root above: the
|
|
110
|
+
* cache is wiped by clean installs, and a regenerated install ID would break source
|
|
111
|
+
* grouping — this state must survive a cache wipe. This is the OS's designated
|
|
112
|
+
* location for exactly this kind of config, so it adds no new `~/` dotdir.
|
|
113
|
+
*/
|
|
114
|
+
export function getUserConfigRoot() {
|
|
115
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
116
|
+
if (xdg) {
|
|
117
|
+
return path.join(path.resolve(xdg), 'code-auditor');
|
|
118
|
+
}
|
|
119
|
+
if (process.platform === 'darwin') {
|
|
120
|
+
return path.join(os.homedir(), 'Library', 'Application Support', 'code-auditor');
|
|
121
|
+
}
|
|
122
|
+
if (process.platform === 'win32') {
|
|
123
|
+
const local = process.env.LOCALAPPDATA?.trim();
|
|
124
|
+
return path.join(local ? path.resolve(local) : os.homedir(), 'code-auditor');
|
|
125
|
+
}
|
|
126
|
+
return path.join(os.homedir(), '.config', 'code-auditor');
|
|
127
|
+
}
|
|
107
128
|
/**
|
|
108
129
|
* Resolve symlinks (and other path aliases) so the same physical project
|
|
109
130
|
* hashes identically regardless of how it was spelled. On macOS `/tmp` is a
|
package/dist/dataPaths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataPaths.js","sourceRoot":"","sources":["../src/dataPaths.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dataPaths.js","sourceRoot":"","sources":["../src/dataPaths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,yBAAyB,CAAC,WAAoB;IAC5D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,EAAE,CAAC;IACtD,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC9D,yEAAyE;QACzE,wEAAwE;QACxE,IAAI,WAAW,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC;YACpD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACrC,CAAC;IAED,4EAA4E;IAC5E,OAAO,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC;AACtF,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,uBAAuB,CAAC,WAAoB;IAC1D,OAAO,IAAI,CAAC,OAAO,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAAmB;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,SAAS,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,MAAM,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AACxE,CAAC;AAED,8FAA8F;AAC9F,SAAS,kBAAkB,CAAC,KAAa;IACvC,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,SAAS,CAAC;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QACjD,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACrE,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED,kFAAkF;AAClF,SAAS,oBAAoB;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IAChD,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,cAAc,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,CAAS;IAChC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,2DAA2D;QAC3D,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3F,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AuditResult, Violation } from './types.js';
|
|
2
|
+
/** One dismissed finding. `reason` is the product — a dismissal without one is a suppression. */
|
|
3
|
+
export interface DismissalEntry {
|
|
4
|
+
/** SHA-256 fingerprint of [analyzer, rule, file, symbol] — the scoping key. */
|
|
5
|
+
fingerprint: string;
|
|
6
|
+
/** Canonical rule ID, for grouping/readability (R4) and the telemetry payload (R2). */
|
|
7
|
+
rule: string;
|
|
8
|
+
/** File path at dismissal time, for readability (the fingerprint is the identity). */
|
|
9
|
+
file: string;
|
|
10
|
+
/** Canonical symbol at dismissal time, for readability. */
|
|
11
|
+
symbol: string;
|
|
12
|
+
/** Why this finding was dismissed — REQUIRED. The reason is the product. */
|
|
13
|
+
reason: string;
|
|
14
|
+
/** ISO-8601 timestamp of the dismissal. */
|
|
15
|
+
dismissedAt: string;
|
|
16
|
+
/** Tool version (package.json) at dismissal time. */
|
|
17
|
+
toolVersion: string;
|
|
18
|
+
}
|
|
19
|
+
/** The committed dismissals file. */
|
|
20
|
+
export interface DismissalsFile {
|
|
21
|
+
schemaVersion: 1;
|
|
22
|
+
entries: DismissalEntry[];
|
|
23
|
+
}
|
|
24
|
+
/** Result of matching a run's findings against the dismissals file. */
|
|
25
|
+
export interface DismissalMatch {
|
|
26
|
+
/** Findings whose fingerprint is dismissed — they never gate. */
|
|
27
|
+
dismissed: Violation[];
|
|
28
|
+
/** Findings with no matching dismissal — they gate normally. */
|
|
29
|
+
active: Violation[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Load the dismissals file from the project root. Returns `null` when absent.
|
|
33
|
+
*
|
|
34
|
+
* When the file exists but is structurally invalid (wrong schema version, or an
|
|
35
|
+
* entry missing a non-empty `fingerprint`/`reason`), a config error is reported
|
|
36
|
+
* to stderr and `null` is returned — the run proceeds with zero dismissals
|
|
37
|
+
* rather than silently honouring a malformed suppression list.
|
|
38
|
+
*/
|
|
39
|
+
export declare function loadDismissals(projectRoot: string): DismissalsFile | null;
|
|
40
|
+
/** Write the dismissals file to the project root (committed, reviewable in a diff). */
|
|
41
|
+
export declare function saveDismissals(projectRoot: string, dismissals: DismissalsFile): void;
|
|
42
|
+
/** Build a dismissal entry from a live violation and a required reason. */
|
|
43
|
+
export declare function buildDismissalEntry(violation: Violation, reason: string, toolVersion: string): DismissalEntry;
|
|
44
|
+
/**
|
|
45
|
+
* Add (or replace) a dismissal entry, keyed by fingerprint. Idempotent: re-
|
|
46
|
+
* dismissing an already-dismissed finding updates its reason and timestamp.
|
|
47
|
+
*/
|
|
48
|
+
export declare function upsertDismissal(projectRoot: string, entry: DismissalEntry): DismissalsFile;
|
|
49
|
+
/**
|
|
50
|
+
* Partition a run's findings into dismissed vs active by fingerprint.
|
|
51
|
+
*/
|
|
52
|
+
export declare function matchDismissals(violations: Violation[], dismissals: DismissalsFile): DismissalMatch;
|
|
53
|
+
/**
|
|
54
|
+
* Apply dismissals to a completed audit result: mark dismissed findings so the
|
|
55
|
+
* gate skips them, and record the dismissed count in the summary (never subtracted
|
|
56
|
+
* from `totalViolations`).
|
|
57
|
+
*/
|
|
58
|
+
export declare function applyDismissals(result: AuditResult, projectRoot: string): void;
|
|
59
|
+
//# sourceMappingURL=dismissals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dismissals.d.ts","sourceRoot":"","sources":["../src/dismissals.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIzD,iGAAiG;AACjG,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,gEAAgE;IAChE,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AASD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAyBzE;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,GAAG,IAAI,CAGpF;AAID,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc,CAW7G;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,cAAc,CAU1F;AAID;;GAEG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,SAAS,EAAE,EACvB,UAAU,EAAE,cAAc,GACzB,cAAc,CAchB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAY9E"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec 57 — Dismissals.
|
|
3
|
+
*
|
|
4
|
+
* A dismissal clears exactly one finding, scoped by its fingerprint (rule +
|
|
5
|
+
* file + symbol, via the shared `buildFingerprintInput`/`fingerprint` tuple the
|
|
6
|
+
* baseline, SARIF and tasks already use). It is a *decision about specific code*,
|
|
7
|
+
* not configuration, so it lives in its own committed dotfile — never in
|
|
8
|
+
* `.codeauditor.json`.
|
|
9
|
+
*
|
|
10
|
+
* What distinguishes a dismissal from a baseline (which was repeatedly rejected
|
|
11
|
+
* because it accumulates and nobody revisits it):
|
|
12
|
+
*
|
|
13
|
+
* - a **written reason is required** (a dismissal without one is a config error),
|
|
14
|
+
* - it is **scoped to one finding** (not the rule, not the file), and
|
|
15
|
+
* - it is **counted in every report** ("43 findings, 3 dismissed"), never
|
|
16
|
+
* silently subtracted from the total.
|
|
17
|
+
*/
|
|
18
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { fingerprint, buildFingerprintInput } from './fingerprint.js';
|
|
21
|
+
import { canonicalRuleId } from './ruleAliases.js';
|
|
22
|
+
import { extractSymbol } from './symbols.js';
|
|
23
|
+
// ── Constants ────────────────────────────────────────────────────────────────
|
|
24
|
+
const DISMISSALS_FILENAME = '.codeauditor.dismissals.json';
|
|
25
|
+
const SCHEMA_VERSION = 1;
|
|
26
|
+
// ── Load / save ──────────────────────────────────────────────────────────────
|
|
27
|
+
/**
|
|
28
|
+
* Load the dismissals file from the project root. Returns `null` when absent.
|
|
29
|
+
*
|
|
30
|
+
* When the file exists but is structurally invalid (wrong schema version, or an
|
|
31
|
+
* entry missing a non-empty `fingerprint`/`reason`), a config error is reported
|
|
32
|
+
* to stderr and `null` is returned — the run proceeds with zero dismissals
|
|
33
|
+
* rather than silently honouring a malformed suppression list.
|
|
34
|
+
*/
|
|
35
|
+
export function loadDismissals(projectRoot) {
|
|
36
|
+
const filePath = path.join(projectRoot, DISMISSALS_FILENAME);
|
|
37
|
+
try {
|
|
38
|
+
if (!existsSync(filePath))
|
|
39
|
+
return null;
|
|
40
|
+
const parsed = JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
41
|
+
if (!parsed || parsed.schemaVersion !== SCHEMA_VERSION || !Array.isArray(parsed.entries)) {
|
|
42
|
+
console.error(`Dismissals file has an unsupported shape (expected schemaVersion ${SCHEMA_VERSION} with an "entries" array): ${filePath}`);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const invalid = parsed.entries.filter((e) => typeof e.fingerprint !== 'string' || !e.fingerprint || typeof e.reason !== 'string' || !e.reason.trim());
|
|
46
|
+
if (invalid.length > 0) {
|
|
47
|
+
console.error(`Dismissals file has ${invalid.length} entry(ies) missing a fingerprint or a non-empty reason ` +
|
|
48
|
+
`(a dismissal without a reason is a config error, not a suppression): ${filePath}`);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return parsed;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Write the dismissals file to the project root (committed, reviewable in a diff). */
|
|
58
|
+
export function saveDismissals(projectRoot, dismissals) {
|
|
59
|
+
const filePath = path.join(projectRoot, DISMISSALS_FILENAME);
|
|
60
|
+
writeFileSync(filePath, JSON.stringify(dismissals, null, 2) + '\n', 'utf-8');
|
|
61
|
+
}
|
|
62
|
+
// ── Mutation ─────────────────────────────────────────────────────────────────
|
|
63
|
+
/** Build a dismissal entry from a live violation and a required reason. */
|
|
64
|
+
export function buildDismissalEntry(violation, reason, toolVersion) {
|
|
65
|
+
const input = buildFingerprintInput(violation);
|
|
66
|
+
return {
|
|
67
|
+
fingerprint: fingerprint(input),
|
|
68
|
+
rule: canonicalRuleId(violation.rule ?? ''),
|
|
69
|
+
file: violation.file ?? '',
|
|
70
|
+
symbol: extractSymbol(violation),
|
|
71
|
+
reason,
|
|
72
|
+
dismissedAt: new Date().toISOString(),
|
|
73
|
+
toolVersion,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Add (or replace) a dismissal entry, keyed by fingerprint. Idempotent: re-
|
|
78
|
+
* dismissing an already-dismissed finding updates its reason and timestamp.
|
|
79
|
+
*/
|
|
80
|
+
export function upsertDismissal(projectRoot, entry) {
|
|
81
|
+
const dismissals = loadDismissals(projectRoot) ?? { schemaVersion: SCHEMA_VERSION, entries: [] };
|
|
82
|
+
const existing = dismissals.entries.find((e) => e.fingerprint === entry.fingerprint);
|
|
83
|
+
if (existing) {
|
|
84
|
+
Object.assign(existing, entry);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
dismissals.entries.push(entry);
|
|
88
|
+
}
|
|
89
|
+
saveDismissals(projectRoot, dismissals);
|
|
90
|
+
return dismissals;
|
|
91
|
+
}
|
|
92
|
+
// ── Matching ─────────────────────────────────────────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* Partition a run's findings into dismissed vs active by fingerprint.
|
|
95
|
+
*/
|
|
96
|
+
export function matchDismissals(violations, dismissals) {
|
|
97
|
+
const dismissalMap = new Map();
|
|
98
|
+
for (const entry of dismissals.entries)
|
|
99
|
+
dismissalMap.set(entry.fingerprint, entry);
|
|
100
|
+
const dismissed = [];
|
|
101
|
+
const active = [];
|
|
102
|
+
for (const v of violations) {
|
|
103
|
+
const fp = fingerprint(buildFingerprintInput(v));
|
|
104
|
+
if (dismissalMap.has(fp))
|
|
105
|
+
dismissed.push(v);
|
|
106
|
+
else
|
|
107
|
+
active.push(v);
|
|
108
|
+
}
|
|
109
|
+
return { dismissed, active };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Apply dismissals to a completed audit result: mark dismissed findings so the
|
|
113
|
+
* gate skips them, and record the dismissed count in the summary (never subtracted
|
|
114
|
+
* from `totalViolations`).
|
|
115
|
+
*/
|
|
116
|
+
export function applyDismissals(result, projectRoot) {
|
|
117
|
+
const dismissals = loadDismissals(projectRoot);
|
|
118
|
+
result.summary.dismissed = 0;
|
|
119
|
+
if (!dismissals)
|
|
120
|
+
return;
|
|
121
|
+
const violations = Object.values(result.analyzerResults).flatMap((r) => r.violations);
|
|
122
|
+
const { dismissed } = matchDismissals(violations, dismissals);
|
|
123
|
+
for (const v of dismissed) {
|
|
124
|
+
v.dismissed = true;
|
|
125
|
+
}
|
|
126
|
+
result.summary.dismissed = dismissed.length;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=dismissals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dismissals.js","sourceRoot":"","sources":["../src/dismissals.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/enforcement/gate.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvD,6EAA6E;AAC7E,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,SAAS,EAAE,EACvB,kBAAkB,EAAE,WAAW,CAAC,QAAQ,CAAC,GACxC,cAAc,
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/enforcement/gate.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvD,6EAA6E;AAC7E,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,SAAS,EAAE,EACvB,kBAAkB,EAAE,WAAW,CAAC,QAAQ,CAAC,GACxC,cAAc,CA8BhB"}
|
package/dist/enforcement/gate.js
CHANGED
|
@@ -34,6 +34,11 @@ export function computeGatingDecision(violations, blockingSeverities) {
|
|
|
34
34
|
// A path-profile-excluded file never blocks.
|
|
35
35
|
if (v.gateExcluded)
|
|
36
36
|
continue;
|
|
37
|
+
// Spec 57 — a dismissed finding never blocks. Dismissal is a recorded
|
|
38
|
+
// decision about one specific finding, not a narrowing of what is reported:
|
|
39
|
+
// the finding still appears in every report at its real severity.
|
|
40
|
+
if (v.dismissed)
|
|
41
|
+
continue;
|
|
37
42
|
// R2 — only findings at a blocking severity block.
|
|
38
43
|
if (!blockingSeverities.has(v.severity))
|
|
39
44
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/enforcement/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAwBrE;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,UAAuB,EACvB,kBAAyC;IAEzC,MAAM,QAAQ,GAAgB,EAAE,CAAC;IACjC,MAAM,cAAc,GAAoB,EAAE,CAAC;IAE3C,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,6CAA6C;QAC7C,IAAI,CAAC,CAAC,YAAY;YAAE,SAAS;QAC7B,mDAAmD;QACnD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,SAAS;QAElD,MAAM,KAAK,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACvC,sEAAsE;QACtE,iEAAiE;QACjE,IAAI,KAAK,EAAE,UAAU,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;YACvC,cAAc,CAAC,IAAI,CAAC;gBAClB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,eAAe;aACxB,CAAC,CAAC;QACL,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AACtC,CAAC"}
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/enforcement/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAwBrE;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,UAAuB,EACvB,kBAAyC;IAEzC,MAAM,QAAQ,GAAgB,EAAE,CAAC;IACjC,MAAM,cAAc,GAAoB,EAAE,CAAC;IAE3C,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,6CAA6C;QAC7C,IAAI,CAAC,CAAC,YAAY;YAAE,SAAS;QAC7B,sEAAsE;QACtE,4EAA4E;QAC5E,kEAAkE;QAClE,IAAI,CAAC,CAAC,SAAS;YAAE,SAAS;QAC1B,mDAAmD;QACnD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,SAAS;QAElD,MAAM,KAAK,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACvC,sEAAsE;QACtE,iEAAiE;QACjE,IAAI,KAAK,EAAE,UAAU,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;YACvC,cAAc,CAAC,IAAI,CAAC;gBAClB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,eAAe;aACxB,CAAC,CAAC;QACL,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec 57 — anonymous install ID + telemetry opt-in, persisted at the user level.
|
|
3
|
+
*
|
|
4
|
+
* The install ID is a random value generated locally (never derived from the
|
|
5
|
+
* machine, the user, the project, or anything else) and sent with each telemetry
|
|
6
|
+
* submission so submissions can be grouped by source. It lives in the OS config
|
|
7
|
+
* dir (see `getUserConfigRoot`), NOT the cache dir — a cache wipe must not
|
|
8
|
+
* regenerate it, or source grouping breaks.
|
|
9
|
+
*
|
|
10
|
+
* The opt-in is a one-time decision recorded here (default OFF), toggled by the
|
|
11
|
+
* `telemetry` MCP tool. It is *not* a default and *not* a per-invocation flag.
|
|
12
|
+
*/
|
|
13
|
+
/** Privacy statement shared by the tool, SKILL, and docs. */
|
|
14
|
+
export declare const PRIVACY_MESSAGE = "Data is anonymous, and the ID is generated locally to avoid tracking anything personal.";
|
|
15
|
+
/**
|
|
16
|
+
* The default ingest endpoint (the operator's service). Shipped so opt-in is a
|
|
17
|
+
* one-step toggle with a known destination; overridable at enable time and via
|
|
18
|
+
* the CLI `--telemetry-endpoint` flag. It is a default, not a contract — a
|
|
19
|
+
* domain can be pointed at the service later by changing this one value.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_TELEMETRY_ENDPOINT = "https://code-auditor-dismissals.ben-a-hammond.workers.dev/ingest";
|
|
22
|
+
/** Resolve the effective endpoint: an explicit non-blank value wins, else the shipped default. */
|
|
23
|
+
export declare function resolveTelemetryEndpoint(input?: string): string;
|
|
24
|
+
export interface TelemetryOptIn {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
endpoint: string;
|
|
27
|
+
}
|
|
28
|
+
/** Resolve the user config dir (overridable for tests). */
|
|
29
|
+
export declare function configDir(dir?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Return the anonymous install ID, generating and persisting it on first use.
|
|
32
|
+
* Random and carrying nothing. Never throws — a config read/write failure falls
|
|
33
|
+
* back to a fresh random UUID so telemetry can never block on local config I/O.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getInstallId(dir?: string): string;
|
|
36
|
+
/** Read the telemetry opt-in. Any read failure is fail-closed (off, no endpoint). */
|
|
37
|
+
export declare function getTelemetryOptIn(dir?: string): TelemetryOptIn;
|
|
38
|
+
/** Persist the telemetry opt-in. Throws on write failure (an explicit user action). */
|
|
39
|
+
export declare function setTelemetryOptIn(optIn: TelemetryOptIn, dir?: string): void;
|
|
40
|
+
//# sourceMappingURL=installConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installConfig.d.ts","sourceRoot":"","sources":["../src/installConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,6DAA6D;AAC7D,eAAO,MAAM,eAAe,4FAC+D,CAAC;AAE5F;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,qEAC6B,CAAC;AAErE,kGAAkG;AAClG,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAG/D;AAKD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAejD;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAa9D;AAED,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAS3E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec 57 — anonymous install ID + telemetry opt-in, persisted at the user level.
|
|
3
|
+
*
|
|
4
|
+
* The install ID is a random value generated locally (never derived from the
|
|
5
|
+
* machine, the user, the project, or anything else) and sent with each telemetry
|
|
6
|
+
* submission so submissions can be grouped by source. It lives in the OS config
|
|
7
|
+
* dir (see `getUserConfigRoot`), NOT the cache dir — a cache wipe must not
|
|
8
|
+
* regenerate it, or source grouping breaks.
|
|
9
|
+
*
|
|
10
|
+
* The opt-in is a one-time decision recorded here (default OFF), toggled by the
|
|
11
|
+
* `telemetry` MCP tool. It is *not* a default and *not* a per-invocation flag.
|
|
12
|
+
*/
|
|
13
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { randomUUID } from 'node:crypto';
|
|
16
|
+
import { getUserConfigRoot } from './dataPaths.js';
|
|
17
|
+
/** Privacy statement shared by the tool, SKILL, and docs. */
|
|
18
|
+
export const PRIVACY_MESSAGE = 'Data is anonymous, and the ID is generated locally to avoid tracking anything personal.';
|
|
19
|
+
/**
|
|
20
|
+
* The default ingest endpoint (the operator's service). Shipped so opt-in is a
|
|
21
|
+
* one-step toggle with a known destination; overridable at enable time and via
|
|
22
|
+
* the CLI `--telemetry-endpoint` flag. It is a default, not a contract — a
|
|
23
|
+
* domain can be pointed at the service later by changing this one value.
|
|
24
|
+
*/
|
|
25
|
+
export const DEFAULT_TELEMETRY_ENDPOINT = 'https://code-auditor-dismissals.ben-a-hammond.workers.dev/ingest';
|
|
26
|
+
/** Resolve the effective endpoint: an explicit non-blank value wins, else the shipped default. */
|
|
27
|
+
export function resolveTelemetryEndpoint(input) {
|
|
28
|
+
const trimmed = (input ?? '').trim();
|
|
29
|
+
return trimmed || DEFAULT_TELEMETRY_ENDPOINT;
|
|
30
|
+
}
|
|
31
|
+
const INSTALL_ID_FILENAME = 'install-id';
|
|
32
|
+
const TELEMETRY_FILENAME = 'telemetry.json';
|
|
33
|
+
/** Resolve the user config dir (overridable for tests). */
|
|
34
|
+
export function configDir(dir) {
|
|
35
|
+
return dir ?? getUserConfigRoot();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Return the anonymous install ID, generating and persisting it on first use.
|
|
39
|
+
* Random and carrying nothing. Never throws — a config read/write failure falls
|
|
40
|
+
* back to a fresh random UUID so telemetry can never block on local config I/O.
|
|
41
|
+
*/
|
|
42
|
+
export function getInstallId(dir) {
|
|
43
|
+
const root = configDir(dir);
|
|
44
|
+
const filePath = path.join(root, INSTALL_ID_FILENAME);
|
|
45
|
+
try {
|
|
46
|
+
if (existsSync(filePath)) {
|
|
47
|
+
const existing = readFileSync(filePath, 'utf-8').trim();
|
|
48
|
+
if (existing)
|
|
49
|
+
return existing;
|
|
50
|
+
}
|
|
51
|
+
const id = randomUUID();
|
|
52
|
+
mkdirSync(root, { recursive: true });
|
|
53
|
+
writeFileSync(filePath, id + '\n', { mode: 0o600 });
|
|
54
|
+
return id;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return randomUUID();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Read the telemetry opt-in. Any read failure is fail-closed (off, no endpoint). */
|
|
61
|
+
export function getTelemetryOptIn(dir) {
|
|
62
|
+
const root = configDir(dir);
|
|
63
|
+
const filePath = path.join(root, TELEMETRY_FILENAME);
|
|
64
|
+
try {
|
|
65
|
+
if (!existsSync(filePath))
|
|
66
|
+
return { enabled: false, endpoint: '' };
|
|
67
|
+
const parsed = JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
68
|
+
return {
|
|
69
|
+
enabled: parsed?.enabled === true,
|
|
70
|
+
endpoint: typeof parsed?.endpoint === 'string' ? parsed.endpoint : '',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return { enabled: false, endpoint: '' };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Persist the telemetry opt-in. Throws on write failure (an explicit user action). */
|
|
78
|
+
export function setTelemetryOptIn(optIn, dir) {
|
|
79
|
+
const root = configDir(dir);
|
|
80
|
+
const filePath = path.join(root, TELEMETRY_FILENAME);
|
|
81
|
+
mkdirSync(root, { recursive: true });
|
|
82
|
+
writeFileSync(filePath, JSON.stringify({ enabled: optIn.enabled === true, endpoint: optIn.endpoint ?? '' }, null, 2) + '\n', { mode: 0o600 });
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=installConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installConfig.js","sourceRoot":"","sources":["../src/installConfig.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
|
@@ -57,9 +57,12 @@ func (s *SOLIDAnalyzer) analyzeFunctionSize() []Violation {
|
|
|
57
57
|
|
|
58
58
|
for _, function := range s.functions {
|
|
59
59
|
returns := strings.Split(function.ReturnType, ",")
|
|
60
|
-
|
|
60
|
+
// 2026-09-12 recalibration: complexity ceiling aligned to the 20-cyclomatic
|
|
61
|
+
// threshold, params aligned to the TS `parameter-count` default of 6. The
|
|
62
|
+
// rule is AND-combined (complexity + returns + params) so it stays conservative.
|
|
63
|
+
complex := function.Complexity > 20
|
|
61
64
|
multiReturn := len(returns) > 2
|
|
62
|
-
manyParams := len(function.Parameters) >
|
|
65
|
+
manyParams := len(function.Parameters) > 6
|
|
63
66
|
if complex && multiReturn && manyParams {
|
|
64
67
|
violations = append(violations, Violation{
|
|
65
68
|
File: function.File,
|
|
@@ -94,7 +97,8 @@ func (s *SOLIDAnalyzer) analyzeStructSize() []Violation {
|
|
|
94
97
|
var violations []Violation
|
|
95
98
|
|
|
96
99
|
for _, structInfo := range s.structs {
|
|
97
|
-
|
|
100
|
+
// 2026-09-12 recalibration: 10 flags ordinary config/model structs; 15 is a god-struct.
|
|
101
|
+
if len(structInfo.Fields) > 15 {
|
|
98
102
|
violations = append(violations, Violation{
|
|
99
103
|
File: structInfo.File,
|
|
100
104
|
Line: structInfo.StartLine,
|
|
@@ -131,7 +135,9 @@ func (s *SOLIDAnalyzer) analyzeSwitchSize() []Violation {
|
|
|
131
135
|
switch node := n.(type) {
|
|
132
136
|
case *ast.SwitchStmt:
|
|
133
137
|
caseCount := s.countSwitchCases(node)
|
|
134
|
-
|
|
138
|
+
// 2026-09-12 recalibration: 5 flags idiomatic dispatch (HTTP status /
|
|
139
|
+
// command maps); 8 suggests table-driven lookup.
|
|
140
|
+
if caseCount > 8 {
|
|
135
141
|
pos := s.parser.fileSet.Position(node.Pos())
|
|
136
142
|
violations = append(violations, Violation{
|
|
137
143
|
File: filePath,
|
|
@@ -149,7 +155,7 @@ func (s *SOLIDAnalyzer) analyzeSwitchSize() []Violation {
|
|
|
149
155
|
}
|
|
150
156
|
case *ast.TypeSwitchStmt:
|
|
151
157
|
caseCount := s.countTypeSwitchCases(node)
|
|
152
|
-
if caseCount >
|
|
158
|
+
if caseCount > 8 {
|
|
153
159
|
pos := s.parser.fileSet.Position(node.Pos())
|
|
154
160
|
violations = append(violations, Violation{
|
|
155
161
|
File: filePath,
|
|
@@ -233,7 +239,9 @@ func (s *SOLIDAnalyzer) analyzeISP() []Violation {
|
|
|
233
239
|
var violations []Violation
|
|
234
240
|
|
|
235
241
|
for _, interfaceInfo := range s.interfaces {
|
|
236
|
-
|
|
242
|
+
// 2026-09-12 recalibration: 5 flags idiomatic Reader/Writer-style interfaces;
|
|
243
|
+
// 10 is where segregation is warranted.
|
|
244
|
+
if len(interfaceInfo.Methods) > 10 {
|
|
237
245
|
violations = append(violations, Violation{
|
|
238
246
|
File: interfaceInfo.File,
|
|
239
247
|
Line: interfaceInfo.StartLine,
|
package/dist/mcp.js
CHANGED
|
@@ -63,6 +63,7 @@ import { searchFunctions, findDefinition, syncFileIndex, getDatabase } from './c
|
|
|
63
63
|
import { CodeMapGenerator } from './services/CodeMapGenerator.js';
|
|
64
64
|
import { analyzeDocumentation } from './analyzers/documentationAnalyzer.js';
|
|
65
65
|
import { ConfigGeneratorFactory } from './generators/ConfigGeneratorFactory.js';
|
|
66
|
+
import { getInstallId, getTelemetryOptIn, setTelemetryOptIn, PRIVACY_MESSAGE, resolveTelemetryEndpoint } from './installConfig.js';
|
|
66
67
|
import { MCP_DEFAULT_ANALYZERS } from './analyzers/ruleRegistry.js';
|
|
67
68
|
import { DEFAULT_SERVER_URL, IS_DEV_MODE, PACKAGE_VERSION } from './constants.js';
|
|
68
69
|
import { getAuditJobStatus, getAuditResultsPage, getAuditResultsAsSarif, startAuditJob } from './mcpAuditJobs.js';
|
|
@@ -1269,6 +1270,59 @@ function registerAllTools(registry) {
|
|
|
1269
1270
|
},
|
|
1270
1271
|
],
|
|
1271
1272
|
});
|
|
1273
|
+
// ── telemetry ──────────────────────────────────────────────────────────────
|
|
1274
|
+
registry.register({
|
|
1275
|
+
name: 'telemetry',
|
|
1276
|
+
description: 'Manage anonymous dismissal feedback opt-in (default OFF). Actions: status, enable, disable. When enabled, a dismissal and its reason are sent to the feedback endpoint, grouped by an anonymous install ID generated locally.',
|
|
1277
|
+
actions: [
|
|
1278
|
+
{
|
|
1279
|
+
name: 'status',
|
|
1280
|
+
description: 'Show whether anonymous dismissal feedback is enabled, its endpoint, and the anonymous install ID.',
|
|
1281
|
+
parameters: [],
|
|
1282
|
+
handler: async () => {
|
|
1283
|
+
const optIn = getTelemetryOptIn();
|
|
1284
|
+
return {
|
|
1285
|
+
enabled: optIn.enabled,
|
|
1286
|
+
endpoint: optIn.endpoint,
|
|
1287
|
+
installId: optIn.enabled ? getInstallId() : null,
|
|
1288
|
+
message: PRIVACY_MESSAGE,
|
|
1289
|
+
};
|
|
1290
|
+
},
|
|
1291
|
+
},
|
|
1292
|
+
{
|
|
1293
|
+
name: 'enable',
|
|
1294
|
+
description: 'Opt in to anonymous dismissal feedback. Defaults to the built-in service endpoint. Generates the anonymous install ID on first use.',
|
|
1295
|
+
parameters: [
|
|
1296
|
+
{
|
|
1297
|
+
name: 'endpoint',
|
|
1298
|
+
type: 'string',
|
|
1299
|
+
required: false,
|
|
1300
|
+
description: 'Optional ingest URL. Defaults to the built-in service endpoint.',
|
|
1301
|
+
},
|
|
1302
|
+
],
|
|
1303
|
+
handler: async (args) => {
|
|
1304
|
+
const endpoint = resolveTelemetryEndpoint(args.endpoint);
|
|
1305
|
+
setTelemetryOptIn({ enabled: true, endpoint });
|
|
1306
|
+
return {
|
|
1307
|
+
enabled: true,
|
|
1308
|
+
endpoint,
|
|
1309
|
+
installId: getInstallId(),
|
|
1310
|
+
message: PRIVACY_MESSAGE,
|
|
1311
|
+
};
|
|
1312
|
+
},
|
|
1313
|
+
},
|
|
1314
|
+
{
|
|
1315
|
+
name: 'disable',
|
|
1316
|
+
description: 'Turn off anonymous dismissal feedback. The endpoint is remembered; nothing further is sent.',
|
|
1317
|
+
parameters: [],
|
|
1318
|
+
handler: async () => {
|
|
1319
|
+
const current = getTelemetryOptIn();
|
|
1320
|
+
setTelemetryOptIn({ enabled: false, endpoint: current.endpoint });
|
|
1321
|
+
return { enabled: false, message: PRIVACY_MESSAGE };
|
|
1322
|
+
},
|
|
1323
|
+
},
|
|
1324
|
+
],
|
|
1325
|
+
});
|
|
1272
1326
|
// ── code_map ───────────────────────────────────────────────────────────────
|
|
1273
1327
|
registry.register({
|
|
1274
1328
|
name: 'code_map',
|