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 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.dev1' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
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=socket.gethostname(),
42
- platform=platform.system(),
43
- logged_in_user=_get_logged_in_user(),
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
- platform: Optional[str] = None,
98
- logged_in_user: Optional[str] = None,
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
- 'platform': platform,
107
- 'logged_in_user': logged_in_user,
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycode
3
- Version: 3.16.3.dev1
3
+ Version: 3.16.3.dev2
4
4
  Summary: Boost security in your dev lifecycle via SAST, SCA, Secrets & IaC scanning.
5
5
  License-Expression: MIT
6
6
  License-File: LICENCE
@@ -1,4 +1,4 @@
1
- cycode/__init__.py,sha256=CcpAyD7Y_714Ds_2eFLqD8gokAUY-k6EVd6dYaW2NI8,396
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=WzFE_12sxDq2lrVmMN_G2q_d9pfbsEO3CvjJXBcbFI0,3684
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=EhPzP_jia9c9hw98UgHBemwFKluuhg5AJVAfngXkWfM,4543
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.dev1.dist-info/METADATA,sha256=GwuZ-h9XsghaNYx3U3Cl5f73NllN-rc-G3DyCr8Q8fk,89245
211
- cycode-3.16.3.dev1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
212
- cycode-3.16.3.dev1.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
213
- cycode-3.16.3.dev1.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
214
- cycode-3.16.3.dev1.dist-info/RECORD,,
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,,