reachscan 0.1.0__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.
- reachscan-0.1.0/LICENSE +90 -0
- reachscan-0.1.0/PKG-INFO +329 -0
- reachscan-0.1.0/README.md +312 -0
- reachscan-0.1.0/pyproject.toml +32 -0
- reachscan-0.1.0/setup.cfg +4 -0
- reachscan-0.1.0/src/reachscan/__init__.py +0 -0
- reachscan-0.1.0/src/reachscan/analysis/__init__.py +6 -0
- reachscan-0.1.0/src/reachscan/analysis/finding_enrichment.py +85 -0
- reachscan-0.1.0/src/reachscan/analysis/impact.py +81 -0
- reachscan-0.1.0/src/reachscan/call_graph.py +474 -0
- reachscan-0.1.0/src/reachscan/cli.py +85 -0
- reachscan-0.1.0/src/reachscan/detectors/__init__.py +6 -0
- reachscan-0.1.0/src/reachscan/detectors/autonomy.py +154 -0
- reachscan-0.1.0/src/reachscan/detectors/base.py +60 -0
- reachscan-0.1.0/src/reachscan/detectors/dynamic_exec.py +125 -0
- reachscan-0.1.0/src/reachscan/detectors/file_access.py +169 -0
- reachscan-0.1.0/src/reachscan/detectors/network.py +218 -0
- reachscan-0.1.0/src/reachscan/detectors/registry.py +110 -0
- reachscan-0.1.0/src/reachscan/detectors/secrets.py +242 -0
- reachscan-0.1.0/src/reachscan/detectors/shell_exec.py +32 -0
- reachscan-0.1.0/src/reachscan/py_entry_points.py +612 -0
- reachscan-0.1.0/src/reachscan/reachability.py +325 -0
- reachscan-0.1.0/src/reachscan/reporters/__init__.py +0 -0
- reachscan-0.1.0/src/reachscan/reporters/json_reporter.py +19 -0
- reachscan-0.1.0/src/reachscan/reporters/text_reporter.py +204 -0
- reachscan-0.1.0/src/reachscan/scanner.py +344 -0
- reachscan-0.1.0/src/reachscan/schema.py +92 -0
- reachscan-0.1.0/src/reachscan/source_loader.py +388 -0
- reachscan-0.1.0/src/reachscan/ts_entry_points.py +426 -0
- reachscan-0.1.0/src/reachscan/utils.py +0 -0
- reachscan-0.1.0/src/reachscan.egg-info/PKG-INFO +329 -0
- reachscan-0.1.0/src/reachscan.egg-info/SOURCES.txt +52 -0
- reachscan-0.1.0/src/reachscan.egg-info/dependency_links.txt +1 -0
- reachscan-0.1.0/src/reachscan.egg-info/entry_points.txt +2 -0
- reachscan-0.1.0/src/reachscan.egg-info/requires.txt +6 -0
- reachscan-0.1.0/src/reachscan.egg-info/top_level.txt +1 -0
- reachscan-0.1.0/tests/test_analysis_impact.py +19 -0
- reachscan-0.1.0/tests/test_autonomy.py +18 -0
- reachscan-0.1.0/tests/test_call_graph.py +591 -0
- reachscan-0.1.0/tests/test_dynamic_exec.py +19 -0
- reachscan-0.1.0/tests/test_exit_codes.py +142 -0
- reachscan-0.1.0/tests/test_file_access.py +11 -0
- reachscan-0.1.0/tests/test_network.py +36 -0
- reachscan-0.1.0/tests/test_py_entry_points.py +850 -0
- reachscan-0.1.0/tests/test_pypi_loader.py +197 -0
- reachscan-0.1.0/tests/test_reachability.py +503 -0
- reachscan-0.1.0/tests/test_scan_target.py +45 -0
- reachscan-0.1.0/tests/test_scanner_v2_output.py +47 -0
- reachscan-0.1.0/tests/test_schema.py +170 -0
- reachscan-0.1.0/tests/test_secrets.py +82 -0
- reachscan-0.1.0/tests/test_shell_exec.py +6 -0
- reachscan-0.1.0/tests/test_source_loader.py +40 -0
- reachscan-0.1.0/tests/test_text_reporter.py +183 -0
- reachscan-0.1.0/tests/test_ts_entry_points.py +588 -0
reachscan-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity.
|
|
18
|
+
|
|
19
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
20
|
+
exercising permissions granted by this License.
|
|
21
|
+
|
|
22
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
23
|
+
including but not limited to software source code, documentation
|
|
24
|
+
source, and configuration files.
|
|
25
|
+
|
|
26
|
+
"Object" form shall mean any form resulting from mechanical
|
|
27
|
+
transformation or translation of a Source form.
|
|
28
|
+
|
|
29
|
+
"Work" shall mean the work of authorship made available under the
|
|
30
|
+
License.
|
|
31
|
+
|
|
32
|
+
"Derivative Works" shall mean any work based on the Work.
|
|
33
|
+
|
|
34
|
+
"Contribution" shall mean any work intentionally submitted for
|
|
35
|
+
inclusion in the Work by the copyright owner.
|
|
36
|
+
|
|
37
|
+
2. Grant of Copyright License.
|
|
38
|
+
|
|
39
|
+
Subject to the terms and conditions of this License, each Contributor
|
|
40
|
+
hereby grants You a perpetual, worldwide, non-exclusive, no-charge,
|
|
41
|
+
royalty-free, irrevocable copyright license to reproduce, prepare
|
|
42
|
+
Derivative Works of, publicly display, publicly perform, sublicense,
|
|
43
|
+
and distribute the Work and such Derivative Works.
|
|
44
|
+
|
|
45
|
+
3. Grant of Patent License.
|
|
46
|
+
|
|
47
|
+
Each Contributor hereby grants You a perpetual, worldwide,
|
|
48
|
+
non-exclusive, no-charge, royalty-free, irrevocable patent license
|
|
49
|
+
to make, have made, use, offer to sell, sell, import, and otherwise
|
|
50
|
+
transfer the Work.
|
|
51
|
+
|
|
52
|
+
4. Redistribution.
|
|
53
|
+
|
|
54
|
+
You may reproduce and distribute copies of the Work provided that You:
|
|
55
|
+
|
|
56
|
+
(a) Give any other recipients a copy of this License; and
|
|
57
|
+
(b) Cause any modified files to carry prominent notices stating that You changed the files; and
|
|
58
|
+
(c) Retain all copyright, patent, trademark, and attribution notices; and
|
|
59
|
+
(d) If the Work includes a NOTICE file, include it in distributions.
|
|
60
|
+
|
|
61
|
+
5. Submission of Contributions.
|
|
62
|
+
|
|
63
|
+
Unless You explicitly state otherwise, any Contribution intentionally
|
|
64
|
+
submitted for inclusion in the Work shall be under the terms of this
|
|
65
|
+
License.
|
|
66
|
+
|
|
67
|
+
6. Trademarks.
|
|
68
|
+
|
|
69
|
+
This License does not grant permission to use the trade names,
|
|
70
|
+
trademarks, service marks, or product names of the Licensor.
|
|
71
|
+
|
|
72
|
+
7. Disclaimer of Warranty.
|
|
73
|
+
|
|
74
|
+
Unless required by applicable law or agreed to in writing, Licensor
|
|
75
|
+
provides the Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
76
|
+
CONDITIONS OF ANY KIND.
|
|
77
|
+
|
|
78
|
+
8. Limitation of Liability.
|
|
79
|
+
|
|
80
|
+
In no event shall any Contributor be liable for damages arising from
|
|
81
|
+
use of the Work.
|
|
82
|
+
|
|
83
|
+
9. Accepting Warranty or Additional Liability.
|
|
84
|
+
|
|
85
|
+
You may offer support or warranty for a fee, but only on Your own
|
|
86
|
+
behalf and responsibility.
|
|
87
|
+
|
|
88
|
+
END OF TERMS AND CONDITIONS
|
|
89
|
+
|
|
90
|
+
Copyright 2026 Vinmay Nair
|
reachscan-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: reachscan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reachability-based capability scanner for AI agent and MCP server codebases.
|
|
5
|
+
Author-email: Vinmay Nair <vinmay.nair@gmail.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/vinmay/reachscan
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest; extra == "dev"
|
|
13
|
+
Requires-Dist: ruff; extra == "dev"
|
|
14
|
+
Requires-Dist: pipx; extra == "dev"
|
|
15
|
+
Requires-Dist: click; extra == "dev"
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# reachscan
|
|
19
|
+
|
|
20
|
+
> Static capability analysis for Python and TypeScript/JavaScript AI code.
|
|
21
|
+
> Know what it can do before it does it.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## The problem
|
|
26
|
+
|
|
27
|
+
You're giving an LLM tools. Tools mean real-world access — files, shell, network, credentials.
|
|
28
|
+
|
|
29
|
+
Most developers add tools without a clear accounting of what permissions they're actually granting. The agent docs tell you what the tool is *for*. They don't tell you what it *can do*.
|
|
30
|
+
|
|
31
|
+
`reachscan` is the accounting.
|
|
32
|
+
|
|
33
|
+
It analyzes Python and TypeScript/JavaScript code and reports the actual capabilities present: what the code can read, write, execute, send, and access. Not what the README says. What the code does.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## What it detects
|
|
38
|
+
|
|
39
|
+
Seven capability classes, built from AST analysis and pattern matching:
|
|
40
|
+
|
|
41
|
+
| Capability | What it means |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `EXECUTE` | Shell commands, subprocess, OS exec APIs |
|
|
44
|
+
| `READ` | Local file reads, path traversal |
|
|
45
|
+
| `WRITE` | File creation, modification, deletion |
|
|
46
|
+
| `SEND` | Outbound HTTP, websockets, raw sockets |
|
|
47
|
+
| `SECRETS` | Env vars, credential managers, secret stores |
|
|
48
|
+
| `DYNAMIC` | eval, exec, dynamic imports |
|
|
49
|
+
| `AUTONOMY` | Background tasks, schedulers, self-directed execution |
|
|
50
|
+
|
|
51
|
+
Cross-capability risks are also flagged — READ + SEND detected together raises a data exfiltration flag. SECRETS + SEND raises a credential leak flag.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Reachability analysis
|
|
56
|
+
|
|
57
|
+
Knowing a capability exists in a codebase is useful. Knowing whether the LLM can actually trigger it is what matters.
|
|
58
|
+
|
|
59
|
+
`reachscan` detects the LLM-facing entry points in your codebase, builds an intra-project call graph, and traces which capabilities are reachable from those entry points. Every finding is tagged with one of five states:
|
|
60
|
+
|
|
61
|
+
| State | Meaning |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `reachable` | Confirmed on a call path from an LLM entry point |
|
|
64
|
+
| `unreachable` | Exists in the codebase, not on any LLM call path |
|
|
65
|
+
| `module_level` | Runs on import — executes when the module loads, not via a function call |
|
|
66
|
+
| `unknown` | Inside code that can't be statically resolved (dynamic dispatch, parse failure) |
|
|
67
|
+
| `no_entry_points` | No entry points detected — full reachability analysis not possible |
|
|
68
|
+
|
|
69
|
+
The call graph follows up to 8 hops from each entry point. Call paths are shown in the report so you can see exactly how the LLM reaches a capability.
|
|
70
|
+
|
|
71
|
+
### Entry point detection — Python
|
|
72
|
+
|
|
73
|
+
`reachscan` recognises LLM-callable functions across all major Python agent frameworks:
|
|
74
|
+
|
|
75
|
+
| Framework | Detection pattern |
|
|
76
|
+
|---|---|
|
|
77
|
+
| Pydantic AI | `@agent.tool`, `@agent.tool_plain` |
|
|
78
|
+
| LangChain / CrewAI | `@tool`, `class MyTool(BaseTool)` |
|
|
79
|
+
| OpenAI Agents SDK | `@function_tool` |
|
|
80
|
+
| MCP (Python SDK / FastMCP) | `@mcp.tool()`, `@server.tool()` |
|
|
81
|
+
| MCP (lowlevel server API) | `@app.call_tool()`, `@app.list_tools()` |
|
|
82
|
+
| Semantic Kernel | `@kernel_function` |
|
|
83
|
+
| AutoGen | `@register_for_llm` |
|
|
84
|
+
|
|
85
|
+
Framework attribution uses a confidence-graded resolution chain: direct imports are resolved at 0.95 confidence, inferred instance variables (e.g. `weather_agent = Agent[Deps, T](...)`) at 0.80, and unresolvable decorator names fall back to the best available label at 0.60.
|
|
86
|
+
|
|
87
|
+
Python entry points feed into the reachability pass — the call graph is traced from each detected entry point to identify which capabilities the LLM can actually trigger.
|
|
88
|
+
|
|
89
|
+
### Entry point detection — TypeScript and JavaScript
|
|
90
|
+
|
|
91
|
+
`reachscan` scans `.ts`, `.js`, `.mts`, `.mjs`, `.cts`, and `.cjs` files using regex-based pattern matching. No Node.js runtime is required.
|
|
92
|
+
|
|
93
|
+
| Pattern | What it detects | Confidence |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `mcp_tool` | `server.tool("name", schema, handler)` — MCP SDK | 0.95 |
|
|
96
|
+
| `mcp_tool` | `server.registerTool("name", schema, handler)` — MCP SDK v1.6+ | 0.95 |
|
|
97
|
+
| `mcp_tool` | `server.addTool({ name: "...", ... })` — FastMCP | 0.90 |
|
|
98
|
+
| `mcp_tool_definition` | `{ name: "...", description: ..., inputSchema: ... }` objects | 0.85 |
|
|
99
|
+
| `langchain_tool` | `new DynamicTool({ name: "...", ... })` | 0.85 |
|
|
100
|
+
| `mcp_handler` | `server.setRequestHandler(Schema, ...)` | 0.80 |
|
|
101
|
+
|
|
102
|
+
Both same-line and multi-line registration styles are handled for each pattern. Declaration files (`.d.ts`), test files, minified bundles, and `node_modules`/`dist`/`build` directories are automatically excluded.
|
|
103
|
+
|
|
104
|
+
**Current limitation:** TypeScript and JavaScript function bodies are not capability-analyzed — only entry points are detected. When a project mixes Python and TypeScript, capability findings come from the Python side and TypeScript entry points are listed separately in the report.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## What it looks like
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
Agent Capability Report
|
|
112
|
+
=======================
|
|
113
|
+
|
|
114
|
+
Python Entry Points (LLM-controlled surface)
|
|
115
|
+
----------------------------------------------
|
|
116
|
+
• get_lat_lng (pydantic_ai/decorator @ weather_agent.py:50)
|
|
117
|
+
• get_weather (pydantic_ai/decorator @ weather_agent.py:67)
|
|
118
|
+
|
|
119
|
+
Capabilities
|
|
120
|
+
------------
|
|
121
|
+
• SEND
|
|
122
|
+
|
|
123
|
+
Combined Risks
|
|
124
|
+
--------------
|
|
125
|
+
None inferred from combined-capability rules.
|
|
126
|
+
|
|
127
|
+
Reachability Summary
|
|
128
|
+
--------------------
|
|
129
|
+
3 reachable — LLM can trigger these directly
|
|
130
|
+
117 unreachable — exist in codebase, not on any LLM call path
|
|
131
|
+
3 module-level — execute on import, not on any call path
|
|
132
|
+
|
|
133
|
+
Reachable Findings — LLM can trigger these directly
|
|
134
|
+
------------------------------------------------------
|
|
135
|
+
[HIGH] SEND via ctx.deps.client.get -> https://api.weather.example.com (network @ weather_agent.py:58)
|
|
136
|
+
path: get_lat_lng
|
|
137
|
+
explanation: This code can send data over the network to external services.
|
|
138
|
+
impact: Sensitive local data could be transmitted to untrusted endpoints.
|
|
139
|
+
|
|
140
|
+
Other Findings — not on LLM call path
|
|
141
|
+
-----------------------------------------
|
|
142
|
+
[HIGH] UNREACHABLE SECRETS via os.getenv('ANTHROPIC_API_KEY') (secrets @ model_client.py:12)
|
|
143
|
+
explanation: This code accesses secrets or credential sources.
|
|
144
|
+
impact: Credentials may be disclosed and used for unauthorized access.
|
|
145
|
+
|
|
146
|
+
[HIGH] MODULE_LEVEL SECRETS via os.getenv('PYDANTIC_AI_MODEL') (secrets @ config.py:25)
|
|
147
|
+
reachability: Executes on import — runs whenever this module loads
|
|
148
|
+
explanation: This code accesses secrets or credential sources.
|
|
149
|
+
impact: Credentials may be disclosed and used for unauthorized access.
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
You get file paths and line numbers. Not just "this repo uses subprocess" — you get exactly where, how, and whether the LLM can reach it.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Who needs this
|
|
157
|
+
|
|
158
|
+
**Agent developers** — audit your own code before shipping. Know exactly what you're granting the LLM access to, and where those grants live in your codebase.
|
|
159
|
+
|
|
160
|
+
**Security and platform teams** — you're deploying agents your developers wrote, or agents that use third-party frameworks. Before they hit production, run a scan. Get a fast, defensible answer to "what can this thing actually do?"
|
|
161
|
+
|
|
162
|
+
**Anyone integrating third-party tools** — tools, plugins, and MCP servers come with capabilities attached. Scan them *before* wiring them into your agent. `reachscan https://github.com/some-org/some-tool` takes seconds and requires nothing installed on that repo.
|
|
163
|
+
|
|
164
|
+
**MCP server authors** — show your users exactly what your server can and cannot do. A clean scan result is a trust signal.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## It's not just for agents
|
|
169
|
+
|
|
170
|
+
The name is intentional but the scope is broader.
|
|
171
|
+
|
|
172
|
+
Any Python or TypeScript/JavaScript code that runs in an AI-adjacent context is a valid target — tool libraries, retrieval pipelines, memory modules, execution sandboxes. If an LLM can call it, you want to know what it can do.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Precision
|
|
177
|
+
|
|
178
|
+
Detection quality was validated in a structured false positive audit across 10 major open-source agent repos (AutoGPT, LangChain, LlamaIndex, CrewAI, OpenAI Agents SDK, Autogen, pydantic-ai, agentops, anthropic-cookbook, python-sdk) — approximately 3,900 labeled findings:
|
|
179
|
+
|
|
180
|
+
| Detector | FP Rate |
|
|
181
|
+
|---|---|
|
|
182
|
+
| `file_access` | 0.0% |
|
|
183
|
+
| `secrets` | 0.0% |
|
|
184
|
+
| `dynamic_exec` | 0.0% |
|
|
185
|
+
| `network` | 0.7% |
|
|
186
|
+
| `autonomy` | 1.6% |
|
|
187
|
+
| `shell_exec` | 1.9% |
|
|
188
|
+
| **Overall** | **0.47%** |
|
|
189
|
+
|
|
190
|
+
Low noise by design. When it fires, it's real.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## What this is NOT
|
|
195
|
+
|
|
196
|
+
- Not a vulnerability scanner
|
|
197
|
+
- Not a linter
|
|
198
|
+
- Not a dependency checker
|
|
199
|
+
- Not a compliance tool
|
|
200
|
+
- Not a prompt injection detector *(planned)*
|
|
201
|
+
|
|
202
|
+
**It is a capability audit.** Static analysis only — results describe what the code is capable of, not what it will do in any given execution.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Installation
|
|
207
|
+
|
|
208
|
+
### Option 1 — Recommended (install as a CLI tool)
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
pipx install git+https://github.com/vinmay/reachscan.git
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Then run:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
reachscan .
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Option 2 — Install from source (development)
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
git clone https://github.com/vinmay/reachscan.git
|
|
224
|
+
cd reachscan
|
|
225
|
+
|
|
226
|
+
python -m venv .venv
|
|
227
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
228
|
+
|
|
229
|
+
pip install -e .[dev]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Option 3 — Run without installing
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
python -m reachscan.cli examples/demo_agent
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Requirements
|
|
241
|
+
|
|
242
|
+
- Python 3.11+
|
|
243
|
+
- pip or pipx
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Usage
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
reachscan [target] [--json] [--severity {high,medium,none}]
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`target` accepts:
|
|
254
|
+
|
|
255
|
+
| Input | Example |
|
|
256
|
+
|---|---|
|
|
257
|
+
| Local path | `reachscan .` |
|
|
258
|
+
| Local path, JSON output | `reachscan ./my_agent --json` |
|
|
259
|
+
| GitHub repository URL | `reachscan https://github.com/org/repo` |
|
|
260
|
+
| MCP HTTP endpoint | `reachscan mcp+https://mcp.example.com` |
|
|
261
|
+
| PyPI package (latest) | `reachscan pypi:requests` |
|
|
262
|
+
| PyPI package (pinned) | `reachscan pypi:requests==2.31.0` |
|
|
263
|
+
|
|
264
|
+
The GitHub URL path does a shallow clone — you don't need the repo checked out locally.
|
|
265
|
+
|
|
266
|
+
### Exit codes
|
|
267
|
+
|
|
268
|
+
| Code | Meaning |
|
|
269
|
+
|------|---------|
|
|
270
|
+
| `0` | Scan complete, threshold not exceeded |
|
|
271
|
+
| `1` | Scan complete, ≥1 reachable finding exceeds severity threshold |
|
|
272
|
+
| `2` | Scan failed (bad target, network error, unhandled exception) |
|
|
273
|
+
|
|
274
|
+
### `--severity` flag
|
|
275
|
+
|
|
276
|
+
Controls when the CLI exits 1:
|
|
277
|
+
|
|
278
|
+
| Value | Exit 1 when... |
|
|
279
|
+
|-------|----------------|
|
|
280
|
+
| `high` *(default)* | reachable finding with `risk_level == "high"` |
|
|
281
|
+
| `medium` | reachable finding with `risk_level in ("high", "medium")` |
|
|
282
|
+
| `none` | never — always exits 0 |
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## CI Integration
|
|
287
|
+
|
|
288
|
+
```yaml
|
|
289
|
+
name: Agent Capability Audit
|
|
290
|
+
on: [push, pull_request]
|
|
291
|
+
jobs:
|
|
292
|
+
reachscan:
|
|
293
|
+
runs-on: ubuntu-latest
|
|
294
|
+
steps:
|
|
295
|
+
- uses: actions/checkout@v4
|
|
296
|
+
- run: pipx install reachscan
|
|
297
|
+
- name: Run capability audit
|
|
298
|
+
run: reachscan . --json > reachscan-report.json
|
|
299
|
+
# Exits 1 if HIGH reachable capabilities found
|
|
300
|
+
- uses: actions/upload-artifact@v4
|
|
301
|
+
if: always()
|
|
302
|
+
with:
|
|
303
|
+
name: reachscan-report
|
|
304
|
+
path: reachscan-report.json
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
To audit without blocking the pipeline (report only):
|
|
308
|
+
|
|
309
|
+
```yaml
|
|
310
|
+
- run: reachscan . --json --severity none > reachscan-report.json
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Project direction
|
|
316
|
+
|
|
317
|
+
The goal:
|
|
318
|
+
|
|
319
|
+
> Give AI systems a permission model they've never had.
|
|
320
|
+
|
|
321
|
+
Static capability detection is the foundation. Reachability analysis on top of it answers the harder question: not just *can* this code do something, but *can the LLM trigger it*.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Status
|
|
326
|
+
|
|
327
|
+
Capability detection is stable. Reachability analysis is active — entry point detection covers all major Python agent frameworks and the call graph traversal handles projects of any size. TypeScript/JavaScript entry point detection is stable.
|
|
328
|
+
|
|
329
|
+
The JSON output schema is stable at v1 — see [`docs/schema_v1.md`](docs/schema_v1.md) for the full field reference. Feedback, edge cases, and false positive reports are especially valuable — open an issue.
|