vibesafex 0.3.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.
- vibesafex-0.3.0/.github/workflows/ci.yml +27 -0
- vibesafex-0.3.0/.gitignore +7 -0
- vibesafex-0.3.0/.pre-commit-hooks.yaml +15 -0
- vibesafex-0.3.0/CHANGELOG.md +24 -0
- vibesafex-0.3.0/LICENSE +15 -0
- vibesafex-0.3.0/PKG-INFO +175 -0
- vibesafex-0.3.0/README.md +150 -0
- vibesafex-0.3.0/action.yml +48 -0
- vibesafex-0.3.0/assets/checks_overview.svg +114 -0
- vibesafex-0.3.0/assets/scan_report.svg +132 -0
- vibesafex-0.3.0/examples/auto_fix.py +65 -0
- vibesafex-0.3.0/examples/ci_integration.py +75 -0
- vibesafex-0.3.0/examples/scan_project.py +58 -0
- vibesafex-0.3.0/examples/with_injectionguard.py +90 -0
- vibesafex-0.3.0/pyproject.toml +44 -0
- vibesafex-0.3.0/scripts/generate_assets.py +65 -0
- vibesafex-0.3.0/src/vibesafex/__init__.py +21 -0
- vibesafex-0.3.0/src/vibesafex/checks/__init__.py +1 -0
- vibesafex-0.3.0/src/vibesafex/checks/dead_code.py +124 -0
- vibesafex-0.3.0/src/vibesafex/checks/imports.py +130 -0
- vibesafex-0.3.0/src/vibesafex/checks/patterns.py +121 -0
- vibesafex-0.3.0/src/vibesafex/checks/secrets.py +53 -0
- vibesafex-0.3.0/src/vibesafex/checks/security.py +160 -0
- vibesafex-0.3.0/src/vibesafex/cli.py +198 -0
- vibesafex-0.3.0/src/vibesafex/complexity.py +268 -0
- vibesafex-0.3.0/src/vibesafex/fixer.py +210 -0
- vibesafex-0.3.0/src/vibesafex/mcp.py +175 -0
- vibesafex-0.3.0/src/vibesafex/py.typed +0 -0
- vibesafex-0.3.0/src/vibesafex/sarif.py +169 -0
- vibesafex-0.3.0/src/vibesafex/scanner.py +182 -0
- vibesafex-0.3.0/tests/test_cli.py +83 -0
- vibesafex-0.3.0/tests/test_complexity.py +202 -0
- vibesafex-0.3.0/tests/test_dead_code.py +66 -0
- vibesafex-0.3.0/tests/test_edge_cases.py +111 -0
- vibesafex-0.3.0/tests/test_fixer.py +202 -0
- vibesafex-0.3.0/tests/test_imports.py +40 -0
- vibesafex-0.3.0/tests/test_mcp.py +158 -0
- vibesafex-0.3.0/tests/test_patterns.py +91 -0
- vibesafex-0.3.0/tests/test_sarif.py +188 -0
- vibesafex-0.3.0/tests/test_scanner.py +131 -0
- vibesafex-0.3.0/tests/test_secrets.py +74 -0
- vibesafex-0.3.0/tests/test_security.py +96 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
- name: Install
|
|
23
|
+
run: pip install -e ".[dev]" 2>/dev/null || pip install -e .
|
|
24
|
+
- name: Install test deps
|
|
25
|
+
run: pip install pytest
|
|
26
|
+
- name: Test
|
|
27
|
+
run: pytest tests/ -v
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
- id: vibesafe
|
|
2
|
+
name: vibesafe
|
|
3
|
+
description: Scan AI-generated Python code for security issues and anti-patterns
|
|
4
|
+
entry: vibesafe scan --fail-on error
|
|
5
|
+
language: python
|
|
6
|
+
types: [python]
|
|
7
|
+
require_serial: false
|
|
8
|
+
|
|
9
|
+
- id: vibesafe-fix
|
|
10
|
+
name: vibesafe-fix
|
|
11
|
+
description: Auto-fix common issues in AI-generated Python code
|
|
12
|
+
entry: vibesafe fix
|
|
13
|
+
language: python
|
|
14
|
+
types: [python]
|
|
15
|
+
require_serial: true
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.3.0] - 2025-04-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Add code complexity analysis via `complexity.py`
|
|
12
|
+
- Add SARIF output format support in `sarif.py`
|
|
13
|
+
|
|
14
|
+
## [0.2.0] - 2026-04-10
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- Add MCP server for IDE integration
|
|
18
|
+
- Add --fix auto-fixer, pre-commit hooks, and GitHub Action
|
|
19
|
+
|
|
20
|
+
## [0.1.0] - 2026-04-10
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- Initial release: AI-generated code safety scanner
|
|
24
|
+
|
vibesafex-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
vibesafex-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vibesafex
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: AI-generated code safety scanner for the vibe coding era
|
|
5
|
+
Project-URL: Homepage, https://github.com/stef41/vibesafex
|
|
6
|
+
Project-URL: Repository, https://github.com/stef41/vibesafex
|
|
7
|
+
Project-URL: Issues, https://github.com/stef41/vibesafex/issues
|
|
8
|
+
Author: stef41
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai-code-review,ai-generated-code,claude-code,code-scanner,copilot,cursor,linter,llm,mcp,security,static-analysis,vibe-coding
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Security
|
|
22
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# vibesafex
|
|
27
|
+
|
|
28
|
+
[](https://github.com/stef41/vibesafex/actions/workflows/ci.yml)
|
|
29
|
+
[](https://www.python.org/downloads/)
|
|
30
|
+
[](LICENSE)
|
|
31
|
+
[](https://pypi.org/project/vibesafex/)
|
|
32
|
+
|
|
33
|
+
**Stop shipping AI-generated code you haven't reviewed.**
|
|
34
|
+
|
|
35
|
+
vibesafex catches the bugs your AI coding agent won't tell you about: hallucinated imports, hardcoded secrets, security vulnerabilities, and dead code.
|
|
36
|
+
|
|
37
|
+
Built for the vibe coding era. Works with code from Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install vibesafex
|
|
43
|
+
vibesafex scan .
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## What It Catches
|
|
47
|
+
|
|
48
|
+
| Code | Category | Severity | What |
|
|
49
|
+
|------|----------|----------|------|
|
|
50
|
+
| VS100-VS110 | **Security** | error | `eval()`, `exec()`, `shell=True`, SQL injection, `os.system()`, unsafe YAML, weak hashes |
|
|
51
|
+
| VS200-VS210 | **Secrets** | error | OpenAI/AWS/GitHub/Anthropic/Stripe API keys, private keys, JWTs, hardcoded credentials |
|
|
52
|
+
| VS300 | **Imports** | warning | Hallucinated imports — packages that don't exist (AI's favorite mistake) |
|
|
53
|
+
| VS400-VS403 | **Dead Code** | warning | Unused imports, unreachable code, empty `except: pass`, bare except |
|
|
54
|
+
| VS500-VS507 | **AI Patterns** | warning | TODO/FIXME left by AI, placeholder functions, `NotImplementedError` stubs, mutable defaults, star imports |
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
### Scan a directory
|
|
59
|
+
```bash
|
|
60
|
+
vibesafex scan src/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Scan specific files
|
|
64
|
+
```bash
|
|
65
|
+
vibesafex scan main.py utils.py
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Check code from stdin
|
|
69
|
+
```bash
|
|
70
|
+
echo 'x = eval(input())' | vibesafex check
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### JSON output (for CI/CD)
|
|
74
|
+
```bash
|
|
75
|
+
vibesafex scan . --format json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Filter by severity
|
|
79
|
+
```bash
|
|
80
|
+
vibesafex scan . --severity error # Only errors
|
|
81
|
+
vibesafex scan . --fail-on warning # Fail CI on warnings too
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Python API
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from vibesafex import scan_code, scan_file, scan_directory
|
|
88
|
+
|
|
89
|
+
# Scan a string
|
|
90
|
+
issues = scan_code('x = eval(input())')
|
|
91
|
+
for issue in issues:
|
|
92
|
+
print(f"{issue.code}: {issue.message}")
|
|
93
|
+
|
|
94
|
+
# Scan a file
|
|
95
|
+
issues = scan_file("main.py")
|
|
96
|
+
|
|
97
|
+
# Scan a project
|
|
98
|
+
result = scan_directory("src/")
|
|
99
|
+
print(f"{result.error_count} errors found in {result.files_scanned} files")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Custom scanner configuration
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from vibesafex import Scanner
|
|
106
|
+
|
|
107
|
+
scanner = Scanner(
|
|
108
|
+
severity_threshold="warning", # Skip info-level
|
|
109
|
+
exclude_dirs={".venv", "migrations"},
|
|
110
|
+
)
|
|
111
|
+
result = scanner.scan_directory(".")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Example Output
|
|
115
|
+
|
|
116
|
+
<img src="assets/scan_report.svg" alt="vibesafex scan report" width="800">
|
|
117
|
+
<img src="assets/checks_overview.svg" alt="vibesafex checks" width="800">
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
✗ main.py:5:0 [error] VS100: Use of eval() - potential code injection vulnerability
|
|
121
|
+
✗ main.py:8:0 [error] VS200: Possible OpenAI API key
|
|
122
|
+
⚠ main.py:12:0 [warning] VS300: Import 'magic_ai_lib' - package 'magic_ai_lib' not found (hallucinated import?)
|
|
123
|
+
⚠ main.py:15:0 [warning] VS501: Function 'process' has empty body (pass) - placeholder
|
|
124
|
+
ℹ main.py:20:0 [info] VS500: TODO comment - AI may have left incomplete implementation
|
|
125
|
+
|
|
126
|
+
5 files scanned: 2 errors, 2 warnings, 1 info
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Pre-commit Hook
|
|
130
|
+
|
|
131
|
+
```yaml
|
|
132
|
+
# .pre-commit-config.yaml
|
|
133
|
+
repos:
|
|
134
|
+
- repo: local
|
|
135
|
+
hooks:
|
|
136
|
+
- id: vibesafex
|
|
137
|
+
name: vibesafex
|
|
138
|
+
entry: vibesafex scan --fail-on error
|
|
139
|
+
language: python
|
|
140
|
+
types: [python]
|
|
141
|
+
additional_dependencies: [vibesafex]
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Why Not Just Use Ruff/Pylint?
|
|
145
|
+
|
|
146
|
+
vibesafex focuses specifically on **AI-generated code patterns** that traditional linters miss:
|
|
147
|
+
|
|
148
|
+
- **Hallucinated imports**: AI confidently imports packages that don't exist. vibesafex checks against stdlib, installed packages, and 200+ known popular packages.
|
|
149
|
+
- **Secret leakage**: AI copies real-looking API keys into code. vibesafex detects patterns for 12+ providers.
|
|
150
|
+
- **Placeholder code**: AI leaves `pass`, `...`, `NotImplementedError` stubs that slip through review.
|
|
151
|
+
- **AI anti-patterns**: Mutable defaults, star imports, excessive `Any` — patterns AI generates more often than humans.
|
|
152
|
+
|
|
153
|
+
Use vibesafex **alongside** your existing linter, not instead of it.
|
|
154
|
+
|
|
155
|
+
## See Also
|
|
156
|
+
|
|
157
|
+
Part of the **stef41 LLM toolkit** — open-source tools for every stage of the LLM lifecycle:
|
|
158
|
+
|
|
159
|
+
| Project | What it does |
|
|
160
|
+
|---------|-------------|
|
|
161
|
+
| [tokonomics](https://github.com/stef41/tokonomix) | Token counting & cost management for LLM APIs |
|
|
162
|
+
| [datacrux](https://github.com/stef41/datacruxai) | Training data quality — dedup, PII, contamination |
|
|
163
|
+
| [castwright](https://github.com/stef41/castwright) | Synthetic instruction data generation |
|
|
164
|
+
| [datamix](https://github.com/stef41/datamix) | Dataset mixing & curriculum optimization |
|
|
165
|
+
| [toksight](https://github.com/stef41/toksight) | Tokenizer analysis & comparison |
|
|
166
|
+
| [trainpulse](https://github.com/stef41/trainpulse) | Training health monitoring |
|
|
167
|
+
| [ckpt](https://github.com/stef41/ckptkit) | Checkpoint inspection, diffing & merging |
|
|
168
|
+
| [quantbench](https://github.com/stef41/quantbenchx) | Quantization quality analysis |
|
|
169
|
+
| [infermark](https://github.com/stef41/infermark) | Inference benchmarking |
|
|
170
|
+
| [modeldiff](https://github.com/stef41/modeldiffx) | Behavioral regression testing |
|
|
171
|
+
| [injectionguard](https://github.com/stef41/injectionguard) | Prompt injection detection |
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
Apache 2.0
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# vibesafex
|
|
2
|
+
|
|
3
|
+
[](https://github.com/stef41/vibesafex/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://pypi.org/project/vibesafex/)
|
|
7
|
+
|
|
8
|
+
**Stop shipping AI-generated code you haven't reviewed.**
|
|
9
|
+
|
|
10
|
+
vibesafex catches the bugs your AI coding agent won't tell you about: hallucinated imports, hardcoded secrets, security vulnerabilities, and dead code.
|
|
11
|
+
|
|
12
|
+
Built for the vibe coding era. Works with code from Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install vibesafex
|
|
18
|
+
vibesafex scan .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## What It Catches
|
|
22
|
+
|
|
23
|
+
| Code | Category | Severity | What |
|
|
24
|
+
|------|----------|----------|------|
|
|
25
|
+
| VS100-VS110 | **Security** | error | `eval()`, `exec()`, `shell=True`, SQL injection, `os.system()`, unsafe YAML, weak hashes |
|
|
26
|
+
| VS200-VS210 | **Secrets** | error | OpenAI/AWS/GitHub/Anthropic/Stripe API keys, private keys, JWTs, hardcoded credentials |
|
|
27
|
+
| VS300 | **Imports** | warning | Hallucinated imports — packages that don't exist (AI's favorite mistake) |
|
|
28
|
+
| VS400-VS403 | **Dead Code** | warning | Unused imports, unreachable code, empty `except: pass`, bare except |
|
|
29
|
+
| VS500-VS507 | **AI Patterns** | warning | TODO/FIXME left by AI, placeholder functions, `NotImplementedError` stubs, mutable defaults, star imports |
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Scan a directory
|
|
34
|
+
```bash
|
|
35
|
+
vibesafex scan src/
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Scan specific files
|
|
39
|
+
```bash
|
|
40
|
+
vibesafex scan main.py utils.py
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Check code from stdin
|
|
44
|
+
```bash
|
|
45
|
+
echo 'x = eval(input())' | vibesafex check
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### JSON output (for CI/CD)
|
|
49
|
+
```bash
|
|
50
|
+
vibesafex scan . --format json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Filter by severity
|
|
54
|
+
```bash
|
|
55
|
+
vibesafex scan . --severity error # Only errors
|
|
56
|
+
vibesafex scan . --fail-on warning # Fail CI on warnings too
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Python API
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from vibesafex import scan_code, scan_file, scan_directory
|
|
63
|
+
|
|
64
|
+
# Scan a string
|
|
65
|
+
issues = scan_code('x = eval(input())')
|
|
66
|
+
for issue in issues:
|
|
67
|
+
print(f"{issue.code}: {issue.message}")
|
|
68
|
+
|
|
69
|
+
# Scan a file
|
|
70
|
+
issues = scan_file("main.py")
|
|
71
|
+
|
|
72
|
+
# Scan a project
|
|
73
|
+
result = scan_directory("src/")
|
|
74
|
+
print(f"{result.error_count} errors found in {result.files_scanned} files")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Custom scanner configuration
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from vibesafex import Scanner
|
|
81
|
+
|
|
82
|
+
scanner = Scanner(
|
|
83
|
+
severity_threshold="warning", # Skip info-level
|
|
84
|
+
exclude_dirs={".venv", "migrations"},
|
|
85
|
+
)
|
|
86
|
+
result = scanner.scan_directory(".")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Example Output
|
|
90
|
+
|
|
91
|
+
<img src="assets/scan_report.svg" alt="vibesafex scan report" width="800">
|
|
92
|
+
<img src="assets/checks_overview.svg" alt="vibesafex checks" width="800">
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
✗ main.py:5:0 [error] VS100: Use of eval() - potential code injection vulnerability
|
|
96
|
+
✗ main.py:8:0 [error] VS200: Possible OpenAI API key
|
|
97
|
+
⚠ main.py:12:0 [warning] VS300: Import 'magic_ai_lib' - package 'magic_ai_lib' not found (hallucinated import?)
|
|
98
|
+
⚠ main.py:15:0 [warning] VS501: Function 'process' has empty body (pass) - placeholder
|
|
99
|
+
ℹ main.py:20:0 [info] VS500: TODO comment - AI may have left incomplete implementation
|
|
100
|
+
|
|
101
|
+
5 files scanned: 2 errors, 2 warnings, 1 info
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Pre-commit Hook
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
# .pre-commit-config.yaml
|
|
108
|
+
repos:
|
|
109
|
+
- repo: local
|
|
110
|
+
hooks:
|
|
111
|
+
- id: vibesafex
|
|
112
|
+
name: vibesafex
|
|
113
|
+
entry: vibesafex scan --fail-on error
|
|
114
|
+
language: python
|
|
115
|
+
types: [python]
|
|
116
|
+
additional_dependencies: [vibesafex]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Why Not Just Use Ruff/Pylint?
|
|
120
|
+
|
|
121
|
+
vibesafex focuses specifically on **AI-generated code patterns** that traditional linters miss:
|
|
122
|
+
|
|
123
|
+
- **Hallucinated imports**: AI confidently imports packages that don't exist. vibesafex checks against stdlib, installed packages, and 200+ known popular packages.
|
|
124
|
+
- **Secret leakage**: AI copies real-looking API keys into code. vibesafex detects patterns for 12+ providers.
|
|
125
|
+
- **Placeholder code**: AI leaves `pass`, `...`, `NotImplementedError` stubs that slip through review.
|
|
126
|
+
- **AI anti-patterns**: Mutable defaults, star imports, excessive `Any` — patterns AI generates more often than humans.
|
|
127
|
+
|
|
128
|
+
Use vibesafex **alongside** your existing linter, not instead of it.
|
|
129
|
+
|
|
130
|
+
## See Also
|
|
131
|
+
|
|
132
|
+
Part of the **stef41 LLM toolkit** — open-source tools for every stage of the LLM lifecycle:
|
|
133
|
+
|
|
134
|
+
| Project | What it does |
|
|
135
|
+
|---------|-------------|
|
|
136
|
+
| [tokonomics](https://github.com/stef41/tokonomix) | Token counting & cost management for LLM APIs |
|
|
137
|
+
| [datacrux](https://github.com/stef41/datacruxai) | Training data quality — dedup, PII, contamination |
|
|
138
|
+
| [castwright](https://github.com/stef41/castwright) | Synthetic instruction data generation |
|
|
139
|
+
| [datamix](https://github.com/stef41/datamix) | Dataset mixing & curriculum optimization |
|
|
140
|
+
| [toksight](https://github.com/stef41/toksight) | Tokenizer analysis & comparison |
|
|
141
|
+
| [trainpulse](https://github.com/stef41/trainpulse) | Training health monitoring |
|
|
142
|
+
| [ckpt](https://github.com/stef41/ckptkit) | Checkpoint inspection, diffing & merging |
|
|
143
|
+
| [quantbench](https://github.com/stef41/quantbenchx) | Quantization quality analysis |
|
|
144
|
+
| [infermark](https://github.com/stef41/infermark) | Inference benchmarking |
|
|
145
|
+
| [modeldiff](https://github.com/stef41/modeldiffx) | Behavioral regression testing |
|
|
146
|
+
| [injectionguard](https://github.com/stef41/injectionguard) | Prompt injection detection |
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
Apache 2.0
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: 'vibesafex'
|
|
2
|
+
description: 'Scan AI-generated Python code for security issues and anti-patterns'
|
|
3
|
+
branding:
|
|
4
|
+
icon: 'shield'
|
|
5
|
+
color: 'purple'
|
|
6
|
+
|
|
7
|
+
inputs:
|
|
8
|
+
paths:
|
|
9
|
+
description: 'Paths to scan (space-separated)'
|
|
10
|
+
required: false
|
|
11
|
+
default: '.'
|
|
12
|
+
severity:
|
|
13
|
+
description: 'Minimum severity to report (error, warning, info)'
|
|
14
|
+
required: false
|
|
15
|
+
default: 'info'
|
|
16
|
+
fail-on:
|
|
17
|
+
description: 'Fail if issues at this level or above are found'
|
|
18
|
+
required: false
|
|
19
|
+
default: 'error'
|
|
20
|
+
version:
|
|
21
|
+
description: 'vibesafex version to install'
|
|
22
|
+
required: false
|
|
23
|
+
default: 'latest'
|
|
24
|
+
|
|
25
|
+
runs:
|
|
26
|
+
using: 'composite'
|
|
27
|
+
steps:
|
|
28
|
+
- name: Set up Python
|
|
29
|
+
uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: '3.x'
|
|
32
|
+
|
|
33
|
+
- name: Install vibesafex
|
|
34
|
+
shell: bash
|
|
35
|
+
run: |
|
|
36
|
+
if [ "${{ inputs.version }}" = "latest" ]; then
|
|
37
|
+
pip install vibesafex
|
|
38
|
+
else
|
|
39
|
+
pip install "vibesafex==${{ inputs.version }}"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
- name: Run vibesafex
|
|
43
|
+
shell: bash
|
|
44
|
+
run: |
|
|
45
|
+
vibesafex scan ${{ inputs.paths }} \
|
|
46
|
+
--severity ${{ inputs.severity }} \
|
|
47
|
+
--fail-on ${{ inputs.fail-on }} \
|
|
48
|
+
--format text
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<svg class="rich-terminal" viewBox="0 0 1055 367.2" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Generated with Rich https://www.textualize.io -->
|
|
3
|
+
<style>
|
|
4
|
+
|
|
5
|
+
@font-face {
|
|
6
|
+
font-family: "Fira Code";
|
|
7
|
+
src: local("FiraCode-Regular"),
|
|
8
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
|
9
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
|
10
|
+
font-style: normal;
|
|
11
|
+
font-weight: 400;
|
|
12
|
+
}
|
|
13
|
+
@font-face {
|
|
14
|
+
font-family: "Fira Code";
|
|
15
|
+
src: local("FiraCode-Bold"),
|
|
16
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
|
17
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
|
18
|
+
font-style: bold;
|
|
19
|
+
font-weight: 700;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.terminal-1798561328-matrix {
|
|
23
|
+
font-family: Fira Code, monospace;
|
|
24
|
+
font-size: 20px;
|
|
25
|
+
line-height: 24.4px;
|
|
26
|
+
font-variant-east-asian: full-width;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.terminal-1798561328-title {
|
|
30
|
+
font-size: 18px;
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-family: arial;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.terminal-1798561328-r1 { fill: #c5c8c6;font-style: italic; }
|
|
36
|
+
.terminal-1798561328-r2 { fill: #c5c8c6 }
|
|
37
|
+
.terminal-1798561328-r3 { fill: #68a0b3;font-weight: bold }
|
|
38
|
+
.terminal-1798561328-r4 { fill: #c5c8c6;font-weight: bold }
|
|
39
|
+
.terminal-1798561328-r5 { fill: #cc555a;font-weight: bold }
|
|
40
|
+
.terminal-1798561328-r6 { fill: #d0b344 }
|
|
41
|
+
.terminal-1798561328-r7 { fill: #d0b344;font-weight: bold }
|
|
42
|
+
.terminal-1798561328-r8 { fill: #608ab1;font-weight: bold }
|
|
43
|
+
.terminal-1798561328-r9 { fill: #98a84b;font-weight: bold }
|
|
44
|
+
</style>
|
|
45
|
+
|
|
46
|
+
<defs>
|
|
47
|
+
<clipPath id="terminal-1798561328-clip-terminal">
|
|
48
|
+
<rect x="0" y="0" width="1036.0" height="316.2" />
|
|
49
|
+
</clipPath>
|
|
50
|
+
<clipPath id="terminal-1798561328-line-0">
|
|
51
|
+
<rect x="0" y="1.5" width="1037" height="24.65"/>
|
|
52
|
+
</clipPath>
|
|
53
|
+
<clipPath id="terminal-1798561328-line-1">
|
|
54
|
+
<rect x="0" y="25.9" width="1037" height="24.65"/>
|
|
55
|
+
</clipPath>
|
|
56
|
+
<clipPath id="terminal-1798561328-line-2">
|
|
57
|
+
<rect x="0" y="50.3" width="1037" height="24.65"/>
|
|
58
|
+
</clipPath>
|
|
59
|
+
<clipPath id="terminal-1798561328-line-3">
|
|
60
|
+
<rect x="0" y="74.7" width="1037" height="24.65"/>
|
|
61
|
+
</clipPath>
|
|
62
|
+
<clipPath id="terminal-1798561328-line-4">
|
|
63
|
+
<rect x="0" y="99.1" width="1037" height="24.65"/>
|
|
64
|
+
</clipPath>
|
|
65
|
+
<clipPath id="terminal-1798561328-line-5">
|
|
66
|
+
<rect x="0" y="123.5" width="1037" height="24.65"/>
|
|
67
|
+
</clipPath>
|
|
68
|
+
<clipPath id="terminal-1798561328-line-6">
|
|
69
|
+
<rect x="0" y="147.9" width="1037" height="24.65"/>
|
|
70
|
+
</clipPath>
|
|
71
|
+
<clipPath id="terminal-1798561328-line-7">
|
|
72
|
+
<rect x="0" y="172.3" width="1037" height="24.65"/>
|
|
73
|
+
</clipPath>
|
|
74
|
+
<clipPath id="terminal-1798561328-line-8">
|
|
75
|
+
<rect x="0" y="196.7" width="1037" height="24.65"/>
|
|
76
|
+
</clipPath>
|
|
77
|
+
<clipPath id="terminal-1798561328-line-9">
|
|
78
|
+
<rect x="0" y="221.1" width="1037" height="24.65"/>
|
|
79
|
+
</clipPath>
|
|
80
|
+
<clipPath id="terminal-1798561328-line-10">
|
|
81
|
+
<rect x="0" y="245.5" width="1037" height="24.65"/>
|
|
82
|
+
</clipPath>
|
|
83
|
+
<clipPath id="terminal-1798561328-line-11">
|
|
84
|
+
<rect x="0" y="269.9" width="1037" height="24.65"/>
|
|
85
|
+
</clipPath>
|
|
86
|
+
</defs>
|
|
87
|
+
|
|
88
|
+
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1053" height="365.2" rx="8"/><text class="terminal-1798561328-title" fill="#c5c8c6" text-anchor="middle" x="526" y="27">vibesafe checks</text>
|
|
89
|
+
<g transform="translate(26,22)">
|
|
90
|
+
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
|
91
|
+
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
|
92
|
+
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
|
93
|
+
</g>
|
|
94
|
+
|
|
95
|
+
<g transform="translate(9, 41)" clip-path="url(#terminal-1798561328-clip-terminal)">
|
|
96
|
+
|
|
97
|
+
<g class="terminal-1798561328-matrix">
|
|
98
|
+
<text class="terminal-1798561328-r1" x="0" y="20" textLength="1037" clip-path="url(#terminal-1798561328-line-0)">                              vibesafe check categories                              </text><text class="terminal-1798561328-r2" x="1037" y="20" textLength="12.2" clip-path="url(#terminal-1798561328-line-0)">
|
|
99
|
+
</text><text class="terminal-1798561328-r2" x="0" y="44.4" textLength="1037" clip-path="url(#terminal-1798561328-line-1)">┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓</text><text class="terminal-1798561328-r2" x="1037" y="44.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-1)">
|
|
100
|
+
</text><text class="terminal-1798561328-r2" x="0" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r3" x="24.4" y="68.8" textLength="134.2" clip-path="url(#terminal-1798561328-line-2)">Category   </text><text class="terminal-1798561328-r2" x="170.8" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r3" x="195.2" y="68.8" textLength="134.2" clip-path="url(#terminal-1798561328-line-2)">Codes      </text><text class="terminal-1798561328-r2" x="341.6" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r3" x="366" y="68.8" textLength="73.2" clip-path="url(#terminal-1798561328-line-2)">Checks</text><text class="terminal-1798561328-r2" x="451.4" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r3" x="475.8" y="68.8" textLength="536.8" clip-path="url(#terminal-1798561328-line-2)">What It Catches                             </text><text class="terminal-1798561328-r2" x="1024.8" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r2" x="1037" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">
|
|
101
|
+
</text><text class="terminal-1798561328-r2" x="0" y="93.2" textLength="1037" clip-path="url(#terminal-1798561328-line-3)">┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩</text><text class="terminal-1798561328-r2" x="1037" y="93.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-3)">
|
|
102
|
+
</text><text class="terminal-1798561328-r2" x="0" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r5" x="24.4" y="117.6" textLength="97.6" clip-path="url(#terminal-1798561328-line-4)">Security</text><text class="terminal-1798561328-r2" x="170.8" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r6" x="195.2" y="117.6" textLength="134.2" clip-path="url(#terminal-1798561328-line-4)">VS100-VS110</text><text class="terminal-1798561328-r2" x="341.6" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r2" x="366" y="117.6" textLength="73.2" clip-path="url(#terminal-1798561328-line-4)">    11</text><text class="terminal-1798561328-r2" x="451.4" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r2" x="475.8" y="117.6" textLength="536.8" clip-path="url(#terminal-1798561328-line-4)">eval, exec, shell injection, SQL injection  </text><text class="terminal-1798561328-r2" x="1024.8" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r2" x="1037" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">
|
|
103
|
+
</text><text class="terminal-1798561328-r2" x="0" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r5" x="24.4" y="142" textLength="85.4" clip-path="url(#terminal-1798561328-line-5)">Secrets</text><text class="terminal-1798561328-r2" x="170.8" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r6" x="195.2" y="142" textLength="134.2" clip-path="url(#terminal-1798561328-line-5)">VS200-VS210</text><text class="terminal-1798561328-r2" x="341.6" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r2" x="366" y="142" textLength="73.2" clip-path="url(#terminal-1798561328-line-5)">    12</text><text class="terminal-1798561328-r2" x="451.4" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r2" x="475.8" y="142" textLength="536.8" clip-path="url(#terminal-1798561328-line-5)">API keys, tokens, private keys, credentials </text><text class="terminal-1798561328-r2" x="1024.8" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r2" x="1037" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">
|
|
104
|
+
</text><text class="terminal-1798561328-r2" x="0" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r7" x="24.4" y="166.4" textLength="85.4" clip-path="url(#terminal-1798561328-line-6)">Imports</text><text class="terminal-1798561328-r2" x="170.8" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r6" x="195.2" y="166.4" textLength="134.2" clip-path="url(#terminal-1798561328-line-6)">VS300      </text><text class="terminal-1798561328-r2" x="341.6" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r2" x="366" y="166.4" textLength="73.2" clip-path="url(#terminal-1798561328-line-6)">     1</text><text class="terminal-1798561328-r2" x="451.4" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r2" x="475.8" y="166.4" textLength="536.8" clip-path="url(#terminal-1798561328-line-6)">Hallucinated packages (AI's #1 mistake)     </text><text class="terminal-1798561328-r2" x="1024.8" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r2" x="1037" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">
|
|
105
|
+
</text><text class="terminal-1798561328-r2" x="0" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r7" x="24.4" y="190.8" textLength="109.8" clip-path="url(#terminal-1798561328-line-7)">Dead Code</text><text class="terminal-1798561328-r2" x="170.8" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r6" x="195.2" y="190.8" textLength="134.2" clip-path="url(#terminal-1798561328-line-7)">VS400-VS403</text><text class="terminal-1798561328-r2" x="341.6" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r2" x="366" y="190.8" textLength="73.2" clip-path="url(#terminal-1798561328-line-7)">     4</text><text class="terminal-1798561328-r2" x="451.4" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r2" x="475.8" y="190.8" textLength="536.8" clip-path="url(#terminal-1798561328-line-7)">Unused imports, unreachable code, bare      </text><text class="terminal-1798561328-r2" x="1024.8" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r2" x="1037" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">
|
|
106
|
+
</text><text class="terminal-1798561328-r2" x="0" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="170.8" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="341.6" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="451.4" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="475.8" y="215.2" textLength="536.8" clip-path="url(#terminal-1798561328-line-8)">except                                      </text><text class="terminal-1798561328-r2" x="1024.8" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="1037" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">
|
|
107
|
+
</text><text class="terminal-1798561328-r2" x="0" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r8" x="24.4" y="239.6" textLength="134.2" clip-path="url(#terminal-1798561328-line-9)">AI Patterns</text><text class="terminal-1798561328-r2" x="170.8" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r6" x="195.2" y="239.6" textLength="134.2" clip-path="url(#terminal-1798561328-line-9)">VS500-VS507</text><text class="terminal-1798561328-r2" x="341.6" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r2" x="366" y="239.6" textLength="73.2" clip-path="url(#terminal-1798561328-line-9)">     8</text><text class="terminal-1798561328-r2" x="451.4" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r2" x="475.8" y="239.6" textLength="536.8" clip-path="url(#terminal-1798561328-line-9)">TODOs, stubs, mutable defaults, star imports</text><text class="terminal-1798561328-r2" x="1024.8" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r2" x="1037" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">
|
|
108
|
+
</text><text class="terminal-1798561328-r2" x="0" y="264" textLength="1037" clip-path="url(#terminal-1798561328-line-10)">└─────────────┴─────────────┴────────┴──────────────────────────────────────────────┘</text><text class="terminal-1798561328-r2" x="1037" y="264" textLength="12.2" clip-path="url(#terminal-1798561328-line-10)">
|
|
109
|
+
</text><text class="terminal-1798561328-r2" x="1037" y="288.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-11)">
|
|
110
|
+
</text><text class="terminal-1798561328-r9" x="0" y="312.8" textLength="24.4" clip-path="url(#terminal-1798561328-line-12)">36</text><text class="terminal-1798561328-r9" x="24.4" y="312.8" textLength="195.2" clip-path="url(#terminal-1798561328-line-12)"> built-in checks</text><text class="terminal-1798561328-r2" x="219.6" y="312.8" textLength="463.6" clip-path="url(#terminal-1798561328-line-12)"> • Zero dependencies • <100ms per file</text><text class="terminal-1798561328-r2" x="1037" y="312.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-12)">
|
|
111
|
+
</text>
|
|
112
|
+
</g>
|
|
113
|
+
</g>
|
|
114
|
+
</svg>
|