vulnerability-explorer 1.0.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.
- vulnerability_explorer-1.0.0/PKG-INFO +149 -0
- vulnerability_explorer-1.0.0/README.md +131 -0
- vulnerability_explorer-1.0.0/pyproject.toml +46 -0
- vulnerability_explorer-1.0.0/setup.cfg +4 -0
- vulnerability_explorer-1.0.0/src/vex/__init__.py +3 -0
- vulnerability_explorer-1.0.0/src/vex/commands/__init__.py +1 -0
- vulnerability_explorer-1.0.0/src/vex/commands/interactive.py +14 -0
- vulnerability_explorer-1.0.0/src/vex/commands/list.py +29 -0
- vulnerability_explorer-1.0.0/src/vex/commands/options.py +78 -0
- vulnerability_explorer-1.0.0/src/vex/commands/read.py +42 -0
- vulnerability_explorer-1.0.0/src/vex/commands/search.py +27 -0
- vulnerability_explorer-1.0.0/src/vex/commands/sync.py +50 -0
- vulnerability_explorer-1.0.0/src/vex/commands/tree.py +14 -0
- vulnerability_explorer-1.0.0/src/vex/core/__init__.py +1 -0
- vulnerability_explorer-1.0.0/src/vex/core/catalog.py +59 -0
- vulnerability_explorer-1.0.0/src/vex/core/models.py +24 -0
- vulnerability_explorer-1.0.0/src/vex/main.py +38 -0
- vulnerability_explorer-1.0.0/src/vex/utils/__init__.py +1 -0
- vulnerability_explorer-1.0.0/src/vex/utils/display.py +264 -0
- vulnerability_explorer-1.0.0/src/vex/utils/filesystem.py +49 -0
- vulnerability_explorer-1.0.0/src/vex_lint/__init__.py +5 -0
- vulnerability_explorer-1.0.0/src/vex_lint/core/context.py +25 -0
- vulnerability_explorer-1.0.0/src/vex_lint/core/engine.py +36 -0
- vulnerability_explorer-1.0.0/src/vex_lint/core/models.py +42 -0
- vulnerability_explorer-1.0.0/src/vex_lint/core/rule.py +30 -0
- vulnerability_explorer-1.0.0/src/vex_lint/linter.py +5 -0
- vulnerability_explorer-1.0.0/src/vex_lint/loaders/markdown.py +88 -0
- vulnerability_explorer-1.0.0/src/vex_lint/loaders/taxonomy.py +32 -0
- vulnerability_explorer-1.0.0/src/vex_lint/main.py +34 -0
- vulnerability_explorer-1.0.0/src/vex_lint/rules/cross_reference_rule.py +47 -0
- vulnerability_explorer-1.0.0/src/vex_lint/rules/frontmatter_schema_rule.py +68 -0
- vulnerability_explorer-1.0.0/src/vex_lint/rules/markdown_structure_rule.py +49 -0
- vulnerability_explorer-1.0.0/src/vex_lint/rules/path_convention_rule.py +72 -0
- vulnerability_explorer-1.0.0/src/vex_lint/rules/taxonomy_rule.py +30 -0
- vulnerability_explorer-1.0.0/src/vex_lint/schemas/frontmatter.py +111 -0
- vulnerability_explorer-1.0.0/src/vex_lint/schemas/sections.py +55 -0
- vulnerability_explorer-1.0.0/src/vex_lint/service.py +70 -0
- vulnerability_explorer-1.0.0/src/vulnerability_explorer.egg-info/PKG-INFO +149 -0
- vulnerability_explorer-1.0.0/src/vulnerability_explorer.egg-info/SOURCES.txt +41 -0
- vulnerability_explorer-1.0.0/src/vulnerability_explorer.egg-info/dependency_links.txt +1 -0
- vulnerability_explorer-1.0.0/src/vulnerability_explorer.egg-info/entry_points.txt +3 -0
- vulnerability_explorer-1.0.0/src/vulnerability_explorer.egg-info/requires.txt +11 -0
- vulnerability_explorer-1.0.0/src/vulnerability_explorer.egg-info/top_level.txt +2 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vulnerability-explorer
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A searchable catalog of software vulnerabilities with detailed technical documentation and a CLI explorer.
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: pyyaml>=6.0
|
|
9
|
+
Requires-Dist: types-pyyaml>=6.0.12.20260724
|
|
10
|
+
Requires-Dist: typer>=0.9.0
|
|
11
|
+
Requires-Dist: rich>=13.0
|
|
12
|
+
Requires-Dist: questionary>=2.0.0
|
|
13
|
+
Requires-Dist: pydantic>=2.0.0
|
|
14
|
+
Requires-Dist: markdown-it-py>=3.0.0
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
17
|
+
Requires-Dist: mypy>=1.5.0; extra == "dev"
|
|
18
|
+
|
|
19
|
+
# Vulnerability Explorer (`vex`)
|
|
20
|
+
|
|
21
|
+
> **A git-native, interactive terminal reference and structured knowledge base for software vulnerabilities.**
|
|
22
|
+
|
|
23
|
+
## What is Vulnerability Explorer?
|
|
24
|
+
|
|
25
|
+
Imagine `man` pages built specifically for application security. **Vulnerability Explorer** is a curated, structured knowledge base of software vulnerabilities combined with a versatile command-line tool (`vex`).
|
|
26
|
+
|
|
27
|
+
Each entry in the catalog is an **atomic Markdown file** enriched with structured YAML frontmatter. Entries document concrete vulnerability mechanisms across languages, frameworks, and architectures, detailing:
|
|
28
|
+
|
|
29
|
+
- **White-box identification** (Vulnerable vs. Safe code snippets, Source/Sink taint patterns)
|
|
30
|
+
- **Gray/Black-box behavior** (Observable indicators, protocol tells, timing characteristics)
|
|
31
|
+
- **Remediation & Fixes** (Primary patches, alternative approaches, common mistakes)
|
|
32
|
+
|
|
33
|
+
> [!NOTE] **This is a knowledge base, not a scanner.** It is designed for security engineers reviewing code, developers learning secure coding, AI agents generating structured security documentation, and CLI lovers looking for fast terminal references.
|
|
34
|
+
|
|
35
|
+
## Key Features
|
|
36
|
+
|
|
37
|
+
- **Interactive Terminal CLI (`vex`)**: Built-in arrow-key interactive menu for seamless browsing.
|
|
38
|
+
- **Built-in Pager Reading**: Read rich formatted documentation in the terminal with built-in scrolling (`less`-style).
|
|
39
|
+
- **Multi-dimensional Filtering**: Filter entries by category, programming language, or analysis mode (white-box / black-box).
|
|
40
|
+
- **Full-Text Search**: Instantly query across titles, tags, code snippets, and methodologies.
|
|
41
|
+
- **AI-Native Workflow**: Pre-built LLM prompts in `.github/prompts/` to easily author new entries with strict quality standards.
|
|
42
|
+
- **Structural Linter (`vex-lint`)**: Strict schema, taxonomy, and reference validation tool for contributors and CI/CD pipelines.
|
|
43
|
+
|
|
44
|
+
## Who is this for?
|
|
45
|
+
|
|
46
|
+
| Audience | How They Use Vulnerability Explorer |
|
|
47
|
+
| :----------------------- | :-------------------------------------------------------------------------------------- |
|
|
48
|
+
| **Security Engineers** | Fast reference during penetration tests, code audits, and report writing. |
|
|
49
|
+
| **Developers** | Learn vulnerability root causes and compare side-by-side vulnerable vs. safe code. |
|
|
50
|
+
| **AI Agents & LLMs** | Consume structured YAML/Markdown entries or generate new ones using `.github/prompts/`. |
|
|
51
|
+
| **Educators & Students** | Study standardized vulnerability taxonomy and recognition signals. |
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### 1. Installation
|
|
56
|
+
|
|
57
|
+
#### From PyPI
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Using pip
|
|
61
|
+
pip install vulnerability-explorer
|
|
62
|
+
|
|
63
|
+
# Or using uv
|
|
64
|
+
uv pip install vulnerability-explorer
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### From Source (For Contributors)
|
|
68
|
+
|
|
69
|
+
Clone the repository and install in editable mode:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/othonhugo/vulnerability-explorer.git
|
|
73
|
+
cd vulnerability-explorer
|
|
74
|
+
|
|
75
|
+
# Using uv (recommended)
|
|
76
|
+
uv pip install -e .
|
|
77
|
+
|
|
78
|
+
# Or standard pip
|
|
79
|
+
pip install -e .
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Launch Interactive Mode
|
|
83
|
+
|
|
84
|
+
Simply type `vex` to launch the interactive arrow-key navigation menu:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
vex
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## CLI Usage Overview
|
|
91
|
+
|
|
92
|
+
| Task | Command |
|
|
93
|
+
| :-------------------------------- | :-------------------------------------------- |
|
|
94
|
+
| **Interactive Menu** | `vex` or `vex interactive` |
|
|
95
|
+
| **View Catalog Hierarchy** | `vex tree` |
|
|
96
|
+
| **Filter by Category** | `vex list --category injection` |
|
|
97
|
+
| **Filter by Language & Mode** | `vex list --language python --mode white-box` |
|
|
98
|
+
| **Read Specific Entry** | `vex read injection.sql-injection` |
|
|
99
|
+
| **Search Catalog** | `vex search "prepared statement"` |
|
|
100
|
+
| **Plain Text Output (No Colors)** | `vex list --no-rich` |
|
|
101
|
+
|
|
102
|
+
> For full CLI options, flags, and advanced usage, see the **[CLI Commands Reference](docs/commands/README.md)**.
|
|
103
|
+
|
|
104
|
+
## Catalog Structure At A Glance
|
|
105
|
+
|
|
106
|
+
The catalog is organized logically under `data/`:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
data/
|
|
110
|
+
├── catalog/ # Vulnerability classes & manifestations
|
|
111
|
+
│ ├── access-control/
|
|
112
|
+
│ ├── injection/
|
|
113
|
+
│ │ ├── sql-injection/
|
|
114
|
+
│ │ │ ├── README.md # Concept entry (e.g. injection.sql-injection)
|
|
115
|
+
│ │ │ └── ... # Manifestation entries
|
|
116
|
+
│ │ └── ...
|
|
117
|
+
│ └── ...
|
|
118
|
+
└── signatures/ # Runtime behavioral signatures
|
|
119
|
+
└── ...
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Developer & Contributor Tools
|
|
123
|
+
|
|
124
|
+
If you are authoring entries or developing the `vex` CLI:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Run catalog integrity linter
|
|
128
|
+
vex-lint --root .
|
|
129
|
+
# or via Makefile
|
|
130
|
+
make lint
|
|
131
|
+
|
|
132
|
+
# Run Python code linters (Ruff & Mypy)
|
|
133
|
+
make lint-py
|
|
134
|
+
|
|
135
|
+
# Format Markdown/YAML (Prettier) and Python (Ruff)
|
|
136
|
+
make format
|
|
137
|
+
make format-py
|
|
138
|
+
|
|
139
|
+
# Run all CI checks
|
|
140
|
+
make check
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
- **Authoring Guide**: See [CONTRIBUTING.md](CONTRIBUTING.md) and `docs/contributing/` for detailed authoring guidelines.
|
|
144
|
+
- **CLI Reference**: See [docs/commands/README.md](docs/commands/README.md).
|
|
145
|
+
|
|
146
|
+
## Non-Goals
|
|
147
|
+
|
|
148
|
+
This repository **does not contain weaponized exploits** or automated scanning engines. Entries document recognition signals, root causes, and exploitation _methodology_ necessary to understand, confirm, and fix vulnerabilities responsibly. See `docs/contributing/guides/authoring.md` for our ethical
|
|
149
|
+
boundary guidelines.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Vulnerability Explorer (`vex`)
|
|
2
|
+
|
|
3
|
+
> **A git-native, interactive terminal reference and structured knowledge base for software vulnerabilities.**
|
|
4
|
+
|
|
5
|
+
## What is Vulnerability Explorer?
|
|
6
|
+
|
|
7
|
+
Imagine `man` pages built specifically for application security. **Vulnerability Explorer** is a curated, structured knowledge base of software vulnerabilities combined with a versatile command-line tool (`vex`).
|
|
8
|
+
|
|
9
|
+
Each entry in the catalog is an **atomic Markdown file** enriched with structured YAML frontmatter. Entries document concrete vulnerability mechanisms across languages, frameworks, and architectures, detailing:
|
|
10
|
+
|
|
11
|
+
- **White-box identification** (Vulnerable vs. Safe code snippets, Source/Sink taint patterns)
|
|
12
|
+
- **Gray/Black-box behavior** (Observable indicators, protocol tells, timing characteristics)
|
|
13
|
+
- **Remediation & Fixes** (Primary patches, alternative approaches, common mistakes)
|
|
14
|
+
|
|
15
|
+
> [!NOTE] **This is a knowledge base, not a scanner.** It is designed for security engineers reviewing code, developers learning secure coding, AI agents generating structured security documentation, and CLI lovers looking for fast terminal references.
|
|
16
|
+
|
|
17
|
+
## Key Features
|
|
18
|
+
|
|
19
|
+
- **Interactive Terminal CLI (`vex`)**: Built-in arrow-key interactive menu for seamless browsing.
|
|
20
|
+
- **Built-in Pager Reading**: Read rich formatted documentation in the terminal with built-in scrolling (`less`-style).
|
|
21
|
+
- **Multi-dimensional Filtering**: Filter entries by category, programming language, or analysis mode (white-box / black-box).
|
|
22
|
+
- **Full-Text Search**: Instantly query across titles, tags, code snippets, and methodologies.
|
|
23
|
+
- **AI-Native Workflow**: Pre-built LLM prompts in `.github/prompts/` to easily author new entries with strict quality standards.
|
|
24
|
+
- **Structural Linter (`vex-lint`)**: Strict schema, taxonomy, and reference validation tool for contributors and CI/CD pipelines.
|
|
25
|
+
|
|
26
|
+
## Who is this for?
|
|
27
|
+
|
|
28
|
+
| Audience | How They Use Vulnerability Explorer |
|
|
29
|
+
| :----------------------- | :-------------------------------------------------------------------------------------- |
|
|
30
|
+
| **Security Engineers** | Fast reference during penetration tests, code audits, and report writing. |
|
|
31
|
+
| **Developers** | Learn vulnerability root causes and compare side-by-side vulnerable vs. safe code. |
|
|
32
|
+
| **AI Agents & LLMs** | Consume structured YAML/Markdown entries or generate new ones using `.github/prompts/`. |
|
|
33
|
+
| **Educators & Students** | Study standardized vulnerability taxonomy and recognition signals. |
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
### 1. Installation
|
|
38
|
+
|
|
39
|
+
#### From PyPI
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Using pip
|
|
43
|
+
pip install vulnerability-explorer
|
|
44
|
+
|
|
45
|
+
# Or using uv
|
|
46
|
+
uv pip install vulnerability-explorer
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
#### From Source (For Contributors)
|
|
50
|
+
|
|
51
|
+
Clone the repository and install in editable mode:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git clone https://github.com/othonhugo/vulnerability-explorer.git
|
|
55
|
+
cd vulnerability-explorer
|
|
56
|
+
|
|
57
|
+
# Using uv (recommended)
|
|
58
|
+
uv pip install -e .
|
|
59
|
+
|
|
60
|
+
# Or standard pip
|
|
61
|
+
pip install -e .
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Launch Interactive Mode
|
|
65
|
+
|
|
66
|
+
Simply type `vex` to launch the interactive arrow-key navigation menu:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
vex
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## CLI Usage Overview
|
|
73
|
+
|
|
74
|
+
| Task | Command |
|
|
75
|
+
| :-------------------------------- | :-------------------------------------------- |
|
|
76
|
+
| **Interactive Menu** | `vex` or `vex interactive` |
|
|
77
|
+
| **View Catalog Hierarchy** | `vex tree` |
|
|
78
|
+
| **Filter by Category** | `vex list --category injection` |
|
|
79
|
+
| **Filter by Language & Mode** | `vex list --language python --mode white-box` |
|
|
80
|
+
| **Read Specific Entry** | `vex read injection.sql-injection` |
|
|
81
|
+
| **Search Catalog** | `vex search "prepared statement"` |
|
|
82
|
+
| **Plain Text Output (No Colors)** | `vex list --no-rich` |
|
|
83
|
+
|
|
84
|
+
> For full CLI options, flags, and advanced usage, see the **[CLI Commands Reference](docs/commands/README.md)**.
|
|
85
|
+
|
|
86
|
+
## Catalog Structure At A Glance
|
|
87
|
+
|
|
88
|
+
The catalog is organized logically under `data/`:
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
data/
|
|
92
|
+
├── catalog/ # Vulnerability classes & manifestations
|
|
93
|
+
│ ├── access-control/
|
|
94
|
+
│ ├── injection/
|
|
95
|
+
│ │ ├── sql-injection/
|
|
96
|
+
│ │ │ ├── README.md # Concept entry (e.g. injection.sql-injection)
|
|
97
|
+
│ │ │ └── ... # Manifestation entries
|
|
98
|
+
│ │ └── ...
|
|
99
|
+
│ └── ...
|
|
100
|
+
└── signatures/ # Runtime behavioral signatures
|
|
101
|
+
└── ...
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Developer & Contributor Tools
|
|
105
|
+
|
|
106
|
+
If you are authoring entries or developing the `vex` CLI:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Run catalog integrity linter
|
|
110
|
+
vex-lint --root .
|
|
111
|
+
# or via Makefile
|
|
112
|
+
make lint
|
|
113
|
+
|
|
114
|
+
# Run Python code linters (Ruff & Mypy)
|
|
115
|
+
make lint-py
|
|
116
|
+
|
|
117
|
+
# Format Markdown/YAML (Prettier) and Python (Ruff)
|
|
118
|
+
make format
|
|
119
|
+
make format-py
|
|
120
|
+
|
|
121
|
+
# Run all CI checks
|
|
122
|
+
make check
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- **Authoring Guide**: See [CONTRIBUTING.md](CONTRIBUTING.md) and `docs/contributing/` for detailed authoring guidelines.
|
|
126
|
+
- **CLI Reference**: See [docs/commands/README.md](docs/commands/README.md).
|
|
127
|
+
|
|
128
|
+
## Non-Goals
|
|
129
|
+
|
|
130
|
+
This repository **does not contain weaponized exploits** or automated scanning engines. Entries document recognition signals, root causes, and exploitation _methodology_ necessary to understand, confirm, and fix vulnerabilities responsibly. See `docs/contributing/guides/authoring.md` for our ethical
|
|
131
|
+
boundary guidelines.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vulnerability-explorer"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "A searchable catalog of software vulnerabilities with detailed technical documentation and a CLI explorer."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"pyyaml>=6.0",
|
|
14
|
+
"types-pyyaml>=6.0.12.20260724",
|
|
15
|
+
"typer>=0.9.0",
|
|
16
|
+
"rich>=13.0",
|
|
17
|
+
"questionary>=2.0.0",
|
|
18
|
+
"pydantic>=2.0.0",
|
|
19
|
+
"markdown-it-py>=3.0.0",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
vex = "vex.main:app"
|
|
24
|
+
vex-lint = "vex_lint.main:app"
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
dev = [
|
|
28
|
+
"ruff>=0.1.0",
|
|
29
|
+
"mypy>=1.5.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ["src"]
|
|
34
|
+
|
|
35
|
+
[tool.ruff]
|
|
36
|
+
line-length = 200
|
|
37
|
+
|
|
38
|
+
[tool.ruff.lint]
|
|
39
|
+
ignore = ["B008"]
|
|
40
|
+
|
|
41
|
+
[tool.mypy]
|
|
42
|
+
python_version = "3.10"
|
|
43
|
+
warn_return_any = true
|
|
44
|
+
warn_unused_configs = true
|
|
45
|
+
strict = false
|
|
46
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Typer command definitions for vex CLI."""
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Command to navigate the catalog interactively."""
|
|
2
|
+
|
|
3
|
+
from vex.commands.options import OptRich
|
|
4
|
+
from vex.core.catalog import collect_entries
|
|
5
|
+
from vex.utils.display import interactive_navigation
|
|
6
|
+
from vex.utils.filesystem import find_repo_root
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def cmd_interactive(rich: OptRich = True) -> None:
|
|
10
|
+
"""Interactive navigation menu."""
|
|
11
|
+
|
|
12
|
+
root = find_repo_root()
|
|
13
|
+
entries = collect_entries(root)
|
|
14
|
+
interactive_navigation(entries, use_rich=rich)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Command to list catalog entries with optional filters."""
|
|
2
|
+
|
|
3
|
+
from vex.commands.options import OptCategory, OptLanguage, OptMode, OptRich, OptType
|
|
4
|
+
from vex.core.catalog import collect_entries
|
|
5
|
+
from vex.utils.display import display_list
|
|
6
|
+
from vex.utils.filesystem import find_repo_root
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def cmd_list(category: OptCategory = None, language: OptLanguage = None, mode: OptMode = None, entry_type: OptType = None, rich: OptRich = True) -> None:
|
|
10
|
+
"""List entries with optional filters."""
|
|
11
|
+
|
|
12
|
+
root = find_repo_root()
|
|
13
|
+
entries = collect_entries(root)
|
|
14
|
+
|
|
15
|
+
filtered = entries
|
|
16
|
+
|
|
17
|
+
if category:
|
|
18
|
+
filtered = [e for e in filtered if e["fm"].get("category") == category]
|
|
19
|
+
|
|
20
|
+
if language:
|
|
21
|
+
filtered = [e for e in filtered if language in (e["fm"].get("languages") or [])]
|
|
22
|
+
|
|
23
|
+
if mode:
|
|
24
|
+
filtered = [e for e in filtered if mode in (e["fm"].get("analysis_modes") or [])]
|
|
25
|
+
|
|
26
|
+
if entry_type:
|
|
27
|
+
filtered = [e for e in filtered if e["fm"].get("type") == entry_type]
|
|
28
|
+
|
|
29
|
+
display_list(filtered, use_rich=rich)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Reusable Typer options and arguments definitions using Annotated."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
# Global / Shared Options
|
|
9
|
+
OptRich = Annotated[
|
|
10
|
+
bool,
|
|
11
|
+
typer.Option("--rich/--no-rich", help="Enable or disable Rich formatted output", rich_help_panel="Global Options"),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
OptVersion = Annotated[
|
|
15
|
+
bool | None,
|
|
16
|
+
typer.Option(
|
|
17
|
+
"--version",
|
|
18
|
+
"-V",
|
|
19
|
+
help="Print version and exit.",
|
|
20
|
+
rich_help_panel="Global Options",
|
|
21
|
+
),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
# Explore Command Options & Arguments
|
|
25
|
+
OptCategory = Annotated[
|
|
26
|
+
str | None,
|
|
27
|
+
typer.Option("--category", "-c", help="Filter by category slug"),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
OptLanguage = Annotated[
|
|
31
|
+
str | None,
|
|
32
|
+
typer.Option("--language", "-l", help="Filter by language slug"),
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
OptMode = Annotated[
|
|
36
|
+
str | None,
|
|
37
|
+
typer.Option("--mode", "-m", help="Filter by analysis mode"),
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
OptType = Annotated[
|
|
41
|
+
str | None,
|
|
42
|
+
typer.Option("--type", "-t", help="Filter by entry type (concept, manifestation, runtime-signature)"),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
OptNoPager = Annotated[
|
|
46
|
+
bool,
|
|
47
|
+
typer.Option("--no-pager", help="Disable pager and print directly to terminal"),
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
ArgEntryId = Annotated[
|
|
51
|
+
str,
|
|
52
|
+
typer.Argument(help="Entry ID (exact or prefix match)"),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
ArgQuery = Annotated[
|
|
56
|
+
str,
|
|
57
|
+
typer.Argument(help="Search query string"),
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
# Linter Options
|
|
61
|
+
OptRoot = Annotated[
|
|
62
|
+
Path | None,
|
|
63
|
+
typer.Option("--root", "-r", help="Repository root path (default: auto-detected)"),
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
# Sync Command Options
|
|
67
|
+
DEFAULT_REMOTE_URL = "https://github.com/othonhugo/vulnerability-explorer.git"
|
|
68
|
+
DEFAULT_BRANCH = "unstable"
|
|
69
|
+
|
|
70
|
+
OptRemote = Annotated[
|
|
71
|
+
str,
|
|
72
|
+
typer.Option("--remote", "-r", help="Remote Git repository URL"),
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
OptBranch = Annotated[
|
|
76
|
+
str,
|
|
77
|
+
typer.Option("--branch", "-b", help="Git branch to pull/clone"),
|
|
78
|
+
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Command to read a specific catalog entry by ID."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from vex.commands.options import ArgEntryId, OptNoPager, OptRich
|
|
6
|
+
from vex.core.catalog import collect_entries
|
|
7
|
+
from vex.core.models import CatalogEntry
|
|
8
|
+
from vex.utils.display import display_read
|
|
9
|
+
from vex.utils.filesystem import find_repo_root
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def cmd_read(entry_id: ArgEntryId, no_pager: OptNoPager = False, rich: OptRich = True) -> None:
|
|
13
|
+
"""Read an entry by ID using Pager."""
|
|
14
|
+
|
|
15
|
+
root = find_repo_root()
|
|
16
|
+
entries = collect_entries(root)
|
|
17
|
+
|
|
18
|
+
entry_match: CatalogEntry | None = None
|
|
19
|
+
|
|
20
|
+
for e in entries:
|
|
21
|
+
if e["fm"].get("id") == entry_id:
|
|
22
|
+
entry_match = e
|
|
23
|
+
break
|
|
24
|
+
|
|
25
|
+
if not entry_match:
|
|
26
|
+
candidates = [e for e in entries if str(e["fm"].get("id", "")).startswith(entry_id)]
|
|
27
|
+
|
|
28
|
+
if len(candidates) == 1:
|
|
29
|
+
entry_match = candidates[0]
|
|
30
|
+
elif len(candidates) > 1:
|
|
31
|
+
typer.echo(f"Ambiguous ID '{entry_id}'. Matches:")
|
|
32
|
+
|
|
33
|
+
for c in candidates:
|
|
34
|
+
typer.echo(f" {c['fm'].get('id')}")
|
|
35
|
+
|
|
36
|
+
raise typer.Exit(code=1)
|
|
37
|
+
else:
|
|
38
|
+
typer.echo(f"No entry found with ID '{entry_id}'.")
|
|
39
|
+
|
|
40
|
+
raise typer.Exit(code=1)
|
|
41
|
+
|
|
42
|
+
display_read(entry_match, use_pager=not no_pager, use_rich=rich)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Command to search across the vulnerability catalog."""
|
|
2
|
+
|
|
3
|
+
from vex.commands.options import ArgQuery, OptRich
|
|
4
|
+
from vex.core.catalog import collect_entries
|
|
5
|
+
from vex.core.models import CatalogEntry
|
|
6
|
+
from vex.utils.display import display_search
|
|
7
|
+
from vex.utils.filesystem import find_repo_root
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def cmd_search(query: ArgQuery, rich: OptRich = True) -> None:
|
|
11
|
+
"""Search entries for query term."""
|
|
12
|
+
|
|
13
|
+
root = find_repo_root()
|
|
14
|
+
entries = collect_entries(root)
|
|
15
|
+
q = query.lower()
|
|
16
|
+
|
|
17
|
+
results: list[tuple[int, CatalogEntry]] = []
|
|
18
|
+
|
|
19
|
+
for e in entries:
|
|
20
|
+
full_text = e["path"].read_text(encoding="utf-8").lower()
|
|
21
|
+
|
|
22
|
+
if q in full_text:
|
|
23
|
+
count = full_text.count(q)
|
|
24
|
+
results.append((count, e))
|
|
25
|
+
|
|
26
|
+
results.sort(key=lambda x: x[0], reverse=True)
|
|
27
|
+
display_search(results, query, use_rich=rich)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Command for syncing/updating global vulnerability catalog from remote Git repository."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
from vex.commands.options import OptBranch, OptRemote
|
|
9
|
+
from vex.utils.filesystem import get_global_cache_dir
|
|
10
|
+
|
|
11
|
+
console = Console()
|
|
12
|
+
stderr_console = Console(stderr=True)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def cmd_sync(
|
|
16
|
+
remote: OptRemote,
|
|
17
|
+
branch: OptBranch,
|
|
18
|
+
) -> None:
|
|
19
|
+
"""Download or update the global vulnerability catalog cache."""
|
|
20
|
+
cache_dir = get_global_cache_dir()
|
|
21
|
+
|
|
22
|
+
# Check if git is available in PATH
|
|
23
|
+
try:
|
|
24
|
+
subprocess.run(["git", "--version"], capture_output=True, check=True)
|
|
25
|
+
except (subprocess.SubprocessError, FileNotFoundError):
|
|
26
|
+
stderr_console.print("[bold red]Error:[/] `git` command not found. Please install Git to use `vex sync`.")
|
|
27
|
+
raise typer.Exit(code=1)
|
|
28
|
+
|
|
29
|
+
cache_dir.parent.mkdir(parents=True, exist_ok=True)
|
|
30
|
+
|
|
31
|
+
if (cache_dir / ".git").is_dir():
|
|
32
|
+
console.print(f"[bold cyan]Updating global catalog cache at:[/] {cache_dir}")
|
|
33
|
+
res = subprocess.run(["git", "pull", "origin", branch], cwd=cache_dir, capture_output=True, text=True, check=False)
|
|
34
|
+
|
|
35
|
+
if res.returncode != 0:
|
|
36
|
+
stderr_console.print(f"[bold red]Failed to update catalog:[/] {res.stderr.strip()}")
|
|
37
|
+
raise typer.Exit(code=1)
|
|
38
|
+
|
|
39
|
+
console.print("[bold green]✔ Catalog successfully updated![/]")
|
|
40
|
+
else:
|
|
41
|
+
console.print(f"[bold cyan]Cloning catalog from:[/] {remote}")
|
|
42
|
+
console.print(f"[bold cyan]Target directory:[/] {cache_dir}")
|
|
43
|
+
|
|
44
|
+
res = subprocess.run(["git", "clone", "--depth", "1", "-b", branch, remote, str(cache_dir)], capture_output=True, text=True, check=False)
|
|
45
|
+
|
|
46
|
+
if res.returncode != 0:
|
|
47
|
+
stderr_console.print(f"[bold red]Failed to clone catalog:[/] {res.stderr.strip()}")
|
|
48
|
+
raise typer.Exit(code=1)
|
|
49
|
+
|
|
50
|
+
console.print("[bold green]✔ Catalog successfully downloaded![/]")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Command to show the catalog tree structure."""
|
|
2
|
+
|
|
3
|
+
from vex.commands.options import OptRich
|
|
4
|
+
from vex.core.catalog import collect_entries
|
|
5
|
+
from vex.utils.display import display_tree
|
|
6
|
+
from vex.utils.filesystem import find_repo_root
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def cmd_tree(rich: OptRich = True) -> None:
|
|
10
|
+
"""Show the catalog tree structure."""
|
|
11
|
+
|
|
12
|
+
root = find_repo_root()
|
|
13
|
+
entries = collect_entries(root)
|
|
14
|
+
display_tree(entries, use_rich=rich)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core catalog models and parsing logic."""
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Catalog loading and parsing utilities."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
|
|
9
|
+
from vex.core.models import CatalogEntry
|
|
10
|
+
|
|
11
|
+
FRONTMATTER_RE = re.compile(r"\A---\n(.*?\n)---\n?(.*)\Z", re.DOTALL)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def parse_file(path: Path) -> tuple[dict[str, Any] | None, str | None]:
|
|
15
|
+
"""Parse a catalog file, returning (frontmatter_dict, body_str) or (None, None)."""
|
|
16
|
+
|
|
17
|
+
text = path.read_text(encoding="utf-8")
|
|
18
|
+
m = FRONTMATTER_RE.match(text)
|
|
19
|
+
|
|
20
|
+
if not m:
|
|
21
|
+
return None, None
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
fm: Any = yaml.safe_load(m.group(1))
|
|
25
|
+
except yaml.YAMLError:
|
|
26
|
+
return None, None
|
|
27
|
+
|
|
28
|
+
if not isinstance(fm, dict):
|
|
29
|
+
return None, None
|
|
30
|
+
|
|
31
|
+
return fm, m.group(2)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def collect_entries(root: Path) -> list[CatalogEntry]:
|
|
35
|
+
"""Collect all catalog entries and runtime-signatures."""
|
|
36
|
+
|
|
37
|
+
entries: list[CatalogEntry] = []
|
|
38
|
+
catalog_dir = root / "data" / "catalog"
|
|
39
|
+
signatures_dir = root / "data" / "signatures"
|
|
40
|
+
|
|
41
|
+
dirs: list[Path] = []
|
|
42
|
+
|
|
43
|
+
if catalog_dir.exists():
|
|
44
|
+
dirs.append(catalog_dir)
|
|
45
|
+
|
|
46
|
+
if signatures_dir.exists():
|
|
47
|
+
dirs.append(signatures_dir)
|
|
48
|
+
|
|
49
|
+
for d in dirs:
|
|
50
|
+
for path in sorted(d.rglob("*.md")):
|
|
51
|
+
if path.name == "README.md" and (path.parent == signatures_dir or path.parent == catalog_dir or path.parent.parent == catalog_dir):
|
|
52
|
+
continue # Skip documentation READMEs
|
|
53
|
+
|
|
54
|
+
fm, body = parse_file(path)
|
|
55
|
+
|
|
56
|
+
if fm is not None and body is not None and "id" in fm:
|
|
57
|
+
entries.append({"path": path, "fm": fm, "body": body})
|
|
58
|
+
|
|
59
|
+
return entries
|