rce-path 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.
- rce_path-0.1.0/.github/workflows/ci.yml +29 -0
- rce_path-0.1.0/.github/workflows/publish.yml +49 -0
- rce_path-0.1.0/.gitignore +15 -0
- rce_path-0.1.0/CONTRIBUTING.md +23 -0
- rce_path-0.1.0/LICENSE +21 -0
- rce_path-0.1.0/PKG-INFO +79 -0
- rce_path-0.1.0/README.md +45 -0
- rce_path-0.1.0/docs/providers.md +34 -0
- rce_path-0.1.0/docs/releasing.md +63 -0
- rce_path-0.1.0/docs/usage.md +169 -0
- rce_path-0.1.0/examples/investigate.py +15 -0
- rce_path-0.1.0/examples/rce-path.toml +23 -0
- rce_path-0.1.0/pyproject.toml +63 -0
- rce_path-0.1.0/rce-path_spec.md +144 -0
- rce_path-0.1.0/scripts/check_install.py +52 -0
- rce_path-0.1.0/src/rce_path/__init__.py +8 -0
- rce_path-0.1.0/src/rce_path/__main__.py +4 -0
- rce_path-0.1.0/src/rce_path/_worker.py +149 -0
- rce_path-0.1.0/src/rce_path/cfg.py +76 -0
- rce_path-0.1.0/src/rce_path/cli.py +78 -0
- rce_path-0.1.0/src/rce_path/config.py +100 -0
- rce_path-0.1.0/src/rce_path/findings.py +108 -0
- rce_path-0.1.0/src/rce_path/flow.py +590 -0
- rce_path-0.1.0/src/rce_path/ingest.py +309 -0
- rce_path-0.1.0/src/rce_path/llm/__init__.py +103 -0
- rce_path-0.1.0/src/rce_path/llm/contract.py +195 -0
- rce_path-0.1.0/src/rce_path/llm/providers/__init__.py +4 -0
- rce_path-0.1.0/src/rce_path/llm/providers/base.py +163 -0
- rce_path-0.1.0/src/rce_path/llm/providers/ollama.py +93 -0
- rce_path-0.1.0/src/rce_path/llm/providers/openai.py +82 -0
- rce_path-0.1.0/src/rce_path/py.typed +0 -0
- rce_path-0.1.0/src/rce_path/reports.py +87 -0
- rce_path-0.1.0/src/rce_path/rules.py +60 -0
- rce_path-0.1.0/src/rce_path/symbols.py +59 -0
- rce_path-0.1.0/tests/fixtures/phase1.json +74 -0
- rce_path-0.1.0/tests/test_packaging.py +30 -0
- rce_path-0.1.0/tests/test_phase1.py +81 -0
- rce_path-0.1.0/tests/test_providers.py +306 -0
- rce_path-0.1.0/tests/test_safety.py +227 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Test and build
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: ['**']
|
|
5
|
+
pull_request:
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: '3.13'
|
|
16
|
+
- run: python -m pip install -e ".[dev]"
|
|
17
|
+
- run: python -m pytest -q
|
|
18
|
+
- run: python -m ruff check src tests scripts
|
|
19
|
+
- run: python -m mypy
|
|
20
|
+
- run: python -m build
|
|
21
|
+
- run: python -m twine check dist/*
|
|
22
|
+
- name: Install and smoke-test wheel
|
|
23
|
+
run: |
|
|
24
|
+
python -c "import glob,subprocess,sys; subprocess.check_call([sys.executable,'-m','pip','install','--force-reinstall','--no-deps',glob.glob('dist/*.whl')[0]])"
|
|
25
|
+
python scripts/check_install.py
|
|
26
|
+
- uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: distributions
|
|
29
|
+
path: dist/*
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags: ['rce-path-v*']
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: '3.13'
|
|
16
|
+
- name: Verify release version
|
|
17
|
+
if: github.event_name == 'push'
|
|
18
|
+
run: |
|
|
19
|
+
python - <<'PY'
|
|
20
|
+
import os, tomllib
|
|
21
|
+
version = tomllib.load(open('pyproject.toml', 'rb'))['project']['version']
|
|
22
|
+
assert os.environ['GITHUB_REF_NAME'] == f'rce-path-v{version}', 'Tag/version mismatch'
|
|
23
|
+
PY
|
|
24
|
+
- run: python -m pip install -e ".[dev]"
|
|
25
|
+
- run: python -m pytest -q
|
|
26
|
+
- run: python -m ruff check src tests scripts
|
|
27
|
+
- run: python -m mypy
|
|
28
|
+
- run: python -m build
|
|
29
|
+
- run: python -m twine check dist/*
|
|
30
|
+
- name: Install and smoke-test wheel
|
|
31
|
+
run: |
|
|
32
|
+
python -c "import glob,subprocess,sys; subprocess.check_call([sys.executable,'-m','pip','install','--force-reinstall','--no-deps',glob.glob('dist/*.whl')[0]])"
|
|
33
|
+
python scripts/check_install.py
|
|
34
|
+
- uses: actions/upload-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: distributions
|
|
37
|
+
path: dist/*
|
|
38
|
+
publish:
|
|
39
|
+
needs: build
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
environment: pypi
|
|
42
|
+
permissions:
|
|
43
|
+
id-token: write
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/download-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: distributions
|
|
48
|
+
path: dist/
|
|
49
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Install `python -m pip install -e ".[dev]"`. Keep the static scanner independent
|
|
4
|
+
of optional AI SDKs. Run pytest, Ruff, mypy, build, and Twine before release.
|
|
5
|
+
|
|
6
|
+
`src/rce_path` follows the spec's pipeline: ingestion, symbols, CFG, flow, rules,
|
|
7
|
+
findings, optional `llm/providers`, reports, and CLI. Models are versioned at the
|
|
8
|
+
evidence boundary. Add future cross-function summaries at the flow boundary,
|
|
9
|
+
provider roles at the review contract, and SARIF at the report boundary. Validation
|
|
10
|
+
must be a separate Phase 3 component; do not execute targets to improve static
|
|
11
|
+
coverage. No repository-provided executable plugins are accepted.
|
|
12
|
+
|
|
13
|
+
Labeled synthetic fixtures live in `tests/fixtures/phase1.json`. Each records a
|
|
14
|
+
unique ID, source, expected category/negative control, and relevant diagnostics.
|
|
15
|
+
They are development/release fixtures, not independent holdout benchmarks. Keep
|
|
16
|
+
future project datasets split by project and record provenance, revisions, and
|
|
17
|
+
vulnerable/patched labels before tuning. No detection superiority claim follows
|
|
18
|
+
from this fixture suite.
|
|
19
|
+
|
|
20
|
+
Provider tests use identical scenarios for both adapters, fake transports, no
|
|
21
|
+
credentials, no model downloads, and no network. Optional live tests are manual
|
|
22
|
+
and use the operator's selected model. Never store keys or raw SDK exceptions in
|
|
23
|
+
reports or fixtures. See `docs/providers.md` and `docs/releasing.md`.
|
rce_path-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sai Teja Erukude
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
rce_path-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: rce-path
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local-first, evidence-backed Python execution-path investigation
|
|
5
|
+
Author: Sai Teja Erukude
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: audit,dataflow,rce,security,static-analysis
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Security
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
20
|
+
Provides-Extra: ai
|
|
21
|
+
Requires-Dist: ollama<1,>=0.4.7; extra == 'ai'
|
|
22
|
+
Requires-Dist: openai<3,>=1.68; extra == 'ai'
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
25
|
+
Requires-Dist: mypy>=1.15; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest<10,>=8; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.11; extra == 'dev'
|
|
28
|
+
Requires-Dist: twine>=6; extra == 'dev'
|
|
29
|
+
Provides-Extra: ollama
|
|
30
|
+
Requires-Dist: ollama<1,>=0.4.7; extra == 'ollama'
|
|
31
|
+
Provides-Extra: openai
|
|
32
|
+
Requires-Dist: openai<3,>=1.68; extra == 'openai'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# rce-path
|
|
36
|
+
|
|
37
|
+
Trace potentially untrusted Python inputs to execution sinks, with source
|
|
38
|
+
locations and static flow evidence. Scans local code without executing it.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
python -m pip install .
|
|
44
|
+
# Optional AI backends: ".[openai]" or ".[ollama]"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
After publishing: `pip install rce-path`.
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
rce-path scan ./checkout --format json --output findings.json
|
|
53
|
+
rce-path scan ./checkout --format markdown --output report.md
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from rce_path import scan
|
|
58
|
+
|
|
59
|
+
report = scan("./checkout")
|
|
60
|
+
print(report.summary)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Features
|
|
64
|
+
|
|
65
|
+
- Detects `eval`, `exec`, OS shell calls, and subprocess shell execution.
|
|
66
|
+
- Tracks parameters, Flask request data, and local inputs through assignments,
|
|
67
|
+
branches, and bounded loops.
|
|
68
|
+
- Exports evidence, assumptions, coverage diagnostics, and stable fingerprints.
|
|
69
|
+
- Supports optional OpenAI and Ollama reviews.
|
|
70
|
+
|
|
71
|
+
Static findings require human review. Remote AI code transmission requires
|
|
72
|
+
`--allow-remote-code`. Exit codes: **0** completed, **1** findings policy failed,
|
|
73
|
+
**2** incomplete scan or operational error.
|
|
74
|
+
|
|
75
|
+
[Usage & limitations](docs/usage.md) · [Configuration](examples/rce-path.toml) ·
|
|
76
|
+
[AI providers](docs/providers.md) · [Contributing](CONTRIBUTING.md) ·
|
|
77
|
+
[Publishing](docs/releasing.md)
|
|
78
|
+
|
|
79
|
+
Author: Sai Teja Erukude.
|
rce_path-0.1.0/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# rce-path
|
|
2
|
+
|
|
3
|
+
Trace potentially untrusted Python inputs to execution sinks, with source
|
|
4
|
+
locations and static flow evidence. Scans local code without executing it.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
python -m pip install .
|
|
10
|
+
# Optional AI backends: ".[openai]" or ".[ollama]"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
After publishing: `pip install rce-path`.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
rce-path scan ./checkout --format json --output findings.json
|
|
19
|
+
rce-path scan ./checkout --format markdown --output report.md
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from rce_path import scan
|
|
24
|
+
|
|
25
|
+
report = scan("./checkout")
|
|
26
|
+
print(report.summary)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- Detects `eval`, `exec`, OS shell calls, and subprocess shell execution.
|
|
32
|
+
- Tracks parameters, Flask request data, and local inputs through assignments,
|
|
33
|
+
branches, and bounded loops.
|
|
34
|
+
- Exports evidence, assumptions, coverage diagnostics, and stable fingerprints.
|
|
35
|
+
- Supports optional OpenAI and Ollama reviews.
|
|
36
|
+
|
|
37
|
+
Static findings require human review. Remote AI code transmission requires
|
|
38
|
+
`--allow-remote-code`. Exit codes: **0** completed, **1** findings policy failed,
|
|
39
|
+
**2** incomplete scan or operational error.
|
|
40
|
+
|
|
41
|
+
[Usage & limitations](docs/usage.md) · [Configuration](examples/rce-path.toml) ·
|
|
42
|
+
[AI providers](docs/providers.md) · [Contributing](CONTRIBUTING.md) ·
|
|
43
|
+
[Publishing](docs/releasing.md)
|
|
44
|
+
|
|
45
|
+
Author: Sai Teja Erukude.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Provider validation
|
|
2
|
+
|
|
3
|
+
`tests/test_providers.py` applies the same contract fixtures to OpenAI and Ollama:
|
|
4
|
+
valid JSON, malformed JSON, refusal, truncation, unavailable model, timeout, rate
|
|
5
|
+
limit, invalid credentials, unsupported schema/options, and invented citations.
|
|
6
|
+
Tests also cover repair/retry bounds, byte/token budgets, cancellation, consent,
|
|
7
|
+
redaction, cache-key invalidation, and preservation of the static evidence.
|
|
8
|
+
Tests use stubs and require no keys or downloads.
|
|
9
|
+
|
|
10
|
+
For an optional live smoke test, create a temporary file containing:
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
def investigate(code):
|
|
14
|
+
eval(code)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Install the appropriate extra. Start your existing Ollama server and choose a
|
|
18
|
+
model you have already installed; no automatic pulls occur. Then:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
rce-path scan smoke.py --ai ollama --model YOUR_MODEL --output ollama-review.json
|
|
22
|
+
rce-path scan smoke.py --ai openai --model YOUR_MODEL --allow-remote-code --output openai-review.json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For OpenAI, supply `OPENAI_API_KEY` through the environment. Verify `ai_status`,
|
|
26
|
+
cited evidence IDs, usage, static fingerprint, and provider/model identity. An
|
|
27
|
+
unsupported schema/model is a failed review, not a reason to silently drop options.
|
|
28
|
+
Do not run live tests in standard CI. Local model refusals can appear as
|
|
29
|
+
schema-invalid output if the model does not emit a structured refusal marker;
|
|
30
|
+
either result is explicitly unsuccessful.
|
|
31
|
+
|
|
32
|
+
Implementation references: [OpenAI structured output](https://developers.openai.com/api/docs/guides/structured-outputs),
|
|
33
|
+
[Ollama structured output](https://docs.ollama.com/capabilities/structured-outputs),
|
|
34
|
+
and [Ollama chat API](https://docs.ollama.com/api/chat).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Releasing rce-path
|
|
2
|
+
|
|
3
|
+
The repository builds version 0.1.0 as a wheel and source distribution. Before a
|
|
4
|
+
public release, verify availability/ownership of the normalized name `rce-path`
|
|
5
|
+
on PyPI and TestPyPI. Configure the repository URL in project metadata after the
|
|
6
|
+
actual GitHub repository exists. The publishing workflow lives in
|
|
7
|
+
`.github/workflows/publish.yml`.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
python -m pip install -e ".[dev]"
|
|
11
|
+
python -m pytest
|
|
12
|
+
python -m ruff check src tests
|
|
13
|
+
python -m mypy
|
|
14
|
+
python -m build
|
|
15
|
+
python -m twine check dist/*
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Install the built wheel in a fresh environment and run `rce-path --version` and
|
|
19
|
+
`rce-path scan --help`. Run `python scripts/check_install.py` with that environment's
|
|
20
|
+
Python for an offline CLI, metadata, typed-marker, and non-execution smoke test.
|
|
21
|
+
CI runs one Ubuntu job on Python 3.13 for branch pushes and pull requests. The labeled
|
|
22
|
+
fixture gate checks all supported classifications, sink spans, safe controls,
|
|
23
|
+
top-level non-execution, and limits. Provider tests run without external access.
|
|
24
|
+
|
|
25
|
+
To test upload manually (an explicit publishing action):
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python -m twine upload --repository testpypi dist/*
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Use your TestPyPI credentials and install the exact version in a clean environment.
|
|
32
|
+
Install Pydantic from PyPI first, then install the package from TestPyPI with
|
|
33
|
+
`--no-deps` to avoid mixing dependency indexes. See the
|
|
34
|
+
[official TestPyPI guide](https://packaging.python.org/en/latest/guides/using-testpypi/).
|
|
35
|
+
|
|
36
|
+
For GitHub/PyPI trusted publishing:
|
|
37
|
+
|
|
38
|
+
1. Create the GitHub repository and commit this project, including its workflows.
|
|
39
|
+
2. Configure a pending/active PyPI publisher for `rce-path`, the repository owner
|
|
40
|
+
and name, workflow `publish.yml`, and environment `pypi`.
|
|
41
|
+
3. Create/protect the GitHub `pypi` environment with required reviewers.
|
|
42
|
+
4. Ensure `pyproject.toml`, `rce_path.__version__`, CLI version, and report version
|
|
43
|
+
agree; tag the commit `rce-path-v0.1.0` and push that tag.
|
|
44
|
+
5. The workflow verifies version, runs tests/checks, builds and checks artifacts,
|
|
45
|
+
then publishes through OIDC. It does not use a stored PyPI API token.
|
|
46
|
+
|
|
47
|
+
The workflow is present but needs a GitHub repository and PyPI publisher setup.
|
|
48
|
+
Use a new version for each upload; PyPI does not allow overwriting a release.
|
|
49
|
+
|
|
50
|
+
After configuring the publisher, commit and push your changes, then publish 0.1.0:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
git push origin main
|
|
54
|
+
git tag rce-path-v0.1.0
|
|
55
|
+
git push origin rce-path-v0.1.0
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
A normal branch push runs CI; publishing runs on `rce-path-v*` tags. The tag's
|
|
59
|
+
version must match `pyproject.toml`. Alternatively, open GitHub Actions, select
|
|
60
|
+
**Publish to PyPI**, and use **Run workflow** to publish the version from your
|
|
61
|
+
selected branch. The manual button appears once the workflow is on the default
|
|
62
|
+
branch. Both release paths run validation before uploading and honor the `pypi`
|
|
63
|
+
environment's approval rules. Branch pushes do not upload to PyPI.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Usage and limitations
|
|
2
|
+
|
|
3
|
+
Investigate potentially untrusted Python inputs reaching execution sinks, with
|
|
4
|
+
reproducible source locations and ordered static evidence. Built for researchers
|
|
5
|
+
reviewing local checkouts. **Phase 1, version 0.1.0; Python 3.11+.**
|
|
6
|
+
|
|
7
|
+
Author: Sai Teja Erukude. License: MIT. Uses the src layout, Hatch builds, typed API,
|
|
8
|
+
pytest, and trusted publishing conventions of `rai-audit`.
|
|
9
|
+
|
|
10
|
+
An execution sink is not automatically a vulnerability. Static flow does not prove
|
|
11
|
+
exploitability, deployment exposure, or remote code execution. Reports assign no
|
|
12
|
+
automatic severity, CVSS, or exploitability probability.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
From this checkout:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
python -m pip install .
|
|
20
|
+
python -m pip install ".[openai]" # optional official OpenAI SDK
|
|
21
|
+
python -m pip install ".[ollama]" # optional official Ollama client
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
After publishing, the equivalent PyPI installation is `pip install rce-path`.
|
|
25
|
+
The static scanner needs only Pydantic; it does not load either AI SDK.
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
rce-path scan ./checkout --format json --output findings.json
|
|
31
|
+
rce-path scan ./checkout --format markdown --output report.md
|
|
32
|
+
rce-path scan ./checkout --fail-on static-path
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from rce_path import ScanConfig, scan
|
|
37
|
+
|
|
38
|
+
report = scan("./checkout", config=ScanConfig(ai_enabled=False))
|
|
39
|
+
print(report.summary)
|
|
40
|
+
for finding in report.findings:
|
|
41
|
+
print(finding.rule_id, finding.location.file, finding.location.line)
|
|
42
|
+
for step in finding.steps:
|
|
43
|
+
print(step.kind, step.location.line, step.description)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`rce-path` is the distribution/command name; `rce_path` is the Python import name.
|
|
47
|
+
Scan a directory or an individual `.py` file. Report methods include `to_json()`
|
|
48
|
+
and `to_markdown()`; public records are validated, typed Pydantic models.
|
|
49
|
+
|
|
50
|
+
## Phase 1 models
|
|
51
|
+
|
|
52
|
+
- `eval`/`exec`, including builtin imports and common aliases.
|
|
53
|
+
- `os.system`/`os.popen`, including module/from imports and assignment aliases.
|
|
54
|
+
- `subprocess.run`, `call`, `check_call`, `check_output`, `Popen` with shell execution;
|
|
55
|
+
`getoutput` and `getstatusoutput` always imply shell execution. Unknown shell
|
|
56
|
+
values carry an explicit condition. `shell=False` scenarios produce limitations.
|
|
57
|
+
- Function parameters, Flask `request.args`, `request.form`, `request.data`, and
|
|
58
|
+
`request.get_data()`. Environment, CLI, stdin, and file reads are local input.
|
|
59
|
+
- Assignments, reassignment, concatenation, f-strings, branches, early returns,
|
|
60
|
+
and bounded loop fixed points over per-scope control-flow graphs.
|
|
61
|
+
|
|
62
|
+
Literal-only sinks are negative controls. Unknown return values produce
|
|
63
|
+
`sink_only` findings and unresolved evidence; unknown calls never propagate an
|
|
64
|
+
invented path and are never automatically treated as sanitizers. A guard or
|
|
65
|
+
escaping function does not prove the argument safe. Branch joins are conservative
|
|
66
|
+
overapproximations and can retain mutually exclusive conditions.
|
|
67
|
+
|
|
68
|
+
Every finding includes a stable fingerprint, rule/schema versions, exact relative
|
|
69
|
+
file spans (columns are AST UTF-8 byte offsets, zero based), source category,
|
|
70
|
+
evidence tier, ordered evidence, assumptions, unresolved calls, and review state.
|
|
71
|
+
`network_source_modeled` means a modeled network input, with authentication and
|
|
72
|
+
deployment still unknown. Fingerprints exclude AI annotations and absolute roots.
|
|
73
|
+
Content hashes cover read source files; revision is unknown unless supplied by a
|
|
74
|
+
future trusted provenance integration. Dependency-version provenance is empty in
|
|
75
|
+
Phase 1 because its rules are not dependency-version-sensitive.
|
|
76
|
+
|
|
77
|
+
## Safety, completion, and coverage
|
|
78
|
+
|
|
79
|
+
Targets are read as data: no imports, package installation, target build hooks,
|
|
80
|
+
deserialization, or checkpoint loading. Excluded environments/build trees and
|
|
81
|
+
skipped files appear in diagnostics. Symlinks/reparse points are not followed.
|
|
82
|
+
Isolated parser/analysis workers enforce wall time, memory, AST, flow, and evidence
|
|
83
|
+
budgets. Windows uses Job Objects; POSIX uses `RLIMIT_AS`. If enforcement fails,
|
|
84
|
+
the worker fails and the report is incomplete. Source inventory and the static
|
|
85
|
+
scan also have overall time/file/inventory limits. The total scan deadline includes
|
|
86
|
+
requested AI reviews; each review also has its own timeout and token budget.
|
|
87
|
+
|
|
88
|
+
Exit codes: **0** completed and selected policy passed; **1** findings policy
|
|
89
|
+
failed; **2** operational/configuration error, incomplete static scan, or requested
|
|
90
|
+
AI review failed. `--fail-on none` is the default. Incomplete status wins over a
|
|
91
|
+
findings policy. A complete empty report says only **“No modeled findings.”**
|
|
92
|
+
Read coverage diagnostics even when the status is completed.
|
|
93
|
+
|
|
94
|
+
Supported target syntax follows the running Python interpreter (recorded in each
|
|
95
|
+
report). A Python 3.11 runtime cannot parse newer syntax. Cross-file/function flow,
|
|
96
|
+
closures, dynamic dispatch, complex heap mutation, comprehensions, and precise
|
|
97
|
+
exception/finally flow are outside Phase 1 coverage. Known unsupported constructs
|
|
98
|
+
produce diagnostics. Parsing is isolated and bounded, but this scanner is not a
|
|
99
|
+
general-purpose sandbox for running hostile code. Avoid concurrently modifying
|
|
100
|
+
the checkout during a scan.
|
|
101
|
+
|
|
102
|
+
## Configuration
|
|
103
|
+
|
|
104
|
+
Use [`examples/rce-path.toml`](../examples/rce-path.toml) as a starter. `scan(path)`
|
|
105
|
+
and the CLI discover `rce-path.toml` at the scan root. Passing `ScanConfig` directly
|
|
106
|
+
uses exactly that configuration; the CLI also accepts `--config PATH`.
|
|
107
|
+
Unknown keys and invalid budgets fail explicitly. Exclusion patterns use forward
|
|
108
|
+
slashes. Repository configuration cannot enable AI, supply credentials, or grant
|
|
109
|
+
remote transmission permission. AI model/provider settings take effect only after
|
|
110
|
+
runtime opt-in. Repository AI endpoints are ignored unless the operator supplies
|
|
111
|
+
`--accept-config-ai-endpoint`; an explicit `--endpoint` takes precedence.
|
|
112
|
+
|
|
113
|
+
## Optional AI annotations
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
rce-path scan ./checkout --ai ollama --model YOUR_MODEL --format markdown
|
|
117
|
+
rce-path scan ./checkout --ai openai --model YOUR_MODEL --allow-remote-code
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Set `OPENAI_API_KEY` in the operator environment for OpenAI. Model names are always
|
|
121
|
+
operator-selected. OpenAI uses the official Responses API with strict structured
|
|
122
|
+
output and `store=False`; this is not a zero-retention promise. Ollama uses native
|
|
123
|
+
`/api/chat` with a JSON schema; the default is `http://127.0.0.1:11434`.
|
|
124
|
+
|
|
125
|
+
OpenAI and non-loopback Ollama endpoints require `--allow-remote-code`. Numeric
|
|
126
|
+
loopback addresses are recognized; hostnames, including `localhost`, conservatively
|
|
127
|
+
require consent to avoid DNS trust assumptions. No automatic cloud fallback.
|
|
128
|
+
Only bounded evidence slices are sent, with best-effort known-secret redaction.
|
|
129
|
+
Redaction can miss secrets; review your inputs before allowing transmission.
|
|
130
|
+
The scanner does not log raw prompts/source or provider exception bodies.
|
|
131
|
+
|
|
132
|
+
Both providers share `review(EvidenceBundle, ReviewConfig) -> ReviewResult`, validate
|
|
133
|
+
cited evidence IDs, and annotate without altering findings. Malformed output gets
|
|
134
|
+
at most one repair. Refusals/authentication failures do not trigger repairs.
|
|
135
|
+
Only transient failures retry with backoff and jitter. Requests are serial per
|
|
136
|
+
provider, with timeout, input/output size, context, review-count, and total token
|
|
137
|
+
budgets. Byte-based input token reservations are deliberately conservative;
|
|
138
|
+
actual tokenizer/context accounting varies by model. Temperature is omitted
|
|
139
|
+
unless explicitly declared supported through `ReviewConfig`.
|
|
140
|
+
|
|
141
|
+
`ai_status` distinguishes completed, refused, invalid_output, unsupported,
|
|
142
|
+
unavailable, and budget_exceeded. Failed reviews never appear successful.
|
|
143
|
+
Cancellation is available through `Cancellation` when constructing a provider;
|
|
144
|
+
in-flight transport completes or times out before cancellation takes effect.
|
|
145
|
+
No application cache is enabled or persisted; a versioned `cache_key()` helper is
|
|
146
|
+
provided for a future operator-controlled cache. Unknown model revisions remain
|
|
147
|
+
explicit. See [provider testing](providers.md) for optional live smoke tests.
|
|
148
|
+
|
|
149
|
+
## Development and publishing
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
python -m pip install -e ".[dev]"
|
|
153
|
+
python -m pytest
|
|
154
|
+
python -m ruff check src tests
|
|
155
|
+
python -m mypy
|
|
156
|
+
python -m build
|
|
157
|
+
python -m twine check dist/*
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
See [CONTRIBUTING.md](../CONTRIBUTING.md) and [release instructions](releasing.md)
|
|
161
|
+
for TestPyPI, PyPI trusted publishing, and the version/tag checks. Nothing in a
|
|
162
|
+
normal scan uploads code. No publishing occurs when running the tests/build.
|
|
163
|
+
|
|
164
|
+
The full [specification](../rce-path_spec.md) guides module boundaries. Phase 2 will
|
|
165
|
+
add bounded local call summaries, deserialization/version-aware rules, framework
|
|
166
|
+
and process models, independent AI review, evaluation, and SARIF. Phase 3 will add
|
|
167
|
+
separate human-approved validation and evidence bundles. Those phases are not
|
|
168
|
+
implemented in this release. Phase 1's P1 external rule-file enhancement is deferred.
|
|
169
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Library usage. The specified target is inspected, never imported."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from rce_path import ScanConfig, scan
|
|
6
|
+
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
import argparse
|
|
9
|
+
|
|
10
|
+
parser = argparse.ArgumentParser()
|
|
11
|
+
parser.add_argument("target")
|
|
12
|
+
args = parser.parse_args()
|
|
13
|
+
report = scan(args.target, ScanConfig(ai_enabled=False))
|
|
14
|
+
Path("findings.json").write_text(report.to_json(), encoding="utf-8")
|
|
15
|
+
print(report.summary)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[scan]
|
|
2
|
+
rules = ["python.eval", "python.exec", "os.system", "os.popen", "subprocess.shell"]
|
|
3
|
+
excludes = [".git", ".venv", "venv", "__pycache__", "build", "dist", "node_modules", "site-packages"]
|
|
4
|
+
max_file_bytes = 1000000
|
|
5
|
+
max_files = 10000
|
|
6
|
+
parser_timeout_seconds = 10.0
|
|
7
|
+
parser_memory_mb = 256
|
|
8
|
+
scan_timeout_seconds = 120.0
|
|
9
|
+
max_ast_nodes = 30000
|
|
10
|
+
max_flow_steps = 20000
|
|
11
|
+
loop_iterations = 8
|
|
12
|
+
max_evidence_steps = 64
|
|
13
|
+
|
|
14
|
+
[ai]
|
|
15
|
+
provider = "ollama"
|
|
16
|
+
model = "YOUR_MODEL"
|
|
17
|
+
timeout_seconds = 30.0
|
|
18
|
+
max_reviews = 20
|
|
19
|
+
max_input_bytes = 16000
|
|
20
|
+
max_output_tokens = 1024
|
|
21
|
+
total_token_budget = 50000
|
|
22
|
+
# Runtime --ai is required. Endpoint settings require explicit acceptance.
|
|
23
|
+
# endpoint = "http://127.0.0.1:11434"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rce-path"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Local-first, evidence-backed Python execution-path investigation"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{name = "Sai Teja Erukude"}]
|
|
13
|
+
requires-python = ">=3.11"
|
|
14
|
+
keywords = ["security", "static-analysis", "dataflow", "rce", "audit"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Programming Language :: Python :: 3.14",
|
|
23
|
+
"Topic :: Security",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
]
|
|
26
|
+
dependencies = ["pydantic>=2.7,<3"]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
openai = ["openai>=1.68,<3"]
|
|
30
|
+
ollama = ["ollama>=0.4.7,<1"]
|
|
31
|
+
ai = ["openai>=1.68,<3", "ollama>=0.4.7,<1"]
|
|
32
|
+
dev = ["pytest>=8,<10", "build>=1.2", "twine>=6", "ruff>=0.11", "mypy>=1.15"]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
rce-path = "rce_path.cli:main"
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.wheel]
|
|
38
|
+
packages = ["src/rce_path"]
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.sdist]
|
|
41
|
+
include = ["/src", "/tests", "/docs", "/examples", "/scripts", "/README.md", "/LICENSE", "/pyproject.toml", "/rce-path_spec.md", "/.github", "/CONTRIBUTING.md"]
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
testpaths = ["tests"]
|
|
45
|
+
pythonpath = ["src"]
|
|
46
|
+
addopts = "--import-mode=importlib"
|
|
47
|
+
|
|
48
|
+
[tool.ruff]
|
|
49
|
+
target-version = "py311"
|
|
50
|
+
line-length = 100
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
select = ["E4", "E7", "E9", "F", "I", "UP"]
|
|
54
|
+
|
|
55
|
+
[tool.mypy]
|
|
56
|
+
python_version = "3.11"
|
|
57
|
+
files = ["src/rce_path"]
|
|
58
|
+
check_untyped_defs = true
|
|
59
|
+
|
|
60
|
+
[[tool.mypy.overrides]]
|
|
61
|
+
# The static/dev installation intentionally excludes these optional AI SDKs.
|
|
62
|
+
module = ["openai.*", "ollama.*"]
|
|
63
|
+
ignore_missing_imports = true
|