project-shield 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 (71) hide show
  1. package/README.md +440 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +151 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/integrity/failsafe.d.ts +17 -0
  7. package/dist/integrity/failsafe.d.ts.map +1 -0
  8. package/dist/integrity/failsafe.js +45 -0
  9. package/dist/integrity/failsafe.js.map +1 -0
  10. package/dist/integrity/ruleset.d.ts +12 -0
  11. package/dist/integrity/ruleset.d.ts.map +1 -0
  12. package/dist/integrity/ruleset.js +77 -0
  13. package/dist/integrity/ruleset.js.map +1 -0
  14. package/dist/integrity/seal.d.ts +12 -0
  15. package/dist/integrity/seal.d.ts.map +1 -0
  16. package/dist/integrity/seal.js +77 -0
  17. package/dist/integrity/seal.js.map +1 -0
  18. package/dist/output/badge.d.ts +16 -0
  19. package/dist/output/badge.d.ts.map +1 -0
  20. package/dist/output/badge.js +112 -0
  21. package/dist/output/badge.js.map +1 -0
  22. package/dist/output/evidence.d.ts +18 -0
  23. package/dist/output/evidence.d.ts.map +1 -0
  24. package/dist/output/evidence.js +205 -0
  25. package/dist/output/evidence.js.map +1 -0
  26. package/dist/output/fixit.d.ts +32 -0
  27. package/dist/output/fixit.d.ts.map +1 -0
  28. package/dist/output/fixit.js +387 -0
  29. package/dist/output/fixit.js.map +1 -0
  30. package/dist/output/terminal.d.ts +10 -0
  31. package/dist/output/terminal.d.ts.map +1 -0
  32. package/dist/output/terminal.js +190 -0
  33. package/dist/output/terminal.js.map +1 -0
  34. package/dist/scanner/engine.d.ts +6 -0
  35. package/dist/scanner/engine.d.ts.map +1 -0
  36. package/dist/scanner/engine.js +155 -0
  37. package/dist/scanner/engine.js.map +1 -0
  38. package/dist/scanner/ignore.d.ts +20 -0
  39. package/dist/scanner/ignore.d.ts.map +1 -0
  40. package/dist/scanner/ignore.js +125 -0
  41. package/dist/scanner/ignore.js.map +1 -0
  42. package/dist/scanner/injection.d.ts +15 -0
  43. package/dist/scanner/injection.d.ts.map +1 -0
  44. package/dist/scanner/injection.js +234 -0
  45. package/dist/scanner/injection.js.map +1 -0
  46. package/dist/scanner/mcp.d.ts +6 -0
  47. package/dist/scanner/mcp.d.ts.map +1 -0
  48. package/dist/scanner/mcp.js +322 -0
  49. package/dist/scanner/mcp.js.map +1 -0
  50. package/dist/scanner/pii.d.ts +21 -0
  51. package/dist/scanner/pii.d.ts.map +1 -0
  52. package/dist/scanner/pii.js +161 -0
  53. package/dist/scanner/pii.js.map +1 -0
  54. package/dist/scanner/secrets.d.ts +10 -0
  55. package/dist/scanner/secrets.d.ts.map +1 -0
  56. package/dist/scanner/secrets.js +224 -0
  57. package/dist/scanner/secrets.js.map +1 -0
  58. package/dist/scoring/lock.d.ts +12 -0
  59. package/dist/scoring/lock.d.ts.map +1 -0
  60. package/dist/scoring/lock.js +58 -0
  61. package/dist/scoring/lock.js.map +1 -0
  62. package/dist/scoring/score.d.ts +14 -0
  63. package/dist/scoring/score.d.ts.map +1 -0
  64. package/dist/scoring/score.js +74 -0
  65. package/dist/scoring/score.js.map +1 -0
  66. package/dist/types/index.d.ts +205 -0
  67. package/dist/types/index.d.ts.map +1 -0
  68. package/dist/types/index.js +3 -0
  69. package/dist/types/index.js.map +1 -0
  70. package/package.json +52 -0
  71. package/rules/v1.0.0.json +248 -0
package/README.md ADDED
@@ -0,0 +1,440 @@
1
+ # Project Shield
2
+
3
+ **Security scanner for AI coders and MCP users.**
4
+
5
+ Detects leaked API keys, PII, insecure MCP configs, and prompt injection — in one command.
6
+
7
+ ```bash
8
+ npx project-shield scan ./my-project
9
+ ```
10
+
11
+ ```
12
+ Project Shield v1.0.0
13
+ Ruleset: v1.0.0 (SHA-256: f408a4fd...)
14
+ Scanning: 47 files (3 excluded)
15
+
16
+ ━━━ Secrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+ CRITICAL src/config.ts:12
18
+ AWS Access Key detected (AKIA****)
19
+ Layers: regex ✓ entropy ✓ context ✓
20
+
21
+ ━━━ PII ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
22
+ CONFIRMED data/users.csv:5
23
+ Korean Resident Registration Number detected (900*****)
24
+ Layers: regex ✓ checksum ✓
25
+
26
+ ━━━ MCP Config ━━━━━━━━━━━━━━━━━━━━━━━━━━━
27
+ CRITICAL mcp.json (3/5 failed)
28
+ ✗ Auth: No authentication configured
29
+ ✗ Secrets: Hardcoded API key found
30
+ ✓ Tool Meta: OK
31
+ ✗ Permissions: Root filesystem access
32
+ ✓ Logging: OK
33
+
34
+ ━━━ Injection ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
35
+ CRITICAL prompts/system.txt:3
36
+ Hidden injection in comment (Direct instruction override attempt) [structural]
37
+ Pattern: inj_ignore_prev | Layers: keyword ✓ structure ✓
38
+
39
+ ━━━ Score ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
40
+ Grade: F (0/100) — Locked
41
+ Badge generation LOCKED — Fix all critical findings first.
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Why Project Shield?
47
+
48
+ | Problem | Project Shield |
49
+ |---------|---------------|
50
+ | API key leaked in commit | 3-layer detection (regex + entropy + context) |
51
+ | PII in test data | Korean RRN checksum validation, credit card Luhn check |
52
+ | MCP config wide open | 5-point check (auth, secrets, tools, permissions, logging) |
53
+ | Prompt injection in tool descriptions | 2-layer detection (keyword + structural analysis) |
54
+ | "What do I fix first?" | Fix-it guides with code examples |
55
+ | Compliance evidence needed | PDF + JSON evidence pack |
56
+
57
+ ---
58
+
59
+ ## Install
60
+
61
+ ```bash
62
+ # Global
63
+ npm install -g project-shield
64
+
65
+ # npx (no install)
66
+ npx project-shield scan ./my-project
67
+
68
+ # Dev dependency
69
+ npm install -D project-shield
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Usage
75
+
76
+ ### Basic scan
77
+
78
+ ```bash
79
+ project-shield scan ./my-project
80
+ ```
81
+
82
+ ### JSON output
83
+
84
+ ```bash
85
+ project-shield scan ./my-project --format json
86
+ ```
87
+
88
+ ### Fix-it guides
89
+
90
+ ```bash
91
+ # Free: top 3 guides (summary only)
92
+ project-shield scan ./my-project --fix
93
+
94
+ # Pro: all guides with code examples + references
95
+ project-shield scan ./my-project --fix --pro
96
+ ```
97
+
98
+ ### Evidence pack (JSON + PDF)
99
+
100
+ ```bash
101
+ project-shield scan ./my-project --evidence ./report
102
+ # Creates: report.json + report.pdf
103
+ ```
104
+
105
+ ### Badge generation
106
+
107
+ ```bash
108
+ # Free badge (with watermark)
109
+ project-shield scan ./my-project --badge shield-badge.svg
110
+
111
+ # Pro badge (no watermark)
112
+ project-shield scan ./my-project --badge shield-badge.svg --pro
113
+ ```
114
+
115
+ ### Custom ignore
116
+
117
+ ```bash
118
+ project-shield scan ./my-project --ignore .shieldignore
119
+ ```
120
+
121
+ ### All options
122
+
123
+ ```
124
+ project-shield scan <path>
125
+ -f, --format <format> Output format: terminal | json (default: terminal)
126
+ -i, --ignore <path> Path to .shieldignore file
127
+ -r, --ruleset <path> Path to custom ruleset JSON
128
+ -b, --badge <path> Output path for SVG badge
129
+ --pro Pro mode (no watermark, full fix-it guides)
130
+ --fix Show fix-it remediation guides
131
+ --evidence <path> Output path for evidence pack (JSON + PDF)
132
+ ```
133
+
134
+ ---
135
+
136
+ ## What It Detects
137
+
138
+ ### F001: Secrets (3-layer detection)
139
+
140
+ | Layer | Method | Example |
141
+ |-------|--------|---------|
142
+ | Regex | Pattern matching | `AKIA...`, `sk_live_...`, `ghp_...` |
143
+ | Entropy | Shannon entropy > 4.5 | High-randomness strings in secret context |
144
+ | Context | Variable name analysis | `API_KEY=`, `secret:`, `.env` files |
145
+
146
+ **10 built-in patterns**: AWS, Stripe, OpenAI, GitHub PAT/OAuth, Slack, Google, Private Keys + high-entropy catch-all.
147
+
148
+ **Severity rules**:
149
+ - 2+ layers hit = **critical**
150
+ - 1 layer hit = **warning**
151
+ - Pattern override (e.g., `sk_live_` always critical)
152
+
153
+ ### F002: MCP Config (5-point check)
154
+
155
+ | Check | What | Critical When |
156
+ |-------|------|---------------|
157
+ | Auth | Authentication configured? | No auth field found |
158
+ | Secrets | Hardcoded keys in config? | Literal API key (not `${ENV_VAR}`) |
159
+ | Tool Meta | Dangerous tool keywords? | `exec`, `eval`, `shell`, `rm` in tools |
160
+ | Permissions | Overly broad access? | Root `/`, wildcard `*`, `--privileged` |
161
+ | Logging | Audit logging enabled? | No logging/audit field |
162
+
163
+ ### F003: Prompt Injection (2-layer detection)
164
+
165
+ | Layer | Method | Example |
166
+ |-------|--------|---------|
167
+ | Keyword | 11 patterns (6 direct + 5 indirect) | "ignore previous instructions", "secretly" |
168
+ | Structure | Comment hiding, zero-width chars, tool length | `<!-- inject -->`, `\u200B` |
169
+
170
+ **Cross-judgment**:
171
+ - Keyword + Structure = **critical**
172
+ - Keyword only = **warning**
173
+ - Structure only (with hidden keyword) = **critical**
174
+ - Encoded bypass (Base64/URL) = **automatic critical**
175
+
176
+ ### F004: PII (2-layer detection)
177
+
178
+ | Pattern | Locale | Checksum |
179
+ |---------|--------|----------|
180
+ | Korean RRN (주민등록번호) | KR | Yes |
181
+ | Korean Phone | KR | No |
182
+ | Korean Business Number | KR | Yes |
183
+ | Korean Passport | KR | No |
184
+ | Email | Global | No |
185
+ | US SSN | Global | No |
186
+ | Credit Card | Global | Luhn |
187
+
188
+ ### F005: Scoring (0-100)
189
+
190
+ | Grade | Score | Status |
191
+ |-------|-------|--------|
192
+ | A | 90-100 | Excellent |
193
+ | B | 75-89 | Good |
194
+ | C | 60-74 | Pass |
195
+ | D | 40-59 | Warning |
196
+ | E | 20-39 | Warning |
197
+ | F | 0-19 | Locked |
198
+
199
+ **Any critical finding = automatic F + badge locked.**
200
+
201
+ Deductions: critical -25, warning -10, possible -5, info -2.
202
+
203
+ ---
204
+
205
+ ## Inline Suppression
206
+
207
+ Add `shield-ignore` to suppress a specific line:
208
+
209
+ ```javascript
210
+ const API_KEY = "sk_test_abc123"; // shield-ignore
211
+ ```
212
+
213
+ ```python
214
+ API_KEY = "sk_test_abc123" # shield-ignore
215
+ ```
216
+
217
+ Or use `.shieldignore` (gitignore syntax):
218
+
219
+ ```
220
+ # .shieldignore
221
+ tests/fixtures/
222
+ *.test.ts
223
+ docs/examples/
224
+ ```
225
+
226
+ ---
227
+
228
+ ## Evidence Pack
229
+
230
+ The `--evidence` flag generates a compliance-ready report:
231
+
232
+ **JSON** (`report.json`):
233
+ - Full findings (secrets, PII, MCP, injection)
234
+ - Score + lock status
235
+ - Fix-it summary
236
+ - Integrity hashes (result SHA-256 + ruleset SHA-256)
237
+ - Disclaimer
238
+
239
+ **PDF** (`report.pdf`):
240
+ - Cover page with grade
241
+ - Executive summary
242
+ - Findings detail by category
243
+ - Integrity verification
244
+ - Disclaimer
245
+
246
+ ---
247
+
248
+ ## CI Integration
249
+
250
+ ```yaml
251
+ # GitHub Actions
252
+ - name: Security Scan
253
+ run: npx project-shield scan . --format json
254
+ # Exit code 1 if any critical finding
255
+ ```
256
+
257
+ ```yaml
258
+ # With badge
259
+ - name: Security Scan + Badge
260
+ run: |
261
+ npx project-shield scan . --badge shield-badge.svg
262
+ # Commit badge to repo
263
+ ```
264
+
265
+ ---
266
+
267
+ ## Architecture
268
+
269
+ ```
270
+ src/
271
+ index.ts CLI entry (commander)
272
+ types/index.ts All TypeScript interfaces
273
+ scanner/
274
+ engine.ts Scan orchestrator (glob, binary skip, ignore)
275
+ secrets.ts 3-layer secret detection
276
+ pii.ts 2-layer PII detection
277
+ mcp.ts 5-point MCP config check
278
+ injection.ts 2-layer injection detection
279
+ ignore.ts shield-ignore + .shieldignore
280
+ scoring/
281
+ score.ts 0-100 scoring + A-F grading
282
+ lock.ts Badge lock logic
283
+ integrity/
284
+ ruleset.ts Ruleset loader + SHA-256 verification
285
+ failsafe.ts Crash = fail, no ruleset = reject
286
+ seal.ts Result hash sealing (SHA-256 + UUID)
287
+ output/
288
+ terminal.ts Terminal + JSON formatter
289
+ badge.ts SVG badge generator (shields.io style)
290
+ fixit.ts 10-type fix-it guide system
291
+ evidence.ts Evidence pack (JSON + PDF)
292
+ rules/
293
+ v1.0.0.json Ruleset (secrets + PII + MCP + injection patterns)
294
+ ```
295
+
296
+ ---
297
+
298
+ ## Integrity
299
+
300
+ - Ruleset is SHA-256 verified on every load. Tampered ruleset = scan rejected.
301
+ - Scan results are hash-sealed. Same input = same hash.
302
+ - Fail-safe: crash during scan = `SCAN_FAILED` (never false PASS).
303
+
304
+ ---
305
+
306
+ ## License
307
+
308
+ MIT
309
+
310
+ ---
311
+
312
+ <p align="center">
313
+ <sub>Built for developers who ship AI-powered apps and want to sleep at night.</sub>
314
+ </p>
315
+
316
+ ---
317
+
318
+ # Project Shield (한국어)
319
+
320
+ **AI 코더/MCP 사용자를 위한 보안 스캐너 CLI.**
321
+
322
+ API 키 유출, 개인정보, MCP 설정 보안 취약점, 프롬프트 인젝션을 한 번에 탐지합니다.
323
+
324
+ ```bash
325
+ npx project-shield scan ./my-project
326
+ ```
327
+
328
+ ---
329
+
330
+ ## 왜 Project Shield?
331
+
332
+ | 문제 | Project Shield |
333
+ |------|---------------|
334
+ | 커밋에서 API 키 유출 | 3중 탐지 (정규식 + 엔트로피 + 컨텍스트) |
335
+ | 테스트 데이터에서 개인정보 노출 | 주민등록번호 체크섬 검증, 신용카드 Luhn 검증 |
336
+ | MCP 설정 보안 허점 | 5항목 점검 (인증, 시크릿, 툴, 권한, 로깅) |
337
+ | 툴 설명에 숨겨진 프롬프트 인젝션 | 2중 탐지 (키워드 + 구조 분석) |
338
+ | "뭐부터 고쳐야 하지?" | Fix-it 가이드 (코드 예제 포함) |
339
+ | 컴플라이언스 증빙 필요 | PDF + JSON Evidence Pack |
340
+
341
+ ---
342
+
343
+ ## 설치
344
+
345
+ ```bash
346
+ # 글로벌
347
+ npm install -g project-shield
348
+
349
+ # npx (설치 없이)
350
+ npx project-shield scan ./my-project
351
+ ```
352
+
353
+ ---
354
+
355
+ ## 사용법
356
+
357
+ ### 기본 스캔
358
+
359
+ ```bash
360
+ project-shield scan ./my-project
361
+ ```
362
+
363
+ ### Fix-it 가이드 포함
364
+
365
+ ```bash
366
+ # Free: 상위 3개 (요약만)
367
+ project-shield scan ./my-project --fix
368
+
369
+ # Pro: 전체 가이드 + 코드 예제 + 참조
370
+ project-shield scan ./my-project --fix --pro
371
+ ```
372
+
373
+ ### Evidence Pack (JSON + PDF)
374
+
375
+ ```bash
376
+ project-shield scan ./my-project --evidence ./report
377
+ # 생성: report.json + report.pdf
378
+ ```
379
+
380
+ ### 뱃지 생성
381
+
382
+ ```bash
383
+ project-shield scan ./my-project --badge shield-badge.svg
384
+ ```
385
+
386
+ ---
387
+
388
+ ## 탐지 항목
389
+
390
+ ### F001: 시크릿(Secret) 탐지
391
+
392
+ 3중 탐지: 정규식 매칭 + 섀넌 엔트로피 + 컨텍스트 분석 (변수명, `.env` 파일 등)
393
+
394
+ 10종 패턴: AWS, Stripe, OpenAI, GitHub PAT/OAuth, Slack, Google, Private Key
395
+
396
+ ### F002: MCP 설정 점검
397
+
398
+ 5항목 점검: 인증(auth), 시크릿(secrets), 툴(tools), 권한(permissions), 로깅(logging)
399
+
400
+ ### F003: 프롬프트 인젝션 탐지
401
+
402
+ 2중 탐지: 키워드 매칭 (11종 패턴) + 구조 분석 (HTML 주석, zero-width 유니코드, 툴 설명 길이)
403
+
404
+ Base64/URL 인코딩된 우회 시도 감지 시 **자동 critical**
405
+
406
+ ### F004: PII 탐지
407
+
408
+ 주민등록번호 (체크섬 검증), 전화번호, 사업자등록번호, 여권번호, 이메일, US SSN, 신용카드 (Luhn 검증)
409
+
410
+ ### F005: 스코어
411
+
412
+ 0-100점 방식, A-F 등급. **Critical 발견이 1개라도 있으면 자동 F + 뱃지 잠금.**
413
+
414
+ ### F006: Fix-it 가이드
415
+
416
+ 10종 맞춤형 가이드: AWS 키 로테이션, Stripe 키 로테이션, Private Key 제거, RRN 마스킹, 신용카드 제거, MCP 설정 수정 3종, 프롬프트 인젝션 제거
417
+
418
+ ### F007: Evidence Pack
419
+
420
+ JSON + PDF. 점수, 등급, 발견, 수정 가이드, 무결성 해시, 면책조항 포함.
421
+
422
+ ---
423
+
424
+ ## 라인 무시 (shield-ignore)
425
+
426
+ ```javascript
427
+ const key = "sk_test_abc"; // shield-ignore
428
+ ```
429
+
430
+ `.shieldignore` 파일:
431
+ ```
432
+ tests/fixtures/
433
+ *.test.ts
434
+ ```
435
+
436
+ ---
437
+
438
+ ## 라이선스
439
+
440
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const path = __importStar(require("node:path"));
39
+ const engine_js_1 = require("./scanner/engine.js");
40
+ const ruleset_js_1 = require("./integrity/ruleset.js");
41
+ const score_js_1 = require("./scoring/score.js");
42
+ const lock_js_1 = require("./scoring/lock.js");
43
+ const seal_js_1 = require("./integrity/seal.js");
44
+ const badge_js_1 = require("./output/badge.js");
45
+ const terminal_js_1 = require("./output/terminal.js");
46
+ const fixit_js_1 = require("./output/fixit.js");
47
+ const evidence_js_1 = require("./output/evidence.js");
48
+ const failsafe_js_1 = require("./integrity/failsafe.js");
49
+ const program = new commander_1.Command();
50
+ program
51
+ .name('project-shield')
52
+ .description('Security scanner for AI coders and MCP users')
53
+ .version('1.0.0');
54
+ program
55
+ .command('scan')
56
+ .description('Scan a directory for secrets, PII, and MCP config issues')
57
+ .argument('<path>', 'Path to scan')
58
+ .option('-f, --format <format>', 'Output format (terminal or json)', 'terminal')
59
+ .option('-i, --ignore <path>', 'Path to .shieldignore file')
60
+ .option('-r, --ruleset <path>', 'Path to ruleset JSON file')
61
+ .option('-b, --badge <path>', 'Output path for SVG badge', '')
62
+ .option('--pro', 'Generate Pro badge (no watermark)', false)
63
+ .option('--fix', 'Show fix-it remediation guides', false)
64
+ .option('--evidence <path>', 'Output path for evidence pack (JSON + PDF)')
65
+ .action(async (targetPath, options) => {
66
+ try {
67
+ const resolvedPath = path.resolve(targetPath);
68
+ const format = options.format;
69
+ // Load ruleset info for display
70
+ const ruleset = (0, ruleset_js_1.loadRuleset)(options.ruleset);
71
+ const result = await (0, engine_js_1.scan)({
72
+ targetPath: resolvedPath,
73
+ format,
74
+ ignorePath: options.ignore,
75
+ rulesetPath: options.ruleset,
76
+ });
77
+ // Calculate score and lock status
78
+ const score = (0, score_js_1.calculateScore)(result);
79
+ const lockStatus = (0, lock_js_1.getLockStatus)(score);
80
+ const seal = (0, seal_js_1.sealResult)(result, score, ruleset.version, { isPro: options.pro });
81
+ if (format === 'json') {
82
+ const jsonObj = JSON.parse((0, terminal_js_1.formatJsonOutput)(result, score, seal));
83
+ if (options.fix) {
84
+ const guides = (0, fixit_js_1.getFixitGuides)(result, { isPro: options.pro });
85
+ jsonObj.fixit = (0, fixit_js_1.formatFixitJson)(guides, options.pro);
86
+ }
87
+ console.log(JSON.stringify(jsonObj, null, 2));
88
+ }
89
+ else {
90
+ console.log((0, terminal_js_1.formatTerminalOutput)(result, ruleset.version, ruleset.sha256, score, lockStatus));
91
+ if (options.fix) {
92
+ const guides = (0, fixit_js_1.getFixitGuides)(result, { isPro: options.pro });
93
+ console.log((0, fixit_js_1.formatFixitTerminal)(guides, options.pro));
94
+ }
95
+ }
96
+ // Evidence Pack generation
97
+ if (options.evidence) {
98
+ const evidencePath = path.resolve(options.evidence);
99
+ const pack = (0, evidence_js_1.generateEvidenceJSON)(result, score, lockStatus, seal, {
100
+ scanTarget: resolvedPath,
101
+ rulesetHash: ruleset.sha256,
102
+ rulesetVersion: ruleset.version,
103
+ });
104
+ (0, evidence_js_1.saveEvidenceJSON)(pack, `${evidencePath}.json`);
105
+ console.log(`Evidence JSON saved to: ${evidencePath}.json`);
106
+ await (0, evidence_js_1.generateEvidencePDF)(pack, `${evidencePath}.pdf`);
107
+ console.log(`Evidence PDF saved to: ${evidencePath}.pdf`);
108
+ }
109
+ // Badge generation
110
+ if (options.badge) {
111
+ try {
112
+ const svg = (0, badge_js_1.generateBadge)(score, lockStatus, { isPro: options.pro });
113
+ const badgePath = path.resolve(options.badge);
114
+ (0, badge_js_1.saveBadge)(svg, badgePath);
115
+ console.log(`Badge saved to: ${badgePath}`);
116
+ }
117
+ catch (error) {
118
+ if (error instanceof badge_js_1.BadgeLockedError) {
119
+ console.error(`Error: ${error.message}`);
120
+ }
121
+ else {
122
+ throw error;
123
+ }
124
+ }
125
+ }
126
+ // Exit with code 1 if critical findings
127
+ const hasCritical = result.summary.critical > 0 ||
128
+ result.summary.confirmedPii > 0 ||
129
+ result.summary.mcpCritical > 0 ||
130
+ result.summary.injectionCritical > 0;
131
+ process.exit(hasCritical ? 1 : 0);
132
+ }
133
+ catch (error) {
134
+ if (error instanceof failsafe_js_1.RulesetNotFoundError) {
135
+ console.error(`Error: ${error.message}`);
136
+ process.exit(1);
137
+ }
138
+ if (error instanceof failsafe_js_1.RulesetIntegrityError) {
139
+ console.error(`Error: ${error.message}`);
140
+ process.exit(1);
141
+ }
142
+ if (error instanceof failsafe_js_1.ScanFailedError) {
143
+ console.error(`Error: ${error.message}`);
144
+ process.exit(1);
145
+ }
146
+ console.error('SCAN_FAILED:', error instanceof Error ? error.message : String(error));
147
+ process.exit(1);
148
+ }
149
+ });
150
+ program.parse();
151
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ScanResult } from '../types/index.js';
2
+ export declare class ScanFailedError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare class RulesetNotFoundError extends Error {
6
+ constructor(path: string);
7
+ }
8
+ export declare class RulesetIntegrityError extends Error {
9
+ constructor();
10
+ }
11
+ /**
12
+ * Wraps a scan operation with fail-safe logic.
13
+ * - On crash → ScanFailedError (never returns PASS)
14
+ * - Empty result → never claims "safe"
15
+ */
16
+ export declare function withFailsafe(scanFn: () => Promise<ScanResult>): Promise<ScanResult>;
17
+ //# sourceMappingURL=failsafe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failsafe.d.ts","sourceRoot":"","sources":["../../src/integrity/failsafe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,IAAI,EAAE,MAAM;CAIzB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAChC,OAAO,CAAC,UAAU,CAAC,CAcrB"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RulesetIntegrityError = exports.RulesetNotFoundError = exports.ScanFailedError = void 0;
4
+ exports.withFailsafe = withFailsafe;
5
+ class ScanFailedError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = 'ScanFailedError';
9
+ }
10
+ }
11
+ exports.ScanFailedError = ScanFailedError;
12
+ class RulesetNotFoundError extends Error {
13
+ constructor(path) {
14
+ super(`Ruleset not found: ${path}`);
15
+ this.name = 'RulesetNotFoundError';
16
+ }
17
+ }
18
+ exports.RulesetNotFoundError = RulesetNotFoundError;
19
+ class RulesetIntegrityError extends Error {
20
+ constructor() {
21
+ super('Ruleset integrity check failed');
22
+ this.name = 'RulesetIntegrityError';
23
+ }
24
+ }
25
+ exports.RulesetIntegrityError = RulesetIntegrityError;
26
+ /**
27
+ * Wraps a scan operation with fail-safe logic.
28
+ * - On crash → ScanFailedError (never returns PASS)
29
+ * - Empty result → never claims "safe"
30
+ */
31
+ async function withFailsafe(scanFn) {
32
+ try {
33
+ const result = await scanFn();
34
+ return result;
35
+ }
36
+ catch (error) {
37
+ if (error instanceof RulesetNotFoundError ||
38
+ error instanceof RulesetIntegrityError) {
39
+ throw error;
40
+ }
41
+ const message = error instanceof Error ? error.message : String(error);
42
+ throw new ScanFailedError(`SCAN_FAILED: ${message}`);
43
+ }
44
+ }
45
+ //# sourceMappingURL=failsafe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failsafe.js","sourceRoot":"","sources":["../../src/integrity/failsafe.ts"],"names":[],"mappings":";;;AA4BA,oCAgBC;AA1CD,MAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AALD,0CAKC;AAED,MAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,IAAY;QACtB,KAAK,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AALD,oDAKC;AAED,MAAa,qBAAsB,SAAQ,KAAK;IAC9C;QACE,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AALD,sDAKC;AAED;;;;GAIG;AACI,KAAK,UAAU,YAAY,CAChC,MAAiC;IAEjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IACE,KAAK,YAAY,oBAAoB;YACrC,KAAK,YAAY,qBAAqB,EACtC,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,eAAe,CAAC,gBAAgB,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { Ruleset } from '../types/index.js';
2
+ /**
3
+ * Compute SHA-256 hash of the ruleset content (excluding the sha256 field itself).
4
+ */
5
+ export declare function computeRulesetHash(content: string): string;
6
+ /**
7
+ * Load and verify a ruleset file.
8
+ * Throws RulesetNotFoundError if file doesn't exist.
9
+ * Throws RulesetIntegrityError if hash doesn't match.
10
+ */
11
+ export declare function loadRuleset(rulesetPath?: string): Ruleset;
12
+ //# sourceMappingURL=ruleset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ruleset.d.ts","sourceRoot":"","sources":["../../src/integrity/ruleset.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGjD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAwBzD"}