cycode 3.20.1.dev2__py3-none-any.whl → 3.20.1.dev3__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.20.1.dev2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
8
+ __version__ = '3.20.1.dev3' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import tempfile
2
3
  from collections.abc import Hashable
3
4
  from typing import Any, TextIO
4
5
 
@@ -34,22 +35,48 @@ def _yaml_object_safe_load(file: TextIO) -> dict[Hashable, Any]:
34
35
  return loaded_file
35
36
 
36
37
 
38
+ def _quarantine_corrupt_file(filename: str) -> None:
39
+ # Renamed rather than deleted: the file may hold the only copy of the user's credentials,
40
+ # and keeping it around leaves something to look at in the next bug report.
41
+ try:
42
+ os.replace(filename, f'{filename}.corrupt')
43
+ except OSError as e:
44
+ logger.warning('Failed to quarantine corrupt file, %s', {'filename': filename}, exc_info=e)
45
+
46
+
37
47
  def read_yaml_file(filename: str) -> dict[Hashable, Any]:
38
48
  if not os.access(filename, os.R_OK) or not os.path.exists(filename):
39
49
  logger.debug('Config file is not accessible or does not exist: %s', {'filename': filename})
40
50
  return {}
41
51
 
42
- with open(filename, encoding='UTF-8') as file:
43
- return _yaml_object_safe_load(file)
52
+ try:
53
+ with open(filename, encoding='UTF-8') as file:
54
+ return _yaml_object_safe_load(file)
55
+ except yaml.YAMLError as e:
56
+ logger.warning('Config file is corrupt and will be moved aside, %s', {'filename': filename}, exc_info=e)
57
+ _quarantine_corrupt_file(filename)
58
+ return {}
44
59
 
45
60
 
46
61
  def write_yaml_file(filename: str, content: dict[Hashable, Any]) -> None:
47
- if not os.access(filename, os.W_OK) and os.path.exists(filename):
62
+ directory = os.path.dirname(filename)
63
+ if not os.access(directory, os.W_OK) or (os.path.exists(filename) and not os.access(filename, os.W_OK)):
48
64
  logger.warning('No write permission for file. Cannot save config, %s', {'filename': filename})
49
65
  return
50
66
 
51
- with open(filename, 'w', encoding='UTF-8') as file:
52
- yaml.safe_dump(content, file)
67
+ # Atomic write to avoid race conditions between concurrent CLI processes
68
+ file_descriptor, temp_filename = tempfile.mkstemp(dir=directory, prefix=f'.{os.path.basename(filename)}.')
69
+ try:
70
+ with os.fdopen(file_descriptor, 'w', encoding='UTF-8') as file:
71
+ yaml.safe_dump(content, file)
72
+ file.flush()
73
+ os.fsync(file.fileno())
74
+
75
+ os.replace(temp_filename, filename)
76
+ except Exception:
77
+ if os.path.exists(temp_filename):
78
+ os.remove(temp_filename)
79
+ raise
53
80
 
54
81
 
55
82
  def update_yaml_file(filename: str, content: dict[Hashable, Any]) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycode
3
- Version: 3.20.1.dev2
3
+ Version: 3.20.1.dev3
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=jqxID23TPqyJTTsH_6ROeOxePrptCI4C_KrqGQ1EA0g,396
1
+ cycode/__init__.py,sha256=iBtU40BwvU5v1vQV0LNNfaPtyP8qJ7uffvivq9o-Eq8,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
@@ -188,7 +188,7 @@ cycode/cli/utils/task_timer.py,sha256=wxfM2TtJGjc1F17CIja_Qmt6zd4a1qdMwuz0ltgTDA
188
188
  cycode/cli/utils/trust_store.py,sha256=nEVyaDHhBu2f1Lw1CeHogaD8lQIp6u-sxaVDEKEhIW8,1992
189
189
  cycode/cli/utils/url_utils.py,sha256=2ZhRCbQsKnvAl5MBugQ5CrwuALP8uivsCI6chlqxahM,2304
190
190
  cycode/cli/utils/version_checker.py,sha256=0f5PaTk02ZkDxzBqZOeMV9mU_CWcx6HKW80jUKFOOZs,8239
191
- cycode/cli/utils/yaml_utils.py,sha256=R-tqzl0C-zoa42rS7nfWeHu3GJ0jpbQUyyqYYU2hleM,1818
191
+ cycode/cli/utils/yaml_utils.py,sha256=ty4FlwrM49OoYSMv8U6ZGlB0JRds8nxaijHQZebBVoU,2991
192
192
  cycode/config.py,sha256=jHORGZQcAXkAGSf2XreC-RQoc8sdNWja69QKtPWTbWo,1044
193
193
  cycode/cyclient/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
194
194
  cycode/cyclient/ai_security_manager_client.py,sha256=K3fvBC_d-8iDnVnMSVPXiDtuuapiWGT2xg1Kx203XU0,4808
@@ -212,8 +212,8 @@ cycode/cyclient/report_client.py,sha256=Scq30NeJPzgXv0hPLO1U05AdE9i_2iu6cIrSKpEJ
212
212
  cycode/cyclient/scan_client.py,sha256=DqAZ7u6Z_cvw9A9RlLkAQUgLRwPCCAsUq5U9umt4F7Y,16955
213
213
  cycode/cyclient/scan_config_base.py,sha256=mXsPZGYCtp85rv5GIige40yQZXuRcEKUW-VQJ0vgFzk,1201
214
214
  cycode/logger.py,sha256=EfZGRK6VC5rE_LAjIcRrHFiQCueylCDXoG6bvGkrIME,2111
215
- cycode-3.20.1.dev2.dist-info/METADATA,sha256=mHaVhMmqX5VrfmY9dO0d_JEJZ2bWYIjctl-Kg4Bbsy0,92792
216
- cycode-3.20.1.dev2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
217
- cycode-3.20.1.dev2.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
218
- cycode-3.20.1.dev2.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
219
- cycode-3.20.1.dev2.dist-info/RECORD,,
215
+ cycode-3.20.1.dev3.dist-info/METADATA,sha256=LSlFpEMsfot_3vRwUGCS_kTu7AoKUUUShATLR1lCB-Y,92792
216
+ cycode-3.20.1.dev3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
217
+ cycode-3.20.1.dev3.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
218
+ cycode-3.20.1.dev3.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
219
+ cycode-3.20.1.dev3.dist-info/RECORD,,