cycode 3.12.3.dev2__py3-none-any.whl → 3.12.3.dev4__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
@@ -1 +1 @@
1
- __version__ = '3.12.3.dev2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
1
+ __version__ = '3.12.3.dev4' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -116,7 +116,8 @@ def handle_before_read_file(ctx: typer.Context, payload: AIHookPayload, policy:
116
116
 
117
117
  try:
118
118
  # Check path-based denylist first
119
- if is_denied_path(file_path, policy):
119
+ is_sensitive_path = is_denied_path(file_path, policy)
120
+ if is_sensitive_path:
120
121
  block_reason = BlockReason.SENSITIVE_PATH
121
122
  if mode == PolicyMode.BLOCK and action == PolicyMode.BLOCK:
122
123
  outcome = AIHookOutcome.BLOCKED
@@ -125,13 +126,21 @@ def handle_before_read_file(ctx: typer.Context, payload: AIHookPayload, policy:
125
126
  user_message,
126
127
  'This file path is classified as sensitive; do not read/send it to the model.',
127
128
  )
128
- # Warn mode - ask user for permission
129
+ # Warn mode - if content scan is enabled, emit a separate event for the
130
+ # sensitive path so the finally block can independently track the scan result.
131
+ # If content scan is disabled, a single event (from finally) is enough.
129
132
  outcome = AIHookOutcome.WARNED
130
- user_message = f'Cycode flagged {file_path} as sensitive. Allow reading?'
131
- return response_builder.ask_permission(
132
- user_message,
133
- 'This file path is classified as sensitive; proceed with caution.',
134
- )
133
+ if get_policy_value(file_read_config, 'scan_content', default=True):
134
+ ai_client.create_event(
135
+ payload,
136
+ AiHookEventType.FILE_READ,
137
+ outcome,
138
+ block_reason=BlockReason.SENSITIVE_PATH,
139
+ file_path=payload.file_path,
140
+ )
141
+ # Reset for the content scan result tracked by the finally block
142
+ block_reason = None
143
+ outcome = AIHookOutcome.ALLOWED
135
144
 
136
145
  # Scan file content if enabled
137
146
  if get_policy_value(file_read_config, 'scan_content', default=True):
@@ -152,7 +161,14 @@ def handle_before_read_file(ctx: typer.Context, payload: AIHookPayload, policy:
152
161
  user_message,
153
162
  'Possible secrets detected; proceed with caution.',
154
163
  )
155
- return response_builder.allow_permission()
164
+
165
+ # If path was sensitive but content scan found no secrets (or scan disabled), still warn
166
+ if is_sensitive_path:
167
+ user_message = f'Cycode flagged {file_path} as sensitive. Allow reading?'
168
+ return response_builder.ask_permission(
169
+ user_message,
170
+ 'This file path is classified as sensitive; proceed with caution.',
171
+ )
156
172
 
157
173
  return response_builder.allow_permission()
158
174
  except Exception as e:
@@ -342,7 +358,7 @@ def _scan_path_for_secrets(ctx: typer.Context, file_path: str, policy: dict) ->
342
358
  Returns tuple of (violation_summary, scan_id) if secrets found, (None, scan_id) if clean.
343
359
  Raises exception on error or timeout.
344
360
  """
345
- if not file_path or not os.path.exists(file_path):
361
+ if not file_path or not os.path.isfile(file_path):
346
362
  return None, None
347
363
 
348
364
  max_bytes = get_policy_value(policy, 'secrets', 'max_bytes', default=200000)
@@ -44,6 +44,10 @@ def pre_push_command(
44
44
  timeout = configuration_manager.get_pre_push_command_timeout(command_scan_type)
45
45
  with TimeoutAfter(timeout):
46
46
  push_update_details = parse_pre_push_input()
47
+ if not push_update_details:
48
+ logger.info('No pre-push input found, nothing to scan')
49
+ return
50
+
47
51
  commit_range = calculate_pre_push_commit_range(push_update_details)
48
52
  if not commit_range:
49
53
  logger.info(
@@ -228,7 +228,7 @@ def parse_pre_receive_input() -> str:
228
228
  return pre_receive_input.splitlines()[0]
229
229
 
230
230
 
231
- def parse_pre_push_input() -> str:
231
+ def parse_pre_push_input() -> Optional[str]:
232
232
  """Parse input to pre-push hook details.
233
233
 
234
234
  Example input:
@@ -237,13 +237,11 @@ def parse_pre_push_input() -> str:
237
237
  refs/heads/main 9cf90954ef26e7c58284f8ebf7dcd0fcf711152a refs/heads/main 973a96d3e925b65941f7c47fa16129f1577d499f
238
238
  refs/heads/feature-branch 3378e52dcfa47fb11ce3a4a520bea5f85d5d0bf3 refs/heads/feature-branch 59564ef68745bca38c42fc57a7822efd519a6bd9
239
239
 
240
- :return: First, push update details (input's first line)
240
+ :return: First push update details (input's first line), or None if no input was provided
241
241
  """ # noqa: E501
242
242
  pre_push_input = _read_hook_input_from_stdin()
243
243
  if not pre_push_input:
244
- raise ValueError(
245
- 'Pre push input was not found. Make sure that you are using this command only in pre-push hook'
246
- )
244
+ return None
247
245
 
248
246
  # each line represents a branch push request, handle the first one only
249
247
  return pre_push_input.splitlines()[0]
@@ -332,6 +330,15 @@ def calculate_pre_push_commit_range(push_update_details: str) -> Optional[str]:
332
330
  """
333
331
  local_ref, local_object_name, remote_ref, remote_object_name = push_update_details.split()
334
332
 
333
+ # Tag pushes don't contain file diffs that need scanning
334
+ if local_ref.startswith('refs/tags/') or remote_ref.startswith('refs/tags/'):
335
+ logger.info('Skipping scan for tag push: %s -> %s', local_ref, remote_ref)
336
+ return None
337
+
338
+ # If deleting a ref (local_object_name is all zeros), no need to scan
339
+ if local_object_name == consts.EMPTY_COMMIT_SHA:
340
+ return None
341
+
335
342
  if remote_object_name == consts.EMPTY_COMMIT_SHA:
336
343
  try:
337
344
  repo = git_proxy.get_repo(os.getcwd())
@@ -356,10 +363,6 @@ def calculate_pre_push_commit_range(push_update_details: str) -> Optional[str]:
356
363
  logger.debug('Failed to get repo for pre-push commit range calculation: %s', exc_info=e)
357
364
  return consts.COMMIT_RANGE_ALL_COMMITS
358
365
 
359
- # If deleting a branch (local_object_name is all zeros), no need to scan
360
- if local_object_name == consts.EMPTY_COMMIT_SHA:
361
- return None
362
-
363
366
  # For updates to existing branches, scan from remote to local
364
367
  return f'{remote_object_name}..{local_object_name}'
365
368
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycode
3
- Version: 3.12.3.dev2
3
+ Version: 3.12.3.dev4
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=Gny-NPw7ssVE0Ug9mwxX7Y55eomURHuonnfna8G68u4,115
1
+ cycode/__init__.py,sha256=lig0eJ_EAA82PNYTdZ4IwBXVHgUIY39vry0nkPTxcQ4,115
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=bsfXV85RRb1iz19JRC9gkc5Iv30fnEE1cwA8dg552NQ,6482
@@ -12,7 +12,7 @@ cycode/cli/apps/ai_guardrails/hooks_manager.py,sha256=37IcEMCK60pQ8lnuy8GThlq9oe
12
12
  cycode/cli/apps/ai_guardrails/install_command.py,sha256=qlklts1Uj6j3urK6jwAWJY-L_DgVaZWuk7vZcpoKPAQ,4571
13
13
  cycode/cli/apps/ai_guardrails/scan/__init__.py,sha256=qJc82XiQGiAuc1sYY8Ij_A-qXpxgLPuayQq8xWlouMA,48
14
14
  cycode/cli/apps/ai_guardrails/scan/consts.py,sha256=drAslw6vW3kxmbCs2qPCUbUPR7PJouT2lsXtu5sD-lQ,1094
15
- cycode/cli/apps/ai_guardrails/scan/handlers.py,sha256=nTb4kIiaAmd04t0hQlZP-l49RKakvcyn7myZLHNpY7Q,14855
15
+ cycode/cli/apps/ai_guardrails/scan/handlers.py,sha256=e3UlQ6TbFFFAFEAgMUhL5i7bV1mSrmFJuLb9O0FLX2Y,15702
16
16
  cycode/cli/apps/ai_guardrails/scan/payload.py,sha256=-r8BsvP-VPD3XibyIPKreCjJNVXGpe_9ENPF78NlnkQ,10178
17
17
  cycode/cli/apps/ai_guardrails/scan/policy.py,sha256=39s8hnxgjny1l6XAO59wsRcAlpW-LG00GUnO0PfqvuY,2566
18
18
  cycode/cli/apps/ai_guardrails/scan/response_builders.py,sha256=tVFJCnGdqSmyileg-idypOihygct7F6T4KHXYlX8y_c,4653
@@ -66,7 +66,7 @@ cycode/cli/apps/scan/path/path_command.py,sha256=x4HXqq1Wy6onziKMc6ELQxqeI5k-m3t
66
66
  cycode/cli/apps/scan/pre_commit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
67
  cycode/cli/apps/scan/pre_commit/pre_commit_command.py,sha256=49vnVAIiLtcG7lsBX2vKhS-5kqC8wKqCUP-3G8ClPVs,465
68
68
  cycode/cli/apps/scan/pre_push/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
- cycode/cli/apps/scan/pre_push/pre_push_command.py,sha256=tyOghRITb7FPyxAkT68Akk48jNVub28cLFKy0gAtkgo,2418
69
+ cycode/cli/apps/scan/pre_push/pre_push_command.py,sha256=i2k1-il7tOtuIj2ZksjdtgnRVXbj0p6tMrMQuxckynY,2554
70
70
  cycode/cli/apps/scan/pre_receive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
71
  cycode/cli/apps/scan/pre_receive/pre_receive_command.py,sha256=v1sXjl9EKTG65065DzJRJ78we96cqLztzDWw89KUb0o,2522
72
72
  cycode/cli/apps/scan/remote_url_resolver.py,sha256=JCjaAzDMxGFDT7twBpZzjgEHGwlaGIxWG_Y7DSehsb0,5651
@@ -95,7 +95,7 @@ cycode/cli/exceptions/handle_errors.py,sha256=za3vQcM_eFTvbT-53tTc6ky-J0wav6lupD
95
95
  cycode/cli/exceptions/handle_report_sbom_errors.py,sha256=bi0EizHtQLL-ovhHRH98CZ7qXdDPLTYnI59Jn1Y5c0E,926
96
96
  cycode/cli/exceptions/handle_scan_errors.py,sha256=1KkBFb7LniflYRr0vMl1FPIZDALPZu1LiXhORGl0jhs,2195
97
97
  cycode/cli/files_collector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
- cycode/cli/files_collector/commit_range_documents.py,sha256=muWeDjgsbpXjIKnVzFoEdRS9IXrG-dbI1QryWlFINsg,20321
98
+ cycode/cli/files_collector/commit_range_documents.py,sha256=ZAU9er6m8_IF9y9KxZoiEaDOiZC35SEfv5VtqKp4AZc,20484
99
99
  cycode/cli/files_collector/documents_walk_ignore.py,sha256=G4e-3vfP4WZ7wa9-VbZ66xCKCioTXnPBfbrs4_hh8xY,4705
100
100
  cycode/cli/files_collector/file_excluder.py,sha256=5Y7MM6_4x4FRKCV47D_hOXIg9BzYLHqwoWkmtV7Lt4I,7562
101
101
  cycode/cli/files_collector/iac/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -198,8 +198,8 @@ cycode/cyclient/report_client.py,sha256=Scq30NeJPzgXv0hPLO1U05AdE9i_2iu6cIrSKpEJ
198
198
  cycode/cyclient/scan_client.py,sha256=6TK5FQkfrvV7PHqRnUzEn1PBNd2oPYVamvIixcUfe3c,16755
199
199
  cycode/cyclient/scan_config_base.py,sha256=mXsPZGYCtp85rv5GIige40yQZXuRcEKUW-VQJ0vgFzk,1201
200
200
  cycode/logger.py,sha256=EfZGRK6VC5rE_LAjIcRrHFiQCueylCDXoG6bvGkrIME,2111
201
- cycode-3.12.3.dev2.dist-info/METADATA,sha256=kkFFeC4gpGgwhz9oQWVQi5BDjrXf5VoaZAtnXAVuCGM,84350
202
- cycode-3.12.3.dev2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
203
- cycode-3.12.3.dev2.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
204
- cycode-3.12.3.dev2.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
205
- cycode-3.12.3.dev2.dist-info/RECORD,,
201
+ cycode-3.12.3.dev4.dist-info/METADATA,sha256=-FVJcdUsjkhOaDwzI_MuYfe1W1Fzz_lnGJRLVHZlNoI,84350
202
+ cycode-3.12.3.dev4.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
203
+ cycode-3.12.3.dev4.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
204
+ cycode-3.12.3.dev4.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
205
+ cycode-3.12.3.dev4.dist-info/RECORD,,