agentsentinel-cli 0.7.2__tar.gz → 0.7.4__tar.gz
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.
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/PKG-INFO +1 -1
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/cli.py +24 -4
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/discover.py +33 -10
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/pyproject.toml +1 -1
- agentsentinel_cli-0.7.4/tmp/note.md +4 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/.gitignore +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/DOCUMENTATION.md +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/LICENSE +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/README.md +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/__init__.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/a2a_report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/a2a_rules.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/a2a_scanner.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/agent_mode.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/agent_mode_report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/ai_probe.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/attacks/__init__.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/attacks/library.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/discover_report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/fingerprint.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/frameworks.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/inspect.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/inspect_report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/mcp_client.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/mcp_report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/mcp_rules.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/probe.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/probe_report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/rules.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/scanner.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/secrets.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/secrets_report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/secrets_rules.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/supply_chain_ai.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/supply_chain_report.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/supply_chain_rules.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/suppress.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/target.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/tmp/test-mcp-agent/README.md +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/tmp/test-mcp-agent/langchain_agent.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/tmp/test-mcp-agent/mcp_server.py +0 -0
- {agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/tmp/test-mcp-agent/requirements.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentsentinel-cli
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.4
|
|
4
4
|
Summary: Agentic security CLI — AI analyst with memory, supply chain audit, MCP audit, red-team probing, and agent discovery
|
|
5
5
|
Project-URL: Homepage, https://github.com/jaydenaung/agentsentinel-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/jaydenaung/agentsentinel-cli
|
|
@@ -128,6 +128,8 @@ def _enrich_from_platform(agents, scores_map, connect_url, api_key):
|
|
|
128
128
|
help="Probe local ports — confirmed via MCP protocol handshake.")
|
|
129
129
|
@click.option("--docker/--no-docker", default=False, show_default=True,
|
|
130
130
|
help="Inspect running Docker containers for MCP/agent patterns.")
|
|
131
|
+
@click.option("--host", default=None, metavar="IP",
|
|
132
|
+
help="Scan a single host, e.g. 10.0.1.45.")
|
|
131
133
|
@click.option("--subnet", default=None, metavar="CIDR",
|
|
132
134
|
help="Scan a CIDR subnet for MCP servers, e.g. 10.0.0.0/24.")
|
|
133
135
|
@click.option("--ports", default=None, metavar="RANGE",
|
|
@@ -142,6 +144,7 @@ def discover(
|
|
|
142
144
|
process: bool,
|
|
143
145
|
network: bool,
|
|
144
146
|
docker: bool,
|
|
147
|
+
host: str | None,
|
|
145
148
|
subnet: str | None,
|
|
146
149
|
ports: str | None,
|
|
147
150
|
auth_header: str | None,
|
|
@@ -151,12 +154,12 @@ def discover(
|
|
|
151
154
|
"""Find MCP servers and AI agent processes in your environment.
|
|
152
155
|
|
|
153
156
|
Confirms MCP servers via protocol handshake — not just open ports.
|
|
154
|
-
Use --subnet to scan across a network range.
|
|
155
157
|
|
|
156
158
|
\b
|
|
157
159
|
Examples:
|
|
158
160
|
sentinel discover local processes + ports
|
|
159
|
-
sentinel discover --
|
|
161
|
+
sentinel discover --host 10.0.1.45 single remote host
|
|
162
|
+
sentinel discover --subnet 10.0.0.0/24 full subnet scan
|
|
160
163
|
sentinel discover --subnet 10.0.0.0/24 \\
|
|
161
164
|
--auth-header 'Authorization: Bearer token' scan with credentials
|
|
162
165
|
sentinel discover --no-process network only
|
|
@@ -164,7 +167,7 @@ def discover(
|
|
|
164
167
|
sentinel discover --ports 8000-9001 custom port range
|
|
165
168
|
sentinel discover --format json machine-readable output
|
|
166
169
|
"""
|
|
167
|
-
from agentsentinel_cli.discover import run_discovery, as_json as discover_json
|
|
170
|
+
from agentsentinel_cli.discover import run_discovery, scan_network, as_json as discover_json
|
|
168
171
|
from agentsentinel_cli.discover_report import print_discover_result, print_subnet_progress
|
|
169
172
|
|
|
170
173
|
# Parse port range
|
|
@@ -179,6 +182,23 @@ def discover(
|
|
|
179
182
|
key, _, val = auth_header.partition(":")
|
|
180
183
|
extra_headers[key.strip()] = val.strip()
|
|
181
184
|
|
|
185
|
+
# --host: single-host scan — bypass run_discovery and call scan_network directly
|
|
186
|
+
if host:
|
|
187
|
+
if fmt == "text":
|
|
188
|
+
_warn_missing_deps(False, True)
|
|
189
|
+
agents = scan_network(
|
|
190
|
+
host=host,
|
|
191
|
+
ports=port_list,
|
|
192
|
+
extra_headers=extra_headers or None,
|
|
193
|
+
)
|
|
194
|
+
if fmt == "json":
|
|
195
|
+
click.echo(discover_json(agents))
|
|
196
|
+
return
|
|
197
|
+
print_discover_result(agents, vectors=[f"host ({host})"], verbose=verbose)
|
|
198
|
+
if any(a.risk == "CRITICAL" for a in agents):
|
|
199
|
+
sys.exit(1)
|
|
200
|
+
return
|
|
201
|
+
|
|
182
202
|
# Collect active scan vectors for the header
|
|
183
203
|
vectors = []
|
|
184
204
|
if process:
|
|
@@ -192,7 +212,7 @@ def discover(
|
|
|
192
212
|
|
|
193
213
|
if not vectors:
|
|
194
214
|
console.print("[yellow]No scan vectors selected — use at least one of: "
|
|
195
|
-
"--process, --network, --subnet, --docker[/yellow]")
|
|
215
|
+
"--process, --network, --host, --subnet, --docker[/yellow]")
|
|
196
216
|
sys.exit(1)
|
|
197
217
|
|
|
198
218
|
if fmt == "text":
|
|
@@ -379,6 +379,23 @@ def scan_subnet(
|
|
|
379
379
|
|
|
380
380
|
# ── MCP protocol prober ───────────────────────────────────────────────────────
|
|
381
381
|
|
|
382
|
+
def _auth_is_enforced(base: str, timeout: float) -> bool:
|
|
383
|
+
"""Return True only if the server actively rejects unauthenticated requests.
|
|
384
|
+
|
|
385
|
+
Probes without credentials. McpAuthRequired (401/403) → enforced.
|
|
386
|
+
Successful handshake → not enforced (server accepts anyone).
|
|
387
|
+
Any other error → assume not enforced (conservative — don't hide risk).
|
|
388
|
+
"""
|
|
389
|
+
from agentsentinel_cli.mcp_client import scan_http, McpAuthRequired, McpError
|
|
390
|
+
try:
|
|
391
|
+
scan_http(base, extra_headers=None, timeout=timeout)
|
|
392
|
+
return False
|
|
393
|
+
except McpAuthRequired:
|
|
394
|
+
return True
|
|
395
|
+
except (McpError, Exception):
|
|
396
|
+
return False
|
|
397
|
+
|
|
398
|
+
|
|
382
399
|
def _probe_mcp(
|
|
383
400
|
host: str,
|
|
384
401
|
port: int,
|
|
@@ -423,28 +440,34 @@ def _probe_mcp(
|
|
|
423
440
|
except Exception:
|
|
424
441
|
return None
|
|
425
442
|
|
|
426
|
-
# Handshake succeeded — assess risk based on actual tool content
|
|
443
|
+
# Handshake succeeded — assess risk based on actual tool content and whether
|
|
444
|
+
# the server actually enforces authentication.
|
|
427
445
|
tool_names = [t.name for t in server.tools]
|
|
428
446
|
has_dangerous = any(t.is_dangerous for t in server.tools)
|
|
429
447
|
has_write = any(t.scope == "write" for t in server.tools)
|
|
430
|
-
auth_present = bool(extra_headers)
|
|
431
448
|
|
|
432
|
-
|
|
449
|
+
# When credentials were provided, verify the server actually requires them.
|
|
450
|
+
# If it accepts a probe WITHOUT credentials too, auth is not enforced — the
|
|
451
|
+
# server is still open to anyone and the risk doesn't change.
|
|
452
|
+
auth_enforced = False
|
|
453
|
+
if extra_headers:
|
|
454
|
+
auth_enforced = _auth_is_enforced(base, timeout)
|
|
455
|
+
|
|
456
|
+
if not extra_headers or not auth_enforced:
|
|
433
457
|
if has_dangerous or has_write:
|
|
434
458
|
risk = "CRITICAL"
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
f"{', '.join(t.name for t in server.tools if t.is_dangerous or t.scope == 'write')}"
|
|
438
|
-
)
|
|
459
|
+
bad = ", ".join(t.name for t in server.tools if t.is_dangerous or t.scope == "write")
|
|
460
|
+
risk_reason = f"Unauthenticated MCP server with dangerous/write tools: {bad}"
|
|
439
461
|
else:
|
|
462
|
+
n = len(server.tools)
|
|
440
463
|
risk = "HIGH"
|
|
441
464
|
risk_reason = (
|
|
442
|
-
f"Unauthenticated MCP server — {
|
|
443
|
-
f"{'s' if len(server.tools) != 1 else ''} publicly accessible"
|
|
465
|
+
f"Unauthenticated MCP server — {n} tool{'s' if n != 1 else ''} publicly accessible"
|
|
444
466
|
)
|
|
445
467
|
else:
|
|
468
|
+
n = len(server.tools)
|
|
446
469
|
risk = "LOW"
|
|
447
|
-
risk_reason = f"MCP server (
|
|
470
|
+
risk_reason = f"MCP server (auth enforced) — {n} tool{'s' if n != 1 else ''} enumerated"
|
|
448
471
|
|
|
449
472
|
scan_url = f"{base}/sse" if server.transport == "sse" else base
|
|
450
473
|
auth_flag = (
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentsentinel-cli"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.4"
|
|
8
8
|
description = "Agentic security CLI — AI analyst with memory, supply chain audit, MCP audit, red-team probing, and agent discovery"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentsentinel_cli-0.7.2 → agentsentinel_cli-0.7.4}/agentsentinel_cli/supply_chain_report.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|