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,403 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Verified AutoFix Pipeline - Orchestration Layer
|
|
3
|
-
*
|
|
4
|
-
* Pipeline order:
|
|
5
|
-
* 1. format → validate JSON shape + strip markdown
|
|
6
|
-
* 2. diff/path safety → validate unified diff + paths within project
|
|
7
|
-
* 3. command safety → warn on risky commands
|
|
8
|
-
* 4. stub detection → block TODO/placeholder in production
|
|
9
|
-
* 5. apply diff → git apply --check then git apply
|
|
10
|
-
* 6. typecheck → tsc --noEmit
|
|
11
|
-
* 7. build (ship) → npm run build
|
|
12
|
-
* 8. tests → npm test
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import * as fs from 'fs';
|
|
16
|
-
import {
|
|
17
|
-
validateAgentOutput,
|
|
18
|
-
type FullValidationResult,
|
|
19
|
-
type GuardrailV1Output,
|
|
20
|
-
} from './format-validator';
|
|
21
|
-
import { TempWorkspace, type VerifyResult } from './workspace';
|
|
22
|
-
import { fingerprintRepo, type RepoFingerprint } from './repo-fingerprint';
|
|
23
|
-
import { trackUsage, enforceFeature } from '../entitlements';
|
|
24
|
-
|
|
25
|
-
// ============================================================================
|
|
26
|
-
// TYPES
|
|
27
|
-
// ============================================================================
|
|
28
|
-
|
|
29
|
-
export interface PipelineOptions {
|
|
30
|
-
projectPath: string;
|
|
31
|
-
agentOutputFile?: string;
|
|
32
|
-
agentOutputRaw?: string;
|
|
33
|
-
dryRun?: boolean;
|
|
34
|
-
skipTests?: boolean;
|
|
35
|
-
verbose?: boolean;
|
|
36
|
-
timeout?: number;
|
|
37
|
-
skipEntitlements?: boolean;
|
|
38
|
-
strictMarkdown?: boolean;
|
|
39
|
-
onProgress?: (stage: PipelineStage, message: string, data?: unknown) => void;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type PipelineStage =
|
|
43
|
-
| 'init'
|
|
44
|
-
| 'validate'
|
|
45
|
-
| 'fingerprint'
|
|
46
|
-
| 'workspace'
|
|
47
|
-
| 'apply'
|
|
48
|
-
| 'typecheck'
|
|
49
|
-
| 'build'
|
|
50
|
-
| 'test'
|
|
51
|
-
| 'commit'
|
|
52
|
-
| 'done'
|
|
53
|
-
| 'error';
|
|
54
|
-
|
|
55
|
-
export interface PipelineResult {
|
|
56
|
-
success: boolean;
|
|
57
|
-
stage: PipelineStage;
|
|
58
|
-
duration: number;
|
|
59
|
-
validation?: FullValidationResult;
|
|
60
|
-
fingerprint?: RepoFingerprint;
|
|
61
|
-
verification?: VerifyResult;
|
|
62
|
-
filesModified: string[];
|
|
63
|
-
errors: string[];
|
|
64
|
-
warnings: string[];
|
|
65
|
-
failureContext: string[];
|
|
66
|
-
output?: GuardrailV1Output;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ============================================================================
|
|
70
|
-
// PIPELINE CLASS
|
|
71
|
-
// ============================================================================
|
|
72
|
-
|
|
73
|
-
export class VerifiedAutofixPipeline {
|
|
74
|
-
private workspace: TempWorkspace;
|
|
75
|
-
|
|
76
|
-
constructor() {
|
|
77
|
-
this.workspace = new TempWorkspace();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Run the full verification pipeline
|
|
82
|
-
*/
|
|
83
|
-
async run(options: PipelineOptions): Promise<PipelineResult> {
|
|
84
|
-
const startTime = Date.now();
|
|
85
|
-
const result: PipelineResult = {
|
|
86
|
-
success: false,
|
|
87
|
-
stage: 'init',
|
|
88
|
-
duration: 0,
|
|
89
|
-
filesModified: [],
|
|
90
|
-
errors: [],
|
|
91
|
-
warnings: [],
|
|
92
|
-
failureContext: [],
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
let workspaceId: string | null = null;
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
// Enforce feature entitlement (Pro+ required) unless skipped
|
|
99
|
-
if (!options.skipEntitlements && process.env['GUARDRAIL_SKIP_ENTITLEMENTS'] !== '1') {
|
|
100
|
-
await enforceFeature('fix:auto');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
options.onProgress?.('init', 'Starting verified autofix pipeline');
|
|
104
|
-
|
|
105
|
-
// Step 1: Read agent output
|
|
106
|
-
result.stage = 'validate';
|
|
107
|
-
options.onProgress?.('validate', 'Reading agent output');
|
|
108
|
-
|
|
109
|
-
let rawOutput: string;
|
|
110
|
-
if (options.agentOutputFile) {
|
|
111
|
-
if (!fs.existsSync(options.agentOutputFile)) {
|
|
112
|
-
throw new Error(`Agent output file not found: ${options.agentOutputFile}`);
|
|
113
|
-
}
|
|
114
|
-
rawOutput = await fs.promises.readFile(options.agentOutputFile, 'utf8');
|
|
115
|
-
} else if (options.agentOutputRaw) {
|
|
116
|
-
rawOutput = options.agentOutputRaw;
|
|
117
|
-
} else {
|
|
118
|
-
throw new Error('Either agentOutputFile or agentOutputRaw must be provided');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Step 2: Validate format
|
|
122
|
-
options.onProgress?.('validate', 'Validating output format');
|
|
123
|
-
const validation = validateAgentOutput(rawOutput, options.projectPath, {
|
|
124
|
-
strictMarkdown: options.strictMarkdown,
|
|
125
|
-
});
|
|
126
|
-
result.validation = validation;
|
|
127
|
-
|
|
128
|
-
if (!validation.valid || !validation.output) {
|
|
129
|
-
result.errors.push(...validation.errors);
|
|
130
|
-
result.warnings.push(...validation.warnings);
|
|
131
|
-
throw new Error(`Validation failed: ${validation.errors.join('; ')}`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
result.output = validation.output;
|
|
135
|
-
result.warnings.push(...validation.warnings);
|
|
136
|
-
result.filesModified = validation.diffValidation?.filesAffected || [];
|
|
137
|
-
|
|
138
|
-
options.onProgress?.('validate', `Validated ${result.filesModified.length} file(s)`, {
|
|
139
|
-
files: result.filesModified,
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
// Empty diff is a no-op success
|
|
143
|
-
if (!validation.output.diff || validation.output.diff.trim() === '') {
|
|
144
|
-
options.onProgress?.('done', 'No changes to apply');
|
|
145
|
-
result.success = true;
|
|
146
|
-
result.stage = 'done';
|
|
147
|
-
result.duration = Date.now() - startTime;
|
|
148
|
-
return result;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Step 3: Fingerprint repo
|
|
152
|
-
result.stage = 'fingerprint';
|
|
153
|
-
options.onProgress?.('fingerprint', 'Analyzing project structure');
|
|
154
|
-
|
|
155
|
-
const { fingerprint, detectionNotes } = fingerprintRepo(options.projectPath);
|
|
156
|
-
result.fingerprint = fingerprint;
|
|
157
|
-
result.warnings.push(...detectionNotes);
|
|
158
|
-
|
|
159
|
-
options.onProgress?.('fingerprint', `Detected ${fingerprint.framework} + ${fingerprint.packageManager}`, {
|
|
160
|
-
fingerprint,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Dry run: stop here and report what would happen
|
|
164
|
-
if (options.dryRun) {
|
|
165
|
-
options.onProgress?.('done', 'Dry run complete - no changes applied');
|
|
166
|
-
result.success = true;
|
|
167
|
-
result.stage = 'done';
|
|
168
|
-
result.duration = Date.now() - startTime;
|
|
169
|
-
return result;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Step 4: Create temp workspace
|
|
173
|
-
result.stage = 'workspace';
|
|
174
|
-
options.onProgress?.('workspace', 'Creating isolated workspace');
|
|
175
|
-
|
|
176
|
-
const workspaceInfo = await this.workspace.create({
|
|
177
|
-
projectPath: options.projectPath,
|
|
178
|
-
useWorktree: true,
|
|
179
|
-
installDeps: false, // Don't install deps in workspace for speed
|
|
180
|
-
timeout: options.timeout,
|
|
181
|
-
});
|
|
182
|
-
workspaceId = workspaceInfo.id;
|
|
183
|
-
|
|
184
|
-
options.onProgress?.('workspace', `Created ${workspaceInfo.type} workspace`, {
|
|
185
|
-
path: workspaceInfo.path,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// Step 5: Apply diff
|
|
189
|
-
result.stage = 'apply';
|
|
190
|
-
options.onProgress?.('apply', 'Applying diff to workspace');
|
|
191
|
-
|
|
192
|
-
const applyResult = await this.workspace.applyDiff(
|
|
193
|
-
workspaceInfo.path,
|
|
194
|
-
validation.output.diff,
|
|
195
|
-
validation.diffValidation?.hunks || []
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
if (!applyResult.success) {
|
|
199
|
-
result.errors.push(...applyResult.errors);
|
|
200
|
-
throw new Error(`Diff application failed: ${applyResult.errors.join('; ')}`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
options.onProgress?.('apply', `Applied ${applyResult.applied} hunk(s)`);
|
|
204
|
-
|
|
205
|
-
// Step 6-8: Run verification (typecheck, build, tests)
|
|
206
|
-
result.stage = 'typecheck';
|
|
207
|
-
options.onProgress?.('typecheck', 'Running verification checks');
|
|
208
|
-
|
|
209
|
-
const verification = await this.workspace.verify(
|
|
210
|
-
workspaceInfo.path,
|
|
211
|
-
fingerprint,
|
|
212
|
-
{
|
|
213
|
-
skipTests: options.skipTests,
|
|
214
|
-
timeout: options.timeout,
|
|
215
|
-
}
|
|
216
|
-
);
|
|
217
|
-
result.verification = verification;
|
|
218
|
-
result.failureContext = verification.failureContext;
|
|
219
|
-
|
|
220
|
-
// Report check progress
|
|
221
|
-
for (const check of verification.checks) {
|
|
222
|
-
const status = check.passed ? '✓' : '✗';
|
|
223
|
-
const stage = check.name.toLowerCase().includes('build') ? 'build' :
|
|
224
|
-
check.name.toLowerCase().includes('test') ? 'test' : 'typecheck';
|
|
225
|
-
options.onProgress?.(stage as PipelineStage, `${status} ${check.name} (${check.duration}ms)`);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (!verification.passed) {
|
|
229
|
-
result.errors.push('Verification failed');
|
|
230
|
-
result.errors.push(...verification.failureContext);
|
|
231
|
-
throw new Error(`Verification failed: ${verification.failureContext.slice(0, 3).join('; ')}`);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Step 9: Copy verified changes back to project
|
|
235
|
-
result.stage = 'commit';
|
|
236
|
-
options.onProgress?.('commit', 'Applying verified changes to project');
|
|
237
|
-
|
|
238
|
-
await this.workspace.copyBack(
|
|
239
|
-
workspaceInfo.path,
|
|
240
|
-
options.projectPath,
|
|
241
|
-
result.filesModified
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// Track usage
|
|
245
|
-
await trackUsage('fixRuns', 1);
|
|
246
|
-
|
|
247
|
-
// Success!
|
|
248
|
-
result.success = true;
|
|
249
|
-
result.stage = 'done';
|
|
250
|
-
options.onProgress?.('done', `Successfully modified ${result.filesModified.length} file(s)`);
|
|
251
|
-
|
|
252
|
-
} catch (e) {
|
|
253
|
-
const error = e as Error & { code?: string };
|
|
254
|
-
result.errors.push(error.message);
|
|
255
|
-
|
|
256
|
-
// Handle entitlement errors
|
|
257
|
-
if (error.code === 'FEATURE_NOT_AVAILABLE') {
|
|
258
|
-
result.stage = 'error';
|
|
259
|
-
result.errors = [`Feature requires upgrade: ${error.message}`];
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
options.onProgress?.('error', error.message);
|
|
263
|
-
} finally {
|
|
264
|
-
// Cleanup workspace
|
|
265
|
-
if (workspaceId) {
|
|
266
|
-
try {
|
|
267
|
-
await this.workspace.cleanup(workspaceId);
|
|
268
|
-
} catch {
|
|
269
|
-
// Ignore cleanup errors
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
result.duration = Date.now() - startTime;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return result;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Run from a file (CLI convenience method)
|
|
281
|
-
*/
|
|
282
|
-
async runFromFile(
|
|
283
|
-
agentOutputFile: string,
|
|
284
|
-
projectPath: string,
|
|
285
|
-
options?: Partial<PipelineOptions>
|
|
286
|
-
): Promise<PipelineResult> {
|
|
287
|
-
return this.run({
|
|
288
|
-
projectPath,
|
|
289
|
-
agentOutputFile,
|
|
290
|
-
...options,
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Validate only (no apply) - for checking output format
|
|
296
|
-
*/
|
|
297
|
-
validateOnly(raw: string, projectPath: string): FullValidationResult {
|
|
298
|
-
return validateAgentOutput(raw, projectPath);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// ============================================================================
|
|
303
|
-
// RESULT FORMATTING
|
|
304
|
-
// ============================================================================
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Format pipeline result for CLI output
|
|
308
|
-
*/
|
|
309
|
-
export function formatPipelineResult(result: PipelineResult): string {
|
|
310
|
-
const lines: string[] = [];
|
|
311
|
-
|
|
312
|
-
// Header
|
|
313
|
-
if (result.success) {
|
|
314
|
-
lines.push('✓ VERIFIED AUTOFIX SUCCESSFUL');
|
|
315
|
-
} else {
|
|
316
|
-
lines.push('✗ VERIFIED AUTOFIX FAILED');
|
|
317
|
-
}
|
|
318
|
-
lines.push('');
|
|
319
|
-
|
|
320
|
-
// Stage info
|
|
321
|
-
lines.push(`Stage: ${result.stage}`);
|
|
322
|
-
lines.push(`Duration: ${result.duration}ms`);
|
|
323
|
-
lines.push('');
|
|
324
|
-
|
|
325
|
-
// Files modified
|
|
326
|
-
if (result.filesModified.length > 0) {
|
|
327
|
-
lines.push('Files modified:');
|
|
328
|
-
for (const file of result.filesModified.slice(0, 10)) {
|
|
329
|
-
lines.push(` • ${file}`);
|
|
330
|
-
}
|
|
331
|
-
if (result.filesModified.length > 10) {
|
|
332
|
-
lines.push(` ... and ${result.filesModified.length - 10} more`);
|
|
333
|
-
}
|
|
334
|
-
lines.push('');
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Verification results
|
|
338
|
-
if (result.verification) {
|
|
339
|
-
lines.push('Verification:');
|
|
340
|
-
for (const check of result.verification.checks) {
|
|
341
|
-
const icon = check.passed ? '✓' : '✗';
|
|
342
|
-
lines.push(` ${icon} ${check.name} (${check.duration}ms)`);
|
|
343
|
-
}
|
|
344
|
-
lines.push('');
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Errors
|
|
348
|
-
if (result.errors.length > 0) {
|
|
349
|
-
lines.push('Errors:');
|
|
350
|
-
for (const err of result.errors.slice(0, 5)) {
|
|
351
|
-
lines.push(` • ${err}`);
|
|
352
|
-
}
|
|
353
|
-
lines.push('');
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Failure context (top 3)
|
|
357
|
-
if (result.failureContext.length > 0) {
|
|
358
|
-
lines.push('Top failures:');
|
|
359
|
-
for (const ctx of result.failureContext) {
|
|
360
|
-
lines.push(` 1. ${ctx}`);
|
|
361
|
-
}
|
|
362
|
-
lines.push('');
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Warnings
|
|
366
|
-
if (result.warnings.length > 0) {
|
|
367
|
-
lines.push('Warnings:');
|
|
368
|
-
for (const warn of result.warnings.slice(0, 5)) {
|
|
369
|
-
lines.push(` ⚠ ${warn}`);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
return lines.join('\n');
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Format result as JSON for machine consumption
|
|
378
|
-
*/
|
|
379
|
-
export function formatPipelineResultJson(result: PipelineResult): string {
|
|
380
|
-
return JSON.stringify({
|
|
381
|
-
success: result.success,
|
|
382
|
-
stage: result.stage,
|
|
383
|
-
duration: result.duration,
|
|
384
|
-
filesModified: result.filesModified,
|
|
385
|
-
errors: result.errors,
|
|
386
|
-
warnings: result.warnings,
|
|
387
|
-
failureContext: result.failureContext,
|
|
388
|
-
verification: result.verification ? {
|
|
389
|
-
passed: result.verification.passed,
|
|
390
|
-
checks: result.verification.checks.map(c => ({
|
|
391
|
-
name: c.name,
|
|
392
|
-
passed: c.passed,
|
|
393
|
-
duration: c.duration,
|
|
394
|
-
})),
|
|
395
|
-
} : null,
|
|
396
|
-
}, null, 2);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// ============================================================================
|
|
400
|
-
// EXPORTS
|
|
401
|
-
// ============================================================================
|
|
402
|
-
|
|
403
|
-
export const verifiedAutofixPipeline = new VerifiedAutofixPipeline();
|