ship-safe 5.0.1 → 6.1.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.
- package/README.md +110 -23
- package/cli/agents/abom-generator.js +225 -0
- package/cli/agents/agent-config-scanner.js +547 -0
- package/cli/agents/agentic-security-agent.js +1 -1
- package/cli/agents/api-fuzzer.js +1 -1
- package/cli/agents/auth-bypass-agent.js +2 -2
- package/cli/agents/config-auditor.js +3 -11
- package/cli/agents/exception-handler-agent.js +187 -0
- package/cli/agents/html-reporter.js +532 -370
- package/cli/agents/index.js +11 -1
- package/cli/agents/mcp-security-agent.js +182 -0
- package/cli/agents/pii-compliance-agent.js +4 -4
- package/cli/agents/scoring-engine.js +25 -6
- package/cli/agents/vibe-coding-agent.js +250 -0
- package/cli/bin/ship-safe.js +96 -6
- package/cli/commands/abom.js +73 -0
- package/cli/commands/agent.js +4 -4
- package/cli/commands/audit.js +15 -7
- package/cli/commands/baseline.js +1 -1
- package/cli/commands/benchmark.js +327 -0
- package/cli/commands/ci.js +81 -1
- package/cli/commands/deps.js +73 -4
- package/cli/commands/diff.js +200 -0
- package/cli/commands/doctor.js +14 -4
- package/cli/commands/fix.js +1 -1
- package/cli/commands/guard.js +99 -0
- package/cli/commands/init.js +407 -349
- package/cli/commands/openclaw.js +378 -0
- package/cli/commands/red-team.js +2 -2
- package/cli/commands/remediate.js +153 -7
- package/cli/commands/scan-skill.js +329 -0
- package/cli/commands/update-intel.js +55 -0
- package/cli/commands/vibe-check.js +276 -0
- package/cli/commands/watch.js +124 -4
- package/cli/data/threat-intel.json +85 -0
- package/cli/index.js +9 -0
- package/cli/utils/cache-manager.js +1 -1
- package/cli/utils/compliance-map.js +125 -0
- package/cli/utils/output.js +5 -2
- package/cli/utils/patterns.js +3 -0
- package/cli/utils/pdf-generator.js +1 -1
- package/cli/utils/threat-intel.js +167 -0
- package/package.json +2 -2
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,43 @@
|
|
|
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** 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.
|
|
20
21
|
|
|
21
22
|
---
|
|
22
23
|
|
|
23
24
|
## Quick Start
|
|
24
25
|
|
|
25
26
|
```bash
|
|
26
|
-
# Full security audit — secrets +
|
|
27
|
+
# Full security audit — secrets + 18 agents + deps + remediation plan
|
|
27
28
|
npx ship-safe audit .
|
|
28
29
|
|
|
29
30
|
# LLM-powered deep analysis (Anthropic, OpenAI, Google, Ollama)
|
|
30
31
|
npx ship-safe audit . --deep
|
|
31
32
|
|
|
32
|
-
# Red team scan only (
|
|
33
|
+
# Red team scan only (18 agents, 80+ attack classes)
|
|
33
34
|
npx ship-safe red-team .
|
|
34
35
|
|
|
36
|
+
# Scan only changed files (fast pre-commit & PR scanning)
|
|
37
|
+
npx ship-safe diff
|
|
38
|
+
npx ship-safe diff --staged
|
|
39
|
+
|
|
40
|
+
# Fun emoji security grade with shareable badge
|
|
41
|
+
npx ship-safe vibe-check .
|
|
42
|
+
|
|
43
|
+
# Compare your score against industry averages
|
|
44
|
+
npx ship-safe benchmark .
|
|
45
|
+
|
|
35
46
|
# Quick secret scan
|
|
36
47
|
npx ship-safe scan .
|
|
37
48
|
|
|
38
49
|
# Security health score (0-100)
|
|
39
50
|
npx ship-safe score .
|
|
40
51
|
|
|
41
|
-
# CI/CD pipeline mode — compact output, exit codes,
|
|
52
|
+
# CI/CD pipeline mode — compact output, exit codes, PR comments
|
|
42
53
|
npx ship-safe ci .
|
|
54
|
+
npx ship-safe ci . --github-pr
|
|
43
55
|
|
|
44
56
|
# Accept current findings, only report regressions
|
|
45
57
|
npx ship-safe baseline .
|
|
@@ -66,11 +78,11 @@ npx ship-safe audit .
|
|
|
66
78
|
|
|
67
79
|
```
|
|
68
80
|
════════════════════════════════════════════════════════════
|
|
69
|
-
Ship Safe
|
|
81
|
+
Ship Safe v6.0 — Full Security Audit
|
|
70
82
|
════════════════════════════════════════════════════════════
|
|
71
83
|
|
|
72
84
|
[Phase 1/4] Scanning for secrets... ✔ 49 found
|
|
73
|
-
[Phase 2/4] Running
|
|
85
|
+
[Phase 2/4] Running 18 security agents... ✔ 103 findings
|
|
74
86
|
[Phase 3/4] Auditing dependencies... ✔ 44 CVEs
|
|
75
87
|
[Phase 4/4] Computing security score... ✔ 25/100 F
|
|
76
88
|
|
|
@@ -97,14 +109,15 @@ npx ship-safe audit .
|
|
|
97
109
|
|
|
98
110
|
**What it runs:**
|
|
99
111
|
1. **Secret scan** — 50+ patterns with entropy scoring (API keys, passwords, tokens)
|
|
100
|
-
2. **
|
|
101
|
-
3. **Dependency audit** — npm/pip/bundler CVE scanning
|
|
112
|
+
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)
|
|
113
|
+
3. **Dependency audit** — npm/pip/bundler CVE scanning with EPSS exploit probability scores
|
|
102
114
|
4. **Secrets verification** — probes provider APIs (GitHub, Stripe, OpenAI, etc.) to check if leaked keys are still active
|
|
103
115
|
5. **Deep analysis** — LLM-powered taint analysis verifies exploitability of critical/high findings (optional)
|
|
104
|
-
6. **Score computation** —
|
|
116
|
+
6. **Score computation** — OWASP 2025 weighted scoring across 8 categories (0-100, A-F)
|
|
105
117
|
7. **Context-aware confidence tuning** — downgrades findings in test files, docs, and comments
|
|
106
|
-
8. **
|
|
107
|
-
9. **
|
|
118
|
+
8. **Compliance mapping** — maps findings to SOC 2 Type II, ISO 27001:2022, and NIST AI Risk Management Framework controls
|
|
119
|
+
9. **Remediation plan** — prioritized fix list grouped by severity
|
|
120
|
+
10. **Interactive HTML report** — standalone dark-themed report with severity filtering, search, collapsible findings, compliance summary, and click-to-copy ignore annotations
|
|
108
121
|
|
|
109
122
|
**Flags:**
|
|
110
123
|
- `--json` — structured JSON output (clean for piping)
|
|
@@ -127,21 +140,24 @@ npx ship-safe audit .
|
|
|
127
140
|
|
|
128
141
|
---
|
|
129
142
|
|
|
130
|
-
##
|
|
143
|
+
## 18 Security Agents
|
|
131
144
|
|
|
132
145
|
| Agent | Category | What It Detects |
|
|
133
146
|
|-------|----------|-----------------|
|
|
134
147
|
| **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
148
|
| **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
149
|
| **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,
|
|
150
|
+
| **SupplyChainAudit** | Supply Chain | Typosquatting (Levenshtein distance), git/URL dependencies, wildcard versions, suspicious install scripts, dependency confusion, lockfile integrity |
|
|
138
151
|
| **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
152
|
| **SupabaseRLSAgent** | Auth | Supabase Row Level Security — `service_role` key in client code, `CREATE TABLE` without RLS, anon key inserts, unprotected storage operations |
|
|
140
153
|
| **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 |
|
|
154
|
+
| **MCPSecurityAgent** | AI/LLM | MCP server security — unvalidated tool inputs, missing auth, excessive permissions, tool poisoning, typosquatting detection, over-permissioned tools, shadow config discovery |
|
|
142
155
|
| **AgenticSecurityAgent** | AI/LLM | OWASP Agentic AI Top 10 — agent hijacking, privilege escalation, unsafe code execution, memory poisoning |
|
|
143
156
|
| **RAGSecurityAgent** | AI/LLM | RAG pipeline security — unvalidated embeddings, context injection, document poisoning, vector DB access control |
|
|
144
157
|
| **PIIComplianceAgent** | Compliance | PII detection — SSNs, credit cards, emails, phone numbers in source code, logs, and configs |
|
|
158
|
+
| **VibeCodingAgent** | Code Vulns | AI-generated code patterns — no input validation, empty catch blocks, hardcoded secrets, disabled security features, TODO-auth patterns |
|
|
159
|
+
| **ExceptionHandlerAgent** | Code Vulns | OWASP A10:2025 — empty catch blocks, unhandled promise rejections, missing React error boundaries, leaked stack traces, generic catch-all without rethrow |
|
|
160
|
+
| **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
161
|
| **MobileScanner** | Mobile | OWASP Mobile Top 10 2024 — insecure storage, WebView JS injection, HTTP endpoints, excessive permissions, debug mode |
|
|
146
162
|
| **GitHistoryScanner** | Secrets | Leaked secrets in git commit history (checks if still active in working tree) |
|
|
147
163
|
| **CICDScanner** | CI/CD | OWASP CI/CD Top 10 — pipeline poisoning, unpinned actions, secret logging, self-hosted runners, script injection |
|
|
@@ -160,7 +176,7 @@ npx ship-safe audit .
|
|
|
160
176
|
# Full audit with remediation plan + HTML report
|
|
161
177
|
npx ship-safe audit .
|
|
162
178
|
|
|
163
|
-
# Red team:
|
|
179
|
+
# Red team: 18 agents, 80+ attack classes
|
|
164
180
|
npx ship-safe red-team .
|
|
165
181
|
npx ship-safe red-team . --agents injection,auth # Run specific agents
|
|
166
182
|
npx ship-safe red-team . --html report.html # HTML report
|
|
@@ -209,6 +225,28 @@ npx ship-safe baseline --diff
|
|
|
209
225
|
npx ship-safe baseline --clear
|
|
210
226
|
```
|
|
211
227
|
|
|
228
|
+
### Diff Scanning
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Scan only changed files (fast pre-commit & PR scanning)
|
|
232
|
+
npx ship-safe diff # All uncommitted changes
|
|
233
|
+
npx ship-safe diff --staged # Only staged changes
|
|
234
|
+
npx ship-safe diff HEAD~3 # Changes in last 3 commits
|
|
235
|
+
npx ship-safe diff --json # JSON output
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Vibe Check & Benchmark
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# Fun emoji security grade
|
|
242
|
+
npx ship-safe vibe-check .
|
|
243
|
+
npx ship-safe vibe-check . --badge # Generate shields.io README badge
|
|
244
|
+
|
|
245
|
+
# Compare your score against industry averages (OWASP, Synopsys, Snyk)
|
|
246
|
+
npx ship-safe benchmark .
|
|
247
|
+
npx ship-safe benchmark . --json # JSON output
|
|
248
|
+
```
|
|
249
|
+
|
|
212
250
|
### CI/CD Pipeline
|
|
213
251
|
|
|
214
252
|
```bash
|
|
@@ -217,6 +255,7 @@ npx ship-safe ci .
|
|
|
217
255
|
npx ship-safe ci . --threshold 80 # Custom passing score
|
|
218
256
|
npx ship-safe ci . --fail-on critical # Fail on severity
|
|
219
257
|
npx ship-safe ci . --sarif out.sarif # SARIF for GitHub
|
|
258
|
+
npx ship-safe ci . --github-pr # Post results as PR comment
|
|
220
259
|
```
|
|
221
260
|
|
|
222
261
|
### Deep Analysis & Verification
|
|
@@ -238,6 +277,52 @@ npx ship-safe audit . --verify
|
|
|
238
277
|
npx ship-safe doctor
|
|
239
278
|
```
|
|
240
279
|
|
|
280
|
+
### OpenClaw Security
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Focused OpenClaw security scan
|
|
284
|
+
npx ship-safe openclaw .
|
|
285
|
+
|
|
286
|
+
# Auto-harden OpenClaw configs (0.0.0.0→127.0.0.1, add auth, ws→wss)
|
|
287
|
+
npx ship-safe openclaw . --fix
|
|
288
|
+
|
|
289
|
+
# Red team: simulate ClawJacked, prompt injection, data exfil attacks
|
|
290
|
+
npx ship-safe openclaw . --red-team
|
|
291
|
+
|
|
292
|
+
# CI preflight — exit non-zero on critical findings
|
|
293
|
+
npx ship-safe openclaw . --preflight
|
|
294
|
+
|
|
295
|
+
# Scan a skill before installing it
|
|
296
|
+
npx ship-safe scan-skill https://clawhub.io/skills/some-skill
|
|
297
|
+
npx ship-safe scan-skill ./local-skill.json
|
|
298
|
+
npx ship-safe scan-skill --all # Scan all skills from openclaw.json
|
|
299
|
+
|
|
300
|
+
# Generate hardened OpenClaw config
|
|
301
|
+
npx ship-safe init --openclaw
|
|
302
|
+
|
|
303
|
+
# Generate Agent Bill of Materials (CycloneDX 1.5)
|
|
304
|
+
npx ship-safe abom .
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Threat Intelligence
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
# Update threat intel feed (ClawHavoc IOCs, malicious skills, config signatures)
|
|
311
|
+
npx ship-safe update-intel
|
|
312
|
+
|
|
313
|
+
# Ships with offline-first seed data — no internet required for scanning
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Defensive Hooks
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
# Install Claude Code defensive hooks (blocks curl|bash, exfil domains, rm -rf /)
|
|
320
|
+
npx ship-safe guard --generate-hooks
|
|
321
|
+
|
|
322
|
+
# Watch agent config files for drift (.cursorrules, CLAUDE.md, openclaw.json)
|
|
323
|
+
npx ship-safe watch . --configs
|
|
324
|
+
```
|
|
325
|
+
|
|
241
326
|
### Infrastructure Commands
|
|
242
327
|
|
|
243
328
|
```bash
|
|
@@ -275,7 +360,7 @@ claude plugin add github:asamassekou10/ship-safe
|
|
|
275
360
|
|
|
276
361
|
| Command | Description |
|
|
277
362
|
|---------|-------------|
|
|
278
|
-
| `/ship-safe` | Full security audit —
|
|
363
|
+
| `/ship-safe` | Full security audit — 18 agents, remediation plan, auto-fix |
|
|
279
364
|
| `/ship-safe-scan` | Quick scan for leaked secrets |
|
|
280
365
|
| `/ship-safe-score` | Security health score (0-100) |
|
|
281
366
|
| `/ship-safe-deep` | LLM-powered deep taint analysis |
|
|
@@ -344,12 +429,14 @@ Starts at 100. Each finding deducts points by severity and category, weighted by
|
|
|
344
429
|
|----------|--------|----------|------|--------|-----|
|
|
345
430
|
| Secrets | 15% | -25 | -15 | -5 | -15 |
|
|
346
431
|
| Code Vulnerabilities | 15% | -20 | -10 | -3 | -15 |
|
|
347
|
-
| Dependencies |
|
|
432
|
+
| Dependencies | 13% | -20 | -10 | -5 | -13 |
|
|
348
433
|
| Auth & Access Control | 15% | -20 | -10 | -3 | -15 |
|
|
349
|
-
| Configuration |
|
|
350
|
-
| Supply Chain |
|
|
434
|
+
| Configuration | 8% | -15 | -8 | -3 | -8 |
|
|
435
|
+
| Supply Chain | 12% | -15 | -8 | -3 | -12 |
|
|
351
436
|
| API Security | 10% | -15 | -8 | -3 | -10 |
|
|
352
|
-
| AI/LLM Security |
|
|
437
|
+
| AI/LLM Security | 12% | -15 | -8 | -3 | -12 |
|
|
438
|
+
|
|
439
|
+
*Weights aligned with OWASP Top 10 2025 risk rankings.*
|
|
353
440
|
|
|
354
441
|
**Grades:** A (90-100), B (75-89), C (60-74), D (40-59), F (0-39)
|
|
355
442
|
|
|
@@ -411,7 +498,7 @@ jobs:
|
|
|
411
498
|
- uses: actions/checkout@v4
|
|
412
499
|
|
|
413
500
|
- name: Security gate
|
|
414
|
-
run: npx ship-safe ci . --threshold 75 --sarif results.sarif
|
|
501
|
+
run: npx ship-safe ci . --threshold 75 --sarif results.sarif --github-pr
|
|
415
502
|
|
|
416
503
|
- uses: github/codeql-action/upload-sarif@v3
|
|
417
504
|
if: always()
|
|
@@ -504,4 +591,4 @@ MIT - Use it, share it, secure your stuff.
|
|
|
504
591
|
|
|
505
592
|
---
|
|
506
593
|
|
|
507
|
-
**Ship fast. Ship safe.**
|
|
594
|
+
**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;
|