cycode 3.16.3.dev1__py3-none-any.whl → 3.16.3.dev2__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.
- cycode/__init__.py +1 -1
- cycode/cli/apps/ai_guardrails/session_start_command.py +12 -14
- cycode/cli/utils/host_info.py +127 -0
- cycode/cyclient/ai_security_manager_client.py +8 -4
- {cycode-3.16.3.dev1.dist-info → cycode-3.16.3.dev2.dist-info}/METADATA +1 -1
- {cycode-3.16.3.dev1.dist-info → cycode-3.16.3.dev2.dist-info}/RECORD +9 -8
- {cycode-3.16.3.dev1.dist-info → cycode-3.16.3.dev2.dist-info}/WHEEL +0 -0
- {cycode-3.16.3.dev1.dist-info → cycode-3.16.3.dev2.dist-info}/entry_points.txt +0 -0
- {cycode-3.16.3.dev1.dist-info → cycode-3.16.3.dev2.dist-info}/licenses/LICENCE +0 -0
cycode/__init__.py
CHANGED
|
@@ -5,4 +5,4 @@ import time as _time
|
|
|
5
5
|
# end-to-end scan duration from the moment the user actually triggered it.
|
|
6
6
|
_BOOT_WALL: float = _time.time()
|
|
7
7
|
|
|
8
|
-
__version__ = '3.16.3.
|
|
8
|
+
__version__ = '3.16.3.dev2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
"""Handle AI guardrails session start: auth, conversation creation, session context."""
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
|
-
import platform
|
|
5
|
-
import socket
|
|
6
3
|
import sys
|
|
7
4
|
from typing import TYPE_CHECKING, Annotated, Optional
|
|
8
5
|
|
|
@@ -15,6 +12,13 @@ from cycode.cli.apps.auth.auth_common import get_authorization_info
|
|
|
15
12
|
from cycode.cli.apps.auth.auth_manager import AuthManager
|
|
16
13
|
from cycode.cli.exceptions.handle_auth_errors import handle_auth_exception
|
|
17
14
|
from cycode.cli.utils.get_api_client import get_ai_security_manager_client
|
|
15
|
+
from cycode.cli.utils.host_info import (
|
|
16
|
+
get_hostname,
|
|
17
|
+
get_last_login_user,
|
|
18
|
+
get_os_version,
|
|
19
|
+
get_platform_name,
|
|
20
|
+
get_serial_number,
|
|
21
|
+
)
|
|
18
22
|
from cycode.logger import get_logger
|
|
19
23
|
|
|
20
24
|
if TYPE_CHECKING:
|
|
@@ -23,14 +27,6 @@ if TYPE_CHECKING:
|
|
|
23
27
|
logger = get_logger('AI Guardrails')
|
|
24
28
|
|
|
25
29
|
|
|
26
|
-
def _get_logged_in_user() -> Optional[str]:
|
|
27
|
-
"""Best-effort OS account name (whoami). None if it can't be resolved."""
|
|
28
|
-
try:
|
|
29
|
-
return os.getlogin()
|
|
30
|
-
except Exception:
|
|
31
|
-
return None
|
|
32
|
-
|
|
33
|
-
|
|
34
30
|
def _report_session_context(ai_client: 'AISecurityManagerClient', ide: IDE, user_email: Optional[str]) -> None:
|
|
35
31
|
"""Report IDE session context to the AI security manager. Never raises."""
|
|
36
32
|
try:
|
|
@@ -38,9 +34,11 @@ def _report_session_context(ai_client: 'AISecurityManagerClient', ide: IDE, user
|
|
|
38
34
|
if not global_config_file and not enabled_plugins:
|
|
39
35
|
return
|
|
40
36
|
ai_client.report_session_context(
|
|
41
|
-
hostname=
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
hostname=get_hostname(),
|
|
38
|
+
platform_name=get_platform_name(),
|
|
39
|
+
os_version=get_os_version(),
|
|
40
|
+
serial_number=get_serial_number(),
|
|
41
|
+
last_login_user=get_last_login_user(),
|
|
44
42
|
global_config_file=global_config_file,
|
|
45
43
|
enabled_plugins=enabled_plugins,
|
|
46
44
|
user_email=user_email,
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import getpass
|
|
2
|
+
import platform
|
|
3
|
+
import re
|
|
4
|
+
import socket
|
|
5
|
+
import subprocess
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from cycode.logger import get_logger
|
|
9
|
+
|
|
10
|
+
logger = get_logger('HOST INFO')
|
|
11
|
+
|
|
12
|
+
_SUBPROCESS_TIMEOUT_SEC = 5
|
|
13
|
+
|
|
14
|
+
_PLATFORM_NAMES = {'Darwin': 'macOS', 'Windows': 'Windows', 'Linux': 'Linux'}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _run(command: list, timeout: int = _SUBPROCESS_TIMEOUT_SEC) -> Optional[str]:
|
|
18
|
+
"""Run a command and return its stripped stdout. Never raises; returns None on any error."""
|
|
19
|
+
try:
|
|
20
|
+
result = subprocess.run(command, capture_output=True, text=True, timeout=timeout) # noqa: S603
|
|
21
|
+
return result.stdout.strip() or None
|
|
22
|
+
except Exception as e:
|
|
23
|
+
logger.debug('Failed to run command %s', command, exc_info=e)
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _read_text_file(path: str) -> Optional[str]:
|
|
28
|
+
"""Read and strip a text file. Never raises; returns None if it can't be read."""
|
|
29
|
+
try:
|
|
30
|
+
with open(path) as text_file:
|
|
31
|
+
return text_file.read().strip() or None
|
|
32
|
+
except OSError:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_hostname() -> Optional[str]:
|
|
37
|
+
try:
|
|
38
|
+
return socket.gethostname() or None
|
|
39
|
+
except Exception as e:
|
|
40
|
+
logger.debug('Failed to resolve hostname', exc_info=e)
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_platform_name() -> Optional[str]:
|
|
45
|
+
try:
|
|
46
|
+
system = platform.system()
|
|
47
|
+
return _PLATFORM_NAMES.get(system, system or None)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
logger.debug('Failed to resolve platform name', exc_info=e)
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_os_version() -> Optional[str]:
|
|
54
|
+
try:
|
|
55
|
+
system = platform.system()
|
|
56
|
+
if system == 'Darwin':
|
|
57
|
+
return platform.mac_ver()[0] or None
|
|
58
|
+
if system == 'Windows':
|
|
59
|
+
return platform.win32_ver()[1] or platform.version() or None
|
|
60
|
+
if system == 'Linux':
|
|
61
|
+
return _get_linux_os_version()
|
|
62
|
+
return platform.release() or None
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.debug('Failed to resolve OS version', exc_info=e)
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _get_linux_os_version() -> Optional[str]:
|
|
69
|
+
freedesktop_os_release = getattr(platform, 'freedesktop_os_release', None) # Python 3.10+
|
|
70
|
+
if freedesktop_os_release is not None:
|
|
71
|
+
try:
|
|
72
|
+
version_id = freedesktop_os_release().get('VERSION_ID')
|
|
73
|
+
if version_id:
|
|
74
|
+
return version_id
|
|
75
|
+
except OSError:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
os_release = _read_text_file('/etc/os-release') # Python 3.9 fallback: parse manually
|
|
79
|
+
if os_release:
|
|
80
|
+
for line in os_release.splitlines():
|
|
81
|
+
if line.startswith('VERSION_ID='):
|
|
82
|
+
return line.split('=', 1)[1].strip().strip('"') or None
|
|
83
|
+
|
|
84
|
+
return platform.release() or None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_last_login_user() -> Optional[str]:
|
|
88
|
+
try:
|
|
89
|
+
return getpass.getuser() or None
|
|
90
|
+
except Exception as e:
|
|
91
|
+
logger.debug('Failed to resolve last login user', exc_info=e)
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_serial_number() -> Optional[str]:
|
|
96
|
+
try:
|
|
97
|
+
system = platform.system()
|
|
98
|
+
if system == 'Darwin':
|
|
99
|
+
return _get_macos_serial_number()
|
|
100
|
+
if system == 'Windows':
|
|
101
|
+
return _get_windows_serial_number()
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.debug('Failed to resolve serial number', exc_info=e)
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _get_macos_serial_number() -> Optional[str]:
|
|
108
|
+
output = _run(['ioreg', '-c', 'IOPlatformExpertDevice', '-d', '2'])
|
|
109
|
+
if not output:
|
|
110
|
+
return None
|
|
111
|
+
match = re.search(r'"IOPlatformSerialNumber"\s*=\s*"([^"]+)"', output)
|
|
112
|
+
return match.group(1) if match else None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _get_windows_serial_number() -> Optional[str]:
|
|
116
|
+
import pythoncom # from pywin32
|
|
117
|
+
import win32com.client # from pywin32
|
|
118
|
+
|
|
119
|
+
pythoncom.CoInitialize()
|
|
120
|
+
try:
|
|
121
|
+
wmi_service = win32com.client.GetObject('winmgmts:')
|
|
122
|
+
for bios in wmi_service.InstancesOf('Win32_BIOS'):
|
|
123
|
+
serial = bios.SerialNumber
|
|
124
|
+
return serial.strip() if serial else None
|
|
125
|
+
finally:
|
|
126
|
+
pythoncom.CoUninitialize()
|
|
127
|
+
return None
|
|
@@ -94,8 +94,10 @@ class AISecurityManagerClient:
|
|
|
94
94
|
def report_session_context(
|
|
95
95
|
self,
|
|
96
96
|
hostname: Optional[str] = None,
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
platform_name: Optional[str] = None,
|
|
98
|
+
os_version: Optional[str] = None,
|
|
99
|
+
serial_number: Optional[str] = None,
|
|
100
|
+
last_login_user: Optional[str] = None,
|
|
99
101
|
global_config_file: Optional[dict] = None,
|
|
100
102
|
enabled_plugins: Optional[dict] = None,
|
|
101
103
|
user_email: Optional[str] = None,
|
|
@@ -103,8 +105,10 @@ class AISecurityManagerClient:
|
|
|
103
105
|
"""Report session context to the backend."""
|
|
104
106
|
body: dict = {
|
|
105
107
|
'hostname': hostname,
|
|
106
|
-
'
|
|
107
|
-
'
|
|
108
|
+
'platform_name': platform_name,
|
|
109
|
+
'os_version': os_version,
|
|
110
|
+
'serial_number': serial_number,
|
|
111
|
+
'last_login_user': last_login_user,
|
|
108
112
|
'user_email': user_email,
|
|
109
113
|
'global_config_file': global_config_file,
|
|
110
114
|
'enabled_plugins': enabled_plugins,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
cycode/__init__.py,sha256=
|
|
1
|
+
cycode/__init__.py,sha256=a02DIWGLRttTo50tdayCtRosK8xi_hs0uTrsl0YxH90,396
|
|
2
2
|
cycode/__main__.py,sha256=Z3bD5yrA7yPvAChcADQrqCaZd0ChGI1gdiwALwbWJ6U,104
|
|
3
3
|
cycode/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
cycode/cli/app.py,sha256=AlR2durAEbsa47PDfIj7JtMvJDWA_Dq6wPtVuMJYSCs,10250
|
|
@@ -23,7 +23,7 @@ cycode/cli/apps/ai_guardrails/scan/policy.py,sha256=39s8hnxgjny1l6XAO59wsRcAlpW-
|
|
|
23
23
|
cycode/cli/apps/ai_guardrails/scan/scan_command.py,sha256=-Gl7cHELF1wlwLGno6ZVukFtK6NI6Z3-dTpIOsz8ors,6079
|
|
24
24
|
cycode/cli/apps/ai_guardrails/scan/types.py,sha256=lDttkYFBfOkdMEEaRbq1IT2QTK0R-7Ht3T8vZdyB3b4,1038
|
|
25
25
|
cycode/cli/apps/ai_guardrails/scan/utils.py,sha256=KVfX-NrcM-QW4quLtoNqfmz4GF0FlDs-TkqUOu1hAWM,2057
|
|
26
|
-
cycode/cli/apps/ai_guardrails/session_start_command.py,sha256=
|
|
26
|
+
cycode/cli/apps/ai_guardrails/session_start_command.py,sha256=vZKcThgD6qLpPrTlnE9dyakLUti-EcGgOw1zL35gZ5U,3682
|
|
27
27
|
cycode/cli/apps/ai_guardrails/status_command.py,sha256=Uqss68TEPCYPXpLix6Bh-4J3g-khxWsAqlIGYH5x4bQ,3203
|
|
28
28
|
cycode/cli/apps/ai_guardrails/uninstall_command.py,sha256=dOmePfZmlHAPy2zEJM1yMtSuDqvzDwtqgmLKYK-T9PI,2698
|
|
29
29
|
cycode/cli/apps/ai_remediation/__init__.py,sha256=8vYthY9RQeJqEni3AIF5sryz8n-XJQ6VNqG4aEFBAdY,553
|
|
@@ -172,6 +172,7 @@ cycode/cli/utils/binary_utils.py,sha256=PxP-rVJ1lEiOam-DQ1XU68oWtfwup4sCFHXv54cf
|
|
|
172
172
|
cycode/cli/utils/enum_utils.py,sha256=h_VTCfJ-0hnhwDsEznmx56rJrCb5FQ8u6PrI6p8MP3E,187
|
|
173
173
|
cycode/cli/utils/get_api_client.py,sha256=wwHabfVCDbFjcIwOn5Raho8MEPiOAgkHlGUEfXKpl8U,3542
|
|
174
174
|
cycode/cli/utils/git_proxy.py,sha256=FPHMBiyLFK9X9vKYpKySRKJH6Dc9Cb3nO241Q95dASE,2911
|
|
175
|
+
cycode/cli/utils/host_info.py,sha256=yaLGifwoLTCzac5kG-Il_-KmKJALnzr8xpA_0Gy33Sk,3957
|
|
175
176
|
cycode/cli/utils/ignore_utils.py,sha256=cODqhnOHA2kRo8rMY0YcmcKkmXNPOC9UTCmFu62RRqE,15567
|
|
176
177
|
cycode/cli/utils/jwt_utils.py,sha256=EGI-0CKhCGY8hIcZ9b9diq9hqtOUf8Ha8ukeVJIf974,818
|
|
177
178
|
cycode/cli/utils/path_utils.py,sha256=U5te1unzhs9pnU5d9BWExgFWElHQkgKvFxKiOF-lp-w,3245
|
|
@@ -186,7 +187,7 @@ cycode/cli/utils/version_checker.py,sha256=0f5PaTk02ZkDxzBqZOeMV9mU_CWcx6HKW80jU
|
|
|
186
187
|
cycode/cli/utils/yaml_utils.py,sha256=R-tqzl0C-zoa42rS7nfWeHu3GJ0jpbQUyyqYYU2hleM,1818
|
|
187
188
|
cycode/config.py,sha256=jHORGZQcAXkAGSf2XreC-RQoc8sdNWja69QKtPWTbWo,1044
|
|
188
189
|
cycode/cyclient/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
189
|
-
cycode/cyclient/ai_security_manager_client.py,sha256=
|
|
190
|
+
cycode/cyclient/ai_security_manager_client.py,sha256=_LDU8B6_3DuMT-I-K5-Ok2E-NR30aJbD7L0f8UGDDPQ,4730
|
|
190
191
|
cycode/cyclient/ai_security_manager_service_config.py,sha256=83pQzgOb93JW6E-dznJkI4c0NEXmQRlx9YZKMmjVwp8,808
|
|
191
192
|
cycode/cyclient/auth_client.py,sha256=TwbmZ358Ancf-Q-IZolvfljZ8691_6botsqd0R0PLPk,2105
|
|
192
193
|
cycode/cyclient/base_token_auth_client.py,sha256=mn5580d7A8Z2_zcdFKIJk78ADK7mViwTcV-4QCpRCGo,4369
|
|
@@ -207,8 +208,8 @@ cycode/cyclient/report_client.py,sha256=Scq30NeJPzgXv0hPLO1U05AdE9i_2iu6cIrSKpEJ
|
|
|
207
208
|
cycode/cyclient/scan_client.py,sha256=6TK5FQkfrvV7PHqRnUzEn1PBNd2oPYVamvIixcUfe3c,16755
|
|
208
209
|
cycode/cyclient/scan_config_base.py,sha256=mXsPZGYCtp85rv5GIige40yQZXuRcEKUW-VQJ0vgFzk,1201
|
|
209
210
|
cycode/logger.py,sha256=EfZGRK6VC5rE_LAjIcRrHFiQCueylCDXoG6bvGkrIME,2111
|
|
210
|
-
cycode-3.16.3.
|
|
211
|
-
cycode-3.16.3.
|
|
212
|
-
cycode-3.16.3.
|
|
213
|
-
cycode-3.16.3.
|
|
214
|
-
cycode-3.16.3.
|
|
211
|
+
cycode-3.16.3.dev2.dist-info/METADATA,sha256=DBWx5RMjw0IZkbH7-ltfRf7zZxQ8NyjE6iczyICIUk0,89245
|
|
212
|
+
cycode-3.16.3.dev2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
213
|
+
cycode-3.16.3.dev2.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
|
|
214
|
+
cycode-3.16.3.dev2.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
|
|
215
|
+
cycode-3.16.3.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|