164 lines
4.6 KiB
Python
164 lines
4.6 KiB
Python
import getpass
|
|
import os
|
|
from pathlib import Path
|
|
import site
|
|
import socket
|
|
import sys
|
|
import platform
|
|
from typing import List, Optional
|
|
from safety_schemas.models.events.context import (
|
|
ClientInfo,
|
|
EventContext,
|
|
HostInfo,
|
|
OsInfo,
|
|
ProjectInfo,
|
|
PythonInfo,
|
|
RuntimeInfo,
|
|
UserInfo,
|
|
)
|
|
|
|
from safety_schemas.models.events.types import SourceType
|
|
from safety_schemas.models import ProjectModel
|
|
|
|
|
|
def get_user_info() -> UserInfo:
|
|
"""
|
|
Collect information about the current user.
|
|
"""
|
|
return UserInfo(name=getpass.getuser(), home_dir=str(Path.home()))
|
|
|
|
|
|
def get_os_info() -> OsInfo:
|
|
"""
|
|
Get basic OS information using only the platform module.
|
|
Returns a dictionary with architecture, platform, name, version, and kernel_version.
|
|
"""
|
|
# Initialize with required fields
|
|
os_info = {
|
|
"architecture": platform.machine(),
|
|
"platform": platform.system(),
|
|
"name": None,
|
|
"version": None,
|
|
"kernel_version": None,
|
|
}
|
|
|
|
python_version = sys.version_info
|
|
|
|
if sys.platform == "wind32":
|
|
os_info["version"] = platform.release()
|
|
os_info["kernel_version"] = platform.version()
|
|
os_info["name"] = "windows"
|
|
|
|
elif sys.platform == "darwin":
|
|
os_info["version"] = platform.mac_ver()[0]
|
|
os_info["kernel_version"] = platform.release()
|
|
os_info["name"] = "macos"
|
|
|
|
elif sys.platform == "linux":
|
|
os_info["kernel_version"] = platform.release()
|
|
if python_version >= (3, 10):
|
|
try:
|
|
os_release = platform.freedesktop_os_release()
|
|
# Use ID for name (more consistent for programmatic use)
|
|
os_info["name"] = os_release.get("ID", "linux")
|
|
os_info["version"] = os_release.get("VERSION_ID")
|
|
except (OSError, AttributeError):
|
|
# If freedesktop_os_release fails, keep values as is
|
|
pass
|
|
|
|
return OsInfo(**os_info)
|
|
|
|
|
|
def get_host_info() -> HostInfo:
|
|
"""
|
|
Collect information about the host machine.
|
|
"""
|
|
hostname = socket.gethostname()
|
|
|
|
ipv4_addresses = set()
|
|
ipv6_addresses = set()
|
|
try:
|
|
host_info = socket.getaddrinfo(hostname, None)
|
|
for info in host_info:
|
|
ip_family = info[0]
|
|
ip = str(info[4][0])
|
|
|
|
if ip_family == socket.AF_INET:
|
|
if not ip.startswith("127."):
|
|
ipv4_addresses.add(ip)
|
|
elif ip_family == socket.AF_INET6:
|
|
if not ip.startswith("::1") and ip != "fe80::1":
|
|
ipv6_addresses.add(ip)
|
|
|
|
# Prioritize addresses
|
|
primary_ipv4 = next(
|
|
(ip for ip in ipv4_addresses),
|
|
next(iter(ipv4_addresses)) if ipv4_addresses else None,
|
|
)
|
|
|
|
primary_ipv6 = next(
|
|
(ip for ip in ipv6_addresses if not ip.startswith("fe80:")),
|
|
next(iter(ipv6_addresses)) if ipv6_addresses else None,
|
|
)
|
|
|
|
except socket.gaierror:
|
|
primary_ipv4 = None
|
|
primary_ipv6 = None
|
|
|
|
return HostInfo(name=hostname, ipv4=primary_ipv4, ipv6=primary_ipv6, timezone=None)
|
|
|
|
|
|
def get_python_info() -> PythonInfo:
|
|
"""
|
|
Collect detailed information about the Python environment.
|
|
"""
|
|
# Get site-packages directories
|
|
site_packages_dirs = site.getsitepackages()
|
|
|
|
user_site_enabled = bool(site.ENABLE_USER_SITE)
|
|
user_site_packages = site.getusersitepackages()
|
|
|
|
return PythonInfo(
|
|
version=f"{sys.version_info.major}.{sys.version_info.minor}",
|
|
path=sys.executable,
|
|
sys_path=sys.path,
|
|
implementation=platform.python_implementation(),
|
|
implementation_version=platform.python_version(),
|
|
sys_prefix=sys.prefix,
|
|
site_packages=site_packages_dirs,
|
|
user_site_enabled=user_site_enabled,
|
|
user_site_packages=user_site_packages,
|
|
encoding=sys.getdefaultencoding(),
|
|
filesystem_encoding=sys.getfilesystemencoding(),
|
|
)
|
|
|
|
|
|
def create_event_context(
|
|
client_identifier: SourceType,
|
|
client_version: str,
|
|
client_path: str,
|
|
project: Optional[ProjectModel] = None,
|
|
tags: Optional[List[str]] = None,
|
|
) -> EventContext:
|
|
client = ClientInfo(
|
|
identifier=client_identifier, version=client_version, path=client_path
|
|
)
|
|
|
|
project_info = None
|
|
|
|
if project:
|
|
project_info = ProjectInfo(
|
|
id=project.id,
|
|
url=project.url_path,
|
|
)
|
|
|
|
runtime = RuntimeInfo(
|
|
workdir=os.getcwd(),
|
|
user=get_user_info(),
|
|
os=get_os_info(),
|
|
host=get_host_info(),
|
|
python=get_python_info(),
|
|
)
|
|
|
|
return EventContext(client=client, runtime=runtime, project=project_info, tags=tags)
|