aiptx 2.0.7__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.
- aipt_v2/__init__.py +110 -0
- aipt_v2/__main__.py +24 -0
- aipt_v2/agents/AIPTxAgent/__init__.py +10 -0
- aipt_v2/agents/AIPTxAgent/aiptx_agent.py +211 -0
- aipt_v2/agents/__init__.py +46 -0
- aipt_v2/agents/base.py +520 -0
- aipt_v2/agents/exploit_agent.py +688 -0
- aipt_v2/agents/ptt.py +406 -0
- aipt_v2/agents/state.py +168 -0
- aipt_v2/app.py +957 -0
- aipt_v2/browser/__init__.py +31 -0
- aipt_v2/browser/automation.py +458 -0
- aipt_v2/browser/crawler.py +453 -0
- aipt_v2/cli.py +2933 -0
- aipt_v2/compliance/__init__.py +71 -0
- aipt_v2/compliance/compliance_report.py +449 -0
- aipt_v2/compliance/framework_mapper.py +424 -0
- aipt_v2/compliance/nist_mapping.py +345 -0
- aipt_v2/compliance/owasp_mapping.py +330 -0
- aipt_v2/compliance/pci_mapping.py +297 -0
- aipt_v2/config.py +341 -0
- aipt_v2/core/__init__.py +43 -0
- aipt_v2/core/agent.py +630 -0
- aipt_v2/core/llm.py +395 -0
- aipt_v2/core/memory.py +305 -0
- aipt_v2/core/ptt.py +329 -0
- aipt_v2/database/__init__.py +14 -0
- aipt_v2/database/models.py +232 -0
- aipt_v2/database/repository.py +384 -0
- aipt_v2/docker/__init__.py +23 -0
- aipt_v2/docker/builder.py +260 -0
- aipt_v2/docker/manager.py +222 -0
- aipt_v2/docker/sandbox.py +371 -0
- aipt_v2/evasion/__init__.py +58 -0
- aipt_v2/evasion/request_obfuscator.py +272 -0
- aipt_v2/evasion/tls_fingerprint.py +285 -0
- aipt_v2/evasion/ua_rotator.py +301 -0
- aipt_v2/evasion/waf_bypass.py +439 -0
- aipt_v2/execution/__init__.py +23 -0
- aipt_v2/execution/executor.py +302 -0
- aipt_v2/execution/parser.py +544 -0
- aipt_v2/execution/terminal.py +337 -0
- aipt_v2/health.py +437 -0
- aipt_v2/intelligence/__init__.py +194 -0
- aipt_v2/intelligence/adaptation.py +474 -0
- aipt_v2/intelligence/auth.py +520 -0
- aipt_v2/intelligence/chaining.py +775 -0
- aipt_v2/intelligence/correlation.py +536 -0
- aipt_v2/intelligence/cve_aipt.py +334 -0
- aipt_v2/intelligence/cve_info.py +1111 -0
- aipt_v2/intelligence/knowledge_graph.py +590 -0
- aipt_v2/intelligence/learning.py +626 -0
- aipt_v2/intelligence/llm_analyzer.py +502 -0
- aipt_v2/intelligence/llm_tool_selector.py +518 -0
- aipt_v2/intelligence/payload_generator.py +562 -0
- aipt_v2/intelligence/rag.py +239 -0
- aipt_v2/intelligence/scope.py +442 -0
- aipt_v2/intelligence/searchers/__init__.py +5 -0
- aipt_v2/intelligence/searchers/exploitdb_searcher.py +523 -0
- aipt_v2/intelligence/searchers/github_searcher.py +467 -0
- aipt_v2/intelligence/searchers/google_searcher.py +281 -0
- aipt_v2/intelligence/tools.json +443 -0
- aipt_v2/intelligence/triage.py +670 -0
- aipt_v2/interactive_shell.py +559 -0
- aipt_v2/interface/__init__.py +5 -0
- aipt_v2/interface/cli.py +230 -0
- aipt_v2/interface/main.py +501 -0
- aipt_v2/interface/tui.py +1276 -0
- aipt_v2/interface/utils.py +583 -0
- aipt_v2/llm/__init__.py +39 -0
- aipt_v2/llm/config.py +26 -0
- aipt_v2/llm/llm.py +514 -0
- aipt_v2/llm/memory.py +214 -0
- aipt_v2/llm/request_queue.py +89 -0
- aipt_v2/llm/utils.py +89 -0
- aipt_v2/local_tool_installer.py +1467 -0
- aipt_v2/models/__init__.py +15 -0
- aipt_v2/models/findings.py +295 -0
- aipt_v2/models/phase_result.py +224 -0
- aipt_v2/models/scan_config.py +207 -0
- aipt_v2/monitoring/grafana/dashboards/aipt-dashboard.json +355 -0
- aipt_v2/monitoring/grafana/dashboards/default.yml +17 -0
- aipt_v2/monitoring/grafana/datasources/prometheus.yml +17 -0
- aipt_v2/monitoring/prometheus.yml +60 -0
- aipt_v2/orchestration/__init__.py +52 -0
- aipt_v2/orchestration/pipeline.py +398 -0
- aipt_v2/orchestration/progress.py +300 -0
- aipt_v2/orchestration/scheduler.py +296 -0
- aipt_v2/orchestrator.py +2427 -0
- aipt_v2/payloads/__init__.py +27 -0
- aipt_v2/payloads/cmdi.py +150 -0
- aipt_v2/payloads/sqli.py +263 -0
- aipt_v2/payloads/ssrf.py +204 -0
- aipt_v2/payloads/templates.py +222 -0
- aipt_v2/payloads/traversal.py +166 -0
- aipt_v2/payloads/xss.py +204 -0
- aipt_v2/prompts/__init__.py +60 -0
- aipt_v2/proxy/__init__.py +29 -0
- aipt_v2/proxy/history.py +352 -0
- aipt_v2/proxy/interceptor.py +452 -0
- aipt_v2/recon/__init__.py +44 -0
- aipt_v2/recon/dns.py +241 -0
- aipt_v2/recon/osint.py +367 -0
- aipt_v2/recon/subdomain.py +372 -0
- aipt_v2/recon/tech_detect.py +311 -0
- aipt_v2/reports/__init__.py +17 -0
- aipt_v2/reports/generator.py +313 -0
- aipt_v2/reports/html_report.py +378 -0
- aipt_v2/runtime/__init__.py +53 -0
- aipt_v2/runtime/base.py +30 -0
- aipt_v2/runtime/docker.py +401 -0
- aipt_v2/runtime/local.py +346 -0
- aipt_v2/runtime/tool_server.py +205 -0
- aipt_v2/runtime/vps.py +830 -0
- aipt_v2/scanners/__init__.py +28 -0
- aipt_v2/scanners/base.py +273 -0
- aipt_v2/scanners/nikto.py +244 -0
- aipt_v2/scanners/nmap.py +402 -0
- aipt_v2/scanners/nuclei.py +273 -0
- aipt_v2/scanners/web.py +454 -0
- aipt_v2/scripts/security_audit.py +366 -0
- aipt_v2/setup_wizard.py +941 -0
- aipt_v2/skills/__init__.py +80 -0
- aipt_v2/skills/agents/__init__.py +14 -0
- aipt_v2/skills/agents/api_tester.py +706 -0
- aipt_v2/skills/agents/base.py +477 -0
- aipt_v2/skills/agents/code_review.py +459 -0
- aipt_v2/skills/agents/security_agent.py +336 -0
- aipt_v2/skills/agents/web_pentest.py +818 -0
- aipt_v2/skills/prompts/__init__.py +647 -0
- aipt_v2/system_detector.py +539 -0
- aipt_v2/telemetry/__init__.py +7 -0
- aipt_v2/telemetry/tracer.py +347 -0
- aipt_v2/terminal/__init__.py +28 -0
- aipt_v2/terminal/executor.py +400 -0
- aipt_v2/terminal/sandbox.py +350 -0
- aipt_v2/tools/__init__.py +44 -0
- aipt_v2/tools/active_directory/__init__.py +78 -0
- aipt_v2/tools/active_directory/ad_config.py +238 -0
- aipt_v2/tools/active_directory/bloodhound_wrapper.py +447 -0
- aipt_v2/tools/active_directory/kerberos_attacks.py +430 -0
- aipt_v2/tools/active_directory/ldap_enum.py +533 -0
- aipt_v2/tools/active_directory/smb_attacks.py +505 -0
- aipt_v2/tools/agents_graph/__init__.py +19 -0
- aipt_v2/tools/agents_graph/agents_graph_actions.py +69 -0
- aipt_v2/tools/api_security/__init__.py +76 -0
- aipt_v2/tools/api_security/api_discovery.py +608 -0
- aipt_v2/tools/api_security/graphql_scanner.py +622 -0
- aipt_v2/tools/api_security/jwt_analyzer.py +577 -0
- aipt_v2/tools/api_security/openapi_fuzzer.py +761 -0
- aipt_v2/tools/browser/__init__.py +5 -0
- aipt_v2/tools/browser/browser_actions.py +238 -0
- aipt_v2/tools/browser/browser_instance.py +535 -0
- aipt_v2/tools/browser/tab_manager.py +344 -0
- aipt_v2/tools/cloud/__init__.py +70 -0
- aipt_v2/tools/cloud/cloud_config.py +273 -0
- aipt_v2/tools/cloud/cloud_scanner.py +639 -0
- aipt_v2/tools/cloud/prowler_tool.py +571 -0
- aipt_v2/tools/cloud/scoutsuite_tool.py +359 -0
- aipt_v2/tools/executor.py +307 -0
- aipt_v2/tools/parser.py +408 -0
- aipt_v2/tools/proxy/__init__.py +5 -0
- aipt_v2/tools/proxy/proxy_actions.py +103 -0
- aipt_v2/tools/proxy/proxy_manager.py +789 -0
- aipt_v2/tools/registry.py +196 -0
- aipt_v2/tools/scanners/__init__.py +343 -0
- aipt_v2/tools/scanners/acunetix_tool.py +712 -0
- aipt_v2/tools/scanners/burp_tool.py +631 -0
- aipt_v2/tools/scanners/config.py +156 -0
- aipt_v2/tools/scanners/nessus_tool.py +588 -0
- aipt_v2/tools/scanners/zap_tool.py +612 -0
- aipt_v2/tools/terminal/__init__.py +5 -0
- aipt_v2/tools/terminal/terminal_actions.py +37 -0
- aipt_v2/tools/terminal/terminal_manager.py +153 -0
- aipt_v2/tools/terminal/terminal_session.py +449 -0
- aipt_v2/tools/tool_processing.py +108 -0
- aipt_v2/utils/__init__.py +17 -0
- aipt_v2/utils/logging.py +202 -0
- aipt_v2/utils/model_manager.py +187 -0
- aipt_v2/utils/searchers/__init__.py +269 -0
- aipt_v2/verify_install.py +793 -0
- aiptx-2.0.7.dist-info/METADATA +345 -0
- aiptx-2.0.7.dist-info/RECORD +187 -0
- aiptx-2.0.7.dist-info/WHEEL +5 -0
- aiptx-2.0.7.dist-info/entry_points.txt +7 -0
- aiptx-2.0.7.dist-info/licenses/LICENSE +21 -0
- aiptx-2.0.7.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIPTX System Detector
|
|
3
|
+
=====================
|
|
4
|
+
|
|
5
|
+
Automatically detects the user's operating system, package manager,
|
|
6
|
+
and system capabilities for seamless tool installation.
|
|
7
|
+
|
|
8
|
+
Features:
|
|
9
|
+
- OS detection (Linux, macOS, Windows)
|
|
10
|
+
- Package manager detection (apt, brew, yum, pacman, choco)
|
|
11
|
+
- Architecture detection (x86_64, arm64)
|
|
12
|
+
- Capability checks (Docker, Python, Go, Ruby, etc.)
|
|
13
|
+
- Sudo/admin privilege detection
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
detector = SystemDetector()
|
|
17
|
+
info = await detector.detect()
|
|
18
|
+
print(f"OS: {info.os_name}, Package Manager: {info.package_manager}")
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import asyncio
|
|
22
|
+
import os
|
|
23
|
+
import platform
|
|
24
|
+
import shutil
|
|
25
|
+
import subprocess
|
|
26
|
+
from dataclasses import dataclass, field
|
|
27
|
+
from enum import Enum
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
from typing import Dict, List, Optional, Tuple
|
|
30
|
+
|
|
31
|
+
from rich.console import Console
|
|
32
|
+
from rich.table import Table
|
|
33
|
+
from rich import box
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
console = Console()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class OSType(Enum):
|
|
40
|
+
"""Supported operating systems."""
|
|
41
|
+
LINUX = "linux"
|
|
42
|
+
MACOS = "macos"
|
|
43
|
+
WINDOWS = "windows"
|
|
44
|
+
UNKNOWN = "unknown"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PackageManager(Enum):
|
|
48
|
+
"""Supported package managers."""
|
|
49
|
+
APT = "apt" # Debian/Ubuntu
|
|
50
|
+
YUM = "yum" # RHEL/CentOS/Fedora (older)
|
|
51
|
+
DNF = "dnf" # Fedora/RHEL 8+
|
|
52
|
+
PACMAN = "pacman" # Arch Linux
|
|
53
|
+
ZYPPER = "zypper" # openSUSE
|
|
54
|
+
BREW = "brew" # macOS Homebrew
|
|
55
|
+
MACPORTS = "port" # macOS MacPorts
|
|
56
|
+
CHOCO = "choco" # Windows Chocolatey
|
|
57
|
+
SCOOP = "scoop" # Windows Scoop
|
|
58
|
+
WINGET = "winget" # Windows Package Manager
|
|
59
|
+
NIX = "nix" # Nix package manager
|
|
60
|
+
UNKNOWN = "unknown"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Architecture(Enum):
|
|
64
|
+
"""CPU architectures."""
|
|
65
|
+
X86_64 = "x86_64"
|
|
66
|
+
ARM64 = "arm64"
|
|
67
|
+
ARM32 = "arm32"
|
|
68
|
+
X86 = "x86"
|
|
69
|
+
UNKNOWN = "unknown"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class SystemCapabilities:
|
|
74
|
+
"""System capabilities and available runtimes."""
|
|
75
|
+
has_docker: bool = False
|
|
76
|
+
has_python3: bool = False
|
|
77
|
+
has_pip: bool = False
|
|
78
|
+
has_go: bool = False
|
|
79
|
+
has_ruby: bool = False
|
|
80
|
+
has_gem: bool = False
|
|
81
|
+
has_node: bool = False
|
|
82
|
+
has_npm: bool = False
|
|
83
|
+
has_git: bool = False
|
|
84
|
+
has_curl: bool = False
|
|
85
|
+
has_wget: bool = False
|
|
86
|
+
has_sudo: bool = False
|
|
87
|
+
has_make: bool = False
|
|
88
|
+
has_gcc: bool = False
|
|
89
|
+
has_cargo: bool = False
|
|
90
|
+
|
|
91
|
+
# Version info
|
|
92
|
+
python_version: str = ""
|
|
93
|
+
go_version: str = ""
|
|
94
|
+
docker_version: str = ""
|
|
95
|
+
|
|
96
|
+
def to_dict(self) -> Dict[str, bool]:
|
|
97
|
+
"""Convert to dictionary."""
|
|
98
|
+
return {
|
|
99
|
+
"docker": self.has_docker,
|
|
100
|
+
"python3": self.has_python3,
|
|
101
|
+
"pip": self.has_pip,
|
|
102
|
+
"go": self.has_go,
|
|
103
|
+
"ruby": self.has_ruby,
|
|
104
|
+
"gem": self.has_gem,
|
|
105
|
+
"node": self.has_node,
|
|
106
|
+
"npm": self.has_npm,
|
|
107
|
+
"git": self.has_git,
|
|
108
|
+
"curl": self.has_curl,
|
|
109
|
+
"wget": self.has_wget,
|
|
110
|
+
"sudo": self.has_sudo,
|
|
111
|
+
"make": self.has_make,
|
|
112
|
+
"gcc": self.has_gcc,
|
|
113
|
+
"cargo": self.has_cargo,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dataclass
|
|
118
|
+
class SystemInfo:
|
|
119
|
+
"""Complete system information."""
|
|
120
|
+
os_type: OSType = OSType.UNKNOWN
|
|
121
|
+
os_name: str = ""
|
|
122
|
+
os_version: str = ""
|
|
123
|
+
os_codename: str = ""
|
|
124
|
+
architecture: Architecture = Architecture.UNKNOWN
|
|
125
|
+
package_manager: PackageManager = PackageManager.UNKNOWN
|
|
126
|
+
capabilities: SystemCapabilities = field(default_factory=SystemCapabilities)
|
|
127
|
+
home_dir: Path = field(default_factory=Path.home)
|
|
128
|
+
is_wsl: bool = False
|
|
129
|
+
is_container: bool = False
|
|
130
|
+
shell: str = ""
|
|
131
|
+
|
|
132
|
+
def summary(self) -> str:
|
|
133
|
+
"""Return a human-readable summary."""
|
|
134
|
+
return (
|
|
135
|
+
f"{self.os_name} {self.os_version} ({self.architecture.value}) "
|
|
136
|
+
f"with {self.package_manager.value}"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class SystemDetector:
|
|
141
|
+
"""
|
|
142
|
+
Detects system configuration for optimal tool installation.
|
|
143
|
+
|
|
144
|
+
This class automatically detects:
|
|
145
|
+
- Operating system type and version
|
|
146
|
+
- CPU architecture
|
|
147
|
+
- Available package manager
|
|
148
|
+
- Installed runtimes and capabilities
|
|
149
|
+
- Container/WSL environment
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
def __init__(self):
|
|
153
|
+
self._info: Optional[SystemInfo] = None
|
|
154
|
+
|
|
155
|
+
async def detect(self) -> SystemInfo:
|
|
156
|
+
"""
|
|
157
|
+
Perform full system detection.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
SystemInfo with all detected information
|
|
161
|
+
"""
|
|
162
|
+
info = SystemInfo()
|
|
163
|
+
|
|
164
|
+
# Detect OS
|
|
165
|
+
info.os_type = self._detect_os_type()
|
|
166
|
+
info.os_name, info.os_version, info.os_codename = self._detect_os_details()
|
|
167
|
+
info.architecture = self._detect_architecture()
|
|
168
|
+
info.shell = os.environ.get("SHELL", "")
|
|
169
|
+
|
|
170
|
+
# Check for special environments
|
|
171
|
+
info.is_wsl = self._is_wsl()
|
|
172
|
+
info.is_container = self._is_container()
|
|
173
|
+
|
|
174
|
+
# Detect package manager
|
|
175
|
+
info.package_manager = await self._detect_package_manager(info.os_type)
|
|
176
|
+
|
|
177
|
+
# Detect capabilities
|
|
178
|
+
info.capabilities = await self._detect_capabilities()
|
|
179
|
+
|
|
180
|
+
self._info = info
|
|
181
|
+
return info
|
|
182
|
+
|
|
183
|
+
def _detect_os_type(self) -> OSType:
|
|
184
|
+
"""Detect the operating system type."""
|
|
185
|
+
system = platform.system().lower()
|
|
186
|
+
|
|
187
|
+
if system == "linux":
|
|
188
|
+
return OSType.LINUX
|
|
189
|
+
elif system == "darwin":
|
|
190
|
+
return OSType.MACOS
|
|
191
|
+
elif system == "windows":
|
|
192
|
+
return OSType.WINDOWS
|
|
193
|
+
else:
|
|
194
|
+
return OSType.UNKNOWN
|
|
195
|
+
|
|
196
|
+
def _detect_os_details(self) -> Tuple[str, str, str]:
|
|
197
|
+
"""Detect OS name, version, and codename."""
|
|
198
|
+
system = platform.system().lower()
|
|
199
|
+
version = platform.version()
|
|
200
|
+
codename = ""
|
|
201
|
+
name = platform.system()
|
|
202
|
+
|
|
203
|
+
if system == "linux":
|
|
204
|
+
# Try to read /etc/os-release for Linux
|
|
205
|
+
try:
|
|
206
|
+
os_release = {}
|
|
207
|
+
with open("/etc/os-release") as f:
|
|
208
|
+
for line in f:
|
|
209
|
+
if "=" in line:
|
|
210
|
+
key, value = line.strip().split("=", 1)
|
|
211
|
+
os_release[key] = value.strip('"')
|
|
212
|
+
|
|
213
|
+
name = os_release.get("NAME", "Linux")
|
|
214
|
+
version = os_release.get("VERSION_ID", platform.release())
|
|
215
|
+
codename = os_release.get("VERSION_CODENAME", "")
|
|
216
|
+
except FileNotFoundError:
|
|
217
|
+
name = "Linux"
|
|
218
|
+
version = platform.release()
|
|
219
|
+
|
|
220
|
+
elif system == "darwin":
|
|
221
|
+
name = "macOS"
|
|
222
|
+
# Get macOS version name
|
|
223
|
+
mac_ver = platform.mac_ver()[0]
|
|
224
|
+
version = mac_ver
|
|
225
|
+
|
|
226
|
+
# Map version to codename
|
|
227
|
+
version_codenames = {
|
|
228
|
+
"15": "Sequoia",
|
|
229
|
+
"14": "Sonoma",
|
|
230
|
+
"13": "Ventura",
|
|
231
|
+
"12": "Monterey",
|
|
232
|
+
"11": "Big Sur",
|
|
233
|
+
"10.15": "Catalina",
|
|
234
|
+
"10.14": "Mojave",
|
|
235
|
+
}
|
|
236
|
+
major = mac_ver.split(".")[0] if mac_ver else ""
|
|
237
|
+
codename = version_codenames.get(major, "")
|
|
238
|
+
|
|
239
|
+
elif system == "windows":
|
|
240
|
+
name = "Windows"
|
|
241
|
+
version = platform.win32_ver()[0]
|
|
242
|
+
|
|
243
|
+
return name, version, codename
|
|
244
|
+
|
|
245
|
+
def _detect_architecture(self) -> Architecture:
|
|
246
|
+
"""Detect CPU architecture."""
|
|
247
|
+
machine = platform.machine().lower()
|
|
248
|
+
|
|
249
|
+
if machine in ("x86_64", "amd64"):
|
|
250
|
+
return Architecture.X86_64
|
|
251
|
+
elif machine in ("arm64", "aarch64"):
|
|
252
|
+
return Architecture.ARM64
|
|
253
|
+
elif machine in ("armv7l", "armv6l"):
|
|
254
|
+
return Architecture.ARM32
|
|
255
|
+
elif machine in ("i386", "i686"):
|
|
256
|
+
return Architecture.X86
|
|
257
|
+
else:
|
|
258
|
+
return Architecture.UNKNOWN
|
|
259
|
+
|
|
260
|
+
def _is_wsl(self) -> bool:
|
|
261
|
+
"""Check if running in Windows Subsystem for Linux."""
|
|
262
|
+
if platform.system().lower() != "linux":
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
# Check for WSL indicators
|
|
266
|
+
try:
|
|
267
|
+
with open("/proc/version") as f:
|
|
268
|
+
version = f.read().lower()
|
|
269
|
+
return "microsoft" in version or "wsl" in version
|
|
270
|
+
except FileNotFoundError:
|
|
271
|
+
return False
|
|
272
|
+
|
|
273
|
+
def _is_container(self) -> bool:
|
|
274
|
+
"""Check if running inside a container."""
|
|
275
|
+
# Check for Docker
|
|
276
|
+
if os.path.exists("/.dockerenv"):
|
|
277
|
+
return True
|
|
278
|
+
|
|
279
|
+
# Check cgroup for container runtime
|
|
280
|
+
try:
|
|
281
|
+
with open("/proc/1/cgroup") as f:
|
|
282
|
+
cgroup = f.read()
|
|
283
|
+
if "docker" in cgroup or "kubepods" in cgroup or "lxc" in cgroup:
|
|
284
|
+
return True
|
|
285
|
+
except FileNotFoundError:
|
|
286
|
+
pass
|
|
287
|
+
|
|
288
|
+
return False
|
|
289
|
+
|
|
290
|
+
async def _detect_package_manager(self, os_type: OSType) -> PackageManager:
|
|
291
|
+
"""Detect the available package manager."""
|
|
292
|
+
if os_type == OSType.MACOS:
|
|
293
|
+
# Check for Homebrew first (most common)
|
|
294
|
+
if shutil.which("brew"):
|
|
295
|
+
return PackageManager.BREW
|
|
296
|
+
elif shutil.which("port"):
|
|
297
|
+
return PackageManager.MACPORTS
|
|
298
|
+
elif shutil.which("nix"):
|
|
299
|
+
return PackageManager.NIX
|
|
300
|
+
|
|
301
|
+
elif os_type == OSType.LINUX:
|
|
302
|
+
# Check common Linux package managers
|
|
303
|
+
if shutil.which("apt") or shutil.which("apt-get"):
|
|
304
|
+
return PackageManager.APT
|
|
305
|
+
elif shutil.which("dnf"):
|
|
306
|
+
return PackageManager.DNF
|
|
307
|
+
elif shutil.which("yum"):
|
|
308
|
+
return PackageManager.YUM
|
|
309
|
+
elif shutil.which("pacman"):
|
|
310
|
+
return PackageManager.PACMAN
|
|
311
|
+
elif shutil.which("zypper"):
|
|
312
|
+
return PackageManager.ZYPPER
|
|
313
|
+
elif shutil.which("nix"):
|
|
314
|
+
return PackageManager.NIX
|
|
315
|
+
|
|
316
|
+
elif os_type == OSType.WINDOWS:
|
|
317
|
+
# Check Windows package managers
|
|
318
|
+
if shutil.which("winget"):
|
|
319
|
+
return PackageManager.WINGET
|
|
320
|
+
elif shutil.which("choco"):
|
|
321
|
+
return PackageManager.CHOCO
|
|
322
|
+
elif shutil.which("scoop"):
|
|
323
|
+
return PackageManager.SCOOP
|
|
324
|
+
|
|
325
|
+
return PackageManager.UNKNOWN
|
|
326
|
+
|
|
327
|
+
async def _detect_capabilities(self) -> SystemCapabilities:
|
|
328
|
+
"""Detect available tools and runtimes."""
|
|
329
|
+
caps = SystemCapabilities()
|
|
330
|
+
|
|
331
|
+
# Simple binary checks
|
|
332
|
+
caps.has_docker = bool(shutil.which("docker"))
|
|
333
|
+
caps.has_python3 = bool(shutil.which("python3") or shutil.which("python"))
|
|
334
|
+
caps.has_pip = bool(shutil.which("pip3") or shutil.which("pip"))
|
|
335
|
+
caps.has_go = bool(shutil.which("go"))
|
|
336
|
+
caps.has_ruby = bool(shutil.which("ruby"))
|
|
337
|
+
caps.has_gem = bool(shutil.which("gem"))
|
|
338
|
+
caps.has_node = bool(shutil.which("node") or shutil.which("nodejs"))
|
|
339
|
+
caps.has_npm = bool(shutil.which("npm"))
|
|
340
|
+
caps.has_git = bool(shutil.which("git"))
|
|
341
|
+
caps.has_curl = bool(shutil.which("curl"))
|
|
342
|
+
caps.has_wget = bool(shutil.which("wget"))
|
|
343
|
+
caps.has_make = bool(shutil.which("make"))
|
|
344
|
+
caps.has_gcc = bool(shutil.which("gcc") or shutil.which("clang"))
|
|
345
|
+
caps.has_cargo = bool(shutil.which("cargo"))
|
|
346
|
+
|
|
347
|
+
# Check sudo/admin privileges
|
|
348
|
+
caps.has_sudo = await self._check_sudo()
|
|
349
|
+
|
|
350
|
+
# Get version info for key tools
|
|
351
|
+
if caps.has_python3:
|
|
352
|
+
caps.python_version = await self._get_command_output("python3 --version") or \
|
|
353
|
+
await self._get_command_output("python --version") or ""
|
|
354
|
+
|
|
355
|
+
if caps.has_go:
|
|
356
|
+
caps.go_version = await self._get_command_output("go version") or ""
|
|
357
|
+
|
|
358
|
+
if caps.has_docker:
|
|
359
|
+
caps.docker_version = await self._get_command_output("docker --version") or ""
|
|
360
|
+
|
|
361
|
+
return caps
|
|
362
|
+
|
|
363
|
+
async def _check_sudo(self) -> bool:
|
|
364
|
+
"""Check if user has sudo privileges."""
|
|
365
|
+
if platform.system().lower() == "windows":
|
|
366
|
+
# Check for admin on Windows
|
|
367
|
+
try:
|
|
368
|
+
import ctypes
|
|
369
|
+
return ctypes.windll.shell32.IsUserAnAdmin() != 0
|
|
370
|
+
except Exception:
|
|
371
|
+
return False
|
|
372
|
+
else:
|
|
373
|
+
# Check sudo on Unix
|
|
374
|
+
try:
|
|
375
|
+
proc = await asyncio.create_subprocess_shell(
|
|
376
|
+
"sudo -n true 2>/dev/null",
|
|
377
|
+
stdout=asyncio.subprocess.PIPE,
|
|
378
|
+
stderr=asyncio.subprocess.PIPE,
|
|
379
|
+
)
|
|
380
|
+
await proc.communicate()
|
|
381
|
+
return proc.returncode == 0
|
|
382
|
+
except Exception:
|
|
383
|
+
return False
|
|
384
|
+
|
|
385
|
+
async def _get_command_output(self, command: str) -> Optional[str]:
|
|
386
|
+
"""Run a command and return its output."""
|
|
387
|
+
try:
|
|
388
|
+
proc = await asyncio.create_subprocess_shell(
|
|
389
|
+
command,
|
|
390
|
+
stdout=asyncio.subprocess.PIPE,
|
|
391
|
+
stderr=asyncio.subprocess.PIPE,
|
|
392
|
+
)
|
|
393
|
+
stdout, _ = await asyncio.wait_for(proc.communicate(), timeout=5)
|
|
394
|
+
if proc.returncode == 0:
|
|
395
|
+
return stdout.decode().strip()
|
|
396
|
+
except Exception:
|
|
397
|
+
pass
|
|
398
|
+
return None
|
|
399
|
+
|
|
400
|
+
def print_summary(self, info: Optional[SystemInfo] = None):
|
|
401
|
+
"""Print a formatted summary of system information."""
|
|
402
|
+
info = info or self._info
|
|
403
|
+
if not info:
|
|
404
|
+
console.print("[red]No system information available. Run detect() first.[/red]")
|
|
405
|
+
return
|
|
406
|
+
|
|
407
|
+
console.print()
|
|
408
|
+
console.print("[bold cyan]System Detection Results[/bold cyan]")
|
|
409
|
+
console.print("=" * 50)
|
|
410
|
+
|
|
411
|
+
# OS Info
|
|
412
|
+
table = Table(box=box.ROUNDED, show_header=False)
|
|
413
|
+
table.add_column("Property", style="cyan")
|
|
414
|
+
table.add_column("Value", style="green")
|
|
415
|
+
|
|
416
|
+
table.add_row("Operating System", info.os_name)
|
|
417
|
+
table.add_row("Version", f"{info.os_version}" + (f" ({info.os_codename})" if info.os_codename else ""))
|
|
418
|
+
table.add_row("Architecture", info.architecture.value)
|
|
419
|
+
table.add_row("Package Manager", info.package_manager.value)
|
|
420
|
+
|
|
421
|
+
if info.is_wsl:
|
|
422
|
+
table.add_row("Environment", "WSL (Windows Subsystem for Linux)")
|
|
423
|
+
elif info.is_container:
|
|
424
|
+
table.add_row("Environment", "Container (Docker/Podman)")
|
|
425
|
+
|
|
426
|
+
console.print(table)
|
|
427
|
+
|
|
428
|
+
# Capabilities
|
|
429
|
+
console.print("\n[bold cyan]Available Runtimes & Tools[/bold cyan]")
|
|
430
|
+
|
|
431
|
+
caps_table = Table(box=box.ROUNDED)
|
|
432
|
+
caps_table.add_column("Tool", style="cyan")
|
|
433
|
+
caps_table.add_column("Status", justify="center")
|
|
434
|
+
caps_table.add_column("Version", style="dim")
|
|
435
|
+
|
|
436
|
+
caps = info.capabilities
|
|
437
|
+
|
|
438
|
+
caps_table.add_row(
|
|
439
|
+
"Python 3",
|
|
440
|
+
"[green]✓[/green]" if caps.has_python3 else "[red]✗[/red]",
|
|
441
|
+
caps.python_version.replace("Python ", "") if caps.python_version else ""
|
|
442
|
+
)
|
|
443
|
+
caps_table.add_row(
|
|
444
|
+
"pip",
|
|
445
|
+
"[green]✓[/green]" if caps.has_pip else "[red]✗[/red]",
|
|
446
|
+
""
|
|
447
|
+
)
|
|
448
|
+
caps_table.add_row(
|
|
449
|
+
"Go",
|
|
450
|
+
"[green]✓[/green]" if caps.has_go else "[red]✗[/red]",
|
|
451
|
+
caps.go_version.replace("go version ", "").split()[0] if caps.go_version else ""
|
|
452
|
+
)
|
|
453
|
+
caps_table.add_row(
|
|
454
|
+
"Docker",
|
|
455
|
+
"[green]✓[/green]" if caps.has_docker else "[yellow]○[/yellow]",
|
|
456
|
+
caps.docker_version.replace("Docker version ", "").split(",")[0] if caps.docker_version else ""
|
|
457
|
+
)
|
|
458
|
+
caps_table.add_row(
|
|
459
|
+
"Git",
|
|
460
|
+
"[green]✓[/green]" if caps.has_git else "[red]✗[/red]",
|
|
461
|
+
""
|
|
462
|
+
)
|
|
463
|
+
caps_table.add_row(
|
|
464
|
+
"Ruby/Gem",
|
|
465
|
+
"[green]✓[/green]" if caps.has_ruby else "[yellow]○[/yellow]",
|
|
466
|
+
""
|
|
467
|
+
)
|
|
468
|
+
caps_table.add_row(
|
|
469
|
+
"Rust/Cargo",
|
|
470
|
+
"[green]✓[/green]" if caps.has_cargo else "[yellow]○[/yellow]",
|
|
471
|
+
""
|
|
472
|
+
)
|
|
473
|
+
caps_table.add_row(
|
|
474
|
+
"Node.js",
|
|
475
|
+
"[green]✓[/green]" if caps.has_node else "[yellow]○[/yellow]",
|
|
476
|
+
""
|
|
477
|
+
)
|
|
478
|
+
caps_table.add_row(
|
|
479
|
+
"sudo/admin",
|
|
480
|
+
"[green]✓[/green]" if caps.has_sudo else "[yellow]○[/yellow]",
|
|
481
|
+
""
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
console.print(caps_table)
|
|
485
|
+
console.print()
|
|
486
|
+
|
|
487
|
+
# Show legend
|
|
488
|
+
console.print("[dim]Legend: [green]✓[/green] Available [yellow]○[/yellow] Optional [red]✗[/red] Required[/dim]")
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
# Convenience functions
|
|
492
|
+
async def detect_system() -> SystemInfo:
|
|
493
|
+
"""Detect system information."""
|
|
494
|
+
detector = SystemDetector()
|
|
495
|
+
return await detector.detect()
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
async def get_package_manager() -> PackageManager:
|
|
499
|
+
"""Get the system's package manager."""
|
|
500
|
+
info = await detect_system()
|
|
501
|
+
return info.package_manager
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
async def check_prerequisites() -> Tuple[bool, List[str]]:
|
|
505
|
+
"""
|
|
506
|
+
Check if system has all prerequisites for AIPTX.
|
|
507
|
+
|
|
508
|
+
Returns:
|
|
509
|
+
Tuple of (all_ok, list_of_missing_items)
|
|
510
|
+
"""
|
|
511
|
+
info = await detect_system()
|
|
512
|
+
caps = info.capabilities
|
|
513
|
+
missing = []
|
|
514
|
+
|
|
515
|
+
# Required
|
|
516
|
+
if not caps.has_python3:
|
|
517
|
+
missing.append("Python 3.9+")
|
|
518
|
+
if not caps.has_pip:
|
|
519
|
+
missing.append("pip")
|
|
520
|
+
if not caps.has_git:
|
|
521
|
+
missing.append("git")
|
|
522
|
+
if not caps.has_curl and not caps.has_wget:
|
|
523
|
+
missing.append("curl or wget")
|
|
524
|
+
|
|
525
|
+
# Recommended for full functionality
|
|
526
|
+
if not caps.has_go:
|
|
527
|
+
missing.append("Go (for some security tools)")
|
|
528
|
+
|
|
529
|
+
return len(missing) == 0, missing
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
if __name__ == "__main__":
|
|
533
|
+
# Test detection
|
|
534
|
+
async def main():
|
|
535
|
+
detector = SystemDetector()
|
|
536
|
+
info = await detector.detect()
|
|
537
|
+
detector.print_summary(info)
|
|
538
|
+
|
|
539
|
+
asyncio.run(main())
|