python-ubel 0.1.0__py3-none-any.whl
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.
- python_ubel-0.1.0.dist-info/METADATA +224 -0
- python_ubel-0.1.0.dist-info/RECORD +17 -0
- python_ubel-0.1.0.dist-info/WHEEL +5 -0
- python_ubel-0.1.0.dist-info/entry_points.txt +4 -0
- python_ubel-0.1.0.dist-info/licenses/LICENSE +21 -0
- python_ubel-0.1.0.dist-info/top_level.txt +1 -0
- ubel/__init__.py +0 -0
- ubel/cli.py +141 -0
- ubel/client.py +50 -0
- ubel/cvss_parser.py +61 -0
- ubel/info.py +37 -0
- ubel/linux_runner.py +290 -0
- ubel/node_runner.py +399 -0
- ubel/policy.py +44 -0
- ubel/python_runner.py +126 -0
- ubel/ubel_engine.py +640 -0
- ubel/utils.py +32 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-ubel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Supply-chain dependency firewall for: Python, Node, PHP, Ubuntu, Debian, Red Hat, and Almalinux.
|
|
5
|
+
Requires-Python: >=3.8
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: requests
|
|
9
|
+
Requires-Dist: python-dotenv
|
|
10
|
+
Requires-Dist: cvss
|
|
11
|
+
Requires-Dist: reportlab
|
|
12
|
+
Requires-Dist: distro
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# UBEL ( Unified Bill / Enforced Law ) – Multi‑Ecosystem Security & Policy Enforcement CLI
|
|
16
|
+
|
|
17
|
+
Ubel is a fast, cross‑ecosystem security engine that resolves dependencies, generates PURLs, scans them through OSV.dev, and enforces security policies during installation. It works with:
|
|
18
|
+
|
|
19
|
+
- **PyPI** (via `ubel-pip`)
|
|
20
|
+
- **npm** (via `ubel-npm`)
|
|
21
|
+
- **Linux distributions** (Ubuntu, Debian, RHEL, AlmaLinux)
|
|
22
|
+
|
|
23
|
+
Ubel runs in **CLI**, **automation scripts**, and **CI/CD pipelines**, producing clean **JSON** and **PDF** reports.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ✨ Features
|
|
28
|
+
- Full dependency resolution across ecosystems
|
|
29
|
+
- OSV.dev vulnerability scanning (batch API)
|
|
30
|
+
- Policy engine (block/allow by severity & infection)
|
|
31
|
+
- Checking linux-package or node/python dependency or entire project (`check` mode)
|
|
32
|
+
- Install‑time enforcement (`install` mode)
|
|
33
|
+
- Project‑level/Host-level scanning (`health` mode)
|
|
34
|
+
- Catches Non-CVEs
|
|
35
|
+
- It is a supply-chain protection tool
|
|
36
|
+
- Automatic report generation (JSON + PDF)
|
|
37
|
+
- Extremely fast (seconds per scan)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 📦 Installation
|
|
42
|
+
```bash
|
|
43
|
+
pip install ubel
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Ubel exposes three binaries:
|
|
47
|
+
|
|
48
|
+
- `ubel` (Linux package scanning and OS-level operations: Ubuntu , Debian, Red Hat, Almalinux )
|
|
49
|
+
- `ubel-pip` (Python ecosystem)
|
|
50
|
+
- `ubel-npm` (Node.js ecosystem)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
# 🚀 Usage Overview
|
|
55
|
+
|
|
56
|
+
## Main CLI
|
|
57
|
+
```
|
|
58
|
+
usage: ubel [-h] {check,install,health,init,allow,block} [extra_args ...]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## PyPI CLI
|
|
62
|
+
```
|
|
63
|
+
usage: ubel-pip [-h] {check,install,health,init,allow,block} [extra_args ...]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## npm CLI
|
|
67
|
+
```
|
|
68
|
+
usage: ubel-npm [-h] {check,install,health,init,allow,block} [extra_args ...]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
# 🧠 Commands Explained
|
|
74
|
+
|
|
75
|
+
### **check**
|
|
76
|
+
Resolve dependencies/linux-packages → generate report → exit.
|
|
77
|
+
|
|
78
|
+
#### Python example:
|
|
79
|
+
```bash
|
|
80
|
+
ubel-pip check
|
|
81
|
+
```
|
|
82
|
+
If no extra arguments are passed, Ubel will:
|
|
83
|
+
- Detect `requirements.txt`
|
|
84
|
+
- Resolve all packages
|
|
85
|
+
- Scan them
|
|
86
|
+
- Output PDF + JSON
|
|
87
|
+
|
|
88
|
+
#### npm example:
|
|
89
|
+
```bash
|
|
90
|
+
ubel-npm check flask==3.1.0
|
|
91
|
+
```
|
|
92
|
+
If no args are passed, it will detect `package.json` automatically.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### **install**
|
|
97
|
+
Same as `check`, but enforces policies and either **blocks or allows** installation.
|
|
98
|
+
|
|
99
|
+
#### Python example:
|
|
100
|
+
```bash
|
|
101
|
+
ubel-pip install flask==3.1.0
|
|
102
|
+
```
|
|
103
|
+
Or auto-detect project requirements:
|
|
104
|
+
```bash
|
|
105
|
+
ubel-pip install
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### npm example:
|
|
109
|
+
```bash
|
|
110
|
+
ubel-npm install express@5.0.0
|
|
111
|
+
```
|
|
112
|
+
Or simply:
|
|
113
|
+
```bash
|
|
114
|
+
ubel-npm install
|
|
115
|
+
```
|
|
116
|
+
(uses `package.json` automatically)
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### **health**
|
|
121
|
+
Scan the **entire machine** or **running project**, including:
|
|
122
|
+
- Installed PyPI packages
|
|
123
|
+
- Installed npm global packages
|
|
124
|
+
- OS-level packages (Ubuntu/Debian/RHEL/AlmaLinux)
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
( for linux )
|
|
128
|
+
```bash
|
|
129
|
+
ubel health
|
|
130
|
+
```
|
|
131
|
+
or ( for node.js app )
|
|
132
|
+
```bash
|
|
133
|
+
ubel-npm health
|
|
134
|
+
```
|
|
135
|
+
or ( for python app )
|
|
136
|
+
```bash
|
|
137
|
+
ubel-pip health
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This mode produces large, detailed inventories and vulnerability matrices.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### **init**
|
|
145
|
+
Initialize a policy file for the project or system.
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
```bash
|
|
149
|
+
ubel init
|
|
150
|
+
```
|
|
151
|
+
Creates default policy:
|
|
152
|
+
```yaml
|
|
153
|
+
infections: block
|
|
154
|
+
severity:
|
|
155
|
+
critical: block
|
|
156
|
+
high: block
|
|
157
|
+
medium: allow
|
|
158
|
+
low: allow
|
|
159
|
+
unknown: allow
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
### **allow / block**
|
|
165
|
+
Override Ubel's decision from CI/CD or scripted pipelines.
|
|
166
|
+
|
|
167
|
+
The arguments can be: "low", "medium", "high", "critical".
|
|
168
|
+
|
|
169
|
+
Example:
|
|
170
|
+
```bash
|
|
171
|
+
ubel block high critical
|
|
172
|
+
```
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
# 📁 Automatic Project Detection
|
|
176
|
+
|
|
177
|
+
For **npm** and **PyPI**, when running:
|
|
178
|
+
- `install`
|
|
179
|
+
- `check`
|
|
180
|
+
|
|
181
|
+
without arguments:
|
|
182
|
+
|
|
183
|
+
### Ubel automatically loads:
|
|
184
|
+
- `package.json` (for npm)
|
|
185
|
+
- `requirements.txt` (for pip)
|
|
186
|
+
|
|
187
|
+
This makes it ideal for CI/CD workflows.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
# 📤 Output
|
|
192
|
+
Ubel generates:
|
|
193
|
+
|
|
194
|
+
### **1. JSON report**
|
|
195
|
+
Machine‑readable, includes:
|
|
196
|
+
- dependency list
|
|
197
|
+
- purls
|
|
198
|
+
- vulnerabilities
|
|
199
|
+
- severity
|
|
200
|
+
- infection state
|
|
201
|
+
- policy decision
|
|
202
|
+
- Generate complete SBOM-like machine inventory
|
|
203
|
+
|
|
204
|
+
### **2. PDF report**
|
|
205
|
+
Human‑readable, includes:
|
|
206
|
+
- summary statistics
|
|
207
|
+
- per‑dependency vulnerability details
|
|
208
|
+
- fix recommendations
|
|
209
|
+
- tables
|
|
210
|
+
- OSV reference links
|
|
211
|
+
- Generate complete SBOM-like machine inventory
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
# 🧩 Ecosystem Tools
|
|
217
|
+
- `ubel` → system packages, Linux distros
|
|
218
|
+
- `ubel-pip` → PyPI projects, virtual environments\
|
|
219
|
+
- `ubel-npm` → Node.js, npm, package.json projects
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
Ubel – Secure every dependency, before it reaches production.
|
|
224
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
python_ubel-0.1.0.dist-info/licenses/LICENSE,sha256=YuSjxlIwoAbeNKWf3O9NTujI4ax1QLfkBB_XTDLFvXA,1088
|
|
2
|
+
ubel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
ubel/cli.py,sha256=jpUTxhJoCF1sDtarNxlrBr_sVJHEBAh2G65glGFg6uE,3919
|
|
4
|
+
ubel/client.py,sha256=3oJ-3WdykcXmEgHmzgdgBvnCy__f6LkJcu8_r2vdizI,1356
|
|
5
|
+
ubel/cvss_parser.py,sha256=FWI5x9icTRWB_XObSvmTnL5d6YbiSM0LBjSbzeqiT9w,2433
|
|
6
|
+
ubel/info.py,sha256=FRnQiC9Ji7hoKGlO7yIXVRznr59y1H4v-l47AP4GSsQ,1353
|
|
7
|
+
ubel/linux_runner.py,sha256=8tToN1QlDWeykjQVn037RIzq67VMq5AgXEekOYh_1rk,9448
|
|
8
|
+
ubel/node_runner.py,sha256=kprOV8PtMZA4sREjN_r-b7gFRBhoAGdKySyufyogNz8,14301
|
|
9
|
+
ubel/policy.py,sha256=Us3A7c5DMgBN1IvfmltYvdyumo3rYk5CmKbbFeIMDdM,1473
|
|
10
|
+
ubel/python_runner.py,sha256=awZJ74cIHmOVuG2-NgMTGzYwP3fo88If7Nj6wLFfxXk,4016
|
|
11
|
+
ubel/ubel_engine.py,sha256=vNg7MGQFnvPOUtcnw1ooFKbkFDqM5DoiMWW90r6Q2qA,25014
|
|
12
|
+
ubel/utils.py,sha256=-Ls_R2ZLyUoC_H0CHl_0Q15MCqaVcEtSke7FVX0JcIw,853
|
|
13
|
+
python_ubel-0.1.0.dist-info/METADATA,sha256=rChvCsbx3wSgETJuA3MwpKB7butOmFzpXHBoaHADK-U,4788
|
|
14
|
+
python_ubel-0.1.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
|
|
15
|
+
python_ubel-0.1.0.dist-info/entry_points.txt,sha256=VaItRGYmWEUXwHsIEjFHgVF1V2V2_XZmZbkxs7W3vBs,103
|
|
16
|
+
python_ubel-0.1.0.dist-info/top_level.txt,sha256=CfqimShQ7W7iW8Btb9yjfBoS98rHo94ulKa7FRb7VYw,5
|
|
17
|
+
python_ubel-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ala Bouali
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ubel
|
ubel/__init__.py
ADDED
|
File without changes
|
ubel/cli.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from .ubel_engine import Ubel_Engine
|
|
6
|
+
from .python_runner import Pypi_Manager
|
|
7
|
+
from .linux_runner import Linux_Manager
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from .utils import load_environment, create_output_dir, download_file
|
|
10
|
+
from .policy import evaluate_policy
|
|
11
|
+
from .info import banner
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def print_banner():
|
|
15
|
+
|
|
16
|
+
print(banner)
|
|
17
|
+
print()
|
|
18
|
+
print(f"Reports location: {Ubel_Engine.reports_location}")
|
|
19
|
+
print()
|
|
20
|
+
|
|
21
|
+
print(f"Policy location: {Ubel_Engine.policy_dir}")
|
|
22
|
+
print()
|
|
23
|
+
|
|
24
|
+
def set_policy_rules(action,severities):
|
|
25
|
+
data=Ubel_Engine.load_policy()
|
|
26
|
+
for rule in data["severity"]:
|
|
27
|
+
if rule in severities:
|
|
28
|
+
data["severity"][rule]=action
|
|
29
|
+
with open(f"{Ubel_Engine.policy_dir}/{Ubel_Engine.policy_filename}","w") as file:
|
|
30
|
+
json.dump(data,file,indent=4)
|
|
31
|
+
file.close()
|
|
32
|
+
|
|
33
|
+
def non_linux_mode(pkg_manager,ecosystem,description):
|
|
34
|
+
|
|
35
|
+
print_banner()
|
|
36
|
+
|
|
37
|
+
parser = argparse.ArgumentParser(
|
|
38
|
+
description=description
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"mode",
|
|
43
|
+
choices=["check", "install", "health", "init","allow","block"],
|
|
44
|
+
help="Execution mode"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"extra_args",
|
|
49
|
+
nargs="*",
|
|
50
|
+
help="Arguments passed after mode"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
Ubel_Engine.engine=pkg_manager
|
|
54
|
+
Ubel_Engine.system_type=ecosystem
|
|
55
|
+
|
|
56
|
+
args = parser.parse_args()
|
|
57
|
+
Ubel_Engine.initiate_local_policy()
|
|
58
|
+
if args.mode:
|
|
59
|
+
Ubel_Engine.check_mode=args.mode
|
|
60
|
+
else:
|
|
61
|
+
Ubel_Engine.check_mode="init"
|
|
62
|
+
|
|
63
|
+
if Ubel_Engine.check_mode=="init":
|
|
64
|
+
sys.exit(0)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
api_key, asset_id, endpoint = load_environment()
|
|
68
|
+
pkgs=[]
|
|
69
|
+
if args.extra_args in [None,[]] and pkg_manager=="pip" and Ubel_Engine.check_mode in ["check","install"]:
|
|
70
|
+
with open("requirements.txt","r") as requirement_file:
|
|
71
|
+
lines=requirement_file.readlines()
|
|
72
|
+
requirement_file.close()
|
|
73
|
+
pkgs=[line.strip() for line in lines if line.strip()!=""]
|
|
74
|
+
else:
|
|
75
|
+
pkgs=args.extra_args
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if Ubel_Engine.check_mode in ["allow","block"]:
|
|
79
|
+
set_policy_rules(args.mode,args.extra_args)
|
|
80
|
+
sys.exit(0)
|
|
81
|
+
|
|
82
|
+
if not api_key and not asset_id:
|
|
83
|
+
Ubel_Engine.scan(pkgs)
|
|
84
|
+
sys.exit(0)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def linux_mode():
|
|
88
|
+
parser = argparse.ArgumentParser(
|
|
89
|
+
description="Safe Linux policy-driven supply-chain firewall"
|
|
90
|
+
)
|
|
91
|
+
Ubel_Engine.initiate_local_policy()
|
|
92
|
+
|
|
93
|
+
Ubel_Engine.system_type=Linux_Manager.get_os_info()["id"]
|
|
94
|
+
Ubel_Engine.reports_location=f'{Path.home()}/{Ubel_Engine.reports_location}'
|
|
95
|
+
Ubel_Engine.policy_dir=f'{Path.home()}/{Ubel_Engine.policy_dir}'
|
|
96
|
+
|
|
97
|
+
print(banner)
|
|
98
|
+
print()
|
|
99
|
+
print(f"Reports location: {Ubel_Engine.reports_location}")
|
|
100
|
+
print()
|
|
101
|
+
|
|
102
|
+
print(f"Policy location: {Ubel_Engine.policy_dir}")
|
|
103
|
+
print()
|
|
104
|
+
|
|
105
|
+
parser.add_argument(
|
|
106
|
+
"mode",
|
|
107
|
+
choices=["check", "install", "health", "init","allow","block"],
|
|
108
|
+
help="Execution mode"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
parser.add_argument(
|
|
112
|
+
"extra_args",
|
|
113
|
+
nargs="*",
|
|
114
|
+
help="Arguments passed after mode"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
args = parser.parse_args()
|
|
118
|
+
Ubel_Engine.initiate_local_policy()
|
|
119
|
+
if args.mode:
|
|
120
|
+
Ubel_Engine.check_mode=args.mode
|
|
121
|
+
else:
|
|
122
|
+
Ubel_Engine.check_mode="init"
|
|
123
|
+
if Ubel_Engine.check_mode=="init":
|
|
124
|
+
sys.exit(0)
|
|
125
|
+
|
|
126
|
+
if Ubel_Engine.check_mode in ["allow","block"]:
|
|
127
|
+
set_policy_rules(args.mode,args.extra_args)
|
|
128
|
+
sys.exit(0)
|
|
129
|
+
|
|
130
|
+
api_key, asset_id, endpoint = load_environment()
|
|
131
|
+
if not api_key and not asset_id:
|
|
132
|
+
Ubel_Engine.scan(args.extra_args)
|
|
133
|
+
sys.exit(0)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def pip_mode():
|
|
137
|
+
non_linux_mode("pip","pypi","Safe Python policy-driven supply-chain firewall")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def npm_mode():
|
|
141
|
+
non_linux_mode("npm","npm","Safe Node.js policy-driven supply-chain firewall")
|
ubel/client.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class UbelClient:
|
|
6
|
+
def __init__(self, base_url: str, api_key: str, asset_id: str):
|
|
7
|
+
self.base_url = base_url.rstrip("/")
|
|
8
|
+
self.api_key = api_key
|
|
9
|
+
self.asset_id = asset_id
|
|
10
|
+
|
|
11
|
+
def _headers(self):
|
|
12
|
+
return {
|
|
13
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
14
|
+
"Content-Type": "application/json"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def upload_report(self, report_json: dict):
|
|
18
|
+
payload = {
|
|
19
|
+
"asset_id": self.asset_id,
|
|
20
|
+
"data": report_json
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
r = requests.post(
|
|
24
|
+
f"{self.base_url}/scan",
|
|
25
|
+
json=payload,
|
|
26
|
+
headers=self._headers(),
|
|
27
|
+
timeout=120,
|
|
28
|
+
)
|
|
29
|
+
r.raise_for_status()
|
|
30
|
+
return r.json()
|
|
31
|
+
|
|
32
|
+
def poll_until_ready(self, report_id: str, interval=5, timeout=600):
|
|
33
|
+
start = time.time()
|
|
34
|
+
|
|
35
|
+
while True:
|
|
36
|
+
if time.time() - start > timeout:
|
|
37
|
+
raise TimeoutError("Report polling timed out")
|
|
38
|
+
|
|
39
|
+
r = requests.get(
|
|
40
|
+
f"{self.base_url}/report/{report_id}",
|
|
41
|
+
headers=self._headers(),
|
|
42
|
+
timeout=60,
|
|
43
|
+
)
|
|
44
|
+
r.raise_for_status()
|
|
45
|
+
data = r.json()
|
|
46
|
+
|
|
47
|
+
if "json_report" in data:
|
|
48
|
+
return data
|
|
49
|
+
|
|
50
|
+
time.sleep(interval)
|
ubel/cvss_parser.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from cvss import CVSS2, CVSS3, CVSS4
|
|
2
|
+
|
|
3
|
+
class CVSS_Parser:
|
|
4
|
+
|
|
5
|
+
@staticmethod
|
|
6
|
+
def parse(vector:str):
|
|
7
|
+
try:
|
|
8
|
+
if vector.startswith('CVSS:4.'):
|
|
9
|
+
data=CVSS4(vector)
|
|
10
|
+
elif vector.startswith('CVSS:3.'):
|
|
11
|
+
data=CVSS3(vector)
|
|
12
|
+
else:
|
|
13
|
+
data=CVSS3(vector)
|
|
14
|
+
try:
|
|
15
|
+
base_score=data.base_score
|
|
16
|
+
except:
|
|
17
|
+
base_score=None
|
|
18
|
+
try:
|
|
19
|
+
severity=data.severity
|
|
20
|
+
except:
|
|
21
|
+
severity="unknown"
|
|
22
|
+
return str(base_score),severity
|
|
23
|
+
except:
|
|
24
|
+
return None,"unknown"
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def process_vulnerability(vuln:dict):
|
|
28
|
+
if "severity" in vuln:
|
|
29
|
+
severity_vector_list=vuln.get("severity",[])
|
|
30
|
+
if severity_vector_list!=[]:
|
|
31
|
+
severity_vector=severity_vector_list[0].get("score")
|
|
32
|
+
if severity_vector_list[0].get("type").lower()=="ubuntu":
|
|
33
|
+
vuln["severity"]=severity_vector
|
|
34
|
+
vuln["severity_score"]=None
|
|
35
|
+
vuln["severity_vector"]=None
|
|
36
|
+
return
|
|
37
|
+
else:
|
|
38
|
+
info=CVSS_Parser.parse(severity_vector)
|
|
39
|
+
vuln["severity"]=info[1]
|
|
40
|
+
vuln["severity_score"]=info[0]
|
|
41
|
+
vuln["severity_vector"]=severity_vector
|
|
42
|
+
if vuln["severity"] in [None,"","unknown"]:
|
|
43
|
+
if vuln["severity_score"]!=None:
|
|
44
|
+
severity_score=vuln["severity_score"]
|
|
45
|
+
score = float(severity_score)
|
|
46
|
+
if 0.0 < score < 4.0:
|
|
47
|
+
severity = "low"
|
|
48
|
+
elif 4.0 <= score < 7.0:
|
|
49
|
+
severity = "medium"
|
|
50
|
+
elif 7.0 <= score < 9.0:
|
|
51
|
+
severity = "high"
|
|
52
|
+
elif 9.0 <= score <= 10.0:
|
|
53
|
+
severity = "critical"
|
|
54
|
+
else:
|
|
55
|
+
severity = "unknown" # out-of-range protection
|
|
56
|
+
vuln["severity"]=severity
|
|
57
|
+
return
|
|
58
|
+
vuln["severity"]="unknown"
|
|
59
|
+
vuln["severity_score"]=None
|
|
60
|
+
vuln["severity_vector"]=None
|
|
61
|
+
|
ubel/info.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
2
|
+
__tool_name__="Ubel"
|
|
3
|
+
__tool_name_ascii__="""
|
|
4
|
+
|
|
5
|
+
██ ██ ██████▒ ████████ ██
|
|
6
|
+
██ ██ ███████▓ ████████ ██
|
|
7
|
+
██ ██ ██ ▒██ ██ ██
|
|
8
|
+
██ ██ ██ ██ ██ ██
|
|
9
|
+
██ ██ ██ ▒██ ██ ██
|
|
10
|
+
██ ██ ███████░ ███████ ██
|
|
11
|
+
██ ██ ███████░ ███████ ██
|
|
12
|
+
██ ██ ██ ▒██ ██ ██
|
|
13
|
+
██ ██ ██ ██ ██ ██
|
|
14
|
+
██▓ ▓██ ██ ▒██ ██ ██
|
|
15
|
+
▒██████▒ ████████ ████████ ████████
|
|
16
|
+
▒████▒ ██████▓ ████████ ████████
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__author__="Ala Bouali"
|
|
21
|
+
|
|
22
|
+
__company__="Arcane-Spark"
|
|
23
|
+
|
|
24
|
+
__github__="https://github.com/AlaBouali/ubel"
|
|
25
|
+
|
|
26
|
+
banner=f"""
|
|
27
|
+
{__tool_name_ascii__}
|
|
28
|
+
|
|
29
|
+
Version: {__version__}
|
|
30
|
+
|
|
31
|
+
Author: {__author__}
|
|
32
|
+
|
|
33
|
+
GitHub: {__github__}
|
|
34
|
+
|
|
35
|
+
Company: {__company__}
|
|
36
|
+
|
|
37
|
+
"""
|