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.
@@ -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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ ubel = ubel.cli:linux_mode
3
+ ubel-npm = ubel.cli:npm_mode
4
+ ubel-pip = ubel.cli:pip_mode
@@ -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
+ """