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.
Files changed (189) hide show
  1. package/dist/__tests__/autopilot.test.d.ts +7 -0
  2. package/dist/__tests__/autopilot.test.d.ts.map +1 -0
  3. package/dist/__tests__/autopilot.test.js +156 -0
  4. package/dist/__tests__/tier-config.test.d.ts +9 -0
  5. package/dist/__tests__/tier-config.test.d.ts.map +1 -0
  6. package/dist/__tests__/tier-config.test.js +230 -0
  7. package/dist/__tests__/utils/hash-inline.test.d.ts +2 -0
  8. package/dist/__tests__/utils/hash-inline.test.d.ts.map +1 -0
  9. package/dist/__tests__/utils/hash-inline.test.js +62 -0
  10. package/dist/__tests__/utils/hash.test.d.ts +3 -0
  11. package/dist/__tests__/utils/hash.test.d.ts.map +1 -0
  12. package/dist/__tests__/utils/hash.test.js +95 -0
  13. package/dist/__tests__/utils/simple.test.d.ts +1 -0
  14. package/dist/__tests__/utils/simple.test.d.ts.map +1 -0
  15. package/dist/__tests__/utils/simple.test.js +10 -0
  16. package/dist/__tests__/utils/utils-simple.test.d.ts +1 -0
  17. package/dist/__tests__/utils/utils-simple.test.d.ts.map +1 -0
  18. package/dist/__tests__/utils/utils-simple.test.js +6 -0
  19. package/dist/__tests__/utils/utils.test.d.ts +15 -0
  20. package/dist/__tests__/utils/utils.test.d.ts.map +1 -0
  21. package/dist/__tests__/utils/utils.test.js +172 -0
  22. package/dist/autopilot/autopilot-runner.d.ts +33 -0
  23. package/dist/autopilot/autopilot-runner.d.ts.map +1 -0
  24. package/dist/autopilot/autopilot-runner.js +479 -0
  25. package/dist/autopilot/index.d.ts +6 -0
  26. package/dist/autopilot/index.d.ts.map +1 -0
  27. package/dist/autopilot/index.js +25 -0
  28. package/dist/autopilot/types.d.ts +102 -0
  29. package/dist/autopilot/types.d.ts.map +1 -0
  30. package/dist/autopilot/types.js +18 -0
  31. package/dist/cache/index.d.ts +7 -0
  32. package/dist/cache/index.d.ts.map +1 -0
  33. package/dist/cache/index.js +22 -0
  34. package/dist/cache/redis-cache.d.ts +145 -0
  35. package/dist/cache/redis-cache.d.ts.map +1 -0
  36. package/dist/cache/redis-cache.js +459 -0
  37. package/dist/ci/github-actions.d.ts +77 -0
  38. package/dist/ci/github-actions.d.ts.map +1 -0
  39. package/dist/ci/github-actions.js +277 -0
  40. package/dist/ci/index.d.ts +12 -0
  41. package/dist/ci/index.d.ts.map +1 -0
  42. package/dist/ci/index.js +27 -0
  43. package/dist/ci/pre-commit.d.ts +65 -0
  44. package/dist/ci/pre-commit.d.ts.map +1 -0
  45. package/dist/ci/pre-commit.js +286 -0
  46. package/dist/entitlements.d.ts +149 -0
  47. package/dist/entitlements.d.ts.map +1 -0
  48. package/dist/entitlements.js +464 -0
  49. package/dist/env.d.ts +113 -0
  50. package/dist/env.d.ts.map +1 -0
  51. package/dist/env.js +204 -0
  52. package/dist/fix-packs/__tests__/generate-fix-packs.test.d.ts +7 -0
  53. package/dist/fix-packs/__tests__/generate-fix-packs.test.d.ts.map +1 -0
  54. package/dist/fix-packs/__tests__/generate-fix-packs.test.js +250 -0
  55. package/dist/fix-packs/generate-fix-packs.d.ts +15 -0
  56. package/dist/fix-packs/generate-fix-packs.d.ts.map +1 -0
  57. package/dist/fix-packs/generate-fix-packs.js +505 -0
  58. package/dist/fix-packs/index.d.ts +8 -0
  59. package/dist/fix-packs/index.d.ts.map +1 -0
  60. package/dist/fix-packs/index.js +23 -0
  61. package/dist/fix-packs/types.d.ts +113 -0
  62. package/dist/fix-packs/types.d.ts.map +1 -0
  63. package/dist/fix-packs/types.js +71 -0
  64. package/dist/index.d.ts +13 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +28 -0
  67. package/dist/metrics/prometheus.d.ts +99 -0
  68. package/dist/metrics/prometheus.d.ts.map +1 -0
  69. package/dist/metrics/prometheus.js +306 -0
  70. package/dist/quota-ledger.d.ts +119 -0
  71. package/dist/quota-ledger.d.ts.map +1 -0
  72. package/dist/quota-ledger.js +462 -0
  73. package/dist/rbac/__tests__/permissions.test.d.ts +8 -0
  74. package/dist/rbac/__tests__/permissions.test.d.ts.map +1 -0
  75. package/dist/rbac/__tests__/permissions.test.js +350 -0
  76. package/dist/rbac/index.d.ts +9 -0
  77. package/dist/rbac/index.d.ts.map +1 -0
  78. package/dist/rbac/index.js +32 -0
  79. package/dist/rbac/permissions.d.ts +71 -0
  80. package/dist/rbac/permissions.d.ts.map +1 -0
  81. package/dist/rbac/permissions.js +247 -0
  82. package/dist/rbac/types.d.ts +69 -0
  83. package/dist/rbac/types.d.ts.map +1 -0
  84. package/dist/rbac/types.js +213 -0
  85. package/dist/tier-config.d.ts +203 -0
  86. package/dist/tier-config.d.ts.map +1 -0
  87. package/dist/tier-config.js +675 -0
  88. package/dist/types.d.ts +365 -0
  89. package/dist/types.d.ts.map +1 -0
  90. package/dist/types.js +5 -0
  91. package/dist/utils.d.ts +36 -0
  92. package/dist/utils.d.ts.map +1 -0
  93. package/dist/utils.js +127 -0
  94. package/dist/verified-autofix/__tests__/format-validator.test.d.ts +11 -0
  95. package/dist/verified-autofix/__tests__/format-validator.test.d.ts.map +1 -0
  96. package/dist/verified-autofix/__tests__/format-validator.test.js +285 -0
  97. package/dist/verified-autofix/__tests__/pipeline.test.d.ts +11 -0
  98. package/dist/verified-autofix/__tests__/pipeline.test.d.ts.map +1 -0
  99. package/dist/verified-autofix/__tests__/pipeline.test.js +389 -0
  100. package/dist/verified-autofix/__tests__/repo-fingerprint.test.d.ts +11 -0
  101. package/dist/verified-autofix/__tests__/repo-fingerprint.test.d.ts.map +1 -0
  102. package/dist/verified-autofix/__tests__/repo-fingerprint.test.js +236 -0
  103. package/dist/verified-autofix/__tests__/workspace.test.d.ts +11 -0
  104. package/dist/verified-autofix/__tests__/workspace.test.d.ts.map +1 -0
  105. package/dist/verified-autofix/__tests__/workspace.test.js +314 -0
  106. package/dist/verified-autofix/format-validator.d.ts +101 -0
  107. package/dist/verified-autofix/format-validator.d.ts.map +1 -0
  108. package/dist/verified-autofix/format-validator.js +446 -0
  109. package/dist/verified-autofix/index.d.ts +14 -0
  110. package/dist/verified-autofix/index.d.ts.map +1 -0
  111. package/dist/verified-autofix/index.js +39 -0
  112. package/dist/verified-autofix/pipeline.d.ts +68 -0
  113. package/dist/verified-autofix/pipeline.d.ts.map +1 -0
  114. package/dist/verified-autofix/pipeline.js +330 -0
  115. package/dist/verified-autofix/repo-fingerprint.d.ts +56 -0
  116. package/dist/verified-autofix/repo-fingerprint.d.ts.map +1 -0
  117. package/dist/verified-autofix/repo-fingerprint.js +396 -0
  118. package/dist/verified-autofix/workspace.d.ts +83 -0
  119. package/dist/verified-autofix/workspace.d.ts.map +1 -0
  120. package/dist/verified-autofix/workspace.js +454 -0
  121. package/dist/verified-autofix.d.ts +182 -0
  122. package/dist/verified-autofix.d.ts.map +1 -0
  123. package/dist/verified-autofix.js +1021 -0
  124. package/dist/visualization/dependency-graph.d.ts +79 -0
  125. package/dist/visualization/dependency-graph.d.ts.map +1 -0
  126. package/dist/visualization/dependency-graph.js +399 -0
  127. package/dist/visualization/index.d.ts +5 -0
  128. package/dist/visualization/index.d.ts.map +1 -0
  129. package/dist/visualization/index.js +20 -0
  130. package/package.json +29 -0
  131. package/src/__tests__/autopilot.test.ts +196 -0
  132. package/src/__tests__/tier-config.test.ts +289 -0
  133. package/src/__tests__/utils/hash-inline.test.ts +76 -0
  134. package/src/__tests__/utils/hash.test.ts +119 -0
  135. package/src/__tests__/utils/simple.test.ts +10 -0
  136. package/src/__tests__/utils/utils-simple.test.ts +5 -0
  137. package/src/__tests__/utils/utils.test.ts +203 -0
  138. package/src/autopilot/autopilot-runner.ts +503 -0
  139. package/src/autopilot/index.ts +6 -0
  140. package/src/autopilot/types.ts +119 -0
  141. package/src/cache/index.ts +7 -0
  142. package/src/cache/redis-cache.d.ts +155 -0
  143. package/src/cache/redis-cache.d.ts.map +1 -0
  144. package/src/cache/redis-cache.ts +517 -0
  145. package/src/ci/github-actions.ts +335 -0
  146. package/src/ci/index.ts +12 -0
  147. package/src/ci/pre-commit.ts +338 -0
  148. package/src/db/usage-schema.prisma +114 -0
  149. package/src/entitlements.ts +570 -0
  150. package/src/env.d.ts +68 -0
  151. package/src/env.d.ts.map +1 -0
  152. package/src/env.ts +247 -0
  153. package/src/fix-packs/__tests__/generate-fix-packs.test.ts +317 -0
  154. package/src/fix-packs/generate-fix-packs.ts +577 -0
  155. package/src/fix-packs/index.ts +8 -0
  156. package/src/fix-packs/types.ts +206 -0
  157. package/src/index.d.ts +7 -0
  158. package/src/index.d.ts.map +1 -0
  159. package/src/index.ts +12 -0
  160. package/src/metrics/prometheus.d.ts +104 -0
  161. package/src/metrics/prometheus.d.ts.map +1 -0
  162. package/src/metrics/prometheus.ts +446 -0
  163. package/src/quota-ledger.ts +548 -0
  164. package/src/rbac/__tests__/permissions.test.ts +446 -0
  165. package/src/rbac/index.ts +46 -0
  166. package/src/rbac/permissions.ts +301 -0
  167. package/src/rbac/types.ts +298 -0
  168. package/src/tier-config.json +157 -0
  169. package/src/tier-config.ts +815 -0
  170. package/src/types.d.ts +365 -0
  171. package/src/types.d.ts.map +1 -0
  172. package/src/types.ts +441 -0
  173. package/src/utils.d.ts +36 -0
  174. package/src/utils.d.ts.map +1 -0
  175. package/src/utils.ts +140 -0
  176. package/src/verified-autofix/__tests__/format-validator.test.ts +335 -0
  177. package/src/verified-autofix/__tests__/pipeline.test.ts +419 -0
  178. package/src/verified-autofix/__tests__/repo-fingerprint.test.ts +241 -0
  179. package/src/verified-autofix/__tests__/workspace.test.ts +373 -0
  180. package/src/verified-autofix/format-validator.ts +517 -0
  181. package/src/verified-autofix/index.ts +63 -0
  182. package/src/verified-autofix/pipeline.ts +403 -0
  183. package/src/verified-autofix/repo-fingerprint.ts +459 -0
  184. package/src/verified-autofix/workspace.ts +531 -0
  185. package/src/verified-autofix.ts +1187 -0
  186. package/src/visualization/dependency-graph.d.ts +85 -0
  187. package/src/visualization/dependency-graph.d.ts.map +1 -0
  188. package/src/visualization/dependency-graph.ts +495 -0
  189. package/src/visualization/index.ts +5 -0
@@ -0,0 +1,335 @@
1
+ /**
2
+ * GitHub Actions Integration
3
+ *
4
+ * Provides integration with GitHub Actions for automated security scanning
5
+ */
6
+
7
+ export interface GitHubActionsConfig {
8
+ workflowName: string;
9
+ triggers: {
10
+ push?: { branches: string[] };
11
+ pullRequest?: { branches: string[] };
12
+ schedule?: { cron: string }[];
13
+ workflowDispatch?: boolean;
14
+ };
15
+ scanTypes: ('security' | 'secrets' | 'vulnerabilities' | 'compliance' | 'sbom')[];
16
+ failOnCritical: boolean;
17
+ failOnHigh: boolean;
18
+ uploadArtifacts: boolean;
19
+ createPRComments: boolean;
20
+ }
21
+
22
+ export interface WorkflowStep {
23
+ name: string;
24
+ uses?: string;
25
+ run?: string;
26
+ with?: Record<string, string | boolean | number>;
27
+ env?: Record<string, string>;
28
+ if?: string;
29
+ }
30
+
31
+ export interface WorkflowJob {
32
+ name: string;
33
+ runsOn: string;
34
+ permissions?: Record<string, string>;
35
+ steps: WorkflowStep[];
36
+ }
37
+
38
+ export interface GitHubWorkflow {
39
+ name: string;
40
+ on: Record<string, any>;
41
+ permissions?: Record<string, string>;
42
+ jobs: Record<string, WorkflowJob>;
43
+ }
44
+
45
+ export class GitHubActionsGenerator {
46
+ /**
47
+ * Generate a complete GitHub Actions workflow
48
+ */
49
+ generateWorkflow(config: GitHubActionsConfig): string {
50
+ const workflow: GitHubWorkflow = {
51
+ name: config.workflowName,
52
+ on: this.buildTriggers(config.triggers),
53
+ permissions: {
54
+ contents: 'read',
55
+ 'security-events': 'write',
56
+ 'pull-requests': config.createPRComments ? 'write' : 'read',
57
+ },
58
+ jobs: {
59
+ 'Guardrail-scan': this.buildScanJob(config),
60
+ },
61
+ };
62
+
63
+ return this.toYAML(workflow);
64
+ }
65
+
66
+ /**
67
+ * Build workflow triggers
68
+ */
69
+ private buildTriggers(triggers: GitHubActionsConfig['triggers']): Record<string, any> {
70
+ const on: Record<string, any> = {};
71
+
72
+ if (triggers.push) {
73
+ on['push'] = { branches: triggers.push.branches };
74
+ }
75
+
76
+ if (triggers.pullRequest) {
77
+ on['pull_request'] = { branches: triggers.pullRequest.branches };
78
+ }
79
+
80
+ if (triggers.schedule) {
81
+ on['schedule'] = triggers.schedule.map(s => ({ cron: s.cron }));
82
+ }
83
+
84
+ if (triggers.workflowDispatch) {
85
+ on['workflow_dispatch'] = {};
86
+ }
87
+
88
+ return on;
89
+ }
90
+
91
+ /**
92
+ * Build the main scan job
93
+ */
94
+ private buildScanJob(config: GitHubActionsConfig): WorkflowJob {
95
+ const steps: WorkflowStep[] = [
96
+ {
97
+ name: 'Checkout code',
98
+ uses: 'actions/checkout@v4',
99
+ with: { 'fetch-depth': 0 },
100
+ },
101
+ {
102
+ name: 'Setup Node.js',
103
+ uses: 'actions/setup-node@v4',
104
+ with: { 'node-version': '20' },
105
+ },
106
+ {
107
+ name: 'Install dependencies',
108
+ run: 'npm ci',
109
+ },
110
+ ];
111
+
112
+ // Add scan steps based on config
113
+ if (config.scanTypes.includes('secrets')) {
114
+ steps.push({
115
+ name: 'Scan for secrets',
116
+ run: 'npx Guardrail scan:secrets --format sarif --output secrets-results.sarif',
117
+ env: { Guardrail_CI: 'true' },
118
+ });
119
+ }
120
+
121
+ if (config.scanTypes.includes('vulnerabilities')) {
122
+ steps.push({
123
+ name: 'Scan for vulnerabilities',
124
+ run: 'npx Guardrail scan:vulnerabilities --format sarif --output vuln-results.sarif',
125
+ env: { Guardrail_CI: 'true' },
126
+ });
127
+ }
128
+
129
+ if (config.scanTypes.includes('security')) {
130
+ steps.push({
131
+ name: 'Security scan',
132
+ run: 'npx Guardrail scan:security --format sarif --output security-results.sarif',
133
+ env: { Guardrail_CI: 'true' },
134
+ });
135
+ }
136
+
137
+ if (config.scanTypes.includes('compliance')) {
138
+ steps.push({
139
+ name: 'Compliance check',
140
+ run: 'npx Guardrail scan:compliance --format json --output compliance-results.json',
141
+ env: { Guardrail_CI: 'true' },
142
+ });
143
+ }
144
+
145
+ if (config.scanTypes.includes('sbom')) {
146
+ steps.push({
147
+ name: 'Generate SBOM',
148
+ run: 'npx Guardrail sbom:generate --format cyclonedx --output sbom.json',
149
+ env: { Guardrail_CI: 'true' },
150
+ });
151
+ }
152
+
153
+ // Upload SARIF results
154
+ steps.push({
155
+ name: 'Upload SARIF results',
156
+ uses: 'github/codeql-action/upload-sarif@v3',
157
+ with: {
158
+ 'sarif_file': '.',
159
+ 'category': 'Guardrail-security',
160
+ },
161
+ if: 'always()',
162
+ });
163
+
164
+ // Upload artifacts
165
+ if (config.uploadArtifacts) {
166
+ steps.push({
167
+ name: 'Upload scan artifacts',
168
+ uses: 'actions/upload-artifact@v4',
169
+ with: {
170
+ name: 'Guardrail-results',
171
+ path: '*.sarif\n*.json',
172
+ 'retention-days': 30,
173
+ },
174
+ if: 'always()',
175
+ });
176
+ }
177
+
178
+ // Check results and fail if needed
179
+ steps.push({
180
+ name: 'Check scan results',
181
+ run: this.buildCheckScript(config),
182
+ env: {
183
+ FAIL_ON_CRITICAL: String(config.failOnCritical),
184
+ FAIL_ON_HIGH: String(config.failOnHigh),
185
+ },
186
+ });
187
+
188
+ return {
189
+ name: 'Guardrail Security Scan',
190
+ runsOn: 'ubuntu-latest',
191
+ steps,
192
+ };
193
+ }
194
+
195
+ /**
196
+ * Build result check script
197
+ */
198
+ private buildCheckScript(config: GitHubActionsConfig): string {
199
+ return `
200
+ npx Guardrail results:check \\
201
+ --fail-on-critical=${config.failOnCritical} \\
202
+ --fail-on-high=${config.failOnHigh}
203
+ `.trim();
204
+ }
205
+
206
+ /**
207
+ * Convert workflow object to YAML
208
+ */
209
+ private toYAML(workflow: GitHubWorkflow): string {
210
+ const lines: string[] = [];
211
+
212
+ lines.push(`name: ${workflow.name}`);
213
+ lines.push('');
214
+ lines.push('on:');
215
+ lines.push(this.objectToYAML(workflow.on, 2));
216
+ lines.push('');
217
+
218
+ if (workflow.permissions) {
219
+ lines.push('permissions:');
220
+ for (const [key, value] of Object.entries(workflow.permissions)) {
221
+ lines.push(` ${key}: ${value}`);
222
+ }
223
+ lines.push('');
224
+ }
225
+
226
+ lines.push('jobs:');
227
+ for (const [jobId, job] of Object.entries(workflow.jobs)) {
228
+ lines.push(` ${jobId}:`);
229
+ lines.push(` name: ${job.name}`);
230
+ lines.push(` runs-on: ${job.runsOn}`);
231
+ lines.push(' steps:');
232
+
233
+ for (const step of job.steps) {
234
+ lines.push(` - name: ${step.name}`);
235
+ if (step.uses) {
236
+ lines.push(` uses: ${step.uses}`);
237
+ }
238
+ if (step.run) {
239
+ if (step.run.includes('\n')) {
240
+ lines.push(' run: |');
241
+ for (const line of step.run.split('\n')) {
242
+ lines.push(` ${line}`);
243
+ }
244
+ } else {
245
+ lines.push(` run: ${step.run}`);
246
+ }
247
+ }
248
+ if (step.with) {
249
+ lines.push(' with:');
250
+ for (const [key, value] of Object.entries(step.with)) {
251
+ if (typeof value === 'string' && value.includes('\n')) {
252
+ lines.push(` ${key}: |`);
253
+ for (const line of value.split('\n')) {
254
+ lines.push(` ${line}`);
255
+ }
256
+ } else {
257
+ lines.push(` ${key}: ${value}`);
258
+ }
259
+ }
260
+ }
261
+ if (step.env) {
262
+ lines.push(' env:');
263
+ for (const [key, value] of Object.entries(step.env)) {
264
+ lines.push(` ${key}: ${value}`);
265
+ }
266
+ }
267
+ if (step.if) {
268
+ lines.push(` if: ${step.if}`);
269
+ }
270
+ }
271
+ }
272
+
273
+ return lines.join('\n');
274
+ }
275
+
276
+ /**
277
+ * Convert object to YAML with indentation
278
+ */
279
+ private objectToYAML(obj: Record<string, any>, indent: number): string {
280
+ const lines: string[] = [];
281
+ const prefix = ' '.repeat(indent);
282
+
283
+ for (const [key, value] of Object.entries(obj)) {
284
+ if (typeof value === 'object' && !Array.isArray(value)) {
285
+ lines.push(`${prefix}${key}:`);
286
+ lines.push(this.objectToYAML(value, indent + 2));
287
+ } else if (Array.isArray(value)) {
288
+ lines.push(`${prefix}${key}:`);
289
+ for (const item of value) {
290
+ if (typeof item === 'object') {
291
+ const entries = Object.entries(item);
292
+ if (entries.length > 0) {
293
+ const firstEntry = entries[0];
294
+ if (!firstEntry) continue;
295
+ const [firstKey, firstValue] = firstEntry;
296
+ lines.push(`${prefix} - ${firstKey}: ${firstValue}`);
297
+ for (const [k, v] of entries.slice(1)) {
298
+ lines.push(`${prefix} ${k}: ${v}`);
299
+ }
300
+ }
301
+ } else {
302
+ lines.push(`${prefix} - ${item}`);
303
+ }
304
+ }
305
+ } else {
306
+ lines.push(`${prefix}${key}: ${value}`);
307
+ }
308
+ }
309
+
310
+ return lines.join('\n');
311
+ }
312
+
313
+ /**
314
+ * Generate default workflow for quick setup
315
+ */
316
+ generateDefaultWorkflow(): string {
317
+ return this.generateWorkflow({
318
+ workflowName: 'Guardrail Security Scan',
319
+ triggers: {
320
+ push: { branches: ['main', 'master'] },
321
+ pullRequest: { branches: ['main', 'master'] },
322
+ schedule: [{ cron: '0 0 * * 0' }], // Weekly on Sunday
323
+ workflowDispatch: true,
324
+ },
325
+ scanTypes: ['security', 'secrets', 'vulnerabilities', 'sbom'],
326
+ failOnCritical: true,
327
+ failOnHigh: false,
328
+ uploadArtifacts: true,
329
+ createPRComments: true,
330
+ });
331
+ }
332
+ }
333
+
334
+ // Export singleton
335
+ export const githubActionsGenerator = new GitHubActionsGenerator();
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CI/CD Integration Module
3
+ *
4
+ * Provides integrations for:
5
+ * - GitHub Actions
6
+ * - GitLab CI (future)
7
+ * - Jenkins (future)
8
+ * - Azure DevOps (future)
9
+ */
10
+
11
+ export * from './github-actions';
12
+ export * from './pre-commit';
@@ -0,0 +1,338 @@
1
+ /**
2
+ * Pre-commit Hooks Integration
3
+ *
4
+ * Generates pre-commit hook configurations for local validation
5
+ * before commits are pushed to the repository
6
+ */
7
+
8
+ export interface PreCommitConfig {
9
+ scanSecrets: boolean;
10
+ scanVulnerabilities: boolean;
11
+ checkCompliance: boolean;
12
+ validateTypes: boolean;
13
+ runLint: boolean;
14
+ runTests: boolean;
15
+ blockOnCritical: boolean;
16
+ blockOnHigh: boolean;
17
+ maxFileSize: number; // in KB
18
+ excludePatterns: string[];
19
+ }
20
+
21
+ export interface HuskyConfig {
22
+ hooks: {
23
+ 'pre-commit'?: string;
24
+ 'pre-push'?: string;
25
+ 'commit-msg'?: string;
26
+ };
27
+ }
28
+
29
+ export class PreCommitGenerator {
30
+ /**
31
+ * Generate Husky pre-commit configuration
32
+ */
33
+ generateHuskyConfig(config: PreCommitConfig): HuskyConfig {
34
+ const commands: string[] = [];
35
+
36
+ if (config.runLint) {
37
+ commands.push('npx lint-staged');
38
+ }
39
+
40
+ if (config.scanSecrets) {
41
+ commands.push('npx Guardrail scan:secrets --staged --fail-on-detection');
42
+ }
43
+
44
+ if (config.validateTypes) {
45
+ commands.push('npx tsc --noEmit');
46
+ }
47
+
48
+ return {
49
+ hooks: {
50
+ 'pre-commit': commands.join(' && '),
51
+ 'pre-push': this.generatePrePushCommands(config),
52
+ 'commit-msg': 'npx commitlint --edit $1',
53
+ },
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Generate pre-push commands
59
+ */
60
+ private generatePrePushCommands(config: PreCommitConfig): string {
61
+ const commands: string[] = [];
62
+
63
+ if (config.scanVulnerabilities) {
64
+ commands.push('npx Guardrail scan:vulnerabilities');
65
+ }
66
+
67
+ if (config.checkCompliance) {
68
+ commands.push('npx Guardrail scan:compliance');
69
+ }
70
+
71
+ if (config.runTests) {
72
+ commands.push('npm test');
73
+ }
74
+
75
+ return commands.join(' && ');
76
+ }
77
+
78
+ /**
79
+ * Generate .husky/pre-commit script
80
+ */
81
+ generatePreCommitScript(config: PreCommitConfig): string {
82
+ const lines: string[] = [
83
+ '#!/usr/bin/env sh',
84
+ '. "$(dirname -- "$0")/_/husky.sh"',
85
+ '',
86
+ '# Guardrail Pre-commit Hook',
87
+ '# Generated by Guardrail AI',
88
+ '',
89
+ ];
90
+
91
+ if (config.runLint) {
92
+ lines.push('echo "Running lint-staged..."');
93
+ lines.push('npx lint-staged || exit 1');
94
+ lines.push('');
95
+ }
96
+
97
+ if (config.scanSecrets) {
98
+ lines.push('echo "Scanning for secrets..."');
99
+ lines.push('npx Guardrail scan:secrets --staged --fail-on-detection || {');
100
+ lines.push(' echo "ERROR: Secrets detected in staged files!"');
101
+ lines.push(' echo "Please remove secrets before committing."');
102
+ lines.push(' exit 1');
103
+ lines.push('}');
104
+ lines.push('');
105
+ }
106
+
107
+ if (config.validateTypes) {
108
+ lines.push('echo "Checking TypeScript types..."');
109
+ lines.push('npx tsc --noEmit || exit 1');
110
+ lines.push('');
111
+ }
112
+
113
+ if (config.maxFileSize > 0) {
114
+ lines.push(`echo "Checking file sizes (max ${config.maxFileSize}KB)..."`);
115
+ lines.push(`MAX_SIZE=${config.maxFileSize * 1024}`);
116
+ lines.push('for file in $(git diff --cached --name-only); do');
117
+ lines.push(' if [ -f "$file" ]; then');
118
+ lines.push(' size=$(wc -c < "$file")');
119
+ lines.push(' if [ $size -gt $MAX_SIZE ]; then');
120
+ lines.push(' echo "ERROR: $file exceeds maximum file size"');
121
+ lines.push(' exit 1');
122
+ lines.push(' fi');
123
+ lines.push(' fi');
124
+ lines.push('done');
125
+ lines.push('');
126
+ }
127
+
128
+ lines.push('echo "Pre-commit checks passed!"');
129
+
130
+ return lines.join('\n');
131
+ }
132
+
133
+ /**
134
+ * Generate .husky/pre-push script
135
+ */
136
+ generatePrePushScript(config: PreCommitConfig): string {
137
+ const lines: string[] = [
138
+ '#!/usr/bin/env sh',
139
+ '. "$(dirname -- "$0")/_/husky.sh"',
140
+ '',
141
+ '# Guardrail Pre-push Hook',
142
+ '# Generated by Guardrail AI',
143
+ '',
144
+ ];
145
+
146
+ if (config.scanVulnerabilities) {
147
+ lines.push('echo "Scanning for vulnerabilities..."');
148
+ const failCondition = config.blockOnCritical
149
+ ? (config.blockOnHigh ? '--fail-on-high' : '--fail-on-critical')
150
+ : '';
151
+ lines.push(`npx Guardrail scan:vulnerabilities ${failCondition} || {`);
152
+ lines.push(' echo "ERROR: Vulnerabilities detected!"');
153
+ lines.push(' exit 1');
154
+ lines.push('}');
155
+ lines.push('');
156
+ }
157
+
158
+ if (config.checkCompliance) {
159
+ lines.push('echo "Checking compliance..."');
160
+ lines.push('npx Guardrail scan:compliance || {');
161
+ lines.push(' echo "WARNING: Compliance issues detected"');
162
+ lines.push('}');
163
+ lines.push('');
164
+ }
165
+
166
+ if (config.runTests) {
167
+ lines.push('echo "Running tests..."');
168
+ lines.push('npm test || {');
169
+ lines.push(' echo "ERROR: Tests failed!"');
170
+ lines.push(' exit 1');
171
+ lines.push('}');
172
+ lines.push('');
173
+ }
174
+
175
+ lines.push('echo "Pre-push checks passed!"');
176
+
177
+ return lines.join('\n');
178
+ }
179
+
180
+ /**
181
+ * Generate lint-staged configuration
182
+ */
183
+ generateLintStagedConfig(config: PreCommitConfig): Record<string, string[]> {
184
+ const lintStaged: Record<string, string[]> = {};
185
+
186
+ // TypeScript/JavaScript files
187
+ lintStaged['*.{ts,tsx,js,jsx}'] = [
188
+ 'eslint --fix',
189
+ 'prettier --write',
190
+ ];
191
+
192
+ if (config.scanSecrets) {
193
+ lintStaged['*.{ts,tsx,js,jsx}'].push('Guardrail scan:secrets --file');
194
+ }
195
+
196
+ // JSON files
197
+ lintStaged['*.json'] = ['prettier --write'];
198
+
199
+ // Markdown files
200
+ lintStaged['*.md'] = ['prettier --write'];
201
+
202
+ // CSS/SCSS files
203
+ lintStaged['*.{css,scss}'] = ['prettier --write'];
204
+
205
+ return lintStaged;
206
+ }
207
+
208
+ /**
209
+ * Generate package.json scripts for hooks
210
+ */
211
+ generatePackageJsonScripts(): Record<string, string> {
212
+ return {
213
+ 'prepare': 'husky install',
214
+ 'pre-commit': 'lint-staged',
215
+ 'Guardrail:secrets': 'Guardrail scan:secrets',
216
+ 'Guardrail:vulnerabilities': 'Guardrail scan:vulnerabilities',
217
+ 'Guardrail:compliance': 'Guardrail scan:compliance',
218
+ 'Guardrail:full': 'Guardrail scan:all',
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Generate commitlint configuration
224
+ */
225
+ generateCommitlintConfig(): Record<string, any> {
226
+ return {
227
+ extends: ['@commitlint/config-conventional'],
228
+ rules: {
229
+ 'type-enum': [
230
+ 2,
231
+ 'always',
232
+ [
233
+ 'feat',
234
+ 'fix',
235
+ 'docs',
236
+ 'style',
237
+ 'refactor',
238
+ 'perf',
239
+ 'test',
240
+ 'build',
241
+ 'ci',
242
+ 'chore',
243
+ 'revert',
244
+ 'security',
245
+ ],
246
+ ],
247
+ 'subject-case': [2, 'always', 'lower-case'],
248
+ 'subject-max-length': [2, 'always', 72],
249
+ 'body-max-line-length': [2, 'always', 100],
250
+ },
251
+ };
252
+ }
253
+
254
+ /**
255
+ * Generate default configuration
256
+ */
257
+ generateDefaultConfig(): PreCommitConfig {
258
+ return {
259
+ scanSecrets: true,
260
+ scanVulnerabilities: true,
261
+ checkCompliance: false,
262
+ validateTypes: true,
263
+ runLint: true,
264
+ runTests: false,
265
+ blockOnCritical: true,
266
+ blockOnHigh: false,
267
+ maxFileSize: 500, // 500KB
268
+ excludePatterns: [
269
+ 'node_modules/**',
270
+ 'dist/**',
271
+ 'build/**',
272
+ '*.min.js',
273
+ '*.bundle.js',
274
+ ],
275
+ };
276
+ }
277
+
278
+ /**
279
+ * Generate setup instructions
280
+ */
281
+ generateSetupInstructions(): string {
282
+ return `
283
+ # Guardrail Pre-commit Hooks Setup
284
+
285
+ ## Installation
286
+
287
+ 1. Install dependencies:
288
+ \`\`\`bash
289
+ npm install -D husky lint-staged @commitlint/cli @commitlint/config-conventional
290
+ \`\`\`
291
+
292
+ 2. Initialize Husky:
293
+ \`\`\`bash
294
+ npx husky install
295
+ \`\`\`
296
+
297
+ 3. Add prepare script to package.json:
298
+ \`\`\`json
299
+ {
300
+ "scripts": {
301
+ "prepare": "husky install"
302
+ }
303
+ }
304
+ \`\`\`
305
+
306
+ 4. Create pre-commit hook:
307
+ \`\`\`bash
308
+ npx husky add .husky/pre-commit "npx lint-staged"
309
+ \`\`\`
310
+
311
+ 5. Create pre-push hook:
312
+ \`\`\`bash
313
+ npx husky add .husky/pre-push "npx Guardrail scan:vulnerabilities"
314
+ \`\`\`
315
+
316
+ ## Configuration
317
+
318
+ Add lint-staged config to package.json:
319
+ \`\`\`json
320
+ {
321
+ "lint-staged": {
322
+ "*.{ts,tsx,js,jsx}": ["eslint --fix", "prettier --write"]
323
+ }
324
+ }
325
+ \`\`\`
326
+
327
+ ## Usage
328
+
329
+ Hooks will run automatically on:
330
+ - **Pre-commit**: Lint, format, and secret scanning
331
+ - **Pre-push**: Vulnerability and compliance scanning
332
+ - **Commit-msg**: Conventional commit validation
333
+ `.trim();
334
+ }
335
+ }
336
+
337
+ // Export singleton
338
+ export const preCommitGenerator = new PreCommitGenerator();