Skip to content

Commit 7407b42

Browse files
msaad00agent-bom
andauthored
fix: ClawHub trust — optional_env, file_reads justification, source evidence (v0.31.4) (#20)
- Move NVD_API_KEY from requires.env to optional_env with required:false (ClawHub read requires.env as "required" — contradicted "optional" claim) - Add file_reads_justification explaining 27 paths = 11 clients × 2 OS + project - Add Source code evidence section with actual code excerpts from models.py, discovery/__init__.py showing credential handling and config path enumeration - Add test for optional_env, file_reads_justification, source evidence - Version bump 0.31.3 → 0.31.4 - 965 tests pass Co-authored-by: Wagdy Saad <andwgdysaad@gmail.com>
1 parent 86927d5 commit 7407b42

File tree

10 files changed

+99
-25
lines changed

10 files changed

+99
-25
lines changed

Dockerfile.sse

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
FROM python:3.12-slim
1515

16-
ARG VERSION=0.31.3
16+
ARG VERSION=0.31.4
1717

1818
LABEL org.opencontainers.image.title="agent-bom MCP Server"
1919
LABEL org.opencontainers.image.description="AI supply chain security scanner — MCP server with streamable HTTP transport"

PUBLISHING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ npm install -g clawhub@latest
102102
clawhub login --token "$CLAWHUB_TOKEN"
103103
clawhub publish integrations/openclaw \
104104
--slug agent-bom --name "agent-bom" \
105-
--version "0.31.3"
105+
--version "0.31.4"
106106
```
107107

108108
### Verification
@@ -138,8 +138,8 @@ Images published:
138138
Tag push triggers the full pipeline automatically:
139139

140140
```bash
141-
git tag v0.31.3
142-
git push origin v0.31.3
141+
git tag v0.31.4
142+
git push origin v0.31.4
143143
```
144144

145145
This triggers:

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Console, HTML dashboard, SARIF, CycloneDX 1.6, SPDX 3.0, Prometheus, OTLP, JSON,
101101
|----------|------|
102102
| PyPI | `pip install agent-bom` |
103103
| Docker | `docker run agentbom/agent-bom scan` |
104-
| GitHub Action | `uses: msaad00/agent-bom@v0.31.3` |
104+
| GitHub Action | `uses: msaad00/agent-bom@v0.31.4` |
105105
| MCP Registry | [server.json](integrations/mcp-registry/server.json) |
106106
| ToolHive | [registry entry](integrations/toolhive/server.json) |
107107
| OpenClaw | [SKILL.md](integrations/openclaw/SKILL.md) |
@@ -315,7 +315,7 @@ agent-bom scan --aws -f graph -o graph.json # export graph data
315315
|------|---------|----------|
316316
| CLI | `agent-bom scan` | Local audit |
317317
| Pre-install check | `agent-bom check express@4.18.2 -e npm` | Before running MCP servers |
318-
| GitHub Action | `uses: msaad00/agent-bom@v0.31.3` | CI/CD + SARIF |
318+
| GitHub Action | `uses: msaad00/agent-bom@v0.31.4` | CI/CD + SARIF |
319319
| Docker | `docker run agentbom/agent-bom scan` | Isolated scans |
320320
| REST API | `agent-bom api` | Dashboards, SIEM |
321321
| MCP Server | `agent-bom mcp-server` | Inside any MCP client |
@@ -325,7 +325,7 @@ agent-bom scan --aws -f graph -o graph.json # export graph data
325325
### GitHub Action
326326

327327
```yaml
328-
- uses: msaad00/agent-bom@v0.31.3
328+
- uses: msaad00/agent-bom@v0.31.4
329329
with:
330330
severity-threshold: high
331331
upload-sarif: true

integrations/mcp-registry/server.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "io.github.msaad00/agent-bom",
44
"description": "AI supply chain security scanner — CVE scanning, blast radius, policy enforcement, SBOM generation",
55
"title": "agent-bom",
6-
"version": "0.31.3",
6+
"version": "0.31.4",
77
"repository": {
88
"url": "https://github.com/msaad00/agent-bom",
99
"source": "github"
@@ -12,7 +12,7 @@
1212
{
1313
"registryType": "pypi",
1414
"identifier": "agent-bom",
15-
"version": "0.31.3",
15+
"version": "0.31.4",
1616
"transport": {
1717
"type": "stdio"
1818
},

integrations/openclaw/SKILL.md

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
name: agent-bom
33
description: Scan AI agents and MCP servers for CVEs, generate SBOMs, map blast radius, enforce security policies
4-
version: 0.31.3
4+
version: 0.31.4
55
metadata:
66
openclaw:
77
requires:
@@ -10,8 +10,12 @@ metadata:
1010
optional_bins:
1111
- docker
1212
- grype
13-
env:
14-
- NVD_API_KEY
13+
env: []
14+
optional_env:
15+
- name: NVD_API_KEY
16+
purpose: "Increases NVD rate limit from 5 to 50 requests per 30 seconds — not required for any functionality"
17+
sent_only_to: "https://services.nvd.nist.gov"
18+
required: false
1519
emoji: "\U0001F6E1"
1620
homepage: https://github.com/msaad00/agent-bom
1721
source: https://github.com/msaad00/agent-bom
@@ -61,6 +65,16 @@ metadata:
6165
- "docker-compose.yaml"
6266
- "compose.yml"
6367
- "compose.yaml"
68+
file_reads_justification: |
69+
These are the standard config file locations for 11 MCP clients.
70+
Each file is a JSON/YAML config containing MCP server definitions.
71+
agent-bom reads them to discover which MCP servers are configured,
72+
then extracts package names for CVE scanning. On any given system,
73+
only 2-4 of these files typically exist — the rest are silently skipped.
74+
The 27 paths break down as: 11 MCP clients × ~2 OS variants = ~19 global
75+
paths + 5 project-level configs + 4 Docker Compose filenames.
76+
No directory traversal, no glob patterns, no recursive walks.
77+
Use --dry-run to see exactly which files exist on YOUR system.
6478
file_writes: []
6579
network_endpoints:
6680
- url: "https://api.osv.dev/v1/querybatch"
@@ -215,7 +229,7 @@ Users can restrict or bypass auto-discovery entirely:
215229
agent-bom itself optionally uses:
216230
- `NVD_API_KEY` — higher NVD rate limits (optional, never logged or transmitted beyond NVD)
217231

218-
This is declared in `metadata.openclaw.requires.env` above.
232+
This is declared in `metadata.openclaw.optional_env` above. **No env vars are required.**
219233

220234
## Installation
221235

@@ -237,7 +251,7 @@ pipx install agent-bom
237251
### Verify installation
238252
```bash
239253
agent-bom --version
240-
# Should print: agent-bom 0.31.3
254+
# Should print: agent-bom 0.31.4
241255
```
242256

243257
### Verify source
@@ -351,6 +365,50 @@ You can independently verify every claim in this manifest:
351365
| OpenSSF Scorecard | [Scorecard viewer](https://securityscorecards.dev/viewer/?uri=github.com/msaad00/agent-bom) |
352366
| Dry-run audit | `agent-bom scan --dry-run` — shows every file, API, and data element that would be accessed, with a full data audit |
353367

368+
### Source code evidence
369+
370+
The following are actual code excerpts from the agent-bom source that enforce the claims above.
371+
These can be verified at the linked source files.
372+
373+
**Credential names only — values never read** ([models.py:222-233](https://github.com/msaad00/agent-bom/blob/main/src/agent_bom/models.py#L222-L233)):
374+
```python
375+
@property
376+
def credential_names(self) -> list[str]:
377+
"""Return names of env vars that look like credentials."""
378+
sensitive_patterns = [
379+
"key", "token", "secret", "password", "credential",
380+
"api_key", "apikey", "auth", "private",
381+
"connection", "conn_str", "database_url", "db_url",
382+
]
383+
return [
384+
k for k in self.env # self.env is dict of {name: value} but only KEYS are returned
385+
if any(pat in k.lower() for pat in sensitive_patterns)
386+
]
387+
```
388+
389+
**Config parsing extracts structure only** ([discovery/__init__.py:160-167](https://github.com/msaad00/agent-bom/blob/main/src/agent_bom/discovery/__init__.py#L160-L167)):
390+
```python
391+
def parse_mcp_config(config_data: dict, config_path: str) -> list[MCPServer]:
392+
"""Parse MCP server definitions from a config file.
393+
Supports multiple config formats:
394+
- Standard: {"mcpServers": {"name": {"command": ..., "args": [...]}}}
395+
- VS Code: {"servers": {"name": {"type": "stdio", "command": ...}}}
396+
"""
397+
# Only extracts: server name, command, args, env var keys
398+
```
399+
400+
**All file reads are enumerated — no dynamic paths** ([discovery/__init__.py:30-107](https://github.com/msaad00/agent-bom/blob/main/src/agent_bom/discovery/__init__.py#L30-L107)):
401+
```python
402+
CONFIG_LOCATIONS: dict[AgentType, dict[str, list[str]]] = {
403+
AgentType.CLAUDE_DESKTOP: {
404+
"Darwin": ["~/Library/Application Support/Claude/claude_desktop_config.json"],
405+
"Linux": ["~/.config/Claude/claude_desktop_config.json"],
406+
},
407+
# ... 10 more clients, each with hardcoded paths
408+
}
409+
# No dynamic path construction, no user input in paths, no glob patterns
410+
```
411+
354412
### Binary behavior audit
355413

356414
ClawHub notes that `agent-bom` is an external binary not bundled in the skill. To verify it matches the source:

integrations/toolhive/Dockerfile.mcp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM python:3.12-slim
22

3-
ARG VERSION=0.31.3
3+
ARG VERSION=0.31.4
44

55
LABEL maintainer="W S <34316639+msaad00@users.noreply.github.com>"
66
LABEL description="agent-bom MCP Server: AI supply chain security scanning via MCP protocol"

integrations/toolhive/server.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
"name": "io.github.msaad00/agent-bom",
44
"description": "AI supply chain security scanner — CVE scanning, blast radius analysis, policy enforcement, and SBOM generation for MCP servers and AI agents",
55
"title": "agent-bom",
6-
"version": "0.31.3",
6+
"version": "0.31.4",
77
"repository": {
88
"url": "https://github.com/msaad00/agent-bom",
99
"source": "github"
1010
},
1111
"packages": [
1212
{
1313
"registryType": "oci",
14-
"identifier": "ghcr.io/msaad00/agent-bom:v0.31.3",
14+
"identifier": "ghcr.io/msaad00/agent-bom:v0.31.4",
1515
"transport": {
1616
"type": "stdio"
1717
},
@@ -28,7 +28,7 @@
2828
"_meta": {
2929
"io.modelcontextprotocol.registry/publisher-provided": {
3030
"io.github.msaad00": {
31-
"ghcr.io/msaad00/agent-bom:v0.31.3": {
31+
"ghcr.io/msaad00/agent-bom:v0.31.4": {
3232
"tier": "Community",
3333
"status": "Active",
3434
"tags": [

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "agent-bom"
7-
version = "0.31.3"
7+
version = "0.31.4"
88
description = "AI Bill of Materials (AI-BOM) generator — CVE scanning, blast radius, enterprise remediation plans, OWASP LLM Top 10 + MITRE ATLAS + NIST AI RMF threat mapping, LLM-powered enrichment, OpenClaw discovery, MCP runtime introspection, and MCP registry for AI agents."
99
readme = "README.md"
1010
license = {text = "Apache-2.0"}

src/agent_bom/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
try:
66
__version__ = version("agent-bom")
77
except PackageNotFoundError:
8-
__version__ = "0.31.3"
8+
__version__ = "0.31.4"

tests/test_core.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def empty_report():
255255

256256
def test_version_sync():
257257
from agent_bom import __version__
258-
assert __version__ == "0.31.3"
258+
assert __version__ == "0.31.4"
259259

260260

261261
def test_report_version_matches():
@@ -2795,7 +2795,7 @@ def test_toolhive_server_json_valid():
27952795
p = Path(__file__).parent.parent / "integrations" / "toolhive" / "server.json"
27962796
data = _json.loads(p.read_text())
27972797
assert data["name"] == "io.github.msaad00/agent-bom"
2798-
assert data["version"] == "0.31.3"
2798+
assert data["version"] == "0.31.4"
27992799
assert "packages" in data
28002800
assert data["packages"][0]["registryType"] == "oci"
28012801

@@ -2847,13 +2847,15 @@ def test_openclaw_skill_declares_network_endpoints():
28472847

28482848

28492849
def test_openclaw_skill_declares_env():
2850-
"""OpenClaw SKILL.md manifest should declare required env vars."""
2850+
"""OpenClaw SKILL.md manifest should declare NVD_API_KEY as optional, not required."""
28512851
from pathlib import Path
28522852
p = Path(__file__).parent.parent / "integrations" / "openclaw" / "SKILL.md"
28532853
content = p.read_text()
28542854
assert "requires:" in content
2855-
assert "env:" in content
2855+
assert "env: []" in content, "requires.env should be empty — no env vars are required"
2856+
assert "optional_env:" in content
28562857
assert "NVD_API_KEY" in content
2858+
assert "required: false" in content
28572859

28582860

28592861
def test_openclaw_skill_has_all_install_methods():
@@ -2875,6 +2877,19 @@ def test_openclaw_skill_has_verification_section():
28752877
assert "cosign verify-blob" in content
28762878
assert "Binary behavior audit" in content
28772879
assert "--dry-run" in content
2880+
# Source code evidence for binary verifiability
2881+
assert "Source code evidence" in content
2882+
assert "credential_names" in content
2883+
assert "CONFIG_LOCATIONS" in content
2884+
2885+
2886+
def test_openclaw_skill_has_file_reads_justification():
2887+
"""OpenClaw SKILL.md should justify the broad file_reads list."""
2888+
from pathlib import Path
2889+
p = Path(__file__).parent.parent / "integrations" / "openclaw" / "SKILL.md"
2890+
content = p.read_text()
2891+
assert "file_reads_justification:" in content
2892+
assert "silently skipped" in content
28782893

28792894

28802895
def test_openclaw_skill_nvd_auth_consistent():
@@ -2899,6 +2914,7 @@ def test_openclaw_skill_nvd_auth_consistent():
28992914
def test_cli_dry_run_shows_data_audit():
29002915
"""--dry-run should include Data Audit section showing what gets extracted and sent."""
29012916
from click.testing import CliRunner
2917+
29022918
from agent_bom.cli import main
29032919
runner = CliRunner()
29042920
result = runner.invoke(main, ["scan", "--dry-run"])
@@ -2952,7 +2968,7 @@ def test_badge_output_clean():
29522968

29532969
def test_badge_output_with_vulns():
29542970
"""Badge output should reflect vulnerability severity."""
2955-
from agent_bom.models import AIBOMReport, Agent, AgentType, MCPServer, Package, Vulnerability, Severity
2971+
from agent_bom.models import Agent, AgentType, AIBOMReport, MCPServer, Package, Severity, Vulnerability
29562972
report = AIBOMReport()
29572973
vuln = Vulnerability(id="CVE-2024-0001", severity=Severity.HIGH, summary="test")
29582974
pkg = Package(name="test-pkg", version="1.0.0", ecosystem="npm", vulnerabilities=[vuln])

0 commit comments

Comments
 (0)