guardrail-core 1.0.0 → 2.0.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/dist/__tests__/autopilot-enterprise.test.d.ts +7 -0
- package/dist/__tests__/autopilot-enterprise.test.d.ts.map +1 -0
- package/dist/__tests__/autopilot-enterprise.test.js +334 -0
- package/dist/autopilot/autopilot-runner.d.ts +9 -0
- package/dist/autopilot/autopilot-runner.d.ts.map +1 -1
- package/dist/autopilot/autopilot-runner.js +182 -1
- package/dist/autopilot/types.d.ts +18 -2
- package/dist/autopilot/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/smells/index.d.ts +59 -0
- package/dist/smells/index.d.ts.map +1 -0
- package/dist/smells/index.js +251 -0
- package/package.json +19 -2
- package/src/__tests__/autopilot.test.ts +0 -196
- package/src/__tests__/tier-config.test.ts +0 -289
- package/src/__tests__/utils/hash-inline.test.ts +0 -76
- package/src/__tests__/utils/hash.test.ts +0 -119
- package/src/__tests__/utils/simple.test.ts +0 -10
- package/src/__tests__/utils/utils-simple.test.ts +0 -5
- package/src/__tests__/utils/utils.test.ts +0 -203
- package/src/autopilot/autopilot-runner.ts +0 -503
- package/src/autopilot/index.ts +0 -6
- package/src/autopilot/types.ts +0 -119
- package/src/cache/index.ts +0 -7
- package/src/cache/redis-cache.d.ts +0 -155
- package/src/cache/redis-cache.d.ts.map +0 -1
- package/src/cache/redis-cache.ts +0 -517
- package/src/ci/github-actions.ts +0 -335
- package/src/ci/index.ts +0 -12
- package/src/ci/pre-commit.ts +0 -338
- package/src/db/usage-schema.prisma +0 -114
- package/src/entitlements.ts +0 -570
- package/src/env.d.ts +0 -68
- package/src/env.d.ts.map +0 -1
- package/src/env.ts +0 -247
- package/src/fix-packs/__tests__/generate-fix-packs.test.ts +0 -317
- package/src/fix-packs/generate-fix-packs.ts +0 -577
- package/src/fix-packs/index.ts +0 -8
- package/src/fix-packs/types.ts +0 -206
- package/src/index.d.ts +0 -7
- package/src/index.d.ts.map +0 -1
- package/src/index.ts +0 -12
- package/src/metrics/prometheus.d.ts +0 -104
- package/src/metrics/prometheus.d.ts.map +0 -1
- package/src/metrics/prometheus.ts +0 -446
- package/src/quota-ledger.ts +0 -548
- package/src/rbac/__tests__/permissions.test.ts +0 -446
- package/src/rbac/index.ts +0 -46
- package/src/rbac/permissions.ts +0 -301
- package/src/rbac/types.ts +0 -298
- package/src/tier-config.json +0 -157
- package/src/tier-config.ts +0 -815
- package/src/types.d.ts +0 -365
- package/src/types.d.ts.map +0 -1
- package/src/types.ts +0 -441
- package/src/utils.d.ts +0 -36
- package/src/utils.d.ts.map +0 -1
- package/src/utils.ts +0 -140
- package/src/verified-autofix/__tests__/format-validator.test.ts +0 -335
- package/src/verified-autofix/__tests__/pipeline.test.ts +0 -419
- package/src/verified-autofix/__tests__/repo-fingerprint.test.ts +0 -241
- package/src/verified-autofix/__tests__/workspace.test.ts +0 -373
- package/src/verified-autofix/format-validator.ts +0 -517
- package/src/verified-autofix/index.ts +0 -63
- package/src/verified-autofix/pipeline.ts +0 -403
- package/src/verified-autofix/repo-fingerprint.ts +0 -459
- package/src/verified-autofix/workspace.ts +0 -531
- package/src/verified-autofix.ts +0 -1187
- package/src/visualization/dependency-graph.d.ts +0 -85
- package/src/visualization/dependency-graph.d.ts.map +0 -1
- package/src/visualization/dependency-graph.ts +0 -495
- package/src/visualization/index.ts +0 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/autopilot/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/autopilot/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,OAAO,CAAC;AACtB,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,kCAAkC,CAAC;AACjD,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,OAAO,CAAC;AACtB,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,kCAAkC,CAAC;AACjD,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Smell Predictor
|
|
3
|
+
*
|
|
4
|
+
* Predicts technical debt and code smells before they become problems
|
|
5
|
+
*/
|
|
6
|
+
export interface CodeSmell {
|
|
7
|
+
type: 'long-method' | 'large-class' | 'duplication' | 'complexity' | 'coupling' | 'cohesion';
|
|
8
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
9
|
+
file: string;
|
|
10
|
+
line?: number;
|
|
11
|
+
description: string;
|
|
12
|
+
metrics: {
|
|
13
|
+
current: number;
|
|
14
|
+
threshold: number;
|
|
15
|
+
trend?: 'increasing' | 'decreasing' | 'stable';
|
|
16
|
+
};
|
|
17
|
+
prediction: {
|
|
18
|
+
when: 'immediate' | '1-month' | '3-months' | '6-months';
|
|
19
|
+
impact: string;
|
|
20
|
+
cost: 'low' | 'medium' | 'high';
|
|
21
|
+
};
|
|
22
|
+
recommendation: string[];
|
|
23
|
+
remediation?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface TechnicalDebtReport {
|
|
26
|
+
totalSmells: number;
|
|
27
|
+
critical: number;
|
|
28
|
+
estimatedDebt: number;
|
|
29
|
+
smells: CodeSmell[];
|
|
30
|
+
trends: Array<{
|
|
31
|
+
type: string;
|
|
32
|
+
trend: 'improving' | 'worsening' | 'stable';
|
|
33
|
+
change: number;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export declare class CodeSmellPredictor {
|
|
37
|
+
/**
|
|
38
|
+
* Predict code smells and technical debt
|
|
39
|
+
*/
|
|
40
|
+
predict(projectPath: string): Promise<TechnicalDebtReport>;
|
|
41
|
+
/**
|
|
42
|
+
* Predict long methods
|
|
43
|
+
*/
|
|
44
|
+
private predictLongMethods;
|
|
45
|
+
/**
|
|
46
|
+
* Predict large classes
|
|
47
|
+
*/
|
|
48
|
+
private predictLargeClasses;
|
|
49
|
+
private calculateDebt;
|
|
50
|
+
private analyzeTrends;
|
|
51
|
+
private extractFunctions;
|
|
52
|
+
private extractClasses;
|
|
53
|
+
private estimateFunctionLength;
|
|
54
|
+
private estimateClassSize;
|
|
55
|
+
private findCodeFiles;
|
|
56
|
+
private shouldIgnore;
|
|
57
|
+
}
|
|
58
|
+
export declare const codeSmellPredictor: CodeSmellPredictor;
|
|
59
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/smells/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,CAAC;IAC7F,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC;KAChD,CAAC;IACF,UAAU,EAAE;QACV,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;QACxD,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;KACjC,CAAC;IACF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;QAC5C,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,qBAAa,kBAAkB;IAC7B;;OAEG;IACG,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA0BhE;;OAEG;YACW,kBAAkB;IA6ChC;;OAEG;YACW,mBAAmB;IA6CjC,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,cAAc;IAoBtB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,iBAAiB;YAYX,aAAa;IAkB3B,OAAO,CAAC,YAAY;CAGrB;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Code Smell Predictor
|
|
4
|
+
*
|
|
5
|
+
* Predicts technical debt and code smells before they become problems
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.codeSmellPredictor = exports.CodeSmellPredictor = void 0;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
class CodeSmellPredictor {
|
|
45
|
+
/**
|
|
46
|
+
* Predict code smells and technical debt
|
|
47
|
+
*/
|
|
48
|
+
async predict(projectPath) {
|
|
49
|
+
const smells = [];
|
|
50
|
+
// Predict long methods
|
|
51
|
+
const longMethods = await this.predictLongMethods(projectPath);
|
|
52
|
+
smells.push(...longMethods);
|
|
53
|
+
// Predict large classes
|
|
54
|
+
const largeClasses = await this.predictLargeClasses(projectPath);
|
|
55
|
+
smells.push(...largeClasses);
|
|
56
|
+
// Calculate estimated debt
|
|
57
|
+
const estimatedDebt = this.calculateDebt(smells);
|
|
58
|
+
// Analyze trends
|
|
59
|
+
const trends = this.analyzeTrends(smells);
|
|
60
|
+
return {
|
|
61
|
+
totalSmells: smells.length,
|
|
62
|
+
critical: smells.filter(s => s.severity === 'critical').length,
|
|
63
|
+
estimatedDebt,
|
|
64
|
+
smells,
|
|
65
|
+
trends,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Predict long methods
|
|
70
|
+
*/
|
|
71
|
+
async predictLongMethods(projectPath) {
|
|
72
|
+
const smells = [];
|
|
73
|
+
const files = await this.findCodeFiles(projectPath);
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
try {
|
|
76
|
+
const content = await fs.promises.readFile(file, 'utf8');
|
|
77
|
+
const functions = this.extractFunctions(content);
|
|
78
|
+
for (const func of functions) {
|
|
79
|
+
if (func.lines > 50) {
|
|
80
|
+
const severity = func.lines > 100 ? 'critical' : func.lines > 75 ? 'high' : 'medium';
|
|
81
|
+
smells.push({
|
|
82
|
+
type: 'long-method',
|
|
83
|
+
severity,
|
|
84
|
+
file: path.relative(projectPath, file),
|
|
85
|
+
line: func.line,
|
|
86
|
+
description: `Method ${func.name} is ${func.lines} lines long`,
|
|
87
|
+
metrics: {
|
|
88
|
+
current: func.lines,
|
|
89
|
+
threshold: 50,
|
|
90
|
+
trend: 'increasing',
|
|
91
|
+
},
|
|
92
|
+
prediction: {
|
|
93
|
+
when: func.lines > 100 ? 'immediate' : '1-month',
|
|
94
|
+
impact: 'Hard to test, understand, and maintain',
|
|
95
|
+
cost: severity === 'critical' ? 'high' : 'medium',
|
|
96
|
+
},
|
|
97
|
+
recommendation: [
|
|
98
|
+
'Extract smaller methods',
|
|
99
|
+
'Apply Single Responsibility Principle',
|
|
100
|
+
'Break into logical sections',
|
|
101
|
+
],
|
|
102
|
+
remediation: 'Split method into smaller logical units'
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Error reading file
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return smells;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Predict large classes
|
|
115
|
+
*/
|
|
116
|
+
async predictLargeClasses(projectPath) {
|
|
117
|
+
const smells = [];
|
|
118
|
+
const files = await this.findCodeFiles(projectPath);
|
|
119
|
+
for (const file of files) {
|
|
120
|
+
try {
|
|
121
|
+
const content = await fs.promises.readFile(file, 'utf8');
|
|
122
|
+
const classes = this.extractClasses(content);
|
|
123
|
+
for (const cls of classes) {
|
|
124
|
+
if (cls.lines > 300) {
|
|
125
|
+
const severity = cls.lines > 500 ? 'critical' : 'high';
|
|
126
|
+
smells.push({
|
|
127
|
+
type: 'large-class',
|
|
128
|
+
severity,
|
|
129
|
+
file: path.relative(projectPath, file),
|
|
130
|
+
line: cls.line,
|
|
131
|
+
description: `Class ${cls.name} is ${cls.lines} lines long with ${cls.methods} methods`,
|
|
132
|
+
metrics: {
|
|
133
|
+
current: cls.lines,
|
|
134
|
+
threshold: 300,
|
|
135
|
+
trend: 'increasing',
|
|
136
|
+
},
|
|
137
|
+
prediction: {
|
|
138
|
+
when: cls.lines > 500 ? 'immediate' : '3-months',
|
|
139
|
+
impact: 'Violates Single Responsibility Principle, hard to maintain',
|
|
140
|
+
cost: 'high',
|
|
141
|
+
},
|
|
142
|
+
recommendation: [
|
|
143
|
+
'Split into smaller classes',
|
|
144
|
+
'Extract related functionality',
|
|
145
|
+
'Apply composition over inheritance',
|
|
146
|
+
],
|
|
147
|
+
remediation: 'Extract functionality into separate components'
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// Error reading file
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return smells;
|
|
157
|
+
}
|
|
158
|
+
calculateDebt(smells) {
|
|
159
|
+
let totalHours = 0;
|
|
160
|
+
for (const smell of smells) {
|
|
161
|
+
const hours = smell.severity === 'critical' ? 2 :
|
|
162
|
+
smell.severity === 'high' ? 1 :
|
|
163
|
+
smell.severity === 'medium' ? 0.5 :
|
|
164
|
+
0.25;
|
|
165
|
+
totalHours += hours;
|
|
166
|
+
}
|
|
167
|
+
return totalHours;
|
|
168
|
+
}
|
|
169
|
+
analyzeTrends(smells) {
|
|
170
|
+
const byType = new Map();
|
|
171
|
+
for (const smell of smells) {
|
|
172
|
+
byType.set(smell.type, (byType.get(smell.type) || 0) + 1);
|
|
173
|
+
}
|
|
174
|
+
return Array.from(byType.entries()).map(([type, count]) => ({
|
|
175
|
+
type,
|
|
176
|
+
trend: 'worsening',
|
|
177
|
+
change: count,
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
extractFunctions(content) {
|
|
181
|
+
const functions = [];
|
|
182
|
+
const functionRegex = /(?:export\s+)?(?:async\s+)?function\s+(\w+)|(?:export\s+)?const\s+(\w+)\s*[:=]\s*(?:async\s+)?\(/g;
|
|
183
|
+
let match;
|
|
184
|
+
while ((match = functionRegex.exec(content)) !== null) {
|
|
185
|
+
const funcName = match[1] || match[2] || 'anonymous';
|
|
186
|
+
const lineNum = content.substring(0, match.index).split('\n').length;
|
|
187
|
+
// Estimate function length (simplified)
|
|
188
|
+
const funcLines = this.estimateFunctionLength(content, match.index);
|
|
189
|
+
functions.push({ name: funcName, line: lineNum, lines: funcLines });
|
|
190
|
+
}
|
|
191
|
+
return functions;
|
|
192
|
+
}
|
|
193
|
+
extractClasses(content) {
|
|
194
|
+
const classes = [];
|
|
195
|
+
const classRegex = /(?:export\s+)?class\s+(\w+)/g;
|
|
196
|
+
let match;
|
|
197
|
+
while ((match = classRegex.exec(content)) !== null) {
|
|
198
|
+
const className = match[1] || 'AnonymousClass';
|
|
199
|
+
const lineNum = content.substring(0, match.index).split('\n').length;
|
|
200
|
+
const classInfo = this.estimateClassSize(content, match.index);
|
|
201
|
+
classes.push({
|
|
202
|
+
name: className,
|
|
203
|
+
line: lineNum,
|
|
204
|
+
lines: classInfo.lines,
|
|
205
|
+
methods: classInfo.methods,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return classes;
|
|
209
|
+
}
|
|
210
|
+
estimateFunctionLength(content, startIndex) {
|
|
211
|
+
const remaining = content.substring(startIndex);
|
|
212
|
+
const nextFunction = remaining.search(/(?:export\s+)?(?:async\s+)?function\s+\w+|(?:export\s+)?const\s+\w+\s*[:=]\s*(?:async\s+)?\(/);
|
|
213
|
+
const endIndex = nextFunction > 0 ? startIndex + nextFunction : content.length;
|
|
214
|
+
return content.substring(startIndex, endIndex).split('\n').length;
|
|
215
|
+
}
|
|
216
|
+
estimateClassSize(content, startIndex) {
|
|
217
|
+
const remaining = content.substring(startIndex);
|
|
218
|
+
const nextClass = remaining.search(/(?:export\s+)?class\s+\w+/);
|
|
219
|
+
const endIndex = nextClass > 0 ? startIndex + nextClass : content.length;
|
|
220
|
+
const classContent = content.substring(startIndex, endIndex);
|
|
221
|
+
const methods = (classContent.match(/\w+\s*\([^)]*\)\s*{/g) || []).length;
|
|
222
|
+
return {
|
|
223
|
+
lines: classContent.split('\n').length,
|
|
224
|
+
methods,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
async findCodeFiles(dir) {
|
|
228
|
+
const files = [];
|
|
229
|
+
try {
|
|
230
|
+
const items = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
231
|
+
for (const item of items) {
|
|
232
|
+
const fullPath = path.join(dir, item.name);
|
|
233
|
+
if (item.isDirectory() && !this.shouldIgnore(item.name)) {
|
|
234
|
+
files.push(...await this.findCodeFiles(fullPath));
|
|
235
|
+
}
|
|
236
|
+
else if (item.isFile() && /\.(ts|tsx|js|jsx)$/.test(item.name)) {
|
|
237
|
+
files.push(fullPath);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Error reading directory
|
|
243
|
+
}
|
|
244
|
+
return files;
|
|
245
|
+
}
|
|
246
|
+
shouldIgnore(name) {
|
|
247
|
+
return ['node_modules', '.git', 'dist', 'build', '.next', 'coverage'].includes(name);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
exports.CodeSmellPredictor = CodeSmellPredictor;
|
|
251
|
+
exports.codeSmellPredictor = new CodeSmellPredictor();
|
package/package.json
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guardrail-core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Guardrail Core - Code analysis, RBAC, and autopilot remediation",
|
|
4
5
|
"main": "./dist/index.js",
|
|
5
|
-
"files": ["dist/**/*"
|
|
6
|
+
"files": ["dist/**/*"],
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "Guardrail Team <team@getguardrail.io>",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/guardiavault-oss/codeguard.git"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
6
16
|
"types": "./dist/index.d.ts",
|
|
7
17
|
"exports": {
|
|
8
18
|
".": {
|
|
@@ -12,6 +22,10 @@
|
|
|
12
22
|
"./rbac": {
|
|
13
23
|
"types": "./dist/rbac/index.d.ts",
|
|
14
24
|
"default": "./dist/rbac/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./smells": {
|
|
27
|
+
"types": "./dist/smells/index.d.ts",
|
|
28
|
+
"default": "./dist/smells/index.js"
|
|
15
29
|
}
|
|
16
30
|
},
|
|
17
31
|
"scripts": {
|
|
@@ -25,5 +39,8 @@
|
|
|
25
39
|
"devDependencies": {
|
|
26
40
|
"typescript": "^5.3.3",
|
|
27
41
|
"@types/node": "^20.10.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
28
45
|
}
|
|
29
46
|
}
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Autopilot Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for the Autopilot batch remediation feature.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { AutopilotRunner } from '../autopilot/autopilot-runner';
|
|
8
|
-
import {
|
|
9
|
-
AutopilotFinding,
|
|
10
|
-
AutopilotFixPackCategory,
|
|
11
|
-
AUTOPILOT_FIX_PACK_PRIORITY
|
|
12
|
-
} from '../autopilot/types';
|
|
13
|
-
|
|
14
|
-
describe('AutopilotRunner', () => {
|
|
15
|
-
let runner: AutopilotRunner;
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
runner = new AutopilotRunner();
|
|
19
|
-
process.env['GUARDRAIL_SKIP_ENTITLEMENTS'] = '1';
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
delete process.env['GUARDRAIL_SKIP_ENTITLEMENTS'];
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
describe('groupIntoFixPacks', () => {
|
|
27
|
-
it('should group findings by category', () => {
|
|
28
|
-
const findings: AutopilotFinding[] = [
|
|
29
|
-
{ id: '1', category: 'type-errors', severity: 'high', file: 'a.ts', line: 1, message: 'err', fixable: true },
|
|
30
|
-
{ id: '2', category: 'type-errors', severity: 'high', file: 'b.ts', line: 2, message: 'err', fixable: true },
|
|
31
|
-
{ id: '3', category: 'quality', severity: 'low', file: 'c.ts', line: 3, message: 'console.log', fixable: true },
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
const packs = runner.groupIntoFixPacks(findings);
|
|
35
|
-
|
|
36
|
-
expect(packs).toHaveLength(2);
|
|
37
|
-
const typeErrorsPack = packs.find(p => p.category === 'type-errors');
|
|
38
|
-
const qualityPack = packs.find(p => p.category === 'quality');
|
|
39
|
-
expect(typeErrorsPack).toBeDefined();
|
|
40
|
-
expect(qualityPack).toBeDefined();
|
|
41
|
-
expect(typeErrorsPack!.findings).toHaveLength(2);
|
|
42
|
-
expect(qualityPack!.findings).toHaveLength(1);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should exclude non-fixable findings', () => {
|
|
46
|
-
const findings: AutopilotFinding[] = [
|
|
47
|
-
{ id: '1', category: 'quality', severity: 'low', file: 'a.ts', line: 1, message: 'TODO', fixable: false },
|
|
48
|
-
{ id: '2', category: 'quality', severity: 'low', file: 'b.ts', line: 2, message: 'console.log', fixable: true },
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
const packs = runner.groupIntoFixPacks(findings);
|
|
52
|
-
|
|
53
|
-
expect(packs).toHaveLength(1);
|
|
54
|
-
expect(packs[0]!.findings).toHaveLength(1);
|
|
55
|
-
expect(packs[0]!.findings[0]!.id).toBe('2');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should respect maxFixes limit', () => {
|
|
59
|
-
const findings: AutopilotFinding[] = Array.from({ length: 20 }, (_, i) => ({
|
|
60
|
-
id: String(i),
|
|
61
|
-
category: 'type-errors' as AutopilotFixPackCategory,
|
|
62
|
-
severity: 'high' as const,
|
|
63
|
-
file: `file${i}.ts`,
|
|
64
|
-
line: i,
|
|
65
|
-
message: 'error',
|
|
66
|
-
fixable: true,
|
|
67
|
-
}));
|
|
68
|
-
|
|
69
|
-
const packs = runner.groupIntoFixPacks(findings, 5);
|
|
70
|
-
|
|
71
|
-
expect(packs).toHaveLength(1);
|
|
72
|
-
expect(packs[0]!.findings).toHaveLength(5);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should sort packs by priority', () => {
|
|
76
|
-
const findings: AutopilotFinding[] = [
|
|
77
|
-
{ id: '1', category: 'quality', severity: 'low', file: 'a.ts', line: 1, message: 'q', fixable: true },
|
|
78
|
-
{ id: '2', category: 'security', severity: 'critical', file: 'b.ts', line: 2, message: 's', fixable: true },
|
|
79
|
-
{ id: '3', category: 'type-errors', severity: 'high', file: 'c.ts', line: 3, message: 't', fixable: true },
|
|
80
|
-
];
|
|
81
|
-
|
|
82
|
-
const packs = runner.groupIntoFixPacks(findings);
|
|
83
|
-
|
|
84
|
-
expect(packs[0]!.category).toBe('security');
|
|
85
|
-
expect(packs[1]!.category).toBe('type-errors');
|
|
86
|
-
expect(packs[2]!.category).toBe('quality');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should calculate risk based on severity', () => {
|
|
90
|
-
const lowSeverityFindings: AutopilotFinding[] = [
|
|
91
|
-
{ id: '1', category: 'quality', severity: 'low', file: 'a.ts', line: 1, message: 'q', fixable: true },
|
|
92
|
-
];
|
|
93
|
-
|
|
94
|
-
const highSeverityFindings: AutopilotFinding[] = [
|
|
95
|
-
{ id: '2', category: 'security', severity: 'critical', file: 'b.ts', line: 2, message: 's', fixable: true },
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
const lowPacks = runner.groupIntoFixPacks(lowSeverityFindings);
|
|
99
|
-
const highPacks = runner.groupIntoFixPacks(highSeverityFindings);
|
|
100
|
-
|
|
101
|
-
expect(lowPacks[0]!.estimatedRisk).toBe('low');
|
|
102
|
-
expect(highPacks[0]!.estimatedRisk).toBe('medium');
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('should collect impacted files without duplicates', () => {
|
|
106
|
-
const findings: AutopilotFinding[] = [
|
|
107
|
-
{ id: '1', category: 'type-errors', severity: 'high', file: 'a.ts', line: 1, message: 'err', fixable: true },
|
|
108
|
-
{ id: '2', category: 'type-errors', severity: 'high', file: 'a.ts', line: 2, message: 'err', fixable: true },
|
|
109
|
-
{ id: '3', category: 'type-errors', severity: 'high', file: 'b.ts', line: 1, message: 'err', fixable: true },
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
const packs = runner.groupIntoFixPacks(findings);
|
|
113
|
-
|
|
114
|
-
expect(packs[0]!.impactedFiles).toHaveLength(2);
|
|
115
|
-
expect(packs[0]!.impactedFiles).toContain('a.ts');
|
|
116
|
-
expect(packs[0]!.impactedFiles).toContain('b.ts');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should return empty array when no fixable findings', () => {
|
|
120
|
-
const findings: AutopilotFinding[] = [
|
|
121
|
-
{ id: '1', category: 'quality', severity: 'low', file: 'a.ts', line: 1, message: 'TODO', fixable: false },
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
const packs = runner.groupIntoFixPacks(findings);
|
|
125
|
-
|
|
126
|
-
expect(packs).toHaveLength(0);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('should assign correct priority from FIX_PACK_PRIORITY', () => {
|
|
130
|
-
const findings: AutopilotFinding[] = [
|
|
131
|
-
{ id: '1', category: 'security', severity: 'high', file: 'a.ts', line: 1, message: 's', fixable: true },
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
const packs = runner.groupIntoFixPacks(findings);
|
|
135
|
-
|
|
136
|
-
expect(packs[0]!.priority).toBe(AUTOPILOT_FIX_PACK_PRIORITY['security']);
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
describe('FIX_PACK_PRIORITY', () => {
|
|
141
|
-
it('should have security as highest priority', () => {
|
|
142
|
-
expect(AUTOPILOT_FIX_PACK_PRIORITY['security']).toBe(1);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should have quality as lowest priority', () => {
|
|
146
|
-
expect(AUTOPILOT_FIX_PACK_PRIORITY['quality']).toBe(7);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should have all categories defined', () => {
|
|
150
|
-
const categories: AutopilotFixPackCategory[] = [
|
|
151
|
-
'security',
|
|
152
|
-
'build-blockers',
|
|
153
|
-
'type-errors',
|
|
154
|
-
'test-failures',
|
|
155
|
-
'route-integrity',
|
|
156
|
-
'placeholders',
|
|
157
|
-
'quality',
|
|
158
|
-
];
|
|
159
|
-
|
|
160
|
-
for (const category of categories) {
|
|
161
|
-
expect(AUTOPILOT_FIX_PACK_PRIORITY[category]).toBeDefined();
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
describe('Autopilot Entitlement Gating', () => {
|
|
168
|
-
it('should require autopilot feature to be enabled', async () => {
|
|
169
|
-
const runner = new AutopilotRunner();
|
|
170
|
-
|
|
171
|
-
// Without GUARDRAIL_SKIP_ENTITLEMENTS, it should check entitlements
|
|
172
|
-
// In test environment without proper setup, it should fail gracefully
|
|
173
|
-
// This test verifies the entitlement check is wired up
|
|
174
|
-
|
|
175
|
-
delete process.env['GUARDRAIL_SKIP_ENTITLEMENTS'];
|
|
176
|
-
|
|
177
|
-
// The run method should attempt to check entitlements
|
|
178
|
-
// We expect it to either succeed (if entitlements pass) or fail with entitlement error
|
|
179
|
-
try {
|
|
180
|
-
await runner.run({
|
|
181
|
-
projectPath: process.cwd(),
|
|
182
|
-
mode: 'plan',
|
|
183
|
-
});
|
|
184
|
-
// If we get here, entitlements passed (e.g., in CI with proper config)
|
|
185
|
-
} catch (error: any) {
|
|
186
|
-
// Expected to fail with entitlement-related error in test environment
|
|
187
|
-
expect(
|
|
188
|
-
error.message.includes('autopilot') ||
|
|
189
|
-
error.message.includes('tier') ||
|
|
190
|
-
error.message.includes('feature') ||
|
|
191
|
-
error.message.includes('FEATURE_NOT_AVAILABLE') ||
|
|
192
|
-
error.code === 'FEATURE_NOT_AVAILABLE'
|
|
193
|
-
).toBe(true);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
});
|