agentsentinel-cli 0.7.4__tar.gz → 0.7.6__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.4 → agentsentinel_cli-0.7.6}/PKG-INFO +1 -1
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/a2a_rules.py +0 -1
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/cli.py +64 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/mcp_rules.py +42 -37
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/rules.py +10 -20
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/pyproject.toml +1 -1
- agentsentinel_cli-0.7.6/tmp/note.md +16 -0
- agentsentinel_cli-0.7.4/tmp/note.md +0 -4
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/.gitignore +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/DOCUMENTATION.md +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/LICENSE +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/README.md +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/__init__.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/a2a_report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/a2a_scanner.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/agent_mode.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/agent_mode_report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/ai_probe.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/attacks/__init__.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/attacks/library.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/discover.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/discover_report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/fingerprint.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/frameworks.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/inspect.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/inspect_report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/mcp_client.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/mcp_report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/probe.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/probe_report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/scanner.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/secrets.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/secrets_report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/secrets_rules.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/supply_chain_ai.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/supply_chain_report.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/supply_chain_rules.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/suppress.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/agentsentinel_cli/target.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/tmp/test-mcp-agent/README.md +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/tmp/test-mcp-agent/langchain_agent.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/tmp/test-mcp-agent/mcp_server.py +0 -0
- {agentsentinel_cli-0.7.4 → agentsentinel_cli-0.7.6}/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.6
|
|
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
|
|
@@ -119,6 +119,60 @@ def _enrich_from_platform(agents, scores_map, connect_url, api_key):
|
|
|
119
119
|
console.print(f" [dim yellow]Warning: could not connect to AgentSentinel: {exc}[/dim yellow]")
|
|
120
120
|
|
|
121
121
|
|
|
122
|
+
# ── sentinel discover helpers ────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
def _deep_scan_agents(agents: list, extra_headers: dict | None) -> None:
|
|
125
|
+
"""Run mcp scan rules on every confirmed network MCP server from a discover run."""
|
|
126
|
+
from agentsentinel_cli.discover import DiscoveredAgent
|
|
127
|
+
from agentsentinel_cli.mcp_client import scan_http, McpAuthRequired, McpError
|
|
128
|
+
from agentsentinel_cli.mcp_rules import McpContext, run_mcp_rules, mcp_posture_score
|
|
129
|
+
from agentsentinel_cli.mcp_report import print_mcp_result
|
|
130
|
+
from agentsentinel_cli import suppress as _suppress
|
|
131
|
+
|
|
132
|
+
network_agents = [a for a in agents if a.source == "network"]
|
|
133
|
+
if not network_agents:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
console.print()
|
|
137
|
+
console.rule("[bold bright_blue]DEEP SCAN[/bold bright_blue]", style="bright_blue")
|
|
138
|
+
|
|
139
|
+
sup_rules = _suppress.load_ignore_file(Path.cwd())
|
|
140
|
+
|
|
141
|
+
for agent in network_agents:
|
|
142
|
+
base = f"http://{agent.location}"
|
|
143
|
+
scan_url = f"{base}/sse" if agent.transport == "sse" else base
|
|
144
|
+
|
|
145
|
+
# Auth-required servers need credentials — skip silently if none provided
|
|
146
|
+
if not agent.tools and not extra_headers:
|
|
147
|
+
console.print(
|
|
148
|
+
f"\n [dim]Skipping {agent.location} — auth required, "
|
|
149
|
+
f"use --auth-header to deep scan[/dim]"
|
|
150
|
+
)
|
|
151
|
+
continue
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
server = scan_http(scan_url, extra_headers=extra_headers, timeout=15)
|
|
155
|
+
except McpAuthRequired:
|
|
156
|
+
console.print(
|
|
157
|
+
f"\n [dim]Skipping {agent.location} — credentials rejected[/dim]"
|
|
158
|
+
)
|
|
159
|
+
continue
|
|
160
|
+
except (McpError, Exception):
|
|
161
|
+
console.print(
|
|
162
|
+
f"\n [dim]Skipping {agent.location} — could not reconnect[/dim]"
|
|
163
|
+
)
|
|
164
|
+
continue
|
|
165
|
+
|
|
166
|
+
# auth_required: True when the server actually enforces auth (risk LOW/MEDIUM)
|
|
167
|
+
auth_required = agent.risk in ("LOW", "MEDIUM")
|
|
168
|
+
ctx = McpContext(server=server, auth_required=auth_required)
|
|
169
|
+
findings = run_mcp_rules(ctx)
|
|
170
|
+
findings, _ = _suppress.apply(findings, sup_rules)
|
|
171
|
+
score = mcp_posture_score(findings)
|
|
172
|
+
|
|
173
|
+
print_mcp_result(ctx, findings, score, scan_url)
|
|
174
|
+
|
|
175
|
+
|
|
122
176
|
# ── sentinel discover ─────────────────────────────────────────────────────────
|
|
123
177
|
|
|
124
178
|
@main.command()
|
|
@@ -136,6 +190,8 @@ def _enrich_from_platform(agents, scores_map, connect_url, api_key):
|
|
|
136
190
|
help="Custom port range, e.g. 8000-9001. Defaults to common MCP/agent ports.")
|
|
137
191
|
@click.option("--auth-header", "auth_header", default=None, metavar="HEADER",
|
|
138
192
|
help="HTTP auth header for MCP handshakes, e.g. 'Authorization: Bearer token'.")
|
|
193
|
+
@click.option("--scan", "do_scan", is_flag=True, default=False,
|
|
194
|
+
help="Deep-scan every confirmed MCP server with sentinel mcp scan rules.")
|
|
139
195
|
@click.option("--format", "fmt", type=click.Choice(["text", "json"]), default="text",
|
|
140
196
|
help="Output format.")
|
|
141
197
|
@click.option("--verbose", "-v", is_flag=True, default=False,
|
|
@@ -148,17 +204,20 @@ def discover(
|
|
|
148
204
|
subnet: str | None,
|
|
149
205
|
ports: str | None,
|
|
150
206
|
auth_header: str | None,
|
|
207
|
+
do_scan: bool,
|
|
151
208
|
fmt: str,
|
|
152
209
|
verbose: bool,
|
|
153
210
|
) -> None:
|
|
154
211
|
"""Find MCP servers and AI agent processes in your environment.
|
|
155
212
|
|
|
156
213
|
Confirms MCP servers via protocol handshake — not just open ports.
|
|
214
|
+
Add --scan to deep-audit every confirmed server in the same run.
|
|
157
215
|
|
|
158
216
|
\b
|
|
159
217
|
Examples:
|
|
160
218
|
sentinel discover local processes + ports
|
|
161
219
|
sentinel discover --host 10.0.1.45 single remote host
|
|
220
|
+
sentinel discover --host 10.0.1.45 --scan discover + deep audit
|
|
162
221
|
sentinel discover --subnet 10.0.0.0/24 full subnet scan
|
|
163
222
|
sentinel discover --subnet 10.0.0.0/24 \\
|
|
164
223
|
--auth-header 'Authorization: Bearer token' scan with credentials
|
|
@@ -195,6 +254,8 @@ def discover(
|
|
|
195
254
|
click.echo(discover_json(agents))
|
|
196
255
|
return
|
|
197
256
|
print_discover_result(agents, vectors=[f"host ({host})"], verbose=verbose)
|
|
257
|
+
if do_scan:
|
|
258
|
+
_deep_scan_agents(agents, extra_headers or None)
|
|
198
259
|
if any(a.risk == "CRITICAL" for a in agents):
|
|
199
260
|
sys.exit(1)
|
|
200
261
|
return
|
|
@@ -237,6 +298,9 @@ def discover(
|
|
|
237
298
|
|
|
238
299
|
print_discover_result(agents, vectors=vectors, verbose=verbose, subnet_stats=subnet_stats)
|
|
239
300
|
|
|
301
|
+
if do_scan:
|
|
302
|
+
_deep_scan_agents(agents, extra_headers or None)
|
|
303
|
+
|
|
240
304
|
# Exit 1 if any CRITICAL agents found (useful for CI)
|
|
241
305
|
if any(a.risk == "CRITICAL" for a in agents):
|
|
242
306
|
sys.exit(1)
|
|
@@ -114,15 +114,26 @@ def _rule_code_execution(ctx: McpContext) -> McpFinding | None:
|
|
|
114
114
|
|
|
115
115
|
|
|
116
116
|
def _rule_unbounded_input(ctx: McpContext) -> McpFinding | None:
|
|
117
|
-
"""HIGH:
|
|
117
|
+
"""HIGH: dangerous string parameters have no input constraints. (OWASP LLM01)
|
|
118
|
+
|
|
119
|
+
Only flags parameters whose names suggest they feed dangerous operations —
|
|
120
|
+
shell commands, SQL queries, file paths, URLs, code. Generic string fields
|
|
121
|
+
(name, title, message, body) are not flagged.
|
|
122
|
+
"""
|
|
123
|
+
_DANGEROUS_PARAMS = frozenset({
|
|
124
|
+
"command", "cmd", "shell", "shell_command",
|
|
125
|
+
"query", "sql", "sql_query", "expression",
|
|
126
|
+
"path", "file_path", "filepath", "filename", "directory", "dir",
|
|
127
|
+
"url", "uri", "endpoint", "webhook", "target",
|
|
128
|
+
"code", "script", "template", "prompt",
|
|
129
|
+
})
|
|
130
|
+
|
|
118
131
|
unvalidated: list[str] = []
|
|
119
132
|
for tool in ctx.server.tools:
|
|
120
|
-
|
|
121
|
-
props = schema.get("properties", {})
|
|
122
|
-
if not props and schema.get("type") == "object":
|
|
123
|
-
unvalidated.append(f"{tool.name} (no schema)")
|
|
124
|
-
continue
|
|
133
|
+
props = tool.input_schema.get("properties", {})
|
|
125
134
|
for prop_name, prop_def in props.items():
|
|
135
|
+
if prop_name.lower() not in _DANGEROUS_PARAMS:
|
|
136
|
+
continue
|
|
126
137
|
if (
|
|
127
138
|
prop_def.get("type") == "string"
|
|
128
139
|
and "maxLength" not in prop_def
|
|
@@ -130,7 +141,6 @@ def _rule_unbounded_input(ctx: McpContext) -> McpFinding | None:
|
|
|
130
141
|
and "pattern" not in prop_def
|
|
131
142
|
):
|
|
132
143
|
unvalidated.append(f"{tool.name}.{prop_name}")
|
|
133
|
-
break
|
|
134
144
|
|
|
135
145
|
if unvalidated:
|
|
136
146
|
sample = unvalidated[:5]
|
|
@@ -139,24 +149,29 @@ def _rule_unbounded_input(ctx: McpContext) -> McpFinding | None:
|
|
|
139
149
|
severity="HIGH",
|
|
140
150
|
rule_id="UNBOUNDED_INPUT",
|
|
141
151
|
message=(
|
|
142
|
-
"
|
|
143
|
-
"
|
|
152
|
+
"Dangerous parameters (command, path, query, url, code) accept unconstrained "
|
|
153
|
+
"string input. No maxLength, enum, or pattern — injection payloads pass through directly."
|
|
144
154
|
),
|
|
145
|
-
detail=f"Unconstrained inputs: {', '.join(sample)}{suffix}",
|
|
155
|
+
detail=f"Unconstrained dangerous inputs: {', '.join(sample)}{suffix}",
|
|
146
156
|
)
|
|
147
157
|
return None
|
|
148
158
|
|
|
149
159
|
|
|
150
160
|
def _rule_tool_sprawl(ctx: McpContext) -> McpFinding | None:
|
|
151
|
-
"""MEDIUM:
|
|
161
|
+
"""MEDIUM: high tool count across many categories increases blast radius. (OWASP LLM06)
|
|
162
|
+
|
|
163
|
+
Requires BOTH high count AND diverse categories. A server with 14 file-system
|
|
164
|
+
tools is a focused file manager. A server with 12 tools spanning code execution,
|
|
165
|
+
email, database, and web is a broad attack surface.
|
|
166
|
+
"""
|
|
152
167
|
categories = {t.category for t in ctx.server.tools} - {"other"}
|
|
153
|
-
if len(ctx.server.tools) > 10
|
|
168
|
+
if len(ctx.server.tools) > 10 and len(categories) >= 5:
|
|
154
169
|
return McpFinding(
|
|
155
170
|
severity="MEDIUM",
|
|
156
171
|
rule_id="TOOL_SPRAWL",
|
|
157
172
|
message=(
|
|
158
|
-
f"Server exposes {len(ctx.server.tools)} tools across {len(categories)}
|
|
159
|
-
"
|
|
173
|
+
f"Server exposes {len(ctx.server.tools)} tools across {len(categories)} "
|
|
174
|
+
"distinct categories. High cross-category diversity increases blast radius."
|
|
160
175
|
),
|
|
161
176
|
detail=f"Categories: {', '.join(sorted(categories))}",
|
|
162
177
|
)
|
|
@@ -164,33 +179,25 @@ def _rule_tool_sprawl(ctx: McpContext) -> McpFinding | None:
|
|
|
164
179
|
|
|
165
180
|
|
|
166
181
|
def _rule_vague_descriptions(ctx: McpContext) -> McpFinding | None:
|
|
167
|
-
"""MEDIUM:
|
|
168
|
-
|
|
182
|
+
"""MEDIUM: missing or single-word tool descriptions expand prompt injection surface. (OWASP LLM01)
|
|
183
|
+
|
|
184
|
+
Flags descriptions with fewer than 3 words — empty, one-word, or two-word
|
|
185
|
+
descriptions give the LLM no context about what the tool does or what it
|
|
186
|
+
should NOT do.
|
|
187
|
+
"""
|
|
188
|
+
vague = [
|
|
189
|
+
t.name for t in ctx.server.tools
|
|
190
|
+
if len(t.description.strip().split()) < 3
|
|
191
|
+
]
|
|
169
192
|
if len(vague) >= 2:
|
|
170
193
|
return McpFinding(
|
|
171
194
|
severity="MEDIUM",
|
|
172
195
|
rule_id="VAGUE_TOOL_DESCRIPTIONS",
|
|
173
196
|
message=(
|
|
174
|
-
"Multiple tools have
|
|
175
|
-
"
|
|
176
|
-
),
|
|
177
|
-
detail=f"Thin descriptions on: {', '.join(vague[:5])}{'…' if len(vague) > 5 else ''}",
|
|
178
|
-
)
|
|
179
|
-
return None
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
def _rule_missing_rate_limit(ctx: McpContext) -> McpFinding | None:
|
|
183
|
-
"""LOW: MCP protocol has no built-in rate limiting. (OWASP LLM06)"""
|
|
184
|
-
dangerous = [t.name for t in ctx.server.tools if t.is_dangerous]
|
|
185
|
-
if dangerous:
|
|
186
|
-
return McpFinding(
|
|
187
|
-
severity="LOW",
|
|
188
|
-
rule_id="MISSING_RATE_LIMIT",
|
|
189
|
-
message=(
|
|
190
|
-
"Dangerous tools detected. MCP has no built-in rate limiting — "
|
|
191
|
-
"ensure the server layer enforces per-client call limits."
|
|
197
|
+
"Multiple tools have absent or near-absent descriptions (fewer than 3 words). "
|
|
198
|
+
"Without clear descriptions the LLM cannot reason about safe tool use."
|
|
192
199
|
),
|
|
193
|
-
detail=f"
|
|
200
|
+
detail=f"Absent descriptions: {', '.join(vague[:5])}{'…' if len(vague) > 5 else ''}",
|
|
194
201
|
)
|
|
195
202
|
return None
|
|
196
203
|
|
|
@@ -206,8 +213,6 @@ _ALL_RULES = [
|
|
|
206
213
|
# MEDIUM
|
|
207
214
|
_rule_tool_sprawl,
|
|
208
215
|
_rule_vague_descriptions,
|
|
209
|
-
# LOW
|
|
210
|
-
_rule_missing_rate_limit,
|
|
211
216
|
]
|
|
212
217
|
|
|
213
218
|
_SEVERITY_WEIGHT = {"CRITICAL": 40, "HIGH": 20, "MEDIUM": 10, "LOW": 5}
|
|
@@ -145,27 +145,32 @@ def _rule_privilege_excess(agent: AgentInfo) -> Finding | None:
|
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
def _rule_dangerous_grants(agent: AgentInfo) -> Finding | None:
|
|
148
|
-
|
|
148
|
+
# Exclude code_execution tools — CODE_EXECUTION_GRANT already covers them at CRITICAL.
|
|
149
|
+
# This rule catches dangerous tools outside that category (e.g. send_email, delete_record).
|
|
150
|
+
dangerous = [
|
|
151
|
+
t.name for t in agent.tools
|
|
152
|
+
if t.is_dangerous and t.category not in _CODE_EXEC_CATEGORIES
|
|
153
|
+
]
|
|
149
154
|
if dangerous:
|
|
150
155
|
return Finding(
|
|
151
156
|
severity="HIGH",
|
|
152
157
|
rule_id="DANGEROUS_GRANTS",
|
|
153
|
-
message="Agent holds dangerous tool grants. Verify intent
|
|
158
|
+
message="Agent holds dangerous tool grants outside code execution. Verify intent.",
|
|
154
159
|
detail=f"Dangerous tools: {', '.join(dangerous)}",
|
|
155
160
|
)
|
|
156
161
|
return None
|
|
157
162
|
|
|
158
163
|
|
|
159
164
|
def _rule_tool_sprawl(agent: AgentInfo) -> Finding | None:
|
|
160
|
-
"""MEDIUM:
|
|
165
|
+
"""MEDIUM: high tool count across many categories — blast radius scales with diversity."""
|
|
161
166
|
categories = {t.category for t in agent.tools if t.category != "other"}
|
|
162
|
-
if len(agent.tools) > 10
|
|
167
|
+
if len(agent.tools) > 10 and len(categories) >= 5:
|
|
163
168
|
return Finding(
|
|
164
169
|
severity="MEDIUM",
|
|
165
170
|
rule_id="TOOL_SPRAWL",
|
|
166
171
|
message=(
|
|
167
172
|
f"Agent holds {len(agent.tools)} tools across {len(categories)} categories. "
|
|
168
|
-
"
|
|
173
|
+
"High cross-category diversity increases blast radius."
|
|
169
174
|
),
|
|
170
175
|
detail=f"Categories present: {', '.join(sorted(categories))}",
|
|
171
176
|
)
|
|
@@ -187,19 +192,6 @@ def _rule_write_without_description(agent: AgentInfo) -> Finding | None:
|
|
|
187
192
|
return None
|
|
188
193
|
|
|
189
194
|
|
|
190
|
-
def _rule_missing_rate_limit(agent: AgentInfo) -> Finding | None:
|
|
191
|
-
"""Flag dangerous tools — rate limits aren't visible in static analysis."""
|
|
192
|
-
dangerous = [t.name for t in agent.tools if t.is_dangerous]
|
|
193
|
-
if dangerous:
|
|
194
|
-
return Finding(
|
|
195
|
-
severity="LOW",
|
|
196
|
-
rule_id="MISSING_RATE_LIMIT",
|
|
197
|
-
message="Dangerous grants detected. Ensure rate limits are configured at runtime.",
|
|
198
|
-
detail=f"Tools to check: {', '.join(dangerous)}",
|
|
199
|
-
)
|
|
200
|
-
return None
|
|
201
|
-
|
|
202
|
-
|
|
203
195
|
_ALL_RULES = [
|
|
204
196
|
# CRITICAL
|
|
205
197
|
_rule_exfiltration_path,
|
|
@@ -215,8 +207,6 @@ _ALL_RULES = [
|
|
|
215
207
|
# MEDIUM
|
|
216
208
|
_rule_tool_sprawl,
|
|
217
209
|
_rule_write_without_description,
|
|
218
|
-
# LOW
|
|
219
|
-
_rule_missing_rate_limit,
|
|
220
210
|
]
|
|
221
211
|
|
|
222
212
|
_SEVERITY_WEIGHT = {"CRITICAL": 40, "HIGH": 20, "MEDIUM": 10, "LOW": 5}
|
|
@@ -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.6"
|
|
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"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Notes
|
|
2
|
+
ls dist/
|
|
3
|
+
|
|
4
|
+
python3.11 -m build
|
|
5
|
+
twine upload dist/agentsentinel_cli-0.7.3* --username __token__ --password $PYPI_TOKEN
|
|
6
|
+
|
|
7
|
+
lsof -i :8000
|
|
8
|
+
lsof -ti :8000
|
|
9
|
+
|
|
10
|
+
kill $(lsof -ti :8000)
|
|
11
|
+
|
|
12
|
+
kill -9 $(lsof -ti :8000)
|
|
13
|
+
|
|
14
|
+
nsenter -t <PID> -m -u -i -n -p -- /bin/bash
|
|
15
|
+
|
|
16
|
+
ps -p <PID> -o pid,ppid,command
|
|
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.4 → agentsentinel_cli-0.7.6}/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
|