devaudit-cli 0.3.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.
dev_audit/command.py ADDED
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import subprocess
5
+
6
+
7
+ def command_exists(command: str) -> bool:
8
+ return shutil.which(command) is not None
9
+
10
+
11
+ def run_command(
12
+ command: list[str],
13
+ timeout: int = 5,
14
+ ) -> dict:
15
+ try:
16
+ result = subprocess.run(
17
+ command,
18
+ capture_output=True,
19
+ text=True,
20
+ timeout=timeout,
21
+ check=False,
22
+ )
23
+
24
+ return {
25
+ "ok": result.returncode == 0,
26
+ "command": " ".join(command),
27
+ "returncode": result.returncode,
28
+ "stdout": result.stdout.strip(),
29
+ "stderr": result.stderr.strip(),
30
+ "error": None,
31
+ }
32
+
33
+ except FileNotFoundError:
34
+ return {
35
+ "ok": False,
36
+ "command": " ".join(command),
37
+ "returncode": None,
38
+ "stdout": "",
39
+ "stderr": "",
40
+ "error": f"Command not found: {command[0]}",
41
+ }
42
+
43
+ except subprocess.TimeoutExpired:
44
+ return {
45
+ "ok": False,
46
+ "command": " ".join(command),
47
+ "returncode": None,
48
+ "stdout": "",
49
+ "stderr": "",
50
+ "error": f"Command timed out after {timeout}s",
51
+ }
dev_audit/output.py ADDED
@@ -0,0 +1,273 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+
6
+ def format_duration(seconds: float | None) -> str:
7
+ if seconds is None:
8
+ return "unknown"
9
+
10
+ total_seconds = int(seconds)
11
+ days, remainder = divmod(total_seconds, 86400)
12
+ hours, remainder = divmod(remainder, 3600)
13
+ minutes, seconds = divmod(remainder, 60)
14
+
15
+ parts = []
16
+
17
+ if days:
18
+ parts.append(f"{days}d")
19
+ if hours:
20
+ parts.append(f"{hours}h")
21
+ if minutes:
22
+ parts.append(f"{minutes}m")
23
+ if seconds or not parts:
24
+ parts.append(f"{seconds}s")
25
+
26
+ return " ".join(parts)
27
+
28
+
29
+ def print_json(result: dict[str, object]) -> None:
30
+ print(json.dumps(result, indent=2, sort_keys=True))
31
+
32
+
33
+ def print_system(result: dict[str, object], verbose: bool = False) -> None:
34
+ data = result["data"]
35
+
36
+ print("System Information")
37
+ print("────────────────────────")
38
+ print(f"Hostname : {data['hostname']}")
39
+ print(f"OS : {data['os_name']} {data['os_version']}")
40
+ print(f"Kernel : {data['kernel']}")
41
+ print(f"Architecture : {data['architecture']}")
42
+ print(f"User : {data['user']}")
43
+ print(f"Shell : {data['shell']}")
44
+ print(f"Uptime : {format_duration(data['uptime_seconds'])}")
45
+
46
+ warnings = result.get("warnings", [])
47
+
48
+ if warnings:
49
+ print()
50
+ print("Warnings")
51
+ print("────────")
52
+ for warning in warnings:
53
+ print(f"⚠ {warning}")
54
+
55
+ if verbose:
56
+ print()
57
+ print("Raw Result")
58
+ print("──────────")
59
+ print_json(result)
60
+
61
+ def print_resources(result: dict[str, object], verbose: bool = False) -> None:
62
+ data = result["data"]
63
+
64
+ print("Resource Usage")
65
+ print("────────────────────────")
66
+ print(f"CPU Cores : {data['cpu_count']}")
67
+
68
+ load_average = data["load_average"]
69
+ if load_average:
70
+ print(
71
+ "Load Average : "
72
+ f"{load_average['1_min']} "
73
+ f"{load_average['5_min']} "
74
+ f"{load_average['15_min']}"
75
+ )
76
+ else:
77
+ print("Load Average : unknown")
78
+
79
+ memory = data["memory"]
80
+ print()
81
+ print("Memory")
82
+ print("──────")
83
+ print(f"Total : {memory['total_gib']} GiB")
84
+ print(f"Used : {memory['used_gib']} GiB")
85
+ print(f"Available : {memory['available_gib']} GiB")
86
+ print(f"Used Percent : {memory['used_percent']}%")
87
+
88
+ swap = data["swap"]
89
+ print()
90
+ print("Swap")
91
+ print("────")
92
+ print(f"Total : {swap['total_gib']} GiB")
93
+ print(f"Used : {swap['used_gib']} GiB")
94
+ print(f"Free : {swap['free_gib']} GiB")
95
+ print(f"Used Percent : {swap['used_percent']}%")
96
+
97
+ root_disk = data["root_disk"]
98
+ print()
99
+ print("Root Disk")
100
+ print("─────────")
101
+ print(f"Total : {root_disk['total_gib']} GiB")
102
+ print(f"Used : {root_disk['used_gib']} GiB")
103
+ print(f"Free : {root_disk['free_gib']} GiB")
104
+ print(f"Used Percent : {root_disk['used_percent']}%")
105
+
106
+ warnings = result.get("warnings", [])
107
+
108
+ if warnings:
109
+ print()
110
+ print("Warnings")
111
+ print("────────")
112
+ for warning in warnings:
113
+ print(f"⚠ {warning}")
114
+
115
+ if verbose:
116
+ print()
117
+ print("Mounts")
118
+ print("──────")
119
+ for mount in data["mounts"]:
120
+ print(
121
+ f"{mount['mount_point']} "
122
+ f"({mount['filesystem']}) "
123
+ f"← {mount['device']}"
124
+ )
125
+
126
+ print()
127
+ print("Raw Result")
128
+ print("──────────")
129
+ print_json(result)
130
+
131
+ def print_network(result: dict[str, object], verbose: bool = False) -> None:
132
+ data = result["data"]
133
+
134
+ print("Network Information")
135
+ print("────────────────────────")
136
+
137
+ print("Interfaces")
138
+ print("──────────")
139
+
140
+ interfaces = data["interfaces"]
141
+
142
+ if interfaces:
143
+ for interface in interfaces:
144
+ print(
145
+ f"{interface['name']:<20} "
146
+ f"{interface['ipv4'] or 'No IPv4'}"
147
+ )
148
+ else:
149
+ print("No interfaces found")
150
+
151
+ print()
152
+
153
+ print("Default Route")
154
+ print("─────────────")
155
+
156
+ route = data["default_route"]
157
+
158
+ if route:
159
+ print(f"Gateway : {route['gateway']}")
160
+ print(f"Interface : {route['interface']}")
161
+ else:
162
+ print("No default route found")
163
+
164
+ print()
165
+
166
+ print("DNS Servers")
167
+ print("───────────")
168
+
169
+ dns_servers = data["dns_servers"]
170
+
171
+ if dns_servers:
172
+ for server in dns_servers:
173
+ print(f"- {server}")
174
+ else:
175
+ print("No DNS servers found")
176
+
177
+ print()
178
+
179
+ print("Listening Ports")
180
+ print("───────────────")
181
+
182
+ ports = data["listening_ports"]
183
+
184
+ if ports:
185
+ for port in ports[:10]:
186
+ print(
187
+ f"{port['protocol'].upper():<5} "
188
+ f"{port['local_address']}"
189
+ )
190
+
191
+ if len(ports) > 10:
192
+ print(
193
+ f"... {len(ports) - 10} more ports hidden. "
194
+ f"Use --verbose to see all."
195
+ )
196
+ else:
197
+ print("No listening ports found")
198
+
199
+ warnings = result.get("warnings", [])
200
+
201
+ if warnings:
202
+ print()
203
+ print("Warnings")
204
+ print("────────")
205
+
206
+ for warning in warnings:
207
+ print(f"⚠ {warning}")
208
+
209
+ if verbose:
210
+ print()
211
+
212
+ print("All Listening Ports")
213
+ print("──────────────────")
214
+
215
+ for port in ports:
216
+ print(
217
+ f"{port['protocol'].upper():<5} "
218
+ f"{port['local_address']}"
219
+ )
220
+
221
+ print()
222
+
223
+ print("Raw Result")
224
+ print("──────────")
225
+
226
+ print_json(result)
227
+
228
+ def print_devtools(result: dict[str, object], verbose: bool = False) -> None:
229
+ tools = result["data"]["tools"]
230
+
231
+ print("Developer Tools")
232
+ print("────────────────────────")
233
+
234
+ for tool in tools:
235
+ print()
236
+ print(tool["name"])
237
+
238
+ if tool["installed"]:
239
+ print("✓ Installed")
240
+
241
+ if tool["version"]:
242
+ print(f"Version : {tool['version']}")
243
+
244
+ if verbose and tool["path"]:
245
+ print(f"Path : {tool['path']}")
246
+
247
+ else:
248
+ print("✗ Not Installed")
249
+
250
+ warnings = result.get("warnings", [])
251
+
252
+ if warnings:
253
+ print()
254
+ print("Warnings")
255
+ print("────────")
256
+
257
+ for warning in warnings:
258
+ print(f"⚠ {warning}")
259
+
260
+ def print_findings(findings: list[str]) -> None:
261
+ if not findings:
262
+ print()
263
+ print("Audit Findings")
264
+ print("──────────────")
265
+ print("No findings detected.")
266
+ return
267
+
268
+ print()
269
+ print("Audit Findings")
270
+ print("──────────────")
271
+
272
+ for finding in findings:
273
+ print(f"⚠ {finding}")
dev_audit/status.py ADDED
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ EXIT_OK = 0
5
+ EXIT_FINDINGS = 1
6
+ EXIT_COLLECTOR_FAILURE = 2
7
+
8
+
9
+ def has_collector_failure(results: dict[str, object]) -> bool:
10
+ for section_result in results.values():
11
+ if not isinstance(section_result, dict):
12
+ continue
13
+
14
+ if section_result.get("success") is False:
15
+ return True
16
+
17
+ return False
18
+
19
+
20
+ def determine_exit_code(
21
+ results: dict[str, object],
22
+ findings: list[str],
23
+ ) -> int:
24
+ if has_collector_failure(results):
25
+ return EXIT_COLLECTOR_FAILURE
26
+
27
+ if findings:
28
+ return EXIT_FINDINGS
29
+
30
+ return EXIT_OK
@@ -0,0 +1,347 @@
1
+ Metadata-Version: 2.4
2
+ Name: devaudit-cli
3
+ Version: 0.3.0
4
+ Summary: Linux system inspection and developer environment audit tool
5
+ Author-email: Brenda Bonareri <bonarerijb24@gmail.com>
6
+ Keywords: linux,audit,cli,diagnostics,system-monitoring
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Environment :: Console
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # dev-audit
22
+
23
+ ![CI](https://github.com/Bonbonjb/dev-audit/actions/workflows/ci.yml/badge.svg)
24
+
25
+ ![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12-blue)
26
+ ![Version](https://img.shields.io/badge/version-0.3.0-green)
27
+ ![Tests](https://img.shields.io/badge/tests-44%20passing-brightgreen)
28
+ ![Coverage](https://img.shields.io/badge/coverage-50%25-yellow)
29
+
30
+ ## Project Status
31
+
32
+ **Current Release:** v0.3.0
33
+
34
+ ### Features
35
+
36
+ * Linux system inspection
37
+ * Resource monitoring
38
+ * Network auditing
39
+ * Developer tool validation
40
+ * Audit findings engine
41
+ * JSON output support
42
+ * Verbose output support
43
+ * Exit code support for automation
44
+ * GitHub Actions CI/CD
45
+
46
+ ### Quality Metrics
47
+
48
+ * 44 passing tests
49
+ * 50% code coverage
50
+ * Automated CI validation
51
+ * Semantic versioning
52
+ * Tagged releases
53
+
54
+
55
+ A Linux system inspection and diagnostic CLI built for Ubuntu environments.
56
+
57
+ `dev-audit` collects system information, resource metrics, network configuration, and developer environment details, then evaluates the results against audit rules to identify potential issues.
58
+
59
+ ---
60
+
61
+ ## Features
62
+
63
+ ### System Audit
64
+
65
+ * Operating system information
66
+ * Kernel version
67
+ * Hostname
68
+ * Architecture
69
+ * User and shell
70
+ * System uptime
71
+
72
+ ### Resource Audit
73
+
74
+ * CPU core count
75
+ * Load averages
76
+ * Memory utilization
77
+ * Swap utilization
78
+ * Root filesystem usage
79
+
80
+ ### Network Audit
81
+
82
+ * Network interfaces
83
+ * Default route
84
+ * DNS configuration
85
+ * Listening TCP and UDP ports
86
+
87
+ ### Developer Environment Audit
88
+
89
+ * Python
90
+ * pip
91
+ * Git
92
+ * Docker
93
+ * Docker Compose
94
+ * Node.js
95
+ * npm
96
+
97
+ ### Audit Engine
98
+
99
+ Detects:
100
+
101
+ * Exposed SSH services
102
+ * HTTP services listening on all interfaces
103
+ * Inconsistent development tool installations
104
+ * WSL-specific tool resolution issues
105
+
106
+ ### Output Modes
107
+
108
+ * Human-readable terminal output
109
+ * JSON output
110
+ * Verbose diagnostics
111
+
112
+ ### Exit Codes
113
+
114
+ | Exit Code | Meaning |
115
+ | --------- | ----------------- |
116
+ | 0 | Healthy audit |
117
+ | 1 | Findings detected |
118
+ | 2 | Collector failure |
119
+
120
+ ---
121
+
122
+ ## Architecture
123
+
124
+ dev-audit follows a modular collector-based architecture.
125
+
126
+ ```text
127
+ CLI
128
+
129
+ ├── System Collector
130
+ │ ├── OS Information
131
+ │ ├── Kernel Information
132
+ │ └── Uptime
133
+
134
+ ├── Resource Collector
135
+ │ ├── CPU Usage
136
+ │ ├── Memory Usage
137
+ │ ├── Swap Usage
138
+ │ └── Disk Usage
139
+
140
+ ├── Network Collector
141
+ │ ├── Interfaces
142
+ │ ├── DNS Servers
143
+ │ ├── Default Route
144
+ │ └── Listening Ports
145
+
146
+ ├── DevTools Collector
147
+ │ ├── Python
148
+ │ ├── pip
149
+ │ ├── Git
150
+ │ ├── Docker
151
+ │ ├── Docker Compose
152
+ │ ├── Node.js
153
+ │ └── npm
154
+
155
+ └── Audit Engine
156
+ ├── Resource Checks
157
+ ├── Network Checks
158
+ └── Environment Checks
159
+
160
+ Output Layer
161
+ ├── Human Readable Output
162
+ ├── JSON Output
163
+ └── Exit Codes
164
+ ```
165
+
166
+ ### Design Goals
167
+
168
+ * Modular collector architecture
169
+ * Linux-first implementation
170
+ * Machine-readable JSON output
171
+ * Human-readable terminal output
172
+ * CI/CD validated
173
+ * Test-driven development
174
+ * Suitable for automation and scripting
175
+
176
+ ## Example Output
177
+
178
+ ```bash
179
+ $ dev-audit
180
+
181
+ System Information
182
+ ────────────────────────
183
+ Hostname : ubuntu-server
184
+ OS : Ubuntu 24.04 LTS
185
+ Kernel : 6.8.0
186
+ Architecture : x86_64
187
+ User : ubuntu
188
+
189
+ Resource Usage
190
+ ────────────────────────
191
+ CPU Cores : 8
192
+ Load Average : 0.10 0.12 0.08
193
+
194
+ Memory
195
+ ──────
196
+ Total : 16.0 GiB
197
+ Used : 4.2 GiB
198
+ Available : 11.8 GiB
199
+
200
+ Audit Findings
201
+ ──────────────
202
+ ⚠ SSH is listening on all interfaces.
203
+ ⚠ HTTP service exposed on all IPv4 interfaces.
204
+ ```
205
+
206
+ ### JSON Output
207
+
208
+ ```bash
209
+ $ dev-audit --json
210
+ ```
211
+
212
+ ```json
213
+ {
214
+ "system": {
215
+ "hostname": "ubuntu-server",
216
+ "kernel": "6.8.0"
217
+ },
218
+ "findings": [
219
+ "SSH is listening on all interfaces."
220
+ ]
221
+ }
222
+ ```
223
+
224
+ ## Use Cases
225
+
226
+ `dev-audit` can be used to:
227
+
228
+ * Quickly inspect Linux development environments
229
+ * Validate workstation setup before software development
230
+ * Audit servers for exposed services and configuration issues
231
+ * Generate machine-readable JSON reports for automation
232
+ * Troubleshoot networking and developer tool installations
233
+ * Perform lightweight health checks on Ubuntu systems
234
+
235
+ ## Installation
236
+
237
+ ### Clone Repository
238
+
239
+ ```bash
240
+ git clone https://github.com/Bonbonjb/dev-audit.git
241
+ cd dev-audit
242
+ ```
243
+
244
+ ### Create Virtual Environment
245
+
246
+ ```bash
247
+ python3 -m venv .venv
248
+ source .venv/bin/activate
249
+ ```
250
+
251
+ ### Install Package
252
+
253
+ ```bash
254
+ pip install -e .
255
+ ```
256
+
257
+ ---
258
+
259
+ ## Usage
260
+
261
+ ### Full Audit
262
+
263
+ ```bash
264
+ dev-audit
265
+ ```
266
+
267
+ ### Run Individual Sections
268
+
269
+ ```bash
270
+ dev-audit system
271
+ dev-audit resources
272
+ dev-audit network
273
+ dev-audit devtools
274
+ ```
275
+
276
+ ### JSON Output
277
+
278
+ ```bash
279
+ dev-audit --json
280
+ ```
281
+
282
+ ### Verbose Output
283
+
284
+ ```bash
285
+ dev-audit --verbose
286
+ ```
287
+
288
+ ---
289
+
290
+ ## Example Audit Findings
291
+
292
+ ```text
293
+ ⚠ SSH is listening on all interfaces.
294
+ ⚠ HTTP service exposed on all IPv4 interfaces.
295
+ ⚠ npm detected but Node.js executable not found.
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Running Tests
301
+
302
+ ```bash
303
+ pytest
304
+ ```
305
+
306
+ Current test suite:
307
+
308
+ ```text
309
+ 44 passing tests
310
+ ```
311
+
312
+ ---
313
+
314
+ ## Project Structure
315
+
316
+ ```text
317
+ src/dev_audit/
318
+ ├── audit.py
319
+ ├── cli.py
320
+ ├── command.py
321
+ ├── output.py
322
+ ├── status.py
323
+ └── collectors/
324
+ ├── system.py
325
+ ├── resources.py
326
+ ├── network.py
327
+ └── devtools.py
328
+
329
+ tests/
330
+ ├── test_audit.py
331
+ ├── test_command.py
332
+ ├── test_network.py
333
+ ├── test_output.py
334
+ ├── test_resources.py
335
+ ├── test_status.py
336
+ └── test_system.py
337
+ ```
338
+
339
+ ---
340
+
341
+ ## Roadmap
342
+
343
+ * GitHub Actions CI
344
+ * Coverage reporting
345
+ * Additional audit rules
346
+ * Package publishing
347
+ * Extended Linux distribution support
@@ -0,0 +1,18 @@
1
+ dev_audit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ dev_audit/__main__.py,sha256=NMzkhEt4JrPnvOKaIX-PS41GmT7WtA8wdimlZJYB4Ro,88
3
+ dev_audit/audit.py,sha256=6Oi2QCETVvZuA1yfyvJ0-RgiwxdAv5szDKK4BSdrO9s,1276
4
+ dev_audit/cli.py,sha256=mBGVVT_ufyKmy88SECDiiVxroqrAO1D8TcW63RDeM68,2985
5
+ dev_audit/command.py,sha256=ZBqdolTIUgWLWmHEeZrHPw_Td9p-umQxl6uKFeq3ivw,1233
6
+ dev_audit/output.py,sha256=1LGoiRWbCsuupz3vI8B9H3VdHb1rcT3qclFYTaFbk3A,7297
7
+ dev_audit/status.py,sha256=cdbbDP7aSyL4j7G28wzlweKTvEd1nlPRf9v-IC0fKvQ,605
8
+ dev_audit/collectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ dev_audit/collectors/devtools.py,sha256=nNkRV6lCuJ5aS86V8ltCcT7NMFLRFGRF2SKXjx_NHoA,2671
10
+ dev_audit/collectors/network.py,sha256=LrBvQNmHJ5eF1Zz0nTYwyBWo7Yw2ghg6HDkEnDLXmWo,4020
11
+ dev_audit/collectors/resources.py,sha256=5Gc3cpaJVxF2b-a1E70y35d1FYypZL_D3jiJGw7Ixic,3706
12
+ dev_audit/collectors/system.py,sha256=J2bzNOtI4eVGkhzEll498iGNq6maTglmixkxnEeJm68,1739
13
+ devaudit_cli-0.3.0.dist-info/licenses/LICENSE,sha256=-7gN4WoZV6NAULFetK8ovhVGWD7_BkEt1qcTFryzWDw,1092
14
+ devaudit_cli-0.3.0.dist-info/METADATA,sha256=xvqqCiql_fIOITr4ffThGiQ36BH6iPQDVCvnzADNX80,6631
15
+ devaudit_cli-0.3.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
16
+ devaudit_cli-0.3.0.dist-info/entry_points.txt,sha256=3ONwyrlQeBsW4d3u6QG6NYrzSxgsDVS3kt6txVBtOu4,49
17
+ devaudit_cli-0.3.0.dist-info/top_level.txt,sha256=RApWYjNVDZXVB3dwjgw7UHrD8ujDknaeP8T12QBA0nk,10
18
+ devaudit_cli-0.3.0.dist-info/RECORD,,