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.
Files changed (74) hide show
  1. package/dist/__tests__/autopilot-enterprise.test.d.ts +7 -0
  2. package/dist/__tests__/autopilot-enterprise.test.d.ts.map +1 -0
  3. package/dist/__tests__/autopilot-enterprise.test.js +334 -0
  4. package/dist/autopilot/autopilot-runner.d.ts +9 -0
  5. package/dist/autopilot/autopilot-runner.d.ts.map +1 -1
  6. package/dist/autopilot/autopilot-runner.js +182 -1
  7. package/dist/autopilot/types.d.ts +18 -2
  8. package/dist/autopilot/types.d.ts.map +1 -1
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/smells/index.d.ts +59 -0
  13. package/dist/smells/index.d.ts.map +1 -0
  14. package/dist/smells/index.js +251 -0
  15. package/package.json +19 -2
  16. package/src/__tests__/autopilot.test.ts +0 -196
  17. package/src/__tests__/tier-config.test.ts +0 -289
  18. package/src/__tests__/utils/hash-inline.test.ts +0 -76
  19. package/src/__tests__/utils/hash.test.ts +0 -119
  20. package/src/__tests__/utils/simple.test.ts +0 -10
  21. package/src/__tests__/utils/utils-simple.test.ts +0 -5
  22. package/src/__tests__/utils/utils.test.ts +0 -203
  23. package/src/autopilot/autopilot-runner.ts +0 -503
  24. package/src/autopilot/index.ts +0 -6
  25. package/src/autopilot/types.ts +0 -119
  26. package/src/cache/index.ts +0 -7
  27. package/src/cache/redis-cache.d.ts +0 -155
  28. package/src/cache/redis-cache.d.ts.map +0 -1
  29. package/src/cache/redis-cache.ts +0 -517
  30. package/src/ci/github-actions.ts +0 -335
  31. package/src/ci/index.ts +0 -12
  32. package/src/ci/pre-commit.ts +0 -338
  33. package/src/db/usage-schema.prisma +0 -114
  34. package/src/entitlements.ts +0 -570
  35. package/src/env.d.ts +0 -68
  36. package/src/env.d.ts.map +0 -1
  37. package/src/env.ts +0 -247
  38. package/src/fix-packs/__tests__/generate-fix-packs.test.ts +0 -317
  39. package/src/fix-packs/generate-fix-packs.ts +0 -577
  40. package/src/fix-packs/index.ts +0 -8
  41. package/src/fix-packs/types.ts +0 -206
  42. package/src/index.d.ts +0 -7
  43. package/src/index.d.ts.map +0 -1
  44. package/src/index.ts +0 -12
  45. package/src/metrics/prometheus.d.ts +0 -104
  46. package/src/metrics/prometheus.d.ts.map +0 -1
  47. package/src/metrics/prometheus.ts +0 -446
  48. package/src/quota-ledger.ts +0 -548
  49. package/src/rbac/__tests__/permissions.test.ts +0 -446
  50. package/src/rbac/index.ts +0 -46
  51. package/src/rbac/permissions.ts +0 -301
  52. package/src/rbac/types.ts +0 -298
  53. package/src/tier-config.json +0 -157
  54. package/src/tier-config.ts +0 -815
  55. package/src/types.d.ts +0 -365
  56. package/src/types.d.ts.map +0 -1
  57. package/src/types.ts +0 -441
  58. package/src/utils.d.ts +0 -36
  59. package/src/utils.d.ts.map +0 -1
  60. package/src/utils.ts +0 -140
  61. package/src/verified-autofix/__tests__/format-validator.test.ts +0 -335
  62. package/src/verified-autofix/__tests__/pipeline.test.ts +0 -419
  63. package/src/verified-autofix/__tests__/repo-fingerprint.test.ts +0 -241
  64. package/src/verified-autofix/__tests__/workspace.test.ts +0 -373
  65. package/src/verified-autofix/format-validator.ts +0 -517
  66. package/src/verified-autofix/index.ts +0 -63
  67. package/src/verified-autofix/pipeline.ts +0 -403
  68. package/src/verified-autofix/repo-fingerprint.ts +0 -459
  69. package/src/verified-autofix/workspace.ts +0 -531
  70. package/src/verified-autofix.ts +0 -1187
  71. package/src/visualization/dependency-graph.d.ts +0 -85
  72. package/src/visualization/dependency-graph.d.ts.map +0 -1
  73. package/src/visualization/dependency-graph.ts +0 -495
  74. package/src/visualization/index.ts +0 -5
@@ -1,289 +0,0 @@
1
- /**
2
- * Tier Configuration Drift Prevention Tests
3
- *
4
- * These tests ensure that tier definitions remain consistent across
5
- * all parts of the codebase. If a tier is added/removed in one place
6
- * but not others, these tests will fail.
7
- */
8
-
9
- import {
10
- FEATURES,
11
- PURCHASABLE_TIERS,
12
- TIERS,
13
- TIER_CONFIG,
14
- TIER_ORDER,
15
- Tier,
16
- compareTiers,
17
- getMinimumTierForFeature,
18
- getPricingPageTiers,
19
- getRateLimiterTiers,
20
- getTierConfig,
21
- isTierHigher,
22
- isValidTier,
23
- tierHasFeature
24
- } from '../tier-config';
25
-
26
- describe('Tier Configuration', () => {
27
- describe('Tier Enum Consistency', () => {
28
- it('should have exactly 6 tiers', () => {
29
- expect(TIERS).toHaveLength(6);
30
- });
31
-
32
- it('should include all required tiers', () => {
33
- const requiredTiers = ['free', 'starter', 'pro', 'compliance', 'enterprise', 'unlimited'];
34
- for (const tier of requiredTiers) {
35
- expect(TIERS).toContain(tier);
36
- }
37
- });
38
-
39
- it('should have TIER_CONFIG for every tier in TIERS', () => {
40
- for (const tier of TIERS) {
41
- expect(TIER_CONFIG[tier]).toBeDefined();
42
- expect(TIER_CONFIG[tier].id).toBe(tier);
43
- expect(TIER_CONFIG[tier].name).toBeTruthy();
44
- }
45
- });
46
-
47
- it('should have TIER_ORDER match TIERS', () => {
48
- expect(TIER_ORDER).toHaveLength(TIERS.length);
49
- for (const tier of TIERS) {
50
- expect(TIER_ORDER).toContain(tier);
51
- }
52
- });
53
-
54
- it('should have purchasable tiers be a subset of all tiers', () => {
55
- for (const tier of PURCHASABLE_TIERS) {
56
- expect(TIERS).toContain(tier);
57
- }
58
- });
59
-
60
- it('should not include free or unlimited in purchasable tiers', () => {
61
- expect(PURCHASABLE_TIERS).not.toContain('free');
62
- expect(PURCHASABLE_TIERS).not.toContain('unlimited');
63
- });
64
- });
65
-
66
- describe('Tier Configuration Completeness', () => {
67
- it('should have all required fields for each tier', () => {
68
- for (const tier of TIERS) {
69
- const config = TIER_CONFIG[tier];
70
-
71
- // Required fields
72
- expect(config.id).toBe(tier);
73
- expect(typeof config.name).toBe('string');
74
- expect(typeof config.price).toBe('number');
75
- expect(typeof config.annualPrice).toBe('number');
76
- expect(typeof config.description).toBe('string');
77
- expect(Array.isArray(config.features)).toBe(true);
78
-
79
- // Limits
80
- expect(typeof config.limits.scansPerMonth).toBe('number');
81
- expect(typeof config.limits.realityRunsPerMonth).toBe('number');
82
- expect(typeof config.limits.aiAgentRunsPerMonth).toBe('number');
83
- expect(typeof config.limits.projects).toBe('number');
84
- expect(typeof config.limits.teamMembers).toBe('number');
85
- expect(typeof config.limits.complianceFrameworks).toBe('number');
86
-
87
- // Rate limits
88
- expect(typeof config.rateLimit.requestsPerMinute).toBe('number');
89
- expect(typeof config.rateLimit.burstLimit).toBe('number');
90
- expect(typeof config.rateLimit.windowMs).toBe('number');
91
-
92
- // Upsell
93
- expect(typeof config.upsell.message).toBe('string');
94
- expect(TIERS).toContain(config.upsell.nextTier);
95
- }
96
- });
97
-
98
- it('should have features be valid Feature types', () => {
99
- for (const tier of TIERS) {
100
- const config = TIER_CONFIG[tier];
101
- for (const feature of config.features) {
102
- expect(FEATURES).toContain(feature);
103
- }
104
- }
105
- });
106
-
107
- it('should have increasing limits as tiers increase', () => {
108
- const orderedTiers: Tier[] = ['free', 'starter', 'pro', 'compliance', 'enterprise'];
109
-
110
- for (let i = 1; i < orderedTiers.length; i++) {
111
- const prevTierKey = orderedTiers[i - 1]!;
112
- const currTierKey = orderedTiers[i]!;
113
- const prevTier = TIER_CONFIG[prevTierKey];
114
- const currTier = TIER_CONFIG[currTierKey];
115
-
116
- // Scans should increase or stay unlimited
117
- if (prevTier.limits.scansPerMonth !== -1) {
118
- expect(currTier.limits.scansPerMonth).toBeGreaterThanOrEqual(prevTier.limits.scansPerMonth);
119
- }
120
- }
121
- });
122
-
123
- it('should have increasing rate limits as tiers increase', () => {
124
- const orderedTiers: Tier[] = ['free', 'starter', 'pro', 'compliance', 'enterprise'];
125
-
126
- for (let i = 1; i < orderedTiers.length; i++) {
127
- const prevTierKey = orderedTiers[i - 1]!;
128
- const currTierKey = orderedTiers[i]!;
129
- const prevTier = TIER_CONFIG[prevTierKey];
130
- const currTier = TIER_CONFIG[currTierKey];
131
-
132
- expect(currTier.rateLimit.requestsPerMinute).toBeGreaterThanOrEqual(
133
- prevTier.rateLimit.requestsPerMinute
134
- );
135
- }
136
- });
137
- });
138
-
139
- describe('Pricing Consistency', () => {
140
- it('should have free tier at $0', () => {
141
- expect(TIER_CONFIG.free.price).toBe(0);
142
- expect(TIER_CONFIG.free.annualPrice).toBe(0);
143
- });
144
-
145
- it('should have starter at $29/mo', () => {
146
- expect(TIER_CONFIG.starter.price).toBe(29);
147
- });
148
-
149
- it('should have pro at $99/mo', () => {
150
- expect(TIER_CONFIG.pro.price).toBe(99);
151
- });
152
-
153
- it('should have compliance at $199/mo', () => {
154
- expect(TIER_CONFIG.compliance.price).toBe(199);
155
- });
156
-
157
- it('should have annual pricing be exactly 20% off monthly*12', () => {
158
- // IMPORTANT: This test ensures the "Save 20%" marketing claim is accurate.
159
- // If this test fails, either:
160
- // 1. Update annual prices to be exactly 20% off (monthly * 12 * 0.8)
161
- // 2. Update the "Save 20%" copy in the UI to match the actual discount
162
- const EXPECTED_DISCOUNT = 0.20; // 20% off
163
- const TOLERANCE = 0.005; // Allow 0.5% tolerance for rounding
164
-
165
- for (const tier of PURCHASABLE_TIERS) {
166
- const config = TIER_CONFIG[tier];
167
- if (config.price > 0) {
168
- const monthlyTotal = config.price * 12;
169
- const expectedAnnual = monthlyTotal * (1 - EXPECTED_DISCOUNT);
170
- const actualDiscount = (monthlyTotal - config.annualPrice) / monthlyTotal;
171
-
172
- // Assert the discount is within tolerance of 20%
173
- expect(actualDiscount).toBeGreaterThanOrEqual(EXPECTED_DISCOUNT - TOLERANCE);
174
- expect(actualDiscount).toBeLessThanOrEqual(EXPECTED_DISCOUNT + TOLERANCE);
175
-
176
- // Also verify the annual price is close to expected (within $2 for rounding)
177
- expect(config.annualPrice).toBeGreaterThanOrEqual(expectedAnnual - 2);
178
- expect(config.annualPrice).toBeLessThanOrEqual(expectedAnnual + 2);
179
- }
180
- }
181
- });
182
- });
183
-
184
- describe('Helper Functions', () => {
185
- it('isValidTier should validate tier strings', () => {
186
- expect(isValidTier('free')).toBe(true);
187
- expect(isValidTier('starter')).toBe(true);
188
- expect(isValidTier('pro')).toBe(true);
189
- expect(isValidTier('compliance')).toBe(true);
190
- expect(isValidTier('enterprise')).toBe(true);
191
- expect(isValidTier('unlimited')).toBe(true);
192
- expect(isValidTier('invalid')).toBe(false);
193
- expect(isValidTier('team')).toBe(false); // Legacy tier should not be valid
194
- });
195
-
196
- it('getTierConfig should return correct config', () => {
197
- expect(getTierConfig('pro').name).toBe('Pro');
198
- expect(getTierConfig('compliance').name).toBe('Compliance');
199
- });
200
-
201
- it('compareTiers should correctly order tiers', () => {
202
- expect(compareTiers('free', 'pro')).toBeLessThan(0);
203
- expect(compareTiers('pro', 'free')).toBeGreaterThan(0);
204
- expect(compareTiers('pro', 'pro')).toBe(0);
205
- expect(compareTiers('starter', 'compliance')).toBeLessThan(0);
206
- });
207
-
208
- it('isTierHigher should correctly compare tiers', () => {
209
- expect(isTierHigher('pro', 'free')).toBe(true);
210
- expect(isTierHigher('free', 'pro')).toBe(false);
211
- expect(isTierHigher('compliance', 'starter')).toBe(true);
212
- });
213
-
214
- it('getMinimumTierForFeature should find correct tier', () => {
215
- expect(getMinimumTierForFeature('scan')).toBe('free');
216
- expect(getMinimumTierForFeature('reality')).toBe('starter');
217
- expect(getMinimumTierForFeature('ai-agent')).toBe('pro');
218
- expect(getMinimumTierForFeature('compliance:soc2')).toBe('compliance');
219
- });
220
-
221
- it('tierHasFeature should check features correctly', () => {
222
- expect(tierHasFeature('free', 'scan')).toBe(true);
223
- expect(tierHasFeature('free', 'reality')).toBe(false);
224
- expect(tierHasFeature('starter', 'reality')).toBe(true);
225
- expect(tierHasFeature('unlimited', 'compliance:soc2')).toBe(true);
226
- });
227
- });
228
-
229
- describe('Pricing Page Integration', () => {
230
- it('getPricingPageTiers should return 4 tiers for display', () => {
231
- const pricingTiers = getPricingPageTiers();
232
- expect(pricingTiers).toHaveLength(4);
233
- });
234
-
235
- it('getPricingPageTiers should include free, starter, pro, compliance', () => {
236
- const pricingTiers = getPricingPageTiers();
237
- const tierIds = pricingTiers.map(t => t.id);
238
-
239
- expect(tierIds).toContain('free');
240
- expect(tierIds).toContain('starter');
241
- expect(tierIds).toContain('pro');
242
- expect(tierIds).toContain('compliance');
243
- });
244
-
245
- it('getPricingPageTiers should mark pro as popular', () => {
246
- const pricingTiers = getPricingPageTiers();
247
- const proTier = pricingTiers.find(t => t.id === 'pro');
248
-
249
- expect(proTier?.popular).toBe(true);
250
- });
251
-
252
- it('getPricingPageTiers prices should match TIER_CONFIG', () => {
253
- const pricingTiers = getPricingPageTiers();
254
-
255
- for (const tier of pricingTiers) {
256
- const config = TIER_CONFIG[tier.id as Tier];
257
- expect(tier.price).toBe(config.price);
258
- expect(tier.annual).toBe(config.annualPrice);
259
- expect(tier.name).toBe(config.name);
260
- }
261
- });
262
- });
263
-
264
- describe('Rate Limiter Integration', () => {
265
- it('getRateLimiterTiers should return config for all tiers', () => {
266
- const rateLimiterTiers = getRateLimiterTiers();
267
-
268
- for (const tier of TIERS) {
269
- expect(rateLimiterTiers[tier]).toBeDefined();
270
- expect(rateLimiterTiers[tier].name).toBe(TIER_CONFIG[tier].name);
271
- expect(rateLimiterTiers[tier].baseLimit).toBe(TIER_CONFIG[tier].rateLimit.requestsPerMinute);
272
- expect(rateLimiterTiers[tier].burstLimit).toBe(TIER_CONFIG[tier].rateLimit.burstLimit);
273
- expect(rateLimiterTiers[tier].windowMs).toBe(TIER_CONFIG[tier].rateLimit.windowMs);
274
- }
275
- });
276
- });
277
-
278
- describe('No Legacy Tiers', () => {
279
- it('should not have "team" tier (replaced by compliance)', () => {
280
- expect(TIERS).not.toContain('team');
281
- expect(TIER_CONFIG).not.toHaveProperty('team');
282
- });
283
-
284
- it('should not have "basic" tier', () => {
285
- expect(TIERS).not.toContain('basic');
286
- expect(TIER_CONFIG).not.toHaveProperty('basic');
287
- });
288
- });
289
- });
@@ -1,76 +0,0 @@
1
- // @ts-nocheck
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
- const crypto = require('node:crypto');
4
-
5
- // Inline hash function for testing
6
- function calculateHash(content) {
7
- return crypto.createHash('sha256').update(content).digest('hex');
8
- }
9
-
10
- describe('Hash Utils', () => {
11
- describe('calculateHash', () => {
12
- it('should generate consistent hash for same input', () => {
13
- const input = 'test-input';
14
- const hash1 = calculateHash(input);
15
- const hash2 = calculateHash(input);
16
-
17
- expect(hash1).toBe(hash2);
18
- expect(hash1).toMatch(/^[a-f0-9]{64}$/);
19
- });
20
-
21
- it('should generate different hashes for different inputs', () => {
22
- const hash1 = calculateHash('input1');
23
- const hash2 = calculateHash('input2');
24
-
25
- expect(hash1).not.toBe(hash2);
26
- });
27
-
28
- it('should handle empty string', () => {
29
- const hash = calculateHash('');
30
- expect(hash).toMatch(/^[a-f0-9]{64}$/);
31
- });
32
-
33
- it('should handle special characters', () => {
34
- const input = 'test with spaces and symbols !@#$%^&*()';
35
- const hash = calculateHash(input);
36
- expect(hash).toMatch(/^[a-f0-9]{64}$/);
37
- });
38
-
39
- it('should handle unicode characters', () => {
40
- const input = '测试中文 🚀 emoji';
41
- const hash = calculateHash(input);
42
- expect(hash).toMatch(/^[a-f0-9]{64}$/);
43
- });
44
-
45
- it('should handle very long strings', () => {
46
- const input = 'a'.repeat(10000);
47
- const hash = calculateHash(input);
48
- expect(hash).toMatch(/^[a-f0-9]{64}$/);
49
- });
50
- });
51
-
52
- describe('Security Properties', () => {
53
- it('should generate different hashes for similar inputs', () => {
54
- const hash1 = calculateHash('password');
55
- const hash2 = calculateHash('password ');
56
-
57
- expect(hash1).not.toBe(hash2);
58
- });
59
-
60
- it('should be case-sensitive', () => {
61
- const hash1 = calculateHash('Test');
62
- const hash2 = calculateHash('test');
63
-
64
- expect(hash1).not.toBe(hash2);
65
- });
66
-
67
- it('should produce fixed-length hashes', () => {
68
- const inputs = ['a', 'abc', 'a long string with many characters'];
69
- const hashes = inputs.map(calculateHash);
70
-
71
- hashes.forEach(hash => {
72
- expect(hash.length).toBe(64);
73
- });
74
- });
75
- });
76
- });
@@ -1,119 +0,0 @@
1
- // @ts-nocheck
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
- const crypto = require('node:crypto');
4
-
5
- // Hash function for testing
6
- function calculateHash(content) {
7
- return crypto.createHash('sha256').update(content).digest('hex');
8
- }
9
-
10
- // Helper function to verify hash
11
- function verifyHash(input, hash) {
12
- if (!input || !hash) return false;
13
- const calculatedHash = crypto.createHash('sha256').update(input).digest('hex');
14
- return calculatedHash === hash;
15
- }
16
-
17
- describe('Hash Utils', () => {
18
- describe('calculateHash', () => {
19
- it('should generate consistent hash for same input', () => {
20
- const input = 'test-input';
21
- const hash1 = calculateHash(input);
22
- const hash2 = calculateHash(input);
23
-
24
- expect(hash1).toBe(hash2);
25
- expect(hash1).toMatch(/^[a-f0-9]{64}$/);
26
- });
27
-
28
- it('should generate different hashes for different inputs', () => {
29
- const hash1 = calculateHash('input1');
30
- const hash2 = calculateHash('input2');
31
-
32
- expect(hash1).not.toBe(hash2);
33
- });
34
-
35
- it('should handle empty string', () => {
36
- const hash = calculateHash('');
37
- expect(hash).toMatch(/^[a-f0-9]{64}$/);
38
- });
39
-
40
- it('should handle special characters', () => {
41
- const input = 'test with spaces and symbols !@#$%^&*()';
42
- const hash = calculateHash(input);
43
- expect(hash).toMatch(/^[a-f0-9]{64}$/);
44
- });
45
-
46
- it('should handle unicode characters', () => {
47
- const input = '测试中文 🚀 emoji';
48
- const hash = calculateHash(input);
49
- expect(hash).toMatch(/^[a-f0-9]{64}$/);
50
- });
51
-
52
- it('should handle very long strings', () => {
53
- const input = 'a'.repeat(10000);
54
- const hash = calculateHash(input);
55
- expect(hash).toMatch(/^[a-f0-9]{64}$/);
56
- });
57
- });
58
-
59
- describe('verifyHash', () => {
60
- it('should verify correct hash', () => {
61
- const input = 'test-input';
62
- const hash = calculateHash(input);
63
-
64
- expect(verifyHash(input, hash)).toBe(true);
65
- });
66
-
67
- it('should reject incorrect hash', () => {
68
- const input = 'test-input';
69
- const wrongHash = calculateHash('different-input');
70
-
71
- expect(verifyHash(input, wrongHash)).toBe(false);
72
- });
73
-
74
- it('should reject empty hash', () => {
75
- const input = 'test-input';
76
-
77
- expect(verifyHash(input, '')).toBe(false);
78
- });
79
-
80
- it('should reject invalid hash format', () => {
81
- const input = 'test-input';
82
- const invalidHash = 'invalid-hash';
83
-
84
- expect(verifyHash(input, invalidHash)).toBe(false);
85
- });
86
-
87
- it('should handle null/undefined inputs', () => {
88
- const hash = calculateHash('test');
89
-
90
- expect(verifyHash(null, hash)).toBe(false);
91
- expect(verifyHash(undefined, hash)).toBe(false);
92
- });
93
- });
94
-
95
- describe('Security Properties', () => {
96
- it('should generate different hashes for similar inputs', () => {
97
- const hash1 = calculateHash('password');
98
- const hash2 = calculateHash('password ');
99
-
100
- expect(hash1).not.toBe(hash2);
101
- });
102
-
103
- it('should be case-sensitive', () => {
104
- const hash1 = calculateHash('Test');
105
- const hash2 = calculateHash('test');
106
-
107
- expect(hash1).not.toBe(hash2);
108
- });
109
-
110
- it('should produce fixed-length hashes', () => {
111
- const inputs = ['a', 'abc', 'a long string with many characters'];
112
- const hashes = inputs.map(calculateHash);
113
-
114
- hashes.forEach(hash => {
115
- expect(hash.length).toBe(64);
116
- });
117
- });
118
- });
119
- });
@@ -1,10 +0,0 @@
1
- describe('Simple Test', () => {
2
- it('should pass', () => {
3
- expect(1 + 1).toBe(2);
4
- });
5
-
6
- it('should handle async', async () => {
7
- await new Promise(resolve => setTimeout(resolve, 10));
8
- expect(true).toBe(true);
9
- });
10
- });
@@ -1,5 +0,0 @@
1
- describe("Simple Utils Test", () => {
2
- it("should pass", () => {
3
- expect(true).toBe(true);
4
- });
5
- });