@hatem427/code-guard-ci 3.6.1 β 3.6.3
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/README.md +21 -35
- package/config/angular.config.ts +0 -102
- package/dist/config/angular.config.d.ts.map +1 -1
- package/dist/config/angular.config.js +0 -125
- package/dist/config/angular.config.js.map +1 -1
- package/dist/scripts/cli.js +84 -1
- package/dist/scripts/cli.js.map +1 -1
- package/dist/scripts/config-generators/lint-staged-generator.d.ts.map +1 -1
- package/dist/scripts/config-generators/lint-staged-generator.js +8 -2
- package/dist/scripts/config-generators/lint-staged-generator.js.map +1 -1
- package/dist/scripts/install-security-tools.d.ts +14 -0
- package/dist/scripts/install-security-tools.d.ts.map +1 -0
- package/dist/scripts/install-security-tools.js +113 -0
- package/dist/scripts/install-security-tools.js.map +1 -0
- package/dist/scripts/postinstall.js +8 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/precommit-check.js +40 -10
- package/dist/scripts/precommit-check.js.map +1 -1
- package/package.json +3 -2
- package/scripts/cli.ts +84 -1
- package/scripts/config-generators/lint-staged-generator.ts +8 -2
- package/scripts/install-security-tools.ts +128 -0
- package/scripts/postinstall.ts +8 -1
- package/scripts/precommit-check.ts +42 -10
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# π‘οΈ Code Guardian β Complete Documentation
|
|
2
2
|
|
|
3
|
-
> **Version:**
|
|
3
|
+
> **Version:** 3.6.0
|
|
4
4
|
> **Package:** `@hatem427/code-guard-ci`
|
|
5
5
|
> **Author:** Hatem Bassem
|
|
6
6
|
> **License:** MIT
|
|
@@ -309,40 +309,26 @@ Code Guardian is designed so that **each tool handles its own domain** with zero
|
|
|
309
309
|
|
|
310
310
|
## 6. CLI Commands
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
code-guard
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
code
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
npm run lint # ESLint check
|
|
333
|
-
npm run lint:fix # ESLint auto-fix
|
|
334
|
-
npm run format # Prettier format all
|
|
335
|
-
npm run format:check # Prettier check (no write)
|
|
336
|
-
npm run precommit-check # Run Code Guardian rules manually
|
|
337
|
-
npm run validate # Validate structure + naming
|
|
338
|
-
npm run generate-doc # Generate feature documentation
|
|
339
|
-
npm run generate-pr-checklist # Generate PR checklist
|
|
340
|
-
npm run set-bypass-password # Set bypass password
|
|
341
|
-
npm run set-admin-password # Set admin password
|
|
342
|
-
npm run view-bypass-log # View bypass audit log
|
|
343
|
-
npm run delete-bypass-logs # Delete bypass logs (admin only)
|
|
344
|
-
npm run auto-fix # Auto-fix common issues
|
|
345
|
-
```
|
|
312
|
+
> π **Full command reference:** [COMMANDS.md](COMMANDS.md)
|
|
313
|
+
|
|
314
|
+
All commands are run via `npx code-guard <command>`. Quick overview:
|
|
315
|
+
|
|
316
|
+
| Command | Description |
|
|
317
|
+
|---------|-------------|
|
|
318
|
+
| `init` | Full project setup (ESLint, Prettier, Husky, AI configs, β¦) |
|
|
319
|
+
| `check` | Manually run rule checks (same as pre-commit) |
|
|
320
|
+
| `check-vuln` | 3-layer security audit (npm audit + RetireJS + Grype) |
|
|
321
|
+
| `report` | Open last code quality report in editor |
|
|
322
|
+
| `doc` | Generate feature documentation for current branch |
|
|
323
|
+
| `checklist` | Generate PR checklist from active rules |
|
|
324
|
+
| `validate` | Validate folder structure and file naming |
|
|
325
|
+
| `uninstall` | Remove all generated files (uses manifest) |
|
|
326
|
+
| `add-ai <name>` | Add a single AI assistant config |
|
|
327
|
+
| `list-ai` | List all AI integrations and their status |
|
|
328
|
+
| `version` | Print installed version |
|
|
329
|
+
| `help` | Display usage information |
|
|
330
|
+
|
|
331
|
+
See [COMMANDS.md](COMMANDS.md) for flags, examples, and the full npm scripts reference.
|
|
346
332
|
|
|
347
333
|
---
|
|
348
334
|
|
package/config/angular.config.ts
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* - RxJS best practices (async pipe, takeUntilDestroyed, signals)
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import * as fs from 'fs';
|
|
14
13
|
import { registerRules, Rule } from './guidelines.config';
|
|
15
14
|
|
|
16
15
|
const angularRules: Rule[] = [
|
|
@@ -78,107 +77,6 @@ const angularRules: Rule[] = [
|
|
|
78
77
|
category: 'Angular Deprecated APIs',
|
|
79
78
|
},
|
|
80
79
|
|
|
81
|
-
// ββ Template best practices ββββββββββββββββββββββββββββββββββββββββββββ
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
id: 'angular-no-function-in-template',
|
|
85
|
-
label: 'No function calls in templates',
|
|
86
|
-
description:
|
|
87
|
-
'Avoid calling functions in Angular templates β they run on every change detection cycle. Use pipes, computed signals, or memoized getters instead.',
|
|
88
|
-
severity: 'error',
|
|
89
|
-
fileExtensions: ['html'],
|
|
90
|
-
pattern: null,
|
|
91
|
-
customCheck: (file) => {
|
|
92
|
-
const violations: Array<{ line: number | null; message: string }> = [];
|
|
93
|
-
|
|
94
|
-
// ββ 1. Discover signals declared in the companion .ts component file ββββ
|
|
95
|
-
//
|
|
96
|
-
// Angular signals (signal, computed, toSignal, input, output, viewChild,
|
|
97
|
-
// contentChild, model) are read by calling them as functions β e.g.
|
|
98
|
-
// loading() β which looks identical to a regular method call in a template.
|
|
99
|
-
// We resolve the companion TypeScript file and extract every identifier
|
|
100
|
-
// that is assigned to a signal factory so we can whitelist those calls.
|
|
101
|
-
const signalNames = new Set<string>();
|
|
102
|
-
const tsFilePath = file.absolutePath.replace(/\.html$/, '.ts');
|
|
103
|
-
try {
|
|
104
|
-
if (fs.existsSync(tsFilePath)) {
|
|
105
|
-
const tsContent = fs.readFileSync(tsFilePath, 'utf-8');
|
|
106
|
-
// Matches class field assignments like:
|
|
107
|
-
// loading = signal(false)
|
|
108
|
-
// readonly isReady = computed(() => ...)
|
|
109
|
-
// data = toSignal(obs$)
|
|
110
|
-
// name = input('') / name = input.required<string>()
|
|
111
|
-
// clicked = output() / el = viewChild('ref') / val = model(0)
|
|
112
|
-
const signalDeclPattern =
|
|
113
|
-
/\b(\w+)\s*=\s*(?:signal|computed|toSignal|input(?:\.required)?|output(?:Required)?|viewChild(?:Required)?|viewChildren|contentChild(?:Required)?|contentChildren|model)\s*[(<]/g;
|
|
114
|
-
let m: RegExpExecArray | null;
|
|
115
|
-
while ((m = signalDeclPattern.exec(tsContent)) !== null) {
|
|
116
|
-
signalNames.add(m[1]);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
} catch {
|
|
120
|
-
// If the companion file cannot be read, fall back to no signal awareness.
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ββ 2. Helper: returns true when every function call in the expression
|
|
124
|
-
// is either a known signal read or an Angular built-in ($any, $event). ββ
|
|
125
|
-
const ANGULAR_BUILTINS = new Set(['$any', '$event']);
|
|
126
|
-
const allCallsAreSafe = (expression: string): boolean => {
|
|
127
|
-
// Without signal metadata we cannot safely whitelist anything.
|
|
128
|
-
if (signalNames.size === 0) return false;
|
|
129
|
-
const callPattern = /\b(\w+)\s*\(/g;
|
|
130
|
-
let m: RegExpExecArray | null;
|
|
131
|
-
while ((m = callPattern.exec(expression)) !== null) {
|
|
132
|
-
if (!signalNames.has(m[1]) && !ANGULAR_BUILTINS.has(m[1])) {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return true;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// ββ 3. Scan each line ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
140
|
-
const interpolationRegex = /\{\{[^}]*\w+\s*\([^)]*\)[^}]*\}\}/g;
|
|
141
|
-
// Property binding regex β excludes event bindings such as (click), (submit) β¦
|
|
142
|
-
const propertyBindingRegex =
|
|
143
|
-
/\[(?!click|submit|keyup|keydown|change|input|focus|blur)\w+\]\s*=\s*"([^"]*)"/g;
|
|
144
|
-
|
|
145
|
-
for (let i = 0; i < file.lines.length; i++) {
|
|
146
|
-
const line = file.lines[i];
|
|
147
|
-
const trimmed = line.trim();
|
|
148
|
-
|
|
149
|
-
// ββ Interpolation: {{ expr() }} βββββββββββββββββββββββββββββββββββββ
|
|
150
|
-
interpolationRegex.lastIndex = 0;
|
|
151
|
-
if (interpolationRegex.test(line)) {
|
|
152
|
-
// Pipes like {{ value | date }} are always safe.
|
|
153
|
-
if (!trimmed.includes(' | ') && !allCallsAreSafe(trimmed)) {
|
|
154
|
-
violations.push({
|
|
155
|
-
line: i + 1,
|
|
156
|
-
message: `Function call in interpolation: "${trimmed}". Use a pipe or computed signal instead.`,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// ββ Property bindings: [prop]="expr()" ββββββββββββββββββββββββββββββ
|
|
162
|
-
propertyBindingRegex.lastIndex = 0;
|
|
163
|
-
let match: RegExpExecArray | null;
|
|
164
|
-
while ((match = propertyBindingRegex.exec(line)) !== null) {
|
|
165
|
-
const expression = match[1]; // content between the quotes
|
|
166
|
-
if (/\w+\s*\(/.test(expression) && !allCallsAreSafe(expression)) {
|
|
167
|
-
violations.push({
|
|
168
|
-
line: i + 1,
|
|
169
|
-
message: `Function call in property binding: "${trimmed}". Use a signal or computed signal instead.`,
|
|
170
|
-
});
|
|
171
|
-
break; // one violation per line is enough
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return violations;
|
|
177
|
-
},
|
|
178
|
-
applicableTo: ['angular'],
|
|
179
|
-
category: 'Angular Templates',
|
|
180
|
-
},
|
|
181
|
-
|
|
182
80
|
// ββ RxJS best practices ββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
183
81
|
|
|
184
82
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular.config.d.ts","sourceRoot":"","sources":["../../config/angular.config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"angular.config.d.ts","sourceRoot":"","sources":["../../config/angular.config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAiB,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE1D,QAAA,MAAM,YAAY,EAAE,IAAI,EA6QvB,CAAC;AAKF,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -10,42 +10,8 @@
|
|
|
10
10
|
* - Function calls in templates
|
|
11
11
|
* - RxJS best practices (async pipe, takeUntilDestroyed, signals)
|
|
12
12
|
*/
|
|
13
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
-
if (k2 === undefined) k2 = k;
|
|
15
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
-
}
|
|
19
|
-
Object.defineProperty(o, k2, desc);
|
|
20
|
-
}) : (function(o, m, k, k2) {
|
|
21
|
-
if (k2 === undefined) k2 = k;
|
|
22
|
-
o[k2] = m[k];
|
|
23
|
-
}));
|
|
24
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
-
}) : function(o, v) {
|
|
27
|
-
o["default"] = v;
|
|
28
|
-
});
|
|
29
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
-
var ownKeys = function(o) {
|
|
31
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
-
var ar = [];
|
|
33
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
-
return ar;
|
|
35
|
-
};
|
|
36
|
-
return ownKeys(o);
|
|
37
|
-
};
|
|
38
|
-
return function (mod) {
|
|
39
|
-
if (mod && mod.__esModule) return mod;
|
|
40
|
-
var result = {};
|
|
41
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
-
__setModuleDefault(result, mod);
|
|
43
|
-
return result;
|
|
44
|
-
};
|
|
45
|
-
})();
|
|
46
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
14
|
exports.angularRules = void 0;
|
|
48
|
-
const fs = __importStar(require("fs"));
|
|
49
15
|
const guidelines_config_1 = require("./guidelines.config");
|
|
50
16
|
const angularRules = [
|
|
51
17
|
// ββ Lifecycle ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -101,97 +67,6 @@ const angularRules = [
|
|
|
101
67
|
applicableTo: ['angular'],
|
|
102
68
|
category: 'Angular Deprecated APIs',
|
|
103
69
|
},
|
|
104
|
-
// ββ Template best practices ββββββββββββββββββββββββββββββββββββββββββββ
|
|
105
|
-
{
|
|
106
|
-
id: 'angular-no-function-in-template',
|
|
107
|
-
label: 'No function calls in templates',
|
|
108
|
-
description: 'Avoid calling functions in Angular templates β they run on every change detection cycle. Use pipes, computed signals, or memoized getters instead.',
|
|
109
|
-
severity: 'error',
|
|
110
|
-
fileExtensions: ['html'],
|
|
111
|
-
pattern: null,
|
|
112
|
-
customCheck: (file) => {
|
|
113
|
-
const violations = [];
|
|
114
|
-
// ββ 1. Discover signals declared in the companion .ts component file ββββ
|
|
115
|
-
//
|
|
116
|
-
// Angular signals (signal, computed, toSignal, input, output, viewChild,
|
|
117
|
-
// contentChild, model) are read by calling them as functions β e.g.
|
|
118
|
-
// loading() β which looks identical to a regular method call in a template.
|
|
119
|
-
// We resolve the companion TypeScript file and extract every identifier
|
|
120
|
-
// that is assigned to a signal factory so we can whitelist those calls.
|
|
121
|
-
const signalNames = new Set();
|
|
122
|
-
const tsFilePath = file.absolutePath.replace(/\.html$/, '.ts');
|
|
123
|
-
try {
|
|
124
|
-
if (fs.existsSync(tsFilePath)) {
|
|
125
|
-
const tsContent = fs.readFileSync(tsFilePath, 'utf-8');
|
|
126
|
-
// Matches class field assignments like:
|
|
127
|
-
// loading = signal(false)
|
|
128
|
-
// readonly isReady = computed(() => ...)
|
|
129
|
-
// data = toSignal(obs$)
|
|
130
|
-
// name = input('') / name = input.required<string>()
|
|
131
|
-
// clicked = output() / el = viewChild('ref') / val = model(0)
|
|
132
|
-
const signalDeclPattern = /\b(\w+)\s*=\s*(?:signal|computed|toSignal|input(?:\.required)?|output(?:Required)?|viewChild(?:Required)?|viewChildren|contentChild(?:Required)?|contentChildren|model)\s*[(<]/g;
|
|
133
|
-
let m;
|
|
134
|
-
while ((m = signalDeclPattern.exec(tsContent)) !== null) {
|
|
135
|
-
signalNames.add(m[1]);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
// If the companion file cannot be read, fall back to no signal awareness.
|
|
141
|
-
}
|
|
142
|
-
// ββ 2. Helper: returns true when every function call in the expression
|
|
143
|
-
// is either a known signal read or an Angular built-in ($any, $event). ββ
|
|
144
|
-
const ANGULAR_BUILTINS = new Set(['$any', '$event']);
|
|
145
|
-
const allCallsAreSafe = (expression) => {
|
|
146
|
-
// Without signal metadata we cannot safely whitelist anything.
|
|
147
|
-
if (signalNames.size === 0)
|
|
148
|
-
return false;
|
|
149
|
-
const callPattern = /\b(\w+)\s*\(/g;
|
|
150
|
-
let m;
|
|
151
|
-
while ((m = callPattern.exec(expression)) !== null) {
|
|
152
|
-
if (!signalNames.has(m[1]) && !ANGULAR_BUILTINS.has(m[1])) {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return true;
|
|
157
|
-
};
|
|
158
|
-
// ββ 3. Scan each line ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
159
|
-
const interpolationRegex = /\{\{[^}]*\w+\s*\([^)]*\)[^}]*\}\}/g;
|
|
160
|
-
// Property binding regex β excludes event bindings such as (click), (submit) β¦
|
|
161
|
-
const propertyBindingRegex = /\[(?!click|submit|keyup|keydown|change|input|focus|blur)\w+\]\s*=\s*"([^"]*)"/g;
|
|
162
|
-
for (let i = 0; i < file.lines.length; i++) {
|
|
163
|
-
const line = file.lines[i];
|
|
164
|
-
const trimmed = line.trim();
|
|
165
|
-
// ββ Interpolation: {{ expr() }} βββββββββββββββββββββββββββββββββββββ
|
|
166
|
-
interpolationRegex.lastIndex = 0;
|
|
167
|
-
if (interpolationRegex.test(line)) {
|
|
168
|
-
// Pipes like {{ value | date }} are always safe.
|
|
169
|
-
if (!trimmed.includes(' | ') && !allCallsAreSafe(trimmed)) {
|
|
170
|
-
violations.push({
|
|
171
|
-
line: i + 1,
|
|
172
|
-
message: `Function call in interpolation: "${trimmed}". Use a pipe or computed signal instead.`,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// ββ Property bindings: [prop]="expr()" ββββββββββββββββββββββββββββββ
|
|
177
|
-
propertyBindingRegex.lastIndex = 0;
|
|
178
|
-
let match;
|
|
179
|
-
while ((match = propertyBindingRegex.exec(line)) !== null) {
|
|
180
|
-
const expression = match[1]; // content between the quotes
|
|
181
|
-
if (/\w+\s*\(/.test(expression) && !allCallsAreSafe(expression)) {
|
|
182
|
-
violations.push({
|
|
183
|
-
line: i + 1,
|
|
184
|
-
message: `Function call in property binding: "${trimmed}". Use a signal or computed signal instead.`,
|
|
185
|
-
});
|
|
186
|
-
break; // one violation per line is enough
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return violations;
|
|
191
|
-
},
|
|
192
|
-
applicableTo: ['angular'],
|
|
193
|
-
category: 'Angular Templates',
|
|
194
|
-
},
|
|
195
70
|
// ββ RxJS best practices ββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
196
71
|
{
|
|
197
72
|
id: 'angular-use-async-pipe',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular.config.js","sourceRoot":"","sources":["../../config/angular.config.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG
|
|
1
|
+
{"version":3,"file":"angular.config.js","sourceRoot":"","sources":["../../config/angular.config.ts"],"names":[],"mappings":"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"}
|
package/dist/scripts/cli.js
CHANGED
|
@@ -98,7 +98,8 @@ function showHelp() {
|
|
|
98
98
|
${c.bold('Commands:')}
|
|
99
99
|
${c.green('init')} Full automatic setup (zero prompts)
|
|
100
100
|
${c.green('check')} Run pre-commit checks manually
|
|
101
|
-
${c.green('
|
|
101
|
+
${c.green('install-security-tools')} Install Syft + Grype for Layer 3 SBOM scanning (run once)
|
|
102
|
+
${c.green('check-vuln')} Run security scans (npm audit, RetireJS, Grype)
|
|
102
103
|
${c.green('report')} Generate a rich report with fix examples (opens in editor)
|
|
103
104
|
${c.green('doc')} Generate feature documentation
|
|
104
105
|
${c.green('checklist')} Generate PR checklist
|
|
@@ -612,6 +613,13 @@ npx lint-staged
|
|
|
612
613
|
|
|
613
614
|
# Run Code Guardian rules
|
|
614
615
|
npm run precommit-check
|
|
616
|
+
|
|
617
|
+
# Run tests for staged source files (skip JSON/config files)
|
|
618
|
+
STAGED=$(git diff --cached --name-only --diff-filter=d | grep -E '\.(ts|js|html|css|scss)$' | grep -v '\.json$')
|
|
619
|
+
if [ -n "$STAGED" ]; then
|
|
620
|
+
echo "π§ͺ Running test coverage for staged source files..."
|
|
621
|
+
npm run test:coverage
|
|
622
|
+
fi
|
|
615
623
|
# --- code-guardian-hook-end ---
|
|
616
624
|
`;
|
|
617
625
|
if (fs.existsSync(preCommitPath)) {
|
|
@@ -1581,6 +1589,22 @@ async function uninstallCodeGuard() {
|
|
|
1581
1589
|
console.log('');
|
|
1582
1590
|
}
|
|
1583
1591
|
// ββ Vulnerability Check ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1592
|
+
function runInstallSecurityTools() {
|
|
1593
|
+
const scriptPath = path.join(__dirname, 'install-security-tools.js');
|
|
1594
|
+
if (fs.existsSync(scriptPath)) {
|
|
1595
|
+
require(scriptPath);
|
|
1596
|
+
}
|
|
1597
|
+
else {
|
|
1598
|
+
const tsScriptPath = path.join(__dirname, '..', 'scripts', 'install-security-tools.ts');
|
|
1599
|
+
if (fs.existsSync(tsScriptPath)) {
|
|
1600
|
+
(0, child_process_1.execSync)(`npx ts-node ${tsScriptPath}`, { stdio: 'inherit' });
|
|
1601
|
+
}
|
|
1602
|
+
else {
|
|
1603
|
+
console.error(c.red('β Error: Could not find install-security-tools script.'));
|
|
1604
|
+
process.exit(1);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1584
1608
|
function runVulnerabilityCheck() {
|
|
1585
1609
|
showBanner();
|
|
1586
1610
|
console.log(c.bold('π Code Guardian β Vulnerability Scan\n'));
|
|
@@ -1624,42 +1648,101 @@ function runVulnerabilityCheck() {
|
|
|
1624
1648
|
// ββ Main ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1625
1649
|
(async () => {
|
|
1626
1650
|
switch (command) {
|
|
1651
|
+
// Sets up the entire Code Guardian toolchain in one shot:
|
|
1652
|
+
// ESLint, Prettier, TypeScript strict config, lint-staged, CommitLint,
|
|
1653
|
+
// EditorConfig, VS Code settings, Husky pre-commit hook, and AI assistant
|
|
1654
|
+
// config files (Cursor, Copilot, Claude, Gemini, Windsurfβ¦).
|
|
1655
|
+
// Also patches .gitignore so generated files are tracked correctly.
|
|
1656
|
+
// Usage: npx code-guard init [--skip-hooks] [--skip-ai]
|
|
1627
1657
|
case 'init':
|
|
1628
1658
|
initProject();
|
|
1629
1659
|
break;
|
|
1660
|
+
// Manually runs the same rule checks that fire on every git commit.
|
|
1661
|
+
// Useful for checking your work before staging files.
|
|
1662
|
+
// Scans staged files against all shared + framework-specific rules,
|
|
1663
|
+
// then runs ESLint and Prettier in check mode.
|
|
1664
|
+
// Usage: npx code-guard check
|
|
1630
1665
|
case 'check':
|
|
1631
1666
|
runCheck();
|
|
1632
1667
|
break;
|
|
1668
|
+
// Installs Syft + Grype system binaries to enable Layer 3 SBOM scanning.
|
|
1669
|
+
// Auto-detects OS and uses Homebrew (macOS), curl (Linux), or Scoop/Winget (Windows).
|
|
1670
|
+
// Only needs to be run once per machine.
|
|
1671
|
+
// Usage: npx code-guard install-security-tools
|
|
1672
|
+
case 'install-security-tools':
|
|
1673
|
+
runInstallSecurityTools();
|
|
1674
|
+
break;
|
|
1675
|
+
// Runs a 3-layer security audit independently of the pre-commit hook:
|
|
1676
|
+
// Layer 1 β npm audit (known CVEs in your dependencies)
|
|
1677
|
+
// Layer 2 β RetireJS (vulnerable JS libraries)
|
|
1678
|
+
// Layer 3 β Syft + Grype SBOM scan (if installed)
|
|
1679
|
+
// Run this periodically or in CI β not on every commit.
|
|
1680
|
+
// Usage: npx code-guard check-vuln
|
|
1633
1681
|
case 'check-vuln':
|
|
1634
1682
|
runVulnerabilityCheck();
|
|
1635
1683
|
break;
|
|
1684
|
+
// Generates (or re-opens) the last Code Guardian report in VS Code.
|
|
1685
|
+
// The report is a rich Markdown file at .code-guardian/CODE_GUARDIAN_REPORT.md
|
|
1686
|
+
// with violation details, solution examples, and quick-fix hints.
|
|
1687
|
+
// Usage: npx code-guard report
|
|
1636
1688
|
case 'report':
|
|
1637
1689
|
runReport();
|
|
1638
1690
|
break;
|
|
1691
|
+
// Auto-generates a feature documentation file for the current git branch.
|
|
1692
|
+
// Creates docs/features/<branch-name>.md with a structured template.
|
|
1693
|
+
// Encourages documenting every feature branch before merging.
|
|
1694
|
+
// Usage: npx code-guard doc
|
|
1639
1695
|
case 'doc':
|
|
1640
1696
|
generateDoc();
|
|
1641
1697
|
break;
|
|
1698
|
+
// Generates a PR checklist Markdown file based on all active rules.
|
|
1699
|
+
// Lists every rule the reviewer should manually verify.
|
|
1700
|
+
// Useful to paste into pull request descriptions.
|
|
1701
|
+
// Usage: npx code-guard checklist
|
|
1642
1702
|
case 'checklist':
|
|
1643
1703
|
generateChecklist();
|
|
1644
1704
|
break;
|
|
1705
|
+
// Validates the project's folder structure and file naming conventions
|
|
1706
|
+
// against the rules defined in:
|
|
1707
|
+
// .code-guardian/structure-rules.json
|
|
1708
|
+
// .code-guardian/naming-rules.json
|
|
1709
|
+
// Usage: npx code-guard validate
|
|
1645
1710
|
case 'validate':
|
|
1646
1711
|
runValidation();
|
|
1647
1712
|
break;
|
|
1713
|
+
// Removes all files and configurations that Code Guardian created.
|
|
1714
|
+
// Uses the manifest (.code-guardian/manifest.json) to know exactly
|
|
1715
|
+
// what was created vs modified β preserves your original content.
|
|
1716
|
+
// Also restores any backup files (e.g. .eslintrc.backup β .eslintrc).
|
|
1717
|
+
// Usage: npx code-guard uninstall [--yes]
|
|
1648
1718
|
case 'uninstall':
|
|
1649
1719
|
case 'cleanup':
|
|
1650
1720
|
await uninstallCodeGuard();
|
|
1651
1721
|
break;
|
|
1722
|
+
// Generates (or re-generates) an AI assistant config file for a specific tool.
|
|
1723
|
+
// Available assistants: cursor, copilot, claude, gemini, windsurf, junie,
|
|
1724
|
+
// antigravity, aider.
|
|
1725
|
+
// Also patches .gitignore so the generated file is tracked by git.
|
|
1726
|
+
// Usage: npx code-guard add-ai <name>
|
|
1727
|
+
// e.g. npx code-guard add-ai cursor
|
|
1652
1728
|
case 'add-ai':
|
|
1653
1729
|
addAI();
|
|
1654
1730
|
break;
|
|
1731
|
+
// Lists all available AI assistant integrations that Code Guardian can generate,
|
|
1732
|
+
// along with their target file paths and current status (exists / missing).
|
|
1733
|
+
// Usage: npx code-guard list-ai
|
|
1655
1734
|
case 'list-ai':
|
|
1656
1735
|
listAI();
|
|
1657
1736
|
break;
|
|
1737
|
+
// Prints the currently installed version of @hatem427/code-guard-ci.
|
|
1738
|
+
// Usage: npx code-guard version
|
|
1658
1739
|
case 'version':
|
|
1659
1740
|
case '--version':
|
|
1660
1741
|
case '-v':
|
|
1661
1742
|
showVersion();
|
|
1662
1743
|
break;
|
|
1744
|
+
// Displays full usage information: all commands, flags, and examples.
|
|
1745
|
+
// Usage: npx code-guard help
|
|
1663
1746
|
case 'help':
|
|
1664
1747
|
case '--help':
|
|
1665
1748
|
case '-h':
|