guardrail-core 1.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.test.d.ts +7 -0
- package/dist/__tests__/autopilot.test.d.ts.map +1 -0
- package/dist/__tests__/autopilot.test.js +156 -0
- package/dist/__tests__/tier-config.test.d.ts +9 -0
- package/dist/__tests__/tier-config.test.d.ts.map +1 -0
- package/dist/__tests__/tier-config.test.js +230 -0
- package/dist/__tests__/utils/hash-inline.test.d.ts +2 -0
- package/dist/__tests__/utils/hash-inline.test.d.ts.map +1 -0
- package/dist/__tests__/utils/hash-inline.test.js +62 -0
- package/dist/__tests__/utils/hash.test.d.ts +3 -0
- package/dist/__tests__/utils/hash.test.d.ts.map +1 -0
- package/dist/__tests__/utils/hash.test.js +95 -0
- package/dist/__tests__/utils/simple.test.d.ts +1 -0
- package/dist/__tests__/utils/simple.test.d.ts.map +1 -0
- package/dist/__tests__/utils/simple.test.js +10 -0
- package/dist/__tests__/utils/utils-simple.test.d.ts +1 -0
- package/dist/__tests__/utils/utils-simple.test.d.ts.map +1 -0
- package/dist/__tests__/utils/utils-simple.test.js +6 -0
- package/dist/__tests__/utils/utils.test.d.ts +15 -0
- package/dist/__tests__/utils/utils.test.d.ts.map +1 -0
- package/dist/__tests__/utils/utils.test.js +172 -0
- package/dist/autopilot/autopilot-runner.d.ts +33 -0
- package/dist/autopilot/autopilot-runner.d.ts.map +1 -0
- package/dist/autopilot/autopilot-runner.js +479 -0
- package/dist/autopilot/index.d.ts +6 -0
- package/dist/autopilot/index.d.ts.map +1 -0
- package/dist/autopilot/index.js +25 -0
- package/dist/autopilot/types.d.ts +102 -0
- package/dist/autopilot/types.d.ts.map +1 -0
- package/dist/autopilot/types.js +18 -0
- package/dist/cache/index.d.ts +7 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +22 -0
- package/dist/cache/redis-cache.d.ts +145 -0
- package/dist/cache/redis-cache.d.ts.map +1 -0
- package/dist/cache/redis-cache.js +459 -0
- package/dist/ci/github-actions.d.ts +77 -0
- package/dist/ci/github-actions.d.ts.map +1 -0
- package/dist/ci/github-actions.js +277 -0
- package/dist/ci/index.d.ts +12 -0
- package/dist/ci/index.d.ts.map +1 -0
- package/dist/ci/index.js +27 -0
- package/dist/ci/pre-commit.d.ts +65 -0
- package/dist/ci/pre-commit.d.ts.map +1 -0
- package/dist/ci/pre-commit.js +286 -0
- package/dist/entitlements.d.ts +149 -0
- package/dist/entitlements.d.ts.map +1 -0
- package/dist/entitlements.js +464 -0
- package/dist/env.d.ts +113 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +204 -0
- package/dist/fix-packs/__tests__/generate-fix-packs.test.d.ts +7 -0
- package/dist/fix-packs/__tests__/generate-fix-packs.test.d.ts.map +1 -0
- package/dist/fix-packs/__tests__/generate-fix-packs.test.js +250 -0
- package/dist/fix-packs/generate-fix-packs.d.ts +15 -0
- package/dist/fix-packs/generate-fix-packs.d.ts.map +1 -0
- package/dist/fix-packs/generate-fix-packs.js +505 -0
- package/dist/fix-packs/index.d.ts +8 -0
- package/dist/fix-packs/index.d.ts.map +1 -0
- package/dist/fix-packs/index.js +23 -0
- package/dist/fix-packs/types.d.ts +113 -0
- package/dist/fix-packs/types.d.ts.map +1 -0
- package/dist/fix-packs/types.js +71 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/metrics/prometheus.d.ts +99 -0
- package/dist/metrics/prometheus.d.ts.map +1 -0
- package/dist/metrics/prometheus.js +306 -0
- package/dist/quota-ledger.d.ts +119 -0
- package/dist/quota-ledger.d.ts.map +1 -0
- package/dist/quota-ledger.js +462 -0
- package/dist/rbac/__tests__/permissions.test.d.ts +8 -0
- package/dist/rbac/__tests__/permissions.test.d.ts.map +1 -0
- package/dist/rbac/__tests__/permissions.test.js +350 -0
- package/dist/rbac/index.d.ts +9 -0
- package/dist/rbac/index.d.ts.map +1 -0
- package/dist/rbac/index.js +32 -0
- package/dist/rbac/permissions.d.ts +71 -0
- package/dist/rbac/permissions.d.ts.map +1 -0
- package/dist/rbac/permissions.js +247 -0
- package/dist/rbac/types.d.ts +69 -0
- package/dist/rbac/types.d.ts.map +1 -0
- package/dist/rbac/types.js +213 -0
- package/dist/tier-config.d.ts +203 -0
- package/dist/tier-config.d.ts.map +1 -0
- package/dist/tier-config.js +675 -0
- package/dist/types.d.ts +365 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/utils.d.ts +36 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +127 -0
- package/dist/verified-autofix/__tests__/format-validator.test.d.ts +11 -0
- package/dist/verified-autofix/__tests__/format-validator.test.d.ts.map +1 -0
- package/dist/verified-autofix/__tests__/format-validator.test.js +285 -0
- package/dist/verified-autofix/__tests__/pipeline.test.d.ts +11 -0
- package/dist/verified-autofix/__tests__/pipeline.test.d.ts.map +1 -0
- package/dist/verified-autofix/__tests__/pipeline.test.js +389 -0
- package/dist/verified-autofix/__tests__/repo-fingerprint.test.d.ts +11 -0
- package/dist/verified-autofix/__tests__/repo-fingerprint.test.d.ts.map +1 -0
- package/dist/verified-autofix/__tests__/repo-fingerprint.test.js +236 -0
- package/dist/verified-autofix/__tests__/workspace.test.d.ts +11 -0
- package/dist/verified-autofix/__tests__/workspace.test.d.ts.map +1 -0
- package/dist/verified-autofix/__tests__/workspace.test.js +314 -0
- package/dist/verified-autofix/format-validator.d.ts +101 -0
- package/dist/verified-autofix/format-validator.d.ts.map +1 -0
- package/dist/verified-autofix/format-validator.js +446 -0
- package/dist/verified-autofix/index.d.ts +14 -0
- package/dist/verified-autofix/index.d.ts.map +1 -0
- package/dist/verified-autofix/index.js +39 -0
- package/dist/verified-autofix/pipeline.d.ts +68 -0
- package/dist/verified-autofix/pipeline.d.ts.map +1 -0
- package/dist/verified-autofix/pipeline.js +330 -0
- package/dist/verified-autofix/repo-fingerprint.d.ts +56 -0
- package/dist/verified-autofix/repo-fingerprint.d.ts.map +1 -0
- package/dist/verified-autofix/repo-fingerprint.js +396 -0
- package/dist/verified-autofix/workspace.d.ts +83 -0
- package/dist/verified-autofix/workspace.d.ts.map +1 -0
- package/dist/verified-autofix/workspace.js +454 -0
- package/dist/verified-autofix.d.ts +182 -0
- package/dist/verified-autofix.d.ts.map +1 -0
- package/dist/verified-autofix.js +1021 -0
- package/dist/visualization/dependency-graph.d.ts +79 -0
- package/dist/visualization/dependency-graph.d.ts.map +1 -0
- package/dist/visualization/dependency-graph.js +399 -0
- package/dist/visualization/index.d.ts +5 -0
- package/dist/visualization/index.d.ts.map +1 -0
- package/dist/visualization/index.js +20 -0
- package/package.json +29 -0
- package/src/__tests__/autopilot.test.ts +196 -0
- package/src/__tests__/tier-config.test.ts +289 -0
- package/src/__tests__/utils/hash-inline.test.ts +76 -0
- package/src/__tests__/utils/hash.test.ts +119 -0
- package/src/__tests__/utils/simple.test.ts +10 -0
- package/src/__tests__/utils/utils-simple.test.ts +5 -0
- package/src/__tests__/utils/utils.test.ts +203 -0
- package/src/autopilot/autopilot-runner.ts +503 -0
- package/src/autopilot/index.ts +6 -0
- package/src/autopilot/types.ts +119 -0
- package/src/cache/index.ts +7 -0
- package/src/cache/redis-cache.d.ts +155 -0
- package/src/cache/redis-cache.d.ts.map +1 -0
- package/src/cache/redis-cache.ts +517 -0
- package/src/ci/github-actions.ts +335 -0
- package/src/ci/index.ts +12 -0
- package/src/ci/pre-commit.ts +338 -0
- package/src/db/usage-schema.prisma +114 -0
- package/src/entitlements.ts +570 -0
- package/src/env.d.ts +68 -0
- package/src/env.d.ts.map +1 -0
- package/src/env.ts +247 -0
- package/src/fix-packs/__tests__/generate-fix-packs.test.ts +317 -0
- package/src/fix-packs/generate-fix-packs.ts +577 -0
- package/src/fix-packs/index.ts +8 -0
- package/src/fix-packs/types.ts +206 -0
- package/src/index.d.ts +7 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.ts +12 -0
- package/src/metrics/prometheus.d.ts +104 -0
- package/src/metrics/prometheus.d.ts.map +1 -0
- package/src/metrics/prometheus.ts +446 -0
- package/src/quota-ledger.ts +548 -0
- package/src/rbac/__tests__/permissions.test.ts +446 -0
- package/src/rbac/index.ts +46 -0
- package/src/rbac/permissions.ts +301 -0
- package/src/rbac/types.ts +298 -0
- package/src/tier-config.json +157 -0
- package/src/tier-config.ts +815 -0
- package/src/types.d.ts +365 -0
- package/src/types.d.ts.map +1 -0
- package/src/types.ts +441 -0
- package/src/utils.d.ts +36 -0
- package/src/utils.d.ts.map +1 -0
- package/src/utils.ts +140 -0
- package/src/verified-autofix/__tests__/format-validator.test.ts +335 -0
- package/src/verified-autofix/__tests__/pipeline.test.ts +419 -0
- package/src/verified-autofix/__tests__/repo-fingerprint.test.ts +241 -0
- package/src/verified-autofix/__tests__/workspace.test.ts +373 -0
- package/src/verified-autofix/format-validator.ts +517 -0
- package/src/verified-autofix/index.ts +63 -0
- package/src/verified-autofix/pipeline.ts +403 -0
- package/src/verified-autofix/repo-fingerprint.ts +459 -0
- package/src/verified-autofix/workspace.ts +531 -0
- package/src/verified-autofix.ts +1187 -0
- package/src/visualization/dependency-graph.d.ts +85 -0
- package/src/visualization/dependency-graph.d.ts.map +1 -0
- package/src/visualization/dependency-graph.ts +495 -0
- package/src/visualization/index.ts +5 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Format Validator Tests
|
|
4
|
+
*
|
|
5
|
+
* Tests for the verified autofix format validation:
|
|
6
|
+
* - JSON shape validation
|
|
7
|
+
* - Unified diff parsing
|
|
8
|
+
* - Path safety checks
|
|
9
|
+
* - Stub detection
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const format_validator_1 = require("../format-validator");
|
|
13
|
+
describe('stripMarkdownFences', () => {
|
|
14
|
+
it('removes ```json wrapper', () => {
|
|
15
|
+
const raw = '```json\n{"format":"guardrail-v1"}\n```';
|
|
16
|
+
expect((0, format_validator_1.stripMarkdownFences)(raw)).toBe('{"format":"guardrail-v1"}');
|
|
17
|
+
});
|
|
18
|
+
it('removes ``` wrapper without language', () => {
|
|
19
|
+
const raw = '```\n{"format":"guardrail-v1"}\n```';
|
|
20
|
+
expect((0, format_validator_1.stripMarkdownFences)(raw)).toBe('{"format":"guardrail-v1"}');
|
|
21
|
+
});
|
|
22
|
+
it('handles partial fences', () => {
|
|
23
|
+
const raw = '```json\n{"format":"guardrail-v1"}';
|
|
24
|
+
expect((0, format_validator_1.stripMarkdownFences)(raw)).toBe('{"format":"guardrail-v1"}');
|
|
25
|
+
});
|
|
26
|
+
it('returns unchanged if no fences', () => {
|
|
27
|
+
const raw = '{"format":"guardrail-v1"}';
|
|
28
|
+
expect((0, format_validator_1.stripMarkdownFences)(raw)).toBe('{"format":"guardrail-v1"}');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('isMarkdownWrapped', () => {
|
|
32
|
+
it('detects ```json wrapper', () => {
|
|
33
|
+
expect((0, format_validator_1.isMarkdownWrapped)('```json\n{}\n```')).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
it('detects ``` wrapper', () => {
|
|
36
|
+
expect((0, format_validator_1.isMarkdownWrapped)('```\n{}\n```')).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('returns false for plain JSON', () => {
|
|
39
|
+
expect((0, format_validator_1.isMarkdownWrapped)('{}')).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('validateJsonShape', () => {
|
|
43
|
+
it('accepts valid guardrail-v1 output', () => {
|
|
44
|
+
const valid = {
|
|
45
|
+
format: 'guardrail-v1',
|
|
46
|
+
diff: '--- a/file.ts\n+++ b/file.ts\n@@ -1,1 +1,1 @@\n-old\n+new',
|
|
47
|
+
commands: ['npm test'],
|
|
48
|
+
tests: ['test/file.test.ts'],
|
|
49
|
+
notes: 'Fixed the bug',
|
|
50
|
+
};
|
|
51
|
+
const result = (0, format_validator_1.validateJsonShape)(valid);
|
|
52
|
+
expect(result.valid).toBe(true);
|
|
53
|
+
expect(result.errors).toHaveLength(0);
|
|
54
|
+
expect(result.sanitized).toBeDefined();
|
|
55
|
+
});
|
|
56
|
+
it('rejects missing format field', () => {
|
|
57
|
+
const invalid = {
|
|
58
|
+
diff: '',
|
|
59
|
+
commands: [],
|
|
60
|
+
tests: [],
|
|
61
|
+
notes: '',
|
|
62
|
+
};
|
|
63
|
+
const result = (0, format_validator_1.validateJsonShape)(invalid);
|
|
64
|
+
expect(result.valid).toBe(false);
|
|
65
|
+
expect(result.errors).toContain(expect.stringContaining('format'));
|
|
66
|
+
});
|
|
67
|
+
it('rejects wrong format value', () => {
|
|
68
|
+
const invalid = {
|
|
69
|
+
format: 'other-format',
|
|
70
|
+
diff: '',
|
|
71
|
+
commands: [],
|
|
72
|
+
tests: [],
|
|
73
|
+
notes: '',
|
|
74
|
+
};
|
|
75
|
+
const result = (0, format_validator_1.validateJsonShape)(invalid);
|
|
76
|
+
expect(result.valid).toBe(false);
|
|
77
|
+
expect(result.errors[0]).toContain('guardrail-v1');
|
|
78
|
+
});
|
|
79
|
+
it('rejects non-string diff', () => {
|
|
80
|
+
const invalid = {
|
|
81
|
+
format: 'guardrail-v1',
|
|
82
|
+
diff: 123,
|
|
83
|
+
commands: [],
|
|
84
|
+
tests: [],
|
|
85
|
+
notes: '',
|
|
86
|
+
};
|
|
87
|
+
const result = (0, format_validator_1.validateJsonShape)(invalid);
|
|
88
|
+
expect(result.valid).toBe(false);
|
|
89
|
+
expect(result.errors).toContain(expect.stringContaining('diff'));
|
|
90
|
+
});
|
|
91
|
+
it('rejects non-array commands', () => {
|
|
92
|
+
const invalid = {
|
|
93
|
+
format: 'guardrail-v1',
|
|
94
|
+
diff: '',
|
|
95
|
+
commands: 'npm test',
|
|
96
|
+
tests: [],
|
|
97
|
+
notes: '',
|
|
98
|
+
};
|
|
99
|
+
const result = (0, format_validator_1.validateJsonShape)(invalid);
|
|
100
|
+
expect(result.valid).toBe(false);
|
|
101
|
+
expect(result.errors).toContain(expect.stringContaining('commands'));
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe('validateUnifiedDiff', () => {
|
|
105
|
+
it('parses valid unified diff', () => {
|
|
106
|
+
const diff = `--- a/src/file.ts
|
|
107
|
+
+++ b/src/file.ts
|
|
108
|
+
@@ -1,3 +1,4 @@
|
|
109
|
+
const x = 1;
|
|
110
|
+
-const y = 2;
|
|
111
|
+
+const y = 3;
|
|
112
|
+
+const z = 4;
|
|
113
|
+
export { x, y };`;
|
|
114
|
+
const result = (0, format_validator_1.validateUnifiedDiff)(diff);
|
|
115
|
+
expect(result.valid).toBe(true);
|
|
116
|
+
expect(result.filesAffected).toContain('src/file.ts');
|
|
117
|
+
expect(result.hunks).toHaveLength(1);
|
|
118
|
+
});
|
|
119
|
+
it('handles empty diff', () => {
|
|
120
|
+
const result = (0, format_validator_1.validateUnifiedDiff)('');
|
|
121
|
+
expect(result.valid).toBe(true);
|
|
122
|
+
expect(result.hunks).toHaveLength(0);
|
|
123
|
+
});
|
|
124
|
+
it('handles multi-file diff', () => {
|
|
125
|
+
const diff = `diff --git a/file1.ts b/file1.ts
|
|
126
|
+
--- a/file1.ts
|
|
127
|
+
+++ b/file1.ts
|
|
128
|
+
@@ -1,1 +1,1 @@
|
|
129
|
+
-old1
|
|
130
|
+
+new1
|
|
131
|
+
diff --git a/file2.ts b/file2.ts
|
|
132
|
+
--- a/file2.ts
|
|
133
|
+
+++ b/file2.ts
|
|
134
|
+
@@ -1,1 +1,1 @@
|
|
135
|
+
-old2
|
|
136
|
+
+new2`;
|
|
137
|
+
const result = (0, format_validator_1.validateUnifiedDiff)(diff);
|
|
138
|
+
expect(result.valid).toBe(true);
|
|
139
|
+
expect(result.filesAffected).toContain('file1.ts');
|
|
140
|
+
expect(result.filesAffected).toContain('file2.ts');
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('validatePathSafety', () => {
|
|
144
|
+
const projectRoot = '/home/user/project';
|
|
145
|
+
it('accepts paths within project', () => {
|
|
146
|
+
const paths = ['src/file.ts', 'lib/utils.js', 'package.json'];
|
|
147
|
+
const result = (0, format_validator_1.validatePathSafety)(paths, projectRoot);
|
|
148
|
+
expect(result.safe).toBe(true);
|
|
149
|
+
expect(result.issues).toHaveLength(0);
|
|
150
|
+
});
|
|
151
|
+
it('rejects parent directory traversal', () => {
|
|
152
|
+
const paths = ['../../../etc/passwd'];
|
|
153
|
+
const result = (0, format_validator_1.validatePathSafety)(paths, projectRoot);
|
|
154
|
+
expect(result.safe).toBe(false);
|
|
155
|
+
expect(result.issues[0]).toContain('Unsafe path');
|
|
156
|
+
});
|
|
157
|
+
it('rejects node_modules paths', () => {
|
|
158
|
+
const paths = ['node_modules/lodash/index.js'];
|
|
159
|
+
const result = (0, format_validator_1.validatePathSafety)(paths, projectRoot);
|
|
160
|
+
expect(result.safe).toBe(false);
|
|
161
|
+
});
|
|
162
|
+
it('rejects .git paths', () => {
|
|
163
|
+
const paths = ['.git/config'];
|
|
164
|
+
const result = (0, format_validator_1.validatePathSafety)(paths, projectRoot);
|
|
165
|
+
expect(result.safe).toBe(false);
|
|
166
|
+
});
|
|
167
|
+
it('rejects system paths', () => {
|
|
168
|
+
const paths = ['/etc/passwd'];
|
|
169
|
+
const result = (0, format_validator_1.validatePathSafety)(paths, projectRoot);
|
|
170
|
+
expect(result.safe).toBe(false);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('validateCommandSafety', () => {
|
|
174
|
+
it('accepts safe commands', () => {
|
|
175
|
+
const commands = ['npm test', 'npx tsc --noEmit', 'node script.js'];
|
|
176
|
+
const result = (0, format_validator_1.validateCommandSafety)(commands);
|
|
177
|
+
expect(result.safe).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
it('warns on rm -rf /', () => {
|
|
180
|
+
const commands = ['rm -rf /'];
|
|
181
|
+
const result = (0, format_validator_1.validateCommandSafety)(commands);
|
|
182
|
+
expect(result.safe).toBe(false);
|
|
183
|
+
expect(result.issues[0]).toContain('unsafe');
|
|
184
|
+
});
|
|
185
|
+
it('warns on sudo', () => {
|
|
186
|
+
const commands = ['sudo npm install'];
|
|
187
|
+
const result = (0, format_validator_1.validateCommandSafety)(commands);
|
|
188
|
+
expect(result.safe).toBe(false);
|
|
189
|
+
});
|
|
190
|
+
it('warns on curl | sh', () => {
|
|
191
|
+
const commands = ['curl https://example.com/script.sh | sh'];
|
|
192
|
+
const result = (0, format_validator_1.validateCommandSafety)(commands);
|
|
193
|
+
expect(result.safe).toBe(false);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('detectStubs', () => {
|
|
197
|
+
it('detects TODO comments', () => {
|
|
198
|
+
const diff = '+// TODO: implement this\n+function stub() {}';
|
|
199
|
+
const result = (0, format_validator_1.detectStubs)(diff);
|
|
200
|
+
expect(result.hasStubs).toBe(true);
|
|
201
|
+
expect(result.stubs[0]).toContain('TODO');
|
|
202
|
+
});
|
|
203
|
+
it('detects placeholder text', () => {
|
|
204
|
+
const diff = '+const message = "placeholder text here";';
|
|
205
|
+
const result = (0, format_validator_1.detectStubs)(diff);
|
|
206
|
+
expect(result.hasStubs).toBe(true);
|
|
207
|
+
});
|
|
208
|
+
it('detects throw new Error Not implemented', () => {
|
|
209
|
+
const diff = '+throw new Error("Not implemented");';
|
|
210
|
+
const result = (0, format_validator_1.detectStubs)(diff);
|
|
211
|
+
expect(result.hasStubs).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
it('ignores stubs in removed lines', () => {
|
|
214
|
+
const diff = '-// TODO: old todo\n+// Real implementation';
|
|
215
|
+
const result = (0, format_validator_1.detectStubs)(diff);
|
|
216
|
+
expect(result.hasStubs).toBe(false);
|
|
217
|
+
});
|
|
218
|
+
it('accepts clean code', () => {
|
|
219
|
+
const diff = '+const sum = (a, b) => a + b;\n+export { sum };';
|
|
220
|
+
const result = (0, format_validator_1.detectStubs)(diff);
|
|
221
|
+
expect(result.hasStubs).toBe(false);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
describe('validateAgentOutput', () => {
|
|
225
|
+
const projectRoot = '/home/user/project';
|
|
226
|
+
it('validates complete valid output', () => {
|
|
227
|
+
const raw = JSON.stringify({
|
|
228
|
+
format: 'guardrail-v1',
|
|
229
|
+
diff: `--- a/src/file.ts
|
|
230
|
+
+++ b/src/file.ts
|
|
231
|
+
@@ -1,1 +1,1 @@
|
|
232
|
+
-const x = 1;
|
|
233
|
+
+const x = 2;`,
|
|
234
|
+
commands: ['npm test'],
|
|
235
|
+
tests: ['test/file.test.ts'],
|
|
236
|
+
notes: 'Incremented x',
|
|
237
|
+
});
|
|
238
|
+
const result = (0, format_validator_1.validateAgentOutput)(raw, projectRoot);
|
|
239
|
+
expect(result.valid).toBe(true);
|
|
240
|
+
expect(result.output).toBeDefined();
|
|
241
|
+
});
|
|
242
|
+
it('strips markdown fences and validates', () => {
|
|
243
|
+
const raw = '```json\n' + JSON.stringify({
|
|
244
|
+
format: 'guardrail-v1',
|
|
245
|
+
diff: '',
|
|
246
|
+
commands: [],
|
|
247
|
+
tests: [],
|
|
248
|
+
notes: 'No changes needed',
|
|
249
|
+
}) + '\n```';
|
|
250
|
+
const result = (0, format_validator_1.validateAgentOutput)(raw, projectRoot);
|
|
251
|
+
expect(result.valid).toBe(true);
|
|
252
|
+
});
|
|
253
|
+
it('rejects invalid JSON', () => {
|
|
254
|
+
const result = (0, format_validator_1.validateAgentOutput)('not json', projectRoot);
|
|
255
|
+
expect(result.valid).toBe(false);
|
|
256
|
+
expect(result.errors[0]).toContain('Invalid JSON');
|
|
257
|
+
});
|
|
258
|
+
it('rejects output with stubs', () => {
|
|
259
|
+
const raw = JSON.stringify({
|
|
260
|
+
format: 'guardrail-v1',
|
|
261
|
+
diff: '+// TODO: implement this',
|
|
262
|
+
commands: [],
|
|
263
|
+
tests: [],
|
|
264
|
+
notes: '',
|
|
265
|
+
});
|
|
266
|
+
const result = (0, format_validator_1.validateAgentOutput)(raw, projectRoot);
|
|
267
|
+
expect(result.valid).toBe(false);
|
|
268
|
+
expect(result.errors.some(e => e.includes('Stub'))).toBe(true);
|
|
269
|
+
});
|
|
270
|
+
it('rejects output with unsafe paths', () => {
|
|
271
|
+
const raw = JSON.stringify({
|
|
272
|
+
format: 'guardrail-v1',
|
|
273
|
+
diff: `--- a/../../../etc/passwd
|
|
274
|
+
+++ b/../../../etc/passwd
|
|
275
|
+
@@ -1,1 +1,1 @@
|
|
276
|
+
-root
|
|
277
|
+
+hacked`,
|
|
278
|
+
commands: [],
|
|
279
|
+
tests: [],
|
|
280
|
+
notes: '',
|
|
281
|
+
});
|
|
282
|
+
const result = (0, format_validator_1.validateAgentOutput)(raw, projectRoot);
|
|
283
|
+
expect(result.valid).toBe(false);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline Tests - Verified AutoFix Pipeline
|
|
3
|
+
*
|
|
4
|
+
* Tests for the full verification pipeline:
|
|
5
|
+
* - Format validation stage
|
|
6
|
+
* - Diff application stage
|
|
7
|
+
* - Verification stage (typecheck, build, tests)
|
|
8
|
+
* - Top 3 failure context extraction
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=pipeline.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.test.d.ts","sourceRoot":"","sources":["../../../src/verified-autofix/__tests__/pipeline.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pipeline Tests - Verified AutoFix Pipeline
|
|
4
|
+
*
|
|
5
|
+
* Tests for the full verification pipeline:
|
|
6
|
+
* - Format validation stage
|
|
7
|
+
* - Diff application stage
|
|
8
|
+
* - Verification stage (typecheck, build, tests)
|
|
9
|
+
* - Top 3 failure context extraction
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const os = __importStar(require("os"));
|
|
48
|
+
const pipeline_1 = require("../pipeline");
|
|
49
|
+
const format_validator_1 = require("../format-validator");
|
|
50
|
+
describe('VerifiedAutofixPipeline', () => {
|
|
51
|
+
let tempDir;
|
|
52
|
+
let pipeline;
|
|
53
|
+
beforeEach(async () => {
|
|
54
|
+
tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'pipeline-test-'));
|
|
55
|
+
pipeline = new pipeline_1.VerifiedAutofixPipeline();
|
|
56
|
+
// Create minimal project structure
|
|
57
|
+
await fs.promises.writeFile(path.join(tempDir, 'package.json'), JSON.stringify({
|
|
58
|
+
name: 'test-project',
|
|
59
|
+
version: '1.0.0',
|
|
60
|
+
scripts: {
|
|
61
|
+
build: 'echo "build"',
|
|
62
|
+
test: 'echo "test"',
|
|
63
|
+
},
|
|
64
|
+
}));
|
|
65
|
+
});
|
|
66
|
+
afterEach(async () => {
|
|
67
|
+
await fs.promises.rm(tempDir, { recursive: true, force: true });
|
|
68
|
+
});
|
|
69
|
+
describe('validation stage', () => {
|
|
70
|
+
it('rejects missing agent output file', async () => {
|
|
71
|
+
const result = await pipeline.run({
|
|
72
|
+
projectPath: tempDir,
|
|
73
|
+
agentOutputFile: '/nonexistent/file.json',
|
|
74
|
+
skipEntitlements: true,
|
|
75
|
+
});
|
|
76
|
+
expect(result.success).toBe(false);
|
|
77
|
+
expect(result.stage).toBe('validate');
|
|
78
|
+
expect(result.errors.some(e => e.includes('not found'))).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
it('rejects invalid JSON in agent output', async () => {
|
|
81
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
82
|
+
await fs.promises.writeFile(outputFile, 'not valid json');
|
|
83
|
+
const result = await pipeline.run({
|
|
84
|
+
projectPath: tempDir,
|
|
85
|
+
agentOutputFile: outputFile,
|
|
86
|
+
skipEntitlements: true,
|
|
87
|
+
});
|
|
88
|
+
expect(result.success).toBe(false);
|
|
89
|
+
expect(result.errors.some(e => e.includes('Invalid JSON'))).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
it('rejects wrong format field', async () => {
|
|
92
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
93
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
94
|
+
format: 'wrong-format',
|
|
95
|
+
diff: '',
|
|
96
|
+
commands: [],
|
|
97
|
+
tests: [],
|
|
98
|
+
notes: '',
|
|
99
|
+
}));
|
|
100
|
+
const result = await pipeline.run({
|
|
101
|
+
projectPath: tempDir,
|
|
102
|
+
agentOutputFile: outputFile,
|
|
103
|
+
skipEntitlements: true,
|
|
104
|
+
});
|
|
105
|
+
expect(result.success).toBe(false);
|
|
106
|
+
expect(result.errors.some(e => e.includes('guardrail-v1'))).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
it('accepts valid guardrail-v1 output with empty diff', async () => {
|
|
109
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
110
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
111
|
+
format: 'guardrail-v1',
|
|
112
|
+
diff: '',
|
|
113
|
+
commands: [],
|
|
114
|
+
tests: [],
|
|
115
|
+
notes: 'No changes needed',
|
|
116
|
+
}));
|
|
117
|
+
const result = await pipeline.run({
|
|
118
|
+
projectPath: tempDir,
|
|
119
|
+
agentOutputFile: outputFile,
|
|
120
|
+
skipEntitlements: true,
|
|
121
|
+
});
|
|
122
|
+
expect(result.success).toBe(true);
|
|
123
|
+
expect(result.stage).toBe('done');
|
|
124
|
+
});
|
|
125
|
+
it('strips markdown fences and warns', async () => {
|
|
126
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
127
|
+
await fs.promises.writeFile(outputFile, '```json\n' + JSON.stringify({
|
|
128
|
+
format: 'guardrail-v1',
|
|
129
|
+
diff: '',
|
|
130
|
+
commands: [],
|
|
131
|
+
tests: [],
|
|
132
|
+
notes: '',
|
|
133
|
+
}) + '\n```');
|
|
134
|
+
const result = await pipeline.run({
|
|
135
|
+
projectPath: tempDir,
|
|
136
|
+
agentOutputFile: outputFile,
|
|
137
|
+
skipEntitlements: true,
|
|
138
|
+
});
|
|
139
|
+
expect(result.success).toBe(true);
|
|
140
|
+
expect(result.warnings.some(w => w.includes('markdown'))).toBe(true);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('stub detection', () => {
|
|
144
|
+
it('blocks TODO comments in diff', async () => {
|
|
145
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
146
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
147
|
+
format: 'guardrail-v1',
|
|
148
|
+
diff: `--- a/src/file.ts
|
|
149
|
+
+++ b/src/file.ts
|
|
150
|
+
@@ -1,1 +1,2 @@
|
|
151
|
+
const x = 1;
|
|
152
|
+
+// TODO: implement this`,
|
|
153
|
+
commands: [],
|
|
154
|
+
tests: [],
|
|
155
|
+
notes: '',
|
|
156
|
+
}));
|
|
157
|
+
const result = await pipeline.run({
|
|
158
|
+
projectPath: tempDir,
|
|
159
|
+
agentOutputFile: outputFile,
|
|
160
|
+
skipEntitlements: true,
|
|
161
|
+
});
|
|
162
|
+
expect(result.success).toBe(false);
|
|
163
|
+
expect(result.errors.some(e => e.includes('Stub'))).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
it('blocks placeholder text in diff', async () => {
|
|
166
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
167
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
168
|
+
format: 'guardrail-v1',
|
|
169
|
+
diff: `--- a/src/file.ts
|
|
170
|
+
+++ b/src/file.ts
|
|
171
|
+
@@ -1,1 +1,2 @@
|
|
172
|
+
const x = 1;
|
|
173
|
+
+const message = "placeholder content here";`,
|
|
174
|
+
commands: [],
|
|
175
|
+
tests: [],
|
|
176
|
+
notes: '',
|
|
177
|
+
}));
|
|
178
|
+
const result = await pipeline.run({
|
|
179
|
+
projectPath: tempDir,
|
|
180
|
+
agentOutputFile: outputFile,
|
|
181
|
+
skipEntitlements: true,
|
|
182
|
+
});
|
|
183
|
+
expect(result.success).toBe(false);
|
|
184
|
+
expect(result.errors.some(e => e.includes('Stub') || e.includes('placeholder'))).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
it('allows clean code without stubs', async () => {
|
|
187
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
188
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
189
|
+
format: 'guardrail-v1',
|
|
190
|
+
diff: `--- a/src/file.ts
|
|
191
|
+
+++ b/src/file.ts
|
|
192
|
+
@@ -1,1 +1,2 @@
|
|
193
|
+
const x = 1;
|
|
194
|
+
+const y = x + 1;`,
|
|
195
|
+
commands: [],
|
|
196
|
+
tests: [],
|
|
197
|
+
notes: '',
|
|
198
|
+
}));
|
|
199
|
+
// Create the source file
|
|
200
|
+
await fs.promises.mkdir(path.join(tempDir, 'src'), { recursive: true });
|
|
201
|
+
await fs.promises.writeFile(path.join(tempDir, 'src', 'file.ts'), 'const x = 1;\n');
|
|
202
|
+
const result = await pipeline.run({
|
|
203
|
+
projectPath: tempDir,
|
|
204
|
+
agentOutputFile: outputFile,
|
|
205
|
+
dryRun: true,
|
|
206
|
+
skipEntitlements: true,
|
|
207
|
+
});
|
|
208
|
+
// Should pass validation (stub detection at least)
|
|
209
|
+
expect(result.validation?.stubDetection?.hasStubs).toBe(false);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
describe('path safety', () => {
|
|
213
|
+
it('blocks parent directory traversal', async () => {
|
|
214
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
215
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
216
|
+
format: 'guardrail-v1',
|
|
217
|
+
diff: `--- a/../../../etc/passwd
|
|
218
|
+
+++ b/../../../etc/passwd
|
|
219
|
+
@@ -1,1 +1,1 @@
|
|
220
|
+
-root
|
|
221
|
+
+hacked`,
|
|
222
|
+
commands: [],
|
|
223
|
+
tests: [],
|
|
224
|
+
notes: '',
|
|
225
|
+
}));
|
|
226
|
+
const result = await pipeline.run({
|
|
227
|
+
projectPath: tempDir,
|
|
228
|
+
agentOutputFile: outputFile,
|
|
229
|
+
skipEntitlements: true,
|
|
230
|
+
});
|
|
231
|
+
expect(result.success).toBe(false);
|
|
232
|
+
expect(result.errors.some(e => e.includes('Unsafe') || e.includes('path'))).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
it('blocks node_modules modifications', async () => {
|
|
235
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
236
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
237
|
+
format: 'guardrail-v1',
|
|
238
|
+
diff: `--- a/node_modules/lodash/index.js
|
|
239
|
+
+++ b/node_modules/lodash/index.js
|
|
240
|
+
@@ -1,1 +1,1 @@
|
|
241
|
+
-module.exports = {};
|
|
242
|
+
+module.exports = { hacked: true };`,
|
|
243
|
+
commands: [],
|
|
244
|
+
tests: [],
|
|
245
|
+
notes: '',
|
|
246
|
+
}));
|
|
247
|
+
const result = await pipeline.run({
|
|
248
|
+
projectPath: tempDir,
|
|
249
|
+
agentOutputFile: outputFile,
|
|
250
|
+
skipEntitlements: true,
|
|
251
|
+
});
|
|
252
|
+
expect(result.success).toBe(false);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
describe('dry run mode', () => {
|
|
256
|
+
it('validates without applying changes', async () => {
|
|
257
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
258
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
259
|
+
format: 'guardrail-v1',
|
|
260
|
+
diff: `--- a/src/file.ts
|
|
261
|
+
+++ b/src/file.ts
|
|
262
|
+
@@ -1,1 +1,2 @@
|
|
263
|
+
const x = 1;
|
|
264
|
+
+const y = 2;`,
|
|
265
|
+
commands: ['npm test'],
|
|
266
|
+
tests: ['test/file.test.ts'],
|
|
267
|
+
notes: 'Added y constant',
|
|
268
|
+
}));
|
|
269
|
+
// Create source file
|
|
270
|
+
await fs.promises.mkdir(path.join(tempDir, 'src'), { recursive: true });
|
|
271
|
+
await fs.promises.writeFile(path.join(tempDir, 'src', 'file.ts'), 'const x = 1;\n');
|
|
272
|
+
const result = await pipeline.run({
|
|
273
|
+
projectPath: tempDir,
|
|
274
|
+
agentOutputFile: outputFile,
|
|
275
|
+
dryRun: true,
|
|
276
|
+
skipEntitlements: true,
|
|
277
|
+
});
|
|
278
|
+
expect(result.success).toBe(true);
|
|
279
|
+
expect(result.stage).toBe('done');
|
|
280
|
+
// File should NOT be modified in dry run
|
|
281
|
+
const content = await fs.promises.readFile(path.join(tempDir, 'src', 'file.ts'), 'utf8');
|
|
282
|
+
expect(content).toBe('const x = 1;\n');
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
describe('progress callbacks', () => {
|
|
286
|
+
it('calls onProgress for each stage', async () => {
|
|
287
|
+
const outputFile = path.join(tempDir, 'output.json');
|
|
288
|
+
await fs.promises.writeFile(outputFile, JSON.stringify({
|
|
289
|
+
format: 'guardrail-v1',
|
|
290
|
+
diff: '',
|
|
291
|
+
commands: [],
|
|
292
|
+
tests: [],
|
|
293
|
+
notes: '',
|
|
294
|
+
}));
|
|
295
|
+
const stages = [];
|
|
296
|
+
await pipeline.run({
|
|
297
|
+
projectPath: tempDir,
|
|
298
|
+
agentOutputFile: outputFile,
|
|
299
|
+
skipEntitlements: true,
|
|
300
|
+
onProgress: (stage) => {
|
|
301
|
+
stages.push(stage);
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
expect(stages).toContain('init');
|
|
305
|
+
expect(stages).toContain('validate');
|
|
306
|
+
expect(stages).toContain('done');
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
describe('validateAgentOutput strictMarkdown option', () => {
|
|
311
|
+
const projectRoot = '/tmp/project';
|
|
312
|
+
it('rejects markdown in strict mode', () => {
|
|
313
|
+
const raw = '```json\n{"format":"guardrail-v1","diff":"","commands":[],"tests":[],"notes":""}\n```';
|
|
314
|
+
const result = (0, format_validator_1.validateAgentOutput)(raw, projectRoot, { strictMarkdown: true });
|
|
315
|
+
expect(result.valid).toBe(false);
|
|
316
|
+
expect(result.wasMarkdownWrapped).toBe(true);
|
|
317
|
+
expect(result.errors[0]).toContain('markdown');
|
|
318
|
+
});
|
|
319
|
+
it('accepts and strips markdown in forgiving mode', () => {
|
|
320
|
+
const raw = '```json\n{"format":"guardrail-v1","diff":"","commands":[],"tests":[],"notes":""}\n```';
|
|
321
|
+
const result = (0, format_validator_1.validateAgentOutput)(raw, projectRoot);
|
|
322
|
+
expect(result.valid).toBe(true);
|
|
323
|
+
expect(result.wasMarkdownWrapped).toBe(true);
|
|
324
|
+
expect(result.warnings.some(w => w.includes('markdown'))).toBe(true);
|
|
325
|
+
});
|
|
326
|
+
it('accepts raw JSON without warnings', () => {
|
|
327
|
+
const raw = '{"format":"guardrail-v1","diff":"","commands":[],"tests":[],"notes":""}';
|
|
328
|
+
const result = (0, format_validator_1.validateAgentOutput)(raw, projectRoot);
|
|
329
|
+
expect(result.valid).toBe(true);
|
|
330
|
+
expect(result.wasMarkdownWrapped).toBe(false);
|
|
331
|
+
expect(result.warnings.filter(w => w.includes('markdown'))).toHaveLength(0);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
describe('formatPipelineResult', () => {
|
|
335
|
+
it('formats successful result', () => {
|
|
336
|
+
const result = {
|
|
337
|
+
success: true,
|
|
338
|
+
stage: 'done',
|
|
339
|
+
duration: 1234,
|
|
340
|
+
filesModified: ['src/file.ts'],
|
|
341
|
+
errors: [],
|
|
342
|
+
warnings: [],
|
|
343
|
+
failureContext: [],
|
|
344
|
+
};
|
|
345
|
+
const output = (0, pipeline_1.formatPipelineResult)(result);
|
|
346
|
+
expect(output).toContain('SUCCESSFUL');
|
|
347
|
+
expect(output).toContain('src/file.ts');
|
|
348
|
+
expect(output).toContain('1234');
|
|
349
|
+
});
|
|
350
|
+
it('formats failed result with top 3 failures', () => {
|
|
351
|
+
const result = {
|
|
352
|
+
success: false,
|
|
353
|
+
stage: 'typecheck',
|
|
354
|
+
duration: 500,
|
|
355
|
+
filesModified: [],
|
|
356
|
+
errors: ['TypeScript error'],
|
|
357
|
+
warnings: [],
|
|
358
|
+
failureContext: [
|
|
359
|
+
'error TS2322: Type mismatch',
|
|
360
|
+
'error TS2345: Argument type',
|
|
361
|
+
'error TS2339: Property does not exist',
|
|
362
|
+
'error TS2304: Cannot find name', // This 4th one should be cut off
|
|
363
|
+
],
|
|
364
|
+
};
|
|
365
|
+
const output = (0, pipeline_1.formatPipelineResult)(result);
|
|
366
|
+
expect(output).toContain('FAILED');
|
|
367
|
+
expect(output).toContain('TS2322');
|
|
368
|
+
expect(output).toContain('TS2345');
|
|
369
|
+
expect(output).toContain('TS2339');
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
describe('formatPipelineResultJson', () => {
|
|
373
|
+
it('outputs valid JSON', () => {
|
|
374
|
+
const result = {
|
|
375
|
+
success: true,
|
|
376
|
+
stage: 'done',
|
|
377
|
+
duration: 100,
|
|
378
|
+
filesModified: ['a.ts'],
|
|
379
|
+
errors: [],
|
|
380
|
+
warnings: ['warn1'],
|
|
381
|
+
failureContext: [],
|
|
382
|
+
};
|
|
383
|
+
const json = (0, pipeline_1.formatPipelineResultJson)(result);
|
|
384
|
+
const parsed = JSON.parse(json);
|
|
385
|
+
expect(parsed.success).toBe(true);
|
|
386
|
+
expect(parsed.filesModified).toEqual(['a.ts']);
|
|
387
|
+
expect(parsed.warnings).toEqual(['warn1']);
|
|
388
|
+
});
|
|
389
|
+
});
|