ship-safe 6.0.0 → 6.1.1
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 +157 -23
- package/cli/agents/abom-generator.js +225 -0
- package/cli/agents/agent-config-scanner.js +547 -0
- package/cli/agents/html-reporter.js +568 -511
- package/cli/agents/index.js +5 -1
- package/cli/agents/scoring-engine.js +11 -0
- package/cli/bin/ship-safe.js +57 -4
- package/cli/commands/abom.js +73 -0
- package/cli/commands/audit.js +2 -0
- package/cli/commands/ci.js +1 -1
- package/cli/commands/guard.js +99 -0
- package/cli/commands/init.js +58 -0
- package/cli/commands/openclaw.js +378 -0
- package/cli/commands/scan-skill.js +329 -0
- package/cli/commands/scan.js +2 -0
- package/cli/commands/score.js +1 -0
- package/cli/commands/update-intel.js +55 -0
- package/cli/commands/watch.js +120 -0
- package/cli/data/threat-intel.json +85 -0
- package/cli/index.js +2 -0
- package/cli/utils/compliance-map.js +125 -0
- package/cli/utils/output.js +230 -229
- package/cli/utils/threat-intel.js +167 -0
- package/package.json +3 -2
- package/cli/__tests__/agents.test.js +0 -1301
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<img src=".github/assets/logo%20ship%20safe.png" alt="Ship Safe Logo" width="180" />
|
|
3
3
|
</p>
|
|
4
4
|
<p align="center"><strong>AI-powered application security platform for developers.</strong></p>
|
|
5
|
+
<p align="center"><a href="https://shipsafecli.com">shipsafecli.com</a></p>
|
|
5
6
|
|
|
6
7
|
<p align="center">
|
|
7
8
|
<a href="https://www.npmjs.com/package/ship-safe"><img src="https://badge.fury.io/js/ship-safe.svg" alt="npm version" /></a>
|
|
@@ -14,32 +15,47 @@
|
|
|
14
15
|
|
|
15
16
|
---
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
18 security agents. 80+ attack classes. One command.
|
|
18
19
|
|
|
19
|
-
**Ship Safe
|
|
20
|
+
**Ship Safe v6.1.1** is an AI-powered security platform that runs 18 specialized agents in parallel against your codebase, scanning for secrets, injection vulnerabilities, auth bypass, SSRF, supply chain attacks, Supabase RLS misconfigs, Docker/Terraform/Kubernetes misconfigs, CI/CD pipeline poisoning, LLM/agentic AI security, MCP server misuse, RAG poisoning, PII compliance, vibe coding patterns, exception handling, AI agent config security, and more. OWASP 2025 scoring with EPSS exploit probability. LLM-powered deep analysis verifies exploitability of critical findings. Secrets verification probes provider APIs to check if leaked keys are still active. Compliance mapping to SOC 2, ISO 27001, and NIST AI RMF. Built-in threat intelligence feed with offline-first IOC matching. CI integration with GitHub PR comments, threshold gating, and SARIF output.
|
|
21
|
+
|
|
22
|
+
**v6.1.1 highlights:** Supply chain hardening against the [March 2026 Trivy/CanisterWorm attack chain](https://shipsafecli.com/blog/supply-chain-attacks-2026-how-we-hardened-ship-safe). All GitHub Actions SHA-pinned, `postinstall` scripts disabled in CI, OIDC trusted publishing with provenance, CODEOWNERS on critical paths.
|
|
23
|
+
|
|
24
|
+
[Documentation](https://shipsafecli.com/docs) | [Blog](https://shipsafecli.com/blog) | [Pricing](https://shipsafecli.com/pricing)
|
|
20
25
|
|
|
21
26
|
---
|
|
22
27
|
|
|
23
28
|
## Quick Start
|
|
24
29
|
|
|
25
30
|
```bash
|
|
26
|
-
# Full security audit — secrets +
|
|
31
|
+
# Full security audit — secrets + 18 agents + deps + remediation plan
|
|
27
32
|
npx ship-safe audit .
|
|
28
33
|
|
|
29
34
|
# LLM-powered deep analysis (Anthropic, OpenAI, Google, Ollama)
|
|
30
35
|
npx ship-safe audit . --deep
|
|
31
36
|
|
|
32
|
-
# Red team scan only (
|
|
37
|
+
# Red team scan only (18 agents, 80+ attack classes)
|
|
33
38
|
npx ship-safe red-team .
|
|
34
39
|
|
|
40
|
+
# Scan only changed files (fast pre-commit & PR scanning)
|
|
41
|
+
npx ship-safe diff
|
|
42
|
+
npx ship-safe diff --staged
|
|
43
|
+
|
|
44
|
+
# Fun emoji security grade with shareable badge
|
|
45
|
+
npx ship-safe vibe-check .
|
|
46
|
+
|
|
47
|
+
# Compare your score against industry averages
|
|
48
|
+
npx ship-safe benchmark .
|
|
49
|
+
|
|
35
50
|
# Quick secret scan
|
|
36
51
|
npx ship-safe scan .
|
|
37
52
|
|
|
38
53
|
# Security health score (0-100)
|
|
39
54
|
npx ship-safe score .
|
|
40
55
|
|
|
41
|
-
# CI/CD pipeline mode — compact output, exit codes,
|
|
56
|
+
# CI/CD pipeline mode — compact output, exit codes, PR comments
|
|
42
57
|
npx ship-safe ci .
|
|
58
|
+
npx ship-safe ci . --github-pr
|
|
43
59
|
|
|
44
60
|
# Accept current findings, only report regressions
|
|
45
61
|
npx ship-safe baseline .
|
|
@@ -66,11 +82,11 @@ npx ship-safe audit .
|
|
|
66
82
|
|
|
67
83
|
```
|
|
68
84
|
════════════════════════════════════════════════════════════
|
|
69
|
-
Ship Safe
|
|
85
|
+
Ship Safe v6.0 — Full Security Audit
|
|
70
86
|
════════════════════════════════════════════════════════════
|
|
71
87
|
|
|
72
88
|
[Phase 1/4] Scanning for secrets... ✔ 49 found
|
|
73
|
-
[Phase 2/4] Running
|
|
89
|
+
[Phase 2/4] Running 18 security agents... ✔ 103 findings
|
|
74
90
|
[Phase 3/4] Auditing dependencies... ✔ 44 CVEs
|
|
75
91
|
[Phase 4/4] Computing security score... ✔ 25/100 F
|
|
76
92
|
|
|
@@ -97,14 +113,15 @@ npx ship-safe audit .
|
|
|
97
113
|
|
|
98
114
|
**What it runs:**
|
|
99
115
|
1. **Secret scan** — 50+ patterns with entropy scoring (API keys, passwords, tokens)
|
|
100
|
-
2. **
|
|
101
|
-
3. **Dependency audit** — npm/pip/bundler CVE scanning
|
|
116
|
+
2. **18 security agents** — run in parallel with per-agent timeouts and framework-aware filtering (injection, auth, SSRF, supply chain, config, Supabase RLS, LLM, MCP, agentic AI, RAG, PII, vibe coding, exception handling, agent config, mobile, git history, CI/CD, API)
|
|
117
|
+
3. **Dependency audit** — npm/pip/bundler CVE scanning with EPSS exploit probability scores
|
|
102
118
|
4. **Secrets verification** — probes provider APIs (GitHub, Stripe, OpenAI, etc.) to check if leaked keys are still active
|
|
103
119
|
5. **Deep analysis** — LLM-powered taint analysis verifies exploitability of critical/high findings (optional)
|
|
104
|
-
6. **Score computation** —
|
|
120
|
+
6. **Score computation** — OWASP 2025 weighted scoring across 8 categories (0-100, A-F)
|
|
105
121
|
7. **Context-aware confidence tuning** — downgrades findings in test files, docs, and comments
|
|
106
|
-
8. **
|
|
107
|
-
9. **
|
|
122
|
+
8. **Compliance mapping** — maps findings to SOC 2 Type II, ISO 27001:2022, and NIST AI Risk Management Framework controls
|
|
123
|
+
9. **Remediation plan** — prioritized fix list grouped by severity
|
|
124
|
+
10. **Interactive HTML report** — standalone dark-themed report with severity filtering, search, collapsible findings, compliance summary, and click-to-copy ignore annotations
|
|
108
125
|
|
|
109
126
|
**Flags:**
|
|
110
127
|
- `--json` — structured JSON output (clean for piping)
|
|
@@ -127,21 +144,24 @@ npx ship-safe audit .
|
|
|
127
144
|
|
|
128
145
|
---
|
|
129
146
|
|
|
130
|
-
##
|
|
147
|
+
## 18 Security Agents
|
|
131
148
|
|
|
132
149
|
| Agent | Category | What It Detects |
|
|
133
150
|
|-------|----------|-----------------|
|
|
134
151
|
| **InjectionTester** | Code Vulns | SQL/NoSQL injection, command injection, code injection (eval), XSS, path traversal, XXE, ReDoS, prototype pollution, Python f-string SQL injection, Python subprocess shell injection |
|
|
135
152
|
| **AuthBypassAgent** | Auth | JWT vulnerabilities (alg:none, weak secrets), cookie security, CSRF, OAuth misconfig, BOLA/IDOR, weak crypto, timing attacks, TLS bypass, Django `DEBUG = True`, Flask hardcoded secret keys |
|
|
136
153
|
| **SSRFProber** | SSRF | User input in fetch/axios, cloud metadata endpoints, internal IPs, redirect following |
|
|
137
|
-
| **SupplyChainAudit** | Supply Chain | Typosquatting (Levenshtein distance), git/URL dependencies, wildcard versions, suspicious install scripts, dependency confusion,
|
|
154
|
+
| **SupplyChainAudit** | Supply Chain | Typosquatting (Levenshtein distance), git/URL dependencies, wildcard versions, suspicious install scripts, dependency confusion, lockfile integrity |
|
|
138
155
|
| **ConfigAuditor** | Config | Dockerfile (running as root, :latest tags), Terraform (public S3/RDS, open SG, CloudFront HTTP, Lambda admin, S3 no versioning), Kubernetes (privileged containers, `:latest` tags, missing NetworkPolicy), CORS, CSP, Firebase, Nginx |
|
|
139
156
|
| **SupabaseRLSAgent** | Auth | Supabase Row Level Security — `service_role` key in client code, `CREATE TABLE` without RLS, anon key inserts, unprotected storage operations |
|
|
140
157
|
| **LLMRedTeam** | AI/LLM | OWASP LLM Top 10 — prompt injection, excessive agency, system prompt leakage, unbounded consumption, RAG poisoning |
|
|
141
|
-
| **MCPSecurityAgent** | AI/LLM | MCP server security — unvalidated tool inputs, missing auth, excessive permissions, tool poisoning |
|
|
158
|
+
| **MCPSecurityAgent** | AI/LLM | MCP server security — unvalidated tool inputs, missing auth, excessive permissions, tool poisoning, typosquatting detection, over-permissioned tools, shadow config discovery |
|
|
142
159
|
| **AgenticSecurityAgent** | AI/LLM | OWASP Agentic AI Top 10 — agent hijacking, privilege escalation, unsafe code execution, memory poisoning |
|
|
143
160
|
| **RAGSecurityAgent** | AI/LLM | RAG pipeline security — unvalidated embeddings, context injection, document poisoning, vector DB access control |
|
|
144
161
|
| **PIIComplianceAgent** | Compliance | PII detection — SSNs, credit cards, emails, phone numbers in source code, logs, and configs |
|
|
162
|
+
| **VibeCodingAgent** | Code Vulns | AI-generated code patterns — no input validation, empty catch blocks, hardcoded secrets, disabled security features, TODO-auth patterns |
|
|
163
|
+
| **ExceptionHandlerAgent** | Code Vulns | OWASP A10:2025 — empty catch blocks, unhandled promise rejections, missing React error boundaries, leaked stack traces, generic catch-all without rethrow |
|
|
164
|
+
| **AgentConfigScanner** | AI/LLM | AI agent config security — prompt injection in .cursorrules/CLAUDE.md/AGENTS.md/.windsurfrules, malicious Claude Code hooks (CVE-2026), OpenClaw public binding & malicious skills, encoded/obfuscated payloads, data exfiltration instructions, agent memory poisoning |
|
|
145
165
|
| **MobileScanner** | Mobile | OWASP Mobile Top 10 2024 — insecure storage, WebView JS injection, HTTP endpoints, excessive permissions, debug mode |
|
|
146
166
|
| **GitHistoryScanner** | Secrets | Leaked secrets in git commit history (checks if still active in working tree) |
|
|
147
167
|
| **CICDScanner** | CI/CD | OWASP CI/CD Top 10 — pipeline poisoning, unpinned actions, secret logging, self-hosted runners, script injection |
|
|
@@ -160,7 +180,7 @@ npx ship-safe audit .
|
|
|
160
180
|
# Full audit with remediation plan + HTML report
|
|
161
181
|
npx ship-safe audit .
|
|
162
182
|
|
|
163
|
-
# Red team:
|
|
183
|
+
# Red team: 18 agents, 80+ attack classes
|
|
164
184
|
npx ship-safe red-team .
|
|
165
185
|
npx ship-safe red-team . --agents injection,auth # Run specific agents
|
|
166
186
|
npx ship-safe red-team . --html report.html # HTML report
|
|
@@ -209,6 +229,28 @@ npx ship-safe baseline --diff
|
|
|
209
229
|
npx ship-safe baseline --clear
|
|
210
230
|
```
|
|
211
231
|
|
|
232
|
+
### Diff Scanning
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Scan only changed files (fast pre-commit & PR scanning)
|
|
236
|
+
npx ship-safe diff # All uncommitted changes
|
|
237
|
+
npx ship-safe diff --staged # Only staged changes
|
|
238
|
+
npx ship-safe diff HEAD~3 # Changes in last 3 commits
|
|
239
|
+
npx ship-safe diff --json # JSON output
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Vibe Check & Benchmark
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# Fun emoji security grade
|
|
246
|
+
npx ship-safe vibe-check .
|
|
247
|
+
npx ship-safe vibe-check . --badge # Generate shields.io README badge
|
|
248
|
+
|
|
249
|
+
# Compare your score against industry averages (OWASP, Synopsys, Snyk)
|
|
250
|
+
npx ship-safe benchmark .
|
|
251
|
+
npx ship-safe benchmark . --json # JSON output
|
|
252
|
+
```
|
|
253
|
+
|
|
212
254
|
### CI/CD Pipeline
|
|
213
255
|
|
|
214
256
|
```bash
|
|
@@ -217,6 +259,7 @@ npx ship-safe ci .
|
|
|
217
259
|
npx ship-safe ci . --threshold 80 # Custom passing score
|
|
218
260
|
npx ship-safe ci . --fail-on critical # Fail on severity
|
|
219
261
|
npx ship-safe ci . --sarif out.sarif # SARIF for GitHub
|
|
262
|
+
npx ship-safe ci . --github-pr # Post results as PR comment
|
|
220
263
|
```
|
|
221
264
|
|
|
222
265
|
### Deep Analysis & Verification
|
|
@@ -238,6 +281,52 @@ npx ship-safe audit . --verify
|
|
|
238
281
|
npx ship-safe doctor
|
|
239
282
|
```
|
|
240
283
|
|
|
284
|
+
### OpenClaw Security
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
# Focused OpenClaw security scan
|
|
288
|
+
npx ship-safe openclaw .
|
|
289
|
+
|
|
290
|
+
# Auto-harden OpenClaw configs (0.0.0.0→127.0.0.1, add auth, ws→wss)
|
|
291
|
+
npx ship-safe openclaw . --fix
|
|
292
|
+
|
|
293
|
+
# Red team: simulate ClawJacked, prompt injection, data exfil attacks
|
|
294
|
+
npx ship-safe openclaw . --red-team
|
|
295
|
+
|
|
296
|
+
# CI preflight — exit non-zero on critical findings
|
|
297
|
+
npx ship-safe openclaw . --preflight
|
|
298
|
+
|
|
299
|
+
# Scan a skill before installing it
|
|
300
|
+
npx ship-safe scan-skill https://clawhub.io/skills/some-skill
|
|
301
|
+
npx ship-safe scan-skill ./local-skill.json
|
|
302
|
+
npx ship-safe scan-skill --all # Scan all skills from openclaw.json
|
|
303
|
+
|
|
304
|
+
# Generate hardened OpenClaw config
|
|
305
|
+
npx ship-safe init --openclaw
|
|
306
|
+
|
|
307
|
+
# Generate Agent Bill of Materials (CycloneDX 1.5)
|
|
308
|
+
npx ship-safe abom .
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Threat Intelligence
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
# Update threat intel feed (ClawHavoc IOCs, malicious skills, config signatures)
|
|
315
|
+
npx ship-safe update-intel
|
|
316
|
+
|
|
317
|
+
# Ships with offline-first seed data — no internet required for scanning
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Defensive Hooks
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# Install Claude Code defensive hooks (blocks curl|bash, exfil domains, rm -rf /)
|
|
324
|
+
npx ship-safe guard --generate-hooks
|
|
325
|
+
|
|
326
|
+
# Watch agent config files for drift (.cursorrules, CLAUDE.md, openclaw.json)
|
|
327
|
+
npx ship-safe watch . --configs
|
|
328
|
+
```
|
|
329
|
+
|
|
241
330
|
### Infrastructure Commands
|
|
242
331
|
|
|
243
332
|
```bash
|
|
@@ -275,7 +364,7 @@ claude plugin add github:asamassekou10/ship-safe
|
|
|
275
364
|
|
|
276
365
|
| Command | Description |
|
|
277
366
|
|---------|-------------|
|
|
278
|
-
| `/ship-safe` | Full security audit —
|
|
367
|
+
| `/ship-safe` | Full security audit — 18 agents, remediation plan, auto-fix |
|
|
279
368
|
| `/ship-safe-scan` | Quick scan for leaked secrets |
|
|
280
369
|
| `/ship-safe-score` | Security health score (0-100) |
|
|
281
370
|
| `/ship-safe-deep` | LLM-powered deep taint analysis |
|
|
@@ -344,12 +433,14 @@ Starts at 100. Each finding deducts points by severity and category, weighted by
|
|
|
344
433
|
|----------|--------|----------|------|--------|-----|
|
|
345
434
|
| Secrets | 15% | -25 | -15 | -5 | -15 |
|
|
346
435
|
| Code Vulnerabilities | 15% | -20 | -10 | -3 | -15 |
|
|
347
|
-
| Dependencies |
|
|
436
|
+
| Dependencies | 13% | -20 | -10 | -5 | -13 |
|
|
348
437
|
| Auth & Access Control | 15% | -20 | -10 | -3 | -15 |
|
|
349
|
-
| Configuration |
|
|
350
|
-
| Supply Chain |
|
|
438
|
+
| Configuration | 8% | -15 | -8 | -3 | -8 |
|
|
439
|
+
| Supply Chain | 12% | -15 | -8 | -3 | -12 |
|
|
351
440
|
| API Security | 10% | -15 | -8 | -3 | -10 |
|
|
352
|
-
| AI/LLM Security |
|
|
441
|
+
| AI/LLM Security | 12% | -15 | -8 | -3 | -12 |
|
|
442
|
+
|
|
443
|
+
*Weights aligned with OWASP Top 10 2025 risk rankings.*
|
|
353
444
|
|
|
354
445
|
**Grades:** A (90-100), B (75-89), C (60-74), D (40-59), F (0-39)
|
|
355
446
|
|
|
@@ -411,7 +502,7 @@ jobs:
|
|
|
411
502
|
- uses: actions/checkout@v4
|
|
412
503
|
|
|
413
504
|
- name: Security gate
|
|
414
|
-
run: npx ship-safe ci . --threshold 75 --sarif results.sarif
|
|
505
|
+
run: npx ship-safe ci . --threshold 75 --sarif results.sarif --github-pr
|
|
415
506
|
|
|
416
507
|
- uses: github/codeql-action/upload-sarif@v3
|
|
417
508
|
if: always()
|
|
@@ -470,6 +561,49 @@ Manual security audits: launch-day checklist, framework-specific guides.
|
|
|
470
561
|
|
|
471
562
|
---
|
|
472
563
|
|
|
564
|
+
## Add a Security Badge to Your README
|
|
565
|
+
|
|
566
|
+
Show the world your project is secure. After running `npx ship-safe audit .` or `npx ship-safe vibe-check . --badge`, add one of these to your README:
|
|
567
|
+
|
|
568
|
+
```markdown
|
|
569
|
+
<!-- Replace GRADE and COLOR with your results -->
|
|
570
|
+
[](https://shipsafecli.com)
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
| Grade | Badge |
|
|
574
|
+
|-------|-------|
|
|
575
|
+
| A+ | `[](https://shipsafecli.com)` |
|
|
576
|
+
| A | `[](https://shipsafecli.com)` |
|
|
577
|
+
| B | `[](https://shipsafecli.com)` |
|
|
578
|
+
| C | `[](https://shipsafecli.com)` |
|
|
579
|
+
| D | `[](https://shipsafecli.com)` |
|
|
580
|
+
| F | `[](https://shipsafecli.com)` |
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## Supply Chain Hardening
|
|
585
|
+
|
|
586
|
+
Ship Safe practices what it preaches. Our own supply chain is hardened against the [2026 Trivy/CanisterWorm attack chain](https://shipsafecli.com/blog/supply-chain-attacks-2026-how-we-hardened-ship-safe):
|
|
587
|
+
|
|
588
|
+
| Defense | What It Blocks |
|
|
589
|
+
|---------|---------------|
|
|
590
|
+
| All GitHub Actions pinned to full commit SHAs | Tag repointing (Trivy-style) |
|
|
591
|
+
| `permissions: contents: read` in CI | Excessive token scope |
|
|
592
|
+
| `npm ci --ignore-scripts` in all pipelines | CanisterWorm postinstall propagation |
|
|
593
|
+
| OIDC trusted publishing with provenance | Stolen npm token publishing |
|
|
594
|
+
| CODEOWNERS on `action.yml`, `.github/`, `package.json` | Unauthorized changes to critical paths |
|
|
595
|
+
| Strict `files` allowlist in package.json | Accidental inclusion of secrets/configs |
|
|
596
|
+
| Self-scanning with ship-safe in CI | Malicious code injection |
|
|
597
|
+
| 5 direct dependencies | Minimal transitive attack surface |
|
|
598
|
+
|
|
599
|
+
Verify provenance on any Ship Safe release:
|
|
600
|
+
|
|
601
|
+
```bash
|
|
602
|
+
npm audit signatures
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
473
607
|
## Contributing
|
|
474
608
|
|
|
475
609
|
1. Fork the repo
|
|
@@ -504,4 +638,4 @@ MIT - Use it, share it, secure your stuff.
|
|
|
504
638
|
|
|
505
639
|
---
|
|
506
640
|
|
|
507
|
-
**Ship fast. Ship safe.**
|
|
641
|
+
**Ship fast. Ship safe.** — [shipsafecli.com](https://shipsafecli.com)
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Bill of Materials (ABOM) Generator
|
|
3
|
+
* ==========================================
|
|
4
|
+
*
|
|
5
|
+
* Generates an Agent-focused BOM in CycloneDX 1.5 format.
|
|
6
|
+
* Lists all AI agent components: MCP servers, OpenClaw skills,
|
|
7
|
+
* agent config files, LLM providers.
|
|
8
|
+
*
|
|
9
|
+
* This complements the SBOMGenerator (software dependencies)
|
|
10
|
+
* with agent-specific component inventory for compliance and
|
|
11
|
+
* supply chain visibility.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'fs';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import fg from 'fast-glob';
|
|
17
|
+
|
|
18
|
+
// Agent config files to discover (from AgentConfigScanner)
|
|
19
|
+
const AGENT_CONFIG_FILES = [
|
|
20
|
+
'.cursorrules', '.windsurfrules', 'CLAUDE.md', 'AGENTS.md',
|
|
21
|
+
'.github/copilot-instructions.md', '.aider.conf.yml', '.continue/config.json',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const MCP_CONFIG_FILES = [
|
|
25
|
+
'mcp.json', '.cursor/mcp.json', '.vscode/mcp.json',
|
|
26
|
+
'claude_desktop_config.json', '.claude/settings.json',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const OPENCLAW_FILES = ['openclaw.json', 'openclaw.config.json', 'clawhub.json'];
|
|
30
|
+
|
|
31
|
+
const LLM_ENV_VARS = [
|
|
32
|
+
'OPENAI_API_KEY', 'ANTHROPIC_API_KEY', 'GOOGLE_AI_API_KEY',
|
|
33
|
+
'AZURE_OPENAI_API_KEY', 'OLLAMA_HOST', 'GROQ_API_KEY',
|
|
34
|
+
'MISTRAL_API_KEY', 'COHERE_API_KEY',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
export class ABOMGenerator {
|
|
38
|
+
/**
|
|
39
|
+
* Generate a CycloneDX 1.5 ABOM.
|
|
40
|
+
* @param {string} rootPath — Project root directory
|
|
41
|
+
* @returns {object} — CycloneDX JSON with agent components
|
|
42
|
+
*/
|
|
43
|
+
generate(rootPath) {
|
|
44
|
+
const components = [];
|
|
45
|
+
let componentIndex = 0;
|
|
46
|
+
|
|
47
|
+
// ── MCP Servers ──────────────────────────────────────────────────────────
|
|
48
|
+
for (const rel of MCP_CONFIG_FILES) {
|
|
49
|
+
const full = path.join(rootPath, rel);
|
|
50
|
+
if (!fs.existsSync(full)) continue;
|
|
51
|
+
try {
|
|
52
|
+
const data = JSON.parse(fs.readFileSync(full, 'utf-8'));
|
|
53
|
+
const servers = data.mcpServers || data.servers || {};
|
|
54
|
+
for (const [name, config] of Object.entries(servers)) {
|
|
55
|
+
components.push({
|
|
56
|
+
'bom-ref': `agent-${componentIndex++}`,
|
|
57
|
+
type: 'framework',
|
|
58
|
+
name,
|
|
59
|
+
version: config.version || 'unknown',
|
|
60
|
+
description: `MCP server from ${rel}`,
|
|
61
|
+
purl: config.command ? `pkg:mcp/${encodeURIComponent(name)}` : undefined,
|
|
62
|
+
properties: [
|
|
63
|
+
{ name: 'agent:type', value: 'mcp-server' },
|
|
64
|
+
{ name: 'agent:source', value: rel },
|
|
65
|
+
{ name: 'agent:command', value: config.command || 'N/A' },
|
|
66
|
+
{ name: 'agent:transport', value: config.transport || 'stdio' },
|
|
67
|
+
],
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
} catch { /* skip */ }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ── OpenClaw Skills ──────────────────────────────────────────────────────
|
|
74
|
+
for (const rel of OPENCLAW_FILES) {
|
|
75
|
+
const full = path.join(rootPath, rel);
|
|
76
|
+
if (!fs.existsSync(full)) continue;
|
|
77
|
+
try {
|
|
78
|
+
const data = JSON.parse(fs.readFileSync(full, 'utf-8'));
|
|
79
|
+
const skills = data.skills || [];
|
|
80
|
+
for (const skill of skills) {
|
|
81
|
+
const skillName = typeof skill === 'string' ? skill : skill.name || skill.id || 'unnamed';
|
|
82
|
+
const skillSource = typeof skill === 'object' ? (skill.source || skill.url || 'local') : 'config';
|
|
83
|
+
components.push({
|
|
84
|
+
'bom-ref': `agent-${componentIndex++}`,
|
|
85
|
+
type: 'library',
|
|
86
|
+
name: skillName,
|
|
87
|
+
version: (typeof skill === 'object' ? skill.version : null) || 'unknown',
|
|
88
|
+
description: `OpenClaw skill from ${rel}`,
|
|
89
|
+
purl: `pkg:openclaw/${encodeURIComponent(skillName)}`,
|
|
90
|
+
properties: [
|
|
91
|
+
{ name: 'agent:type', value: 'openclaw-skill' },
|
|
92
|
+
{ name: 'agent:source', value: skillSource },
|
|
93
|
+
{ name: 'agent:verified', value: String(typeof skill === 'object' ? !!skill.verified : false) },
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Record OpenClaw config itself
|
|
99
|
+
components.push({
|
|
100
|
+
'bom-ref': `agent-${componentIndex++}`,
|
|
101
|
+
type: 'data',
|
|
102
|
+
name: `openclaw-config:${rel}`,
|
|
103
|
+
version: data.version || '1.0.0',
|
|
104
|
+
description: `OpenClaw gateway configuration`,
|
|
105
|
+
properties: [
|
|
106
|
+
{ name: 'agent:type', value: 'openclaw-config' },
|
|
107
|
+
{ name: 'agent:host', value: data.host || 'localhost' },
|
|
108
|
+
{ name: 'agent:auth', value: data.auth ? 'enabled' : 'disabled' },
|
|
109
|
+
],
|
|
110
|
+
});
|
|
111
|
+
} catch { /* skip */ }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ── Agent Config Files ───────────────────────────────────────────────────
|
|
115
|
+
for (const rel of AGENT_CONFIG_FILES) {
|
|
116
|
+
const full = path.join(rootPath, rel);
|
|
117
|
+
if (!fs.existsSync(full)) continue;
|
|
118
|
+
try {
|
|
119
|
+
const stat = fs.statSync(full);
|
|
120
|
+
components.push({
|
|
121
|
+
'bom-ref': `agent-${componentIndex++}`,
|
|
122
|
+
type: 'data',
|
|
123
|
+
name: `agent-config:${rel}`,
|
|
124
|
+
version: stat.mtime.toISOString().split('T')[0],
|
|
125
|
+
description: `AI agent instruction file`,
|
|
126
|
+
properties: [
|
|
127
|
+
{ name: 'agent:type', value: 'agent-rules' },
|
|
128
|
+
{ name: 'agent:file', value: rel },
|
|
129
|
+
{ name: 'agent:size', value: String(stat.size) },
|
|
130
|
+
],
|
|
131
|
+
});
|
|
132
|
+
} catch { /* skip */ }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ── Glob-based config files ──────────────────────────────────────────────
|
|
136
|
+
try {
|
|
137
|
+
const globs = ['.cursor/rules/*.mdc', '.openclaw/**/*.json', '.claude/commands/*.md'];
|
|
138
|
+
const found = fg.sync(globs, { cwd: rootPath, absolute: true, dot: true });
|
|
139
|
+
for (const full of found) {
|
|
140
|
+
const rel = path.relative(rootPath, full).replace(/\\/g, '/');
|
|
141
|
+
try {
|
|
142
|
+
const stat = fs.statSync(full);
|
|
143
|
+
components.push({
|
|
144
|
+
'bom-ref': `agent-${componentIndex++}`,
|
|
145
|
+
type: 'data',
|
|
146
|
+
name: `agent-config:${rel}`,
|
|
147
|
+
version: stat.mtime.toISOString().split('T')[0],
|
|
148
|
+
description: `AI agent configuration file`,
|
|
149
|
+
properties: [
|
|
150
|
+
{ name: 'agent:type', value: 'agent-config' },
|
|
151
|
+
{ name: 'agent:file', value: rel },
|
|
152
|
+
],
|
|
153
|
+
});
|
|
154
|
+
} catch { /* skip */ }
|
|
155
|
+
}
|
|
156
|
+
} catch { /* skip */ }
|
|
157
|
+
|
|
158
|
+
// ── LLM Providers ────────────────────────────────────────────────────────
|
|
159
|
+
for (const envVar of LLM_ENV_VARS) {
|
|
160
|
+
if (process.env[envVar]) {
|
|
161
|
+
const provider = envVar.replace(/_API_KEY$/, '').replace(/_HOST$/, '').toLowerCase();
|
|
162
|
+
components.push({
|
|
163
|
+
'bom-ref': `agent-${componentIndex++}`,
|
|
164
|
+
type: 'service',
|
|
165
|
+
name: `llm-provider:${provider}`,
|
|
166
|
+
version: 'detected',
|
|
167
|
+
description: `LLM provider detected via ${envVar} environment variable`,
|
|
168
|
+
properties: [
|
|
169
|
+
{ name: 'agent:type', value: 'llm-provider' },
|
|
170
|
+
{ name: 'agent:env-var', value: envVar },
|
|
171
|
+
{ name: 'agent:key-present', value: 'true' },
|
|
172
|
+
],
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── Build CycloneDX BOM ──────────────────────────────────────────────────
|
|
178
|
+
return {
|
|
179
|
+
bomFormat: 'CycloneDX',
|
|
180
|
+
specVersion: '1.5',
|
|
181
|
+
serialNumber: `urn:uuid:${this._uuid()}`,
|
|
182
|
+
version: 1,
|
|
183
|
+
metadata: {
|
|
184
|
+
timestamp: new Date().toISOString(),
|
|
185
|
+
tools: [{ vendor: 'ship-safe', name: 'ship-safe-abom', version: '6.1.0' }],
|
|
186
|
+
component: this._getProjectMeta(rootPath),
|
|
187
|
+
lifecycles: [{ phase: 'build' }],
|
|
188
|
+
},
|
|
189
|
+
components,
|
|
190
|
+
compositions: [{
|
|
191
|
+
aggregate: 'incomplete',
|
|
192
|
+
assemblies: components.map(c => c['bom-ref']),
|
|
193
|
+
}],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Generate ABOM and write to file.
|
|
199
|
+
*/
|
|
200
|
+
generateToFile(rootPath, outputPath) {
|
|
201
|
+
const bom = this.generate(rootPath);
|
|
202
|
+
fs.writeFileSync(outputPath, JSON.stringify(bom, null, 2));
|
|
203
|
+
return outputPath;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
_getProjectMeta(rootPath) {
|
|
207
|
+
try {
|
|
208
|
+
const pkgPath = path.join(rootPath, 'package.json');
|
|
209
|
+
if (fs.existsSync(pkgPath)) {
|
|
210
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
211
|
+
return { type: 'application', name: pkg.name || path.basename(rootPath), version: pkg.version || '0.0.0' };
|
|
212
|
+
}
|
|
213
|
+
} catch { /* skip */ }
|
|
214
|
+
return { type: 'application', name: path.basename(rootPath), version: '0.0.0' };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
_uuid() {
|
|
218
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
|
|
219
|
+
const r = Math.random() * 16 | 0;
|
|
220
|
+
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export default ABOMGenerator;
|