@softspark/ai-toolkit 1.3.13 → 1.3.14

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/CHANGELOG.md CHANGED
@@ -7,6 +7,28 @@ Versioning follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
+ ## v1.3.14 — CVE Scanner + Open Contributions (2026-04-08)
11
+
12
+ ### Added
13
+ - **`/cve-scan` skill** — auto-detect project ecosystems (npm, pip, composer, cargo, go, ruby, dart) and scan dependencies for known CVEs using native audit tools. Includes `cve_scan.py` scanner script with parsers for npm and pip-audit, unified severity report, `--fix` and `--json` modes.
14
+ - **CVE scan in security-auditor agent** — `/cve-scan` is now a mandatory first step in the OWASP A06 (Vulnerable Components) checklist.
15
+ - **CVE scan in `/workflow security-audit`** — security-auditor agent runs CVE scan as part of the parallel audit phase.
16
+ - **`security-audit` CI job** — `audit_skills.py --ci` now runs in GitHub Actions pipeline.
17
+ - **`CODE_OF_CONDUCT.md` in CI** — added to required files check.
18
+ - **`.github/CODEOWNERS`** — auto-assigns maintainer for review.
19
+ - **`.github/FUNDING.yml`** — GitHub Sponsors configuration.
20
+ - **GitHub Security Advisories** — added CVE/advisory procedure to `SECURITY.md`.
21
+ - **Open contribution workflow** — full `CONTRIBUTING.md` rewrite (fork, branch naming, commit conventions, CI requirements), PR checklist template, blank issues enabled.
22
+
23
+ ### Removed
24
+ - **`close-prs.yml`** — removed auto-close workflow to accept external PRs.
25
+
26
+ ### Fixed
27
+ - **Copyright** — `LICENSE` updated from `2024-present` to `2024-2026`.
28
+ - **`SECURITY.md`** — removed duplicate Scope section.
29
+
30
+ ---
31
+
10
32
  ## v1.3.13 — CLI --version flag (2026-04-08)
11
33
 
12
34
  ### Added
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024-present Lukasz Krzemien (biuro@softspark.eu)
3
+ Copyright (c) 2024-2026 Lukasz Krzemien (biuro@softspark.eu)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # ai-toolkit
2
2
 
3
- > Professional-grade AI coding toolkit with multi-platform support. Machine-enforced safety, 90 skills, 44 agents, expanded lifecycle hooks, persona presets, experimental opt-in plugin packs, and benchmark tooling — works with Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, and Augment, ready in 60 seconds.
3
+ > Professional-grade AI coding toolkit with multi-platform support. Machine-enforced safety, 91 skills, 44 agents, expanded lifecycle hooks, persona presets, experimental opt-in plugin packs, and benchmark tooling — works with Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, and Augment, ready in 60 seconds.
4
4
 
5
5
  [![CI](https://github.com/softspark/ai-toolkit/actions/workflows/ci.yml/badge.svg)](https://github.com/softspark/ai-toolkit/actions/workflows/ci.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
- [![Skills](https://img.shields.io/badge/skills-90-brightgreen)](app/skills/)
7
+ [![Skills](https://img.shields.io/badge/skills-91-brightgreen)](app/skills/)
8
8
  [![Agents](https://img.shields.io/badge/agents-44-blue)](app/agents/)
9
9
  [![Tests](https://img.shields.io/badge/tests-377%20passing-success)](tests/)
10
10
 
@@ -21,7 +21,7 @@ ai-toolkit install
21
21
  npx @softspark/ai-toolkit install
22
22
  ```
23
23
 
24
- **That's it.** Claude Code picks up 90 skills, 44 agents, quality hooks, and the safety constitution automatically.
24
+ **That's it.** Claude Code picks up 91 skills, 44 agents, quality hooks, and the safety constitution automatically.
25
25
 
26
26
  ### Update
27
27
 
@@ -134,7 +134,7 @@ Replaces all symlinks with real files, inlines rules into CLAUDE.md, copies cons
134
134
  | Component | Count | Description |
135
135
  |-----------|-------|-------------|
136
136
  | `skills/` (task) | 28 | Slash commands: `/commit`, `/build`, `/deploy`, `/test`, `/skill-audit`, ... |
137
- | `skills/` (hybrid) | 30 | Slash commands with agent knowledge base |
137
+ | `skills/` (hybrid) | 31 | Slash commands with agent knowledge base |
138
138
  | `skills/` (knowledge) | 32 | Domain knowledge auto-loaded by agents |
139
139
  | `agents/` | 44 | Specialized agents across 10 categories |
140
140
  | `hooks/` | 21 global + 5 skill-scoped | Quality gates, path safety, CLAUDE.md enforcement, notifications, prompt governance, subagent lifecycle, session-end handoff, usage tracking, config protection, MCP health, governance audit |
@@ -156,7 +156,7 @@ ai-toolkit/
156
156
  │ │ ├── backend-specialist.md
157
157
  │ │ ├── security-architect.md
158
158
  │ │ └── ... (41 more)
159
- │ ├── skills/ # 90 skills (task / hybrid / knowledge)
159
+ │ ├── skills/ # 91 skills (task / hybrid / knowledge)
160
160
  │ │ ├── commit/ # /commit slash command
161
161
  │ │ ├── review/ # /review slash command
162
162
  │ │ ├── clean-code/ # knowledge skill (auto-loaded)
@@ -223,6 +223,7 @@ ai-toolkit/
223
223
  | `/agent-creator` | Scaffold a new specialized agent with tools and trigger guidance | high |
224
224
  | `/plugin-creator` | Scaffold an experimental plugin pack with manifest and optional modules | high |
225
225
  | `/skill-audit` | Scan skills/agents for security risks: dangerous patterns, secrets, permissions | medium |
226
+ | `/cve-scan` | Scan project dependencies for known CVEs using native audit tools (npm, pip, composer, cargo, go, ruby, dart) | medium |
226
227
  | `/analyze` | Code quality, complexity, and pattern analysis | medium |
227
228
  | `/fix` | Auto-fix lint/type errors | low |
228
229
  | `/build` | Build with issue detection | low |
@@ -329,25 +330,28 @@ Hook logic lives in `app/hooks/*.sh` — not inline JSON one-liners. Scripts are
329
330
  | `/migrate` | Pre | Backup verification |
330
331
  | `/rollback` | Post | State verification |
331
332
 
332
- ### 3. Skill Security Auditing
333
+ ### 3. Security Scanning
333
334
 
334
- Scan all skills and agents for security risks — both interactively and in CI:
335
+ Two complementary security tools:
336
+
337
+ **`/skill-audit`** — scan skills and agents for code-level risks:
335
338
 
336
339
  ```bash
337
- # Interactive (Claude provides remediation suggestions)
338
- /skill-audit
340
+ /skill-audit # Interactive (Claude remediation)
341
+ python3 scripts/audit_skills.py --ci # CI mode: exit 1 on HIGH
342
+ ```
343
+
344
+ Detects: `eval()`/`exec()`, hardcoded secrets, permission issues, bash risks.
339
345
 
340
- # Deterministic Python scanner for CI pipelines
341
- python3 scripts/audit_skills.py # human-readable report
342
- python3 scripts/audit_skills.py --json # machine-readable JSON
343
- python3 scripts/audit_skills.py --ci # exit 1 on any HIGH finding
346
+ **`/cve-scan`** scan project dependencies for known CVEs:
347
+
348
+ ```bash
349
+ /cve-scan # Auto-detect ecosystems, scan all
350
+ python3 app/skills/cve-scan/scripts/cve_scan.py # Direct invocation
351
+ python3 app/skills/cve-scan/scripts/cve_scan.py --json # Machine-readable
344
352
  ```
345
353
 
346
- **What it detects:**
347
- - Dangerous code: `eval()`, `exec()`, `subprocess(shell=True)`, `pickle.loads`
348
- - Hardcoded secrets: AWS keys, GitHub PATs, private keys, API tokens
349
- - Permission issues: knowledge skills with Bash, missing `allowed-tools`
350
- - Bash risks: `curl | bash`, `chmod 777`, unquoted variables
354
+ Supports: npm, pip, composer, cargo, go, ruby, dart. Uses native audit tools — zero external deps.
351
355
 
352
356
  **Severity levels:** HIGH (blocks CI), WARN (should fix), INFO (review)
353
357
 
@@ -134,7 +134,7 @@ Universal multi-agent system for software development. Works across all reposito
134
134
  | `prd-to-issues` | `/prd-to-issues` | Break PRD into GitHub issues with vertical slices and HITL/AFK tagging |
135
135
  | `skill-audit` | `/skill-audit` | Scan skills and agents for security risks, dangerous patterns, secrets |
136
136
 
137
- ### Hybrid Skills (30)
137
+ ### Hybrid Skills (31)
138
138
  | Skill | Slash Command | Purpose |
139
139
  |-------|---------------|---------|
140
140
  | `explore` | `/explore` | Codebase exploration and tech stack discovery |
@@ -143,6 +143,7 @@ Universal multi-agent system for software development. Works across all reposito
143
143
  | `plan` | `/plan` | Create structured plan with task breakdown |
144
144
  | `refactor` | `/refactor` | Plan and execute code refactoring with safety checks |
145
145
  | `analyze` | `/analyze` | Analyze code quality, complexity, and patterns |
146
+ | `cve-scan` | `/cve-scan` | Scan project dependencies for CVEs using native tools (npm, pip, composer, cargo, go, ruby, dart) |
146
147
  | `docs` | `/docs` | Generate/update documentation (README, API docs, architecture notes) |
147
148
  | `search` | `/search` | Search knowledge base (MCP + local fallback) |
148
149
  | `explain` | `/explain` | Explain file/module architecture with Mermaid diagrams |
@@ -63,7 +63,7 @@ hybrid_search_kb(query="vulnerability {type}", limit=10)
63
63
  - [ ] Unnecessary features disabled
64
64
 
65
65
  ### A06:2021 - Vulnerable Components
66
- - [ ] Dependencies scanned for CVEs
66
+ - [ ] Dependencies scanned for CVEs — **run `/cve-scan` or `python3 ${SKILL_DIR}/cve-scan/scripts/cve_scan.py`**
67
67
  - [ ] Components up to date
68
68
  - [ ] SBOM maintained
69
69
 
@@ -91,6 +91,21 @@ hybrid_search_kb(query="vulnerability {type}", limit=10)
91
91
 
92
92
  ## Security Audit Commands
93
93
 
94
+ ### Dependency CVE Scan (MANDATORY — run FIRST)
95
+
96
+ ```bash
97
+ # Auto-detect ecosystems and scan all dependencies for CVEs
98
+ python3 app/skills/cve-scan/scripts/cve_scan.py
99
+
100
+ # JSON output for structured analysis
101
+ python3 app/skills/cve-scan/scripts/cve_scan.py --json
102
+
103
+ # Or use the skill interactively
104
+ /cve-scan
105
+ ```
106
+
107
+ ### Code & Infrastructure Scans
108
+
94
109
  ```bash
95
110
  # Check for secrets in code
96
111
  docker exec {app-container} gitleaks detect --source=/app
@@ -0,0 +1,134 @@
1
+ ---
2
+ name: cve-scan
3
+ description: "Scan project dependencies for known CVEs using native audit tools (npm, pip, composer, cargo, go, bundler, dart)"
4
+ user-invocable: true
5
+ effort: medium
6
+ argument-hint: "[--ecosystem npm|pip|composer|cargo|go|ruby|dart] [--fix] [--json]"
7
+ allowed-tools: Read, Grep, Glob, Bash
8
+ ---
9
+
10
+ # /cve-scan - Dependency CVE Scanner
11
+
12
+ $ARGUMENTS
13
+
14
+ Detect project ecosystems and scan dependencies for known vulnerabilities using native audit tools. Zero external dependencies — uses tools already installed in the project environment.
15
+
16
+ ## Usage
17
+
18
+ ```
19
+ /cve-scan # Auto-detect all ecosystems, scan all
20
+ /cve-scan --ecosystem npm # Force specific ecosystem
21
+ /cve-scan --fix # Auto-fix where possible (npm audit fix, etc.)
22
+ /cve-scan --json # Machine-readable JSON output
23
+ ```
24
+
25
+ ## What This Command Does
26
+
27
+ 1. **Detect** package managers by lock/manifest files in the project
28
+ 2. **Run** the native audit command for each detected ecosystem
29
+ 3. **Parse** results into a unified severity-based report
30
+ 4. **Report** CVE IDs, affected packages, installed vs fixed versions, advisory links
31
+ 5. **Fix** automatically when `--fix` is passed (where the tool supports it)
32
+
33
+ ## Ecosystem Detection & Commands
34
+
35
+ | Manifest File | Lock File | Ecosystem | Audit Command | CVE Database |
36
+ |---------------|-----------|-----------|---------------|--------------|
37
+ | `package.json` | `package-lock.json` / `yarn.lock` / `pnpm-lock.yaml` | npm/yarn/pnpm | `npm audit --json` / `yarn audit --json` / `pnpm audit --json` | GitHub Advisory DB |
38
+ | `requirements.txt` / `pyproject.toml` / `setup.py` | `requirements.txt` | pip | `pip-audit --format=json` | OSV / PyPI Advisory |
39
+ | `composer.json` | `composer.lock` | composer | `composer audit --format=json` | Packagist / FriendsOfPHP |
40
+ | `Cargo.toml` | `Cargo.lock` | cargo | `cargo audit --json` | RustSec Advisory DB |
41
+ | `go.mod` | `go.sum` | go | `govulncheck ./...` | Go Vulnerability DB |
42
+ | `Gemfile` | `Gemfile.lock` | bundler | `bundle-audit check` | Ruby Advisory DB |
43
+ | `pubspec.yaml` | `pubspec.lock` | dart/flutter | `dart pub outdated --json` | pub.dev |
44
+
45
+ ## Steps
46
+
47
+ 1. **Detect ecosystems**: Glob for manifest/lock files at project root and common subdirectories
48
+ 2. **Check tool availability**: Verify audit tool is installed for each detected ecosystem
49
+ 3. **Run audit**: Execute native audit command, capture JSON output where available
50
+ 4. **Parse results**: Extract CVE ID, package name, installed version, fixed version, severity, advisory URL
51
+ 5. **Unified report**: Merge all ecosystems into single report sorted by severity
52
+ 6. **Fix mode**: If `--fix` passed, run `npm audit fix`, `pip-audit --fix`, `cargo audit fix` etc.
53
+ 7. **Exit code**: Non-zero if any CRITICAL or HIGH vulnerabilities found
54
+
55
+ ## Detection Script
56
+
57
+ Run the bundled detection script to quickly identify ecosystems and tool availability:
58
+
59
+ ```bash
60
+ python3 ${CLAUDE_SKILL_DIR}/scripts/cve_scan.py
61
+ ```
62
+
63
+ Options:
64
+ ```bash
65
+ python3 ${CLAUDE_SKILL_DIR}/scripts/cve_scan.py --json # JSON output
66
+ python3 ${CLAUDE_SKILL_DIR}/scripts/cve_scan.py --fix # Auto-fix mode
67
+ python3 ${CLAUDE_SKILL_DIR}/scripts/cve_scan.py --ecosystem npm # Specific ecosystem
68
+ ```
69
+
70
+ ## Output Format
71
+
72
+ ```markdown
73
+ ## CVE Scan Report
74
+
75
+ ### Ecosystems Detected
76
+ - npm (package-lock.json) — `npm audit` available ✓
77
+ - pip (requirements.txt) — `pip-audit` not installed ⚠️
78
+
79
+ ### Summary
80
+ | Severity | Count |
81
+ |----------|-------|
82
+ | CRITICAL | 1 |
83
+ | HIGH | 3 |
84
+ | MEDIUM | 5 |
85
+ | LOW | 2 |
86
+
87
+ ### Findings
88
+
89
+ #### [CRITICAL] lodash@4.17.20 (npm)
90
+ - **CVE**: CVE-2021-23337
91
+ - **Title**: Prototype Pollution
92
+ - **Fixed in**: 4.17.21
93
+ - **Advisory**: https://github.com/advisories/GHSA-35jh-r3h4-6jhm
94
+
95
+ #### [HIGH] django@3.2.0 (pip)
96
+ - **CVE**: CVE-2023-36053
97
+ - **Title**: Potential ReDoS in EmailValidator
98
+ - **Fixed in**: 3.2.20
99
+ - **Advisory**: https://osv.dev/vulnerability/PYSEC-2023-100
100
+
101
+ ### Tool Availability
102
+ | Ecosystem | Tool | Status | Install Hint |
103
+ |-----------|------|--------|--------------|
104
+ | npm | npm audit | ✓ installed | — |
105
+ | pip | pip-audit | ✗ missing | `pip install pip-audit` |
106
+ | cargo | cargo-audit | ✗ missing | `cargo install cargo-audit` |
107
+ ```
108
+
109
+ ## Handling Missing Tools
110
+
111
+ When an audit tool is not installed, the skill:
112
+ 1. Reports it as a warning (not a failure)
113
+ 2. Provides the install command for the missing tool
114
+ 3. Continues scanning other detected ecosystems
115
+
116
+ Install hints per ecosystem:
117
+
118
+ | Tool | Install Command |
119
+ |------|----------------|
120
+ | `pip-audit` | `pip install pip-audit` |
121
+ | `cargo-audit` | `cargo install cargo-audit` |
122
+ | `govulncheck` | `go install golang.org/x/vuln/cmd/govulncheck@latest` |
123
+ | `bundle-audit` | `gem install bundler-audit` |
124
+ | `composer` | Built-in since Composer 2.4 |
125
+
126
+ ## Rules
127
+
128
+ - Never modify `package-lock.json`, `Cargo.lock`, or other lock files without `--fix` flag
129
+ - Always report tool availability — missing tool is a finding, not a failure
130
+ - Parse JSON output when available for structured data; fall back to text parsing
131
+ - CRITICAL and HIGH findings should be highlighted prominently
132
+ - Include advisory URLs for every CVE when available
133
+ - This skill is READ-ONLY by default (no installs, no upgrades) unless `--fix` is passed
134
+ - Respect `.auditrc`, `.nsprc`, or equivalent ignore files if present
@@ -0,0 +1,412 @@
1
+ #!/usr/bin/env python3
2
+ """CVE dependency scanner — detect ecosystems and run native audit tools.
3
+
4
+ Stdlib only. No external dependencies.
5
+ """
6
+
7
+ import json
8
+ import os
9
+ import shutil
10
+ import subprocess
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ ECOSYSTEMS = {
15
+ "npm": {
16
+ "manifests": ["package.json"],
17
+ "locks": ["package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
18
+ "tool": "npm",
19
+ "audit_cmd": ["npm", "audit", "--json"],
20
+ "fix_cmd": ["npm", "audit", "fix"],
21
+ "install_hint": "npm is bundled with Node.js",
22
+ },
23
+ "pip": {
24
+ "manifests": ["requirements.txt", "pyproject.toml", "setup.py", "setup.cfg"],
25
+ "locks": ["requirements.txt"],
26
+ "tool": "pip-audit",
27
+ "audit_cmd": ["pip-audit", "--format=json", "--output=-"],
28
+ "fix_cmd": ["pip-audit", "--fix"],
29
+ "install_hint": "pip install pip-audit",
30
+ },
31
+ "composer": {
32
+ "manifests": ["composer.json"],
33
+ "locks": ["composer.lock"],
34
+ "tool": "composer",
35
+ "audit_cmd": ["composer", "audit", "--format=json"],
36
+ "fix_cmd": ["composer", "update"],
37
+ "install_hint": "https://getcomposer.org/download/",
38
+ },
39
+ "cargo": {
40
+ "manifests": ["Cargo.toml"],
41
+ "locks": ["Cargo.lock"],
42
+ "tool": "cargo-audit",
43
+ "audit_cmd": ["cargo", "audit", "--json"],
44
+ "fix_cmd": ["cargo", "audit", "fix"],
45
+ "install_hint": "cargo install cargo-audit",
46
+ },
47
+ "go": {
48
+ "manifests": ["go.mod"],
49
+ "locks": ["go.sum"],
50
+ "tool": "govulncheck",
51
+ "audit_cmd": ["govulncheck", "-json", "./..."],
52
+ "fix_cmd": ["go", "get", "-u", "./..."],
53
+ "install_hint": "go install golang.org/x/vuln/cmd/govulncheck@latest",
54
+ },
55
+ "ruby": {
56
+ "manifests": ["Gemfile"],
57
+ "locks": ["Gemfile.lock"],
58
+ "tool": "bundle-audit",
59
+ "audit_cmd": ["bundle-audit", "check", "--format=json"],
60
+ "fix_cmd": ["bundle-audit", "update"],
61
+ "install_hint": "gem install bundler-audit",
62
+ },
63
+ "dart": {
64
+ "manifests": ["pubspec.yaml"],
65
+ "locks": ["pubspec.lock"],
66
+ "tool": "dart",
67
+ "audit_cmd": ["dart", "pub", "outdated", "--json"],
68
+ "fix_cmd": ["dart", "pub", "upgrade"],
69
+ "install_hint": "https://dart.dev/get-dart",
70
+ },
71
+ }
72
+
73
+
74
+ def detect_ecosystems(root: Path) -> list[dict]:
75
+ """Detect which package ecosystems are present in the project."""
76
+ found = []
77
+ for name, eco in ECOSYSTEMS.items():
78
+ detected_files = []
79
+ has_lock = False
80
+ for m in eco["manifests"]:
81
+ if (root / m).exists():
82
+ detected_files.append(m)
83
+ for m in eco["locks"]:
84
+ if (root / m).exists():
85
+ detected_files.append(m)
86
+ has_lock = True
87
+ # Deduplicate (requirements.txt is both manifest and lock)
88
+ detected_files = list(dict.fromkeys(detected_files))
89
+ if detected_files:
90
+ tool_path = shutil.which(eco["tool"])
91
+ found.append({
92
+ "name": name,
93
+ "files": detected_files,
94
+ "has_lock": has_lock,
95
+ "tool": eco["tool"],
96
+ "tool_available": tool_path is not None,
97
+ "install_hint": eco["install_hint"],
98
+ "audit_cmd": eco["audit_cmd"],
99
+ "fix_cmd": eco["fix_cmd"],
100
+ })
101
+ return found
102
+
103
+
104
+ def run_audit(eco: dict, root: Path, fix: bool = False) -> dict:
105
+ """Run the native audit command for an ecosystem."""
106
+ cmd = eco["fix_cmd"] if fix else eco["audit_cmd"]
107
+ result = {
108
+ "ecosystem": eco["name"],
109
+ "tool": eco["tool"],
110
+ "command": " ".join(cmd),
111
+ "success": False,
112
+ "raw_output": "",
113
+ "error": "",
114
+ }
115
+
116
+ if not eco["tool_available"]:
117
+ result["error"] = f"Tool '{eco['tool']}' not installed. Install: {eco['install_hint']}"
118
+ return result
119
+
120
+ if not eco.get("has_lock", True) and eco["name"] in ("npm",):
121
+ result["warning"] = "No lock file — run `npm install` first"
122
+ result["success"] = True
123
+ return result
124
+
125
+ try:
126
+ proc = subprocess.run(
127
+ cmd,
128
+ cwd=str(root),
129
+ capture_output=True,
130
+ text=True,
131
+ timeout=120,
132
+ )
133
+ result["raw_output"] = proc.stdout
134
+ result["error"] = proc.stderr if proc.returncode not in (0, 1) else ""
135
+ # npm audit returns 1 when vulnerabilities found — that's not an error
136
+ result["success"] = True
137
+ except FileNotFoundError:
138
+ result["error"] = f"Tool '{eco['tool']}' not found in PATH"
139
+ except subprocess.TimeoutExpired:
140
+ result["error"] = f"Audit command timed out after 120s"
141
+
142
+ return result
143
+
144
+
145
+ def parse_npm_audit(raw: str) -> list[dict]:
146
+ """Parse npm audit JSON output into unified findings."""
147
+ findings = []
148
+ try:
149
+ data = json.loads(raw)
150
+ except (json.JSONDecodeError, ValueError):
151
+ return findings
152
+
153
+ vulns = data.get("vulnerabilities", {})
154
+ for pkg_name, info in vulns.items():
155
+ for via in info.get("via", []):
156
+ if isinstance(via, dict):
157
+ severity = via.get("severity", "unknown").upper()
158
+ findings.append({
159
+ "severity": severity,
160
+ "package": pkg_name,
161
+ "installed": info.get("range", "unknown"),
162
+ "cve": via.get("cve", [via.get("url", "N/A")]),
163
+ "title": via.get("title", "Unknown"),
164
+ "url": via.get("url", ""),
165
+ "fixed_in": info.get("fixAvailable", {}).get("version", "unknown") if isinstance(info.get("fixAvailable"), dict) else "unknown",
166
+ })
167
+ return findings
168
+
169
+
170
+ def parse_pip_audit(raw: str) -> list[dict]:
171
+ """Parse pip-audit JSON output into unified findings."""
172
+ findings = []
173
+ try:
174
+ data = json.loads(raw)
175
+ except (json.JSONDecodeError, ValueError):
176
+ return findings
177
+
178
+ for dep in data.get("dependencies", []):
179
+ for vuln in dep.get("vulns", []):
180
+ vuln_id = vuln.get("id", "N/A")
181
+ aliases = vuln.get("aliases", [])
182
+ # Use GHSA link if available, otherwise OSV
183
+ url = ""
184
+ for alias in aliases:
185
+ if alias.startswith("GHSA-"):
186
+ url = f"https://github.com/advisories/{alias}"
187
+ break
188
+ if not url:
189
+ url = f"https://osv.dev/vulnerability/{vuln_id}"
190
+
191
+ fix_versions = vuln.get("fix_versions", [])
192
+ # Determine severity from CVE ID prefix heuristic — pip-audit
193
+ # doesn't provide severity directly, so we mark as HIGH by default
194
+ severity = "HIGH"
195
+
196
+ findings.append({
197
+ "severity": severity,
198
+ "package": f"{dep['name']}@{dep['version']}",
199
+ "installed": dep.get("version", "unknown"),
200
+ "cve": vuln_id,
201
+ "title": vuln.get("description", "")[:120] + ("..." if len(vuln.get("description", "")) > 120 else ""),
202
+ "url": url,
203
+ "fixed_in": ", ".join(fix_versions) if fix_versions else "unknown",
204
+ })
205
+ return findings
206
+
207
+
208
+ def parse_cargo_audit(raw: str) -> list[dict]:
209
+ """Parse cargo audit JSON output into unified findings."""
210
+ findings = []
211
+ try:
212
+ data = json.loads(raw)
213
+ except (json.JSONDecodeError, ValueError):
214
+ return findings
215
+
216
+ for vuln in data.get("vulnerabilities", {}).get("list", []):
217
+ advisory = vuln.get("advisory", {})
218
+ pkg = vuln.get("package", {})
219
+ findings.append({
220
+ "severity": "HIGH",
221
+ "package": f"{pkg.get('name', 'unknown')}@{pkg.get('version', 'unknown')}",
222
+ "installed": pkg.get("version", "unknown"),
223
+ "cve": advisory.get("id", "N/A"),
224
+ "title": advisory.get("title", "Unknown"),
225
+ "url": advisory.get("url", ""),
226
+ "fixed_in": ", ".join(vuln.get("versions", {}).get("patched", [])) or "unknown",
227
+ })
228
+ return findings
229
+
230
+
231
+ def _table(headers: list[str], rows: list[list[str]]) -> list[str]:
232
+ """Render an aligned plain-text table with box-drawing borders."""
233
+ widths = [len(h) for h in headers]
234
+ for row in rows:
235
+ for i, cell in enumerate(row):
236
+ widths[i] = max(widths[i], len(cell))
237
+
238
+ sep = "├" + "┼".join("─" * (w + 2) for w in widths) + "┤"
239
+ top = "┌" + "┬".join("─" * (w + 2) for w in widths) + "┐"
240
+ bot = "└" + "┴".join("─" * (w + 2) for w in widths) + "┘"
241
+
242
+ def fmt_row(cells: list[str]) -> str:
243
+ parts = []
244
+ for i, cell in enumerate(cells):
245
+ parts.append(f" {cell:<{widths[i]}} ")
246
+ return "│" + "│".join(parts) + "│"
247
+
248
+ lines = [top, fmt_row(headers), sep]
249
+ for row in rows:
250
+ lines.append(fmt_row(row))
251
+ lines.append(bot)
252
+ return lines
253
+
254
+
255
+ def format_text_report(ecosystems: list[dict], results: list[dict], all_findings: list[dict]) -> str:
256
+ """Format findings as a terminal-friendly report."""
257
+ lines = ["", "═══ CVE Scan Report ═══", ""]
258
+
259
+ # Ecosystems detected
260
+ eco_rows = []
261
+ for eco in ecosystems:
262
+ status = "✓" if eco["tool_available"] else "⚠ not installed"
263
+ files = ", ".join(eco["files"])
264
+ eco_rows.append([eco["name"], files, eco["tool"], status])
265
+ lines.extend(_table(["Ecosystem", "Files", "Tool", "Status"], eco_rows))
266
+ lines.append("")
267
+
268
+ # Summary
269
+ severity_counts = {"CRITICAL": 0, "HIGH": 0, "MODERATE": 0, "MEDIUM": 0, "LOW": 0}
270
+ for f in all_findings:
271
+ sev = f["severity"].upper()
272
+ if sev in severity_counts:
273
+ severity_counts[sev] += 1
274
+ else:
275
+ severity_counts[sev] = severity_counts.get(sev, 0) + 1
276
+
277
+ # Merge MODERATE into MEDIUM for display
278
+ severity_counts["MEDIUM"] += severity_counts.pop("MODERATE", 0)
279
+
280
+ total = sum(severity_counts.values())
281
+ summary_rows = []
282
+ for sev in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]:
283
+ if severity_counts.get(sev, 0) > 0:
284
+ summary_rows.append([sev, str(severity_counts[sev])])
285
+ summary_rows.append(["TOTAL", str(total)])
286
+ lines.extend(_table(["Severity", "Count"], summary_rows))
287
+ lines.append("")
288
+
289
+ if not all_findings:
290
+ lines.append("✓ No known vulnerabilities found.")
291
+ lines.append("")
292
+
293
+ # Findings by severity
294
+ if all_findings:
295
+ severity_order = {"CRITICAL": 0, "HIGH": 1, "MODERATE": 2, "MEDIUM": 2, "LOW": 3}
296
+ sorted_findings = sorted(all_findings, key=lambda f: severity_order.get(f["severity"].upper(), 9))
297
+
298
+ finding_rows = []
299
+ for f in sorted_findings:
300
+ sev = f["severity"].upper()
301
+ if sev == "MODERATE":
302
+ sev = "MEDIUM"
303
+ cve = f["cve"] if isinstance(f["cve"], str) else ", ".join(f["cve"]) if f["cve"] else "N/A"
304
+ title = f["title"][:60] + ("..." if len(f["title"]) > 60 else "")
305
+ finding_rows.append([sev, f["package"], cve, f["fixed_in"], title])
306
+
307
+ lines.extend(_table(["Severity", "Package", "CVE", "Fix", "Title"], finding_rows))
308
+ lines.append("")
309
+
310
+ # Detailed advisory links
311
+ lines.append("Advisory links:")
312
+ for f in sorted_findings:
313
+ if f.get("url"):
314
+ cve = f["cve"] if isinstance(f["cve"], str) else ", ".join(f["cve"]) if f["cve"] else "N/A"
315
+ lines.append(f" {cve}: {f['url']}")
316
+ lines.append("")
317
+
318
+ # Install hints for missing tools
319
+ missing = [e for e in ecosystems if not e["tool_available"]]
320
+ if missing:
321
+ lines.append("Missing tools:")
322
+ for eco in missing:
323
+ lines.append(f" {eco['name']}: install with: {eco['install_hint']}")
324
+ lines.append("")
325
+
326
+ # Warnings (non-fatal issues like missing lock files)
327
+ warnings = [r for r in results if r.get("warning")]
328
+ if warnings:
329
+ for r in warnings:
330
+ lines.append(f"⚠ {r['ecosystem']}: {r['warning']}")
331
+ lines.append("")
332
+
333
+ # Errors (fatal issues)
334
+ errors = [r for r in results if r.get("error")]
335
+ if errors:
336
+ for r in errors:
337
+ lines.append(f"✗ {r['ecosystem']}: {r['error']}")
338
+ lines.append("")
339
+
340
+ return "\n".join(lines)
341
+
342
+
343
+ def main():
344
+ import argparse
345
+
346
+ parser = argparse.ArgumentParser(description="CVE dependency scanner")
347
+ parser.add_argument("--json", action="store_true", help="JSON output")
348
+ parser.add_argument("--fix", action="store_true", help="Auto-fix vulnerabilities")
349
+ parser.add_argument("--ecosystem", type=str, help="Scan specific ecosystem only")
350
+ parser.add_argument("path", nargs="?", default=".", help="Project root path")
351
+ args = parser.parse_args()
352
+
353
+ root = Path(args.path).resolve()
354
+ if not root.is_dir():
355
+ print(f"Error: {root} is not a directory", file=sys.stderr)
356
+ sys.exit(1)
357
+
358
+ # Detect
359
+ ecosystems = detect_ecosystems(root)
360
+ if args.ecosystem:
361
+ ecosystems = [e for e in ecosystems if e["name"] == args.ecosystem]
362
+
363
+ if not ecosystems:
364
+ msg = "No supported package ecosystems detected."
365
+ if args.json:
366
+ print(json.dumps({"ecosystems": [], "findings": [], "message": msg}))
367
+ else:
368
+ print(msg)
369
+ sys.exit(0)
370
+
371
+ # Run audits
372
+ results = []
373
+ all_findings = []
374
+ for eco in ecosystems:
375
+ result = run_audit(eco, root, fix=args.fix)
376
+ results.append(result)
377
+
378
+ # Parse results with ecosystem-specific parsers
379
+ if result["success"] and result["raw_output"]:
380
+ parsers = {
381
+ "npm": parse_npm_audit,
382
+ "pip": parse_pip_audit,
383
+ "cargo": parse_cargo_audit,
384
+ }
385
+ parser = parsers.get(eco["name"])
386
+ if parser:
387
+ findings = parser(result["raw_output"])
388
+ for f in findings:
389
+ f["ecosystem"] = eco["name"]
390
+ all_findings.extend(findings)
391
+
392
+ # Output
393
+ if args.json:
394
+ output = {
395
+ "ecosystems": [{"name": e["name"], "files": e["files"], "tool_available": e["tool_available"]} for e in ecosystems],
396
+ "results": results,
397
+ "findings": all_findings,
398
+ "total_findings": len(all_findings),
399
+ }
400
+ print(json.dumps(output, indent=2))
401
+ else:
402
+ report = format_text_report(ecosystems, results, all_findings)
403
+ print(report)
404
+
405
+ # Exit code: non-zero if CRITICAL or HIGH found
406
+ high_or_critical = [f for f in all_findings if f["severity"].upper() in ("CRITICAL", "HIGH")]
407
+ if high_or_critical:
408
+ sys.exit(1)
409
+
410
+
411
+ if __name__ == "__main__":
412
+ main()
@@ -188,13 +188,13 @@ Agent(subagent_type="code-reviewer", prompt="Review test quality — no
188
188
  # Sequential recon:
189
189
  Agent(subagent_type="explorer-agent", prompt="Map attack surface, entry points, data flows. READ-ONLY.")
190
190
  # Parallel audit:
191
- Agent(subagent_type="security-auditor", prompt="OWASP Top 10, injection, auth review. READ-ONLY.")
191
+ Agent(subagent_type="security-auditor", prompt="Run /cve-scan first, then OWASP Top 10, injection, auth review. READ-ONLY.")
192
192
  Agent(subagent_type="code-reviewer", prompt="Secrets in code, error handling, logging gaps. READ-ONLY.")
193
193
  Agent(subagent_type="devops-implementer", prompt="Infra misconfig, Docker hardening, network. READ-ONLY.")
194
194
  Agent(subagent_type="database-architect", prompt="SQL injection vectors, access controls, encryption. READ-ONLY.")
195
195
  # Sequential:
196
- Agent(subagent_type="tech-lead", prompt="Prioritize findings, assign severity (CVSS).")
197
- Agent(subagent_type="documenter", prompt="Security audit report + remediation checklist. Own files: kb/")
196
+ Agent(subagent_type="tech-lead", prompt="Prioritize findings including CVE scan results, assign severity (CVSS).")
197
+ Agent(subagent_type="documenter", prompt="Security audit report + CVE inventory + remediation checklist. Own files: kb/")
198
198
  ```
199
199
 
200
200
  **`codebase-onboarding`** — understand an unfamiliar codebase fast (READ-ONLY)
@@ -3,9 +3,9 @@ title: "AI Toolkit - Architecture Overview"
3
3
  category: reference
4
4
  service: ai-toolkit
5
5
  tags: [architecture, overview, design, structure]
6
- version: "1.3.10"
6
+ version: "1.3.14"
7
7
  created: "2026-03-23"
8
- last_updated: "2026-04-07"
8
+ last_updated: "2026-04-08"
9
9
  description: "Architecture of ai-toolkit: directory layout, global install model, skill tiers, and integration with projects."
10
10
  ---
11
11
 
@@ -166,7 +166,7 @@ Three tiers determine how to approach a task:
166
166
  | Type | Field | Invocation | Count |
167
167
  |------|-------|-----------|-------|
168
168
  | Task | `disable-model-invocation: true` | User via `/skill` only | 28 |
169
- | Hybrid | (neither) | User via `/skill` + agent knowledge | 30 |
169
+ | Hybrid | (neither) | User via `/skill` + agent knowledge | 31 |
170
170
  | Knowledge | `user-invocable: false` | Claude auto-loads | 32 |
171
171
 
172
172
  ## Multi-Agent Execution
@@ -3,9 +3,9 @@ title: "AI Toolkit - Skills Catalog"
3
3
  category: reference
4
4
  service: ai-toolkit
5
5
  tags: [skills, domain-knowledge, catalog, task-skills, hybrid-skills]
6
- version: "1.3.10"
6
+ version: "1.3.14"
7
7
  created: "2026-03-23"
8
- last_updated: "2026-04-07"
8
+ last_updated: "2026-04-08"
9
9
  description: "Complete skills catalog with task, hybrid, and knowledge skills. Includes effort levels, skill-scoped hooks, executable scripts, security auditor, and persona presets."
10
10
  ---
11
11
 
@@ -56,7 +56,7 @@ Task skills execute a specific action. Invoked via slash commands. `disable-mode
56
56
  | **prd-to-issues** | `/prd-to-issues` | medium | Break PRD into GitHub issues with vertical slices and HITL/AFK tagging |
57
57
  | **skill-audit** | `/skill-audit` | medium | Scan skills and agents for security risks: dangerous patterns, secrets, excessive permissions |
58
58
 
59
- ## Hybrid Skills (30)
59
+ ## Hybrid Skills (31)
60
60
 
61
61
  Hybrid skills combine slash-command invocation with domain knowledge that agents reference.
62
62
 
@@ -68,6 +68,7 @@ Hybrid skills combine slash-command invocation with domain knowledge that agents
68
68
  | **plan** | `/plan` | high | Create structured plan with task breakdown and agent assignments |
69
69
  | **refactor** | `/refactor` | high | Plan and execute code refactoring with safety checks (Tier 1 — single agent) |
70
70
  | **analyze** | `/analyze` | medium | Analyze code quality, complexity, and patterns |
71
+ | **cve-scan** | `/cve-scan` | medium | Scan project dependencies for known CVEs using native audit tools (npm, pip, composer, cargo, go, ruby, dart) |
71
72
  | **docs** | `/docs` | high | Generate/update docs: README, API docs, architecture notes, changelogs (Tier 1 — single agent) |
72
73
  | **search** | `/search` | medium | Search knowledge base (MCP tools with local fallback) |
73
74
  | **explain** | `/explain` | medium | Explain architecture of a file/module using Mermaid diagrams |
package/llms-full.txt CHANGED
@@ -63,6 +63,7 @@
63
63
  - **commit**: Create Conventional Commits with pre-commit validation
64
64
  - **council**: 4-perspective decision evaluation for architecture choices. Use when user wants multi-angle analysis, needs to decide between alternatives, or mentions 'council', 'evaluate decision', 'pros cons'.
65
65
  - **csharp-patterns**: Loaded when user asks about C# or .NET development patterns
66
+ - **cve-scan**: Scan project dependencies for known CVEs using native audit tools (npm, pip, composer, cargo, go, bundler, dart)
66
67
  - **database-patterns**: Loaded when user asks about database schema or query optimization
67
68
  - **debug**: Debug errors and trace root causes systematically
68
69
  - **debugging-tactics**: Loaded when user is debugging an issue or needs root cause analysis
@@ -933,9 +934,9 @@ title: "AI Toolkit - Architecture Overview"
933
934
  category: reference
934
935
  service: ai-toolkit
935
936
  tags: [architecture, overview, design, structure]
936
- version: "1.3.10"
937
+ version: "1.3.14"
937
938
  created: "2026-03-23"
938
- last_updated: "2026-04-07"
939
+ last_updated: "2026-04-08"
939
940
  description: "Architecture of ai-toolkit: directory layout, global install model, skill tiers, and integration with projects."
940
941
  ---
941
942
 
@@ -1096,7 +1097,7 @@ Three tiers determine how to approach a task:
1096
1097
  | Type | Field | Invocation | Count |
1097
1098
  |------|-------|-----------|-------|
1098
1099
  | Task | `disable-model-invocation: true` | User via `/skill` only | 28 |
1099
- | Hybrid | (neither) | User via `/skill` + agent knowledge | 30 |
1100
+ | Hybrid | (neither) | User via `/skill` + agent knowledge | 31 |
1100
1101
  | Knowledge | `user-invocable: false` | Claude auto-loads | 32 |
1101
1102
 
1102
1103
  ## Multi-Agent Execution
@@ -4094,9 +4095,9 @@ title: "AI Toolkit - Skills Catalog"
4094
4095
  category: reference
4095
4096
  service: ai-toolkit
4096
4097
  tags: [skills, domain-knowledge, catalog, task-skills, hybrid-skills]
4097
- version: "1.3.10"
4098
+ version: "1.3.14"
4098
4099
  created: "2026-03-23"
4099
- last_updated: "2026-04-07"
4100
+ last_updated: "2026-04-08"
4100
4101
  description: "Complete skills catalog with task, hybrid, and knowledge skills. Includes effort levels, skill-scoped hooks, executable scripts, security auditor, and persona presets."
4101
4102
  ---
4102
4103
 
@@ -4147,7 +4148,7 @@ Task skills execute a specific action. Invoked via slash commands. `disable-mode
4147
4148
  | **prd-to-issues** | `/prd-to-issues` | medium | Break PRD into GitHub issues with vertical slices and HITL/AFK tagging |
4148
4149
  | **skill-audit** | `/skill-audit` | medium | Scan skills and agents for security risks: dangerous patterns, secrets, excessive permissions |
4149
4150
 
4150
- ## Hybrid Skills (30)
4151
+ ## Hybrid Skills (31)
4151
4152
 
4152
4153
  Hybrid skills combine slash-command invocation with domain knowledge that agents reference.
4153
4154
 
@@ -4159,6 +4160,7 @@ Hybrid skills combine slash-command invocation with domain knowledge that agents
4159
4160
  | **plan** | `/plan` | high | Create structured plan with task breakdown and agent assignments |
4160
4161
  | **refactor** | `/refactor` | high | Plan and execute code refactoring with safety checks (Tier 1 — single agent) |
4161
4162
  | **analyze** | `/analyze` | medium | Analyze code quality, complexity, and patterns |
4163
+ | **cve-scan** | `/cve-scan` | medium | Scan project dependencies for known CVEs using native audit tools (npm, pip, composer, cargo, go, ruby, dart) |
4162
4164
  | **docs** | `/docs` | high | Generate/update docs: README, API docs, architecture notes, changelogs (Tier 1 — single agent) |
4163
4165
  | **search** | `/search` | medium | Search knowledge base (MCP tools with local fallback) |
4164
4166
  | **explain** | `/explain` | medium | Explain architecture of a file/module using Mermaid diagrams |
package/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.12",
2
+ "version": "1.3.14",
3
3
  "components": {
4
4
  "agents": {
5
5
  "description": "44 specialized agents (orchestrator, backend, frontend, security, devops, etc.)",
@@ -9,7 +9,7 @@
9
9
  "tags": ["core", "agents"]
10
10
  },
11
11
  "skills": {
12
- "description": "90 skills (28 task + 30 hybrid + 32 knowledge)",
12
+ "description": "91 skills (28 task + 31 hybrid + 32 knowledge)",
13
13
  "path": "app/skills",
14
14
  "target": ".claude/skills",
15
15
  "type": "symlink",
@@ -90,7 +90,7 @@
90
90
  "default": true
91
91
  },
92
92
  "skills": {
93
- "description": "90 skills (task, hybrid, knowledge)",
93
+ "description": "91 skills (task, hybrid, knowledge)",
94
94
  "default": true
95
95
  },
96
96
  "rules-common": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@softspark/ai-toolkit",
3
- "version": "1.3.13",
4
- "description": "Professional-grade AI coding toolkit: 90 skills, 44 agents, multi-platform support (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, Augment), machine-enforced safety constitution, persona presets, skill security auditor, expanded lifecycle hooks, 11 plugin packs, and benchmark tooling.",
3
+ "version": "1.3.14",
4
+ "description": "Professional-grade AI coding toolkit: 91 skills, 44 agents, multi-platform support (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, Augment), machine-enforced safety constitution, persona presets, skill security auditor, expanded lifecycle hooks, 11 plugin packs, and benchmark tooling.",
5
5
  "keywords": [
6
6
  "claude",
7
7
  "claude-code",
@@ -96,6 +96,58 @@ OPTIONAL = [
96
96
  },
97
97
  "reason": "Running toolkit test suite (npm test)",
98
98
  },
99
+ {
100
+ "name": "pip-audit",
101
+ "check": "pip-audit",
102
+ "packages": {
103
+ "brew": "pip-audit # or: pip install pip-audit",
104
+ "apt": "pip-audit # pip install pip-audit",
105
+ "dnf": "pip-audit # pip install pip-audit",
106
+ "pacman": "pip-audit # pip install pip-audit",
107
+ "apk": "pip-audit # pip install pip-audit",
108
+ "zypper": "pip-audit # pip install pip-audit",
109
+ },
110
+ "reason": "CVE scanner (/cve-scan) for Python dependencies",
111
+ },
112
+ {
113
+ "name": "cargo-audit",
114
+ "check": "cargo-audit",
115
+ "packages": {
116
+ "brew": "cargo-audit # or: cargo install cargo-audit",
117
+ "apt": "cargo-audit # cargo install cargo-audit",
118
+ "dnf": "cargo-audit # cargo install cargo-audit",
119
+ "pacman": "cargo-audit # cargo install cargo-audit",
120
+ "apk": "cargo-audit # cargo install cargo-audit",
121
+ "zypper": "cargo-audit # cargo install cargo-audit",
122
+ },
123
+ "reason": "CVE scanner (/cve-scan) for Rust dependencies",
124
+ },
125
+ {
126
+ "name": "govulncheck",
127
+ "check": "govulncheck",
128
+ "packages": {
129
+ "brew": "govulncheck # go install golang.org/x/vuln/cmd/govulncheck@latest",
130
+ "apt": "govulncheck # go install golang.org/x/vuln/cmd/govulncheck@latest",
131
+ "dnf": "govulncheck # go install golang.org/x/vuln/cmd/govulncheck@latest",
132
+ "pacman": "govulncheck # go install golang.org/x/vuln/cmd/govulncheck@latest",
133
+ "apk": "govulncheck # go install golang.org/x/vuln/cmd/govulncheck@latest",
134
+ "zypper": "govulncheck # go install golang.org/x/vuln/cmd/govulncheck@latest",
135
+ },
136
+ "reason": "CVE scanner (/cve-scan) for Go dependencies",
137
+ },
138
+ {
139
+ "name": "bundle-audit",
140
+ "check": "bundle-audit",
141
+ "packages": {
142
+ "brew": "bundler-audit # or: gem install bundler-audit",
143
+ "apt": "bundler-audit # gem install bundler-audit",
144
+ "dnf": "bundler-audit # gem install bundler-audit",
145
+ "pacman": "bundler-audit # gem install bundler-audit",
146
+ "apk": "bundler-audit # gem install bundler-audit",
147
+ "zypper": "bundler-audit # gem install bundler-audit",
148
+ },
149
+ "reason": "CVE scanner (/cve-scan) for Ruby dependencies",
150
+ },
99
151
  ]
100
152
 
101
153