cycode 3.17.3.dev3__py3-none-any.whl → 3.17.3.dev5__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.17.3.dev3' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
8
+ __version__ = '3.17.3.dev5' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -157,6 +157,15 @@ class IDE(ABC):
157
157
  event (e.g. Cursor reading Claude Code hooks from ~/.claude/settings.json).
158
158
  """
159
159
 
160
+ def is_synthetic_prompt(self, raw_payload: dict) -> bool:
161
+ """Return True when a prompt event carries IDE/harness-generated content
162
+ rather than text the user typed.
163
+
164
+ Synthetic prompts are skipped without scanning or telemetry.
165
+ Default: False. Override for IDEs that inject synthetic user turns.
166
+ """
167
+ return False
168
+
160
169
  @abstractmethod
161
170
  def parse_hook_payload(self, raw_payload: dict) -> AIHookPayload:
162
171
  """Normalize a raw stdin payload into the canonical ``AIHookPayload``."""
@@ -22,6 +22,10 @@ logger = get_logger('AI Guardrails Claude Code')
22
22
 
23
23
  _CLAUDE_CODE_EVENT_NAMES = frozenset({'UserPromptSubmit', 'PreToolUse'})
24
24
 
25
+ # When a fork/subagent completes, the harness injects its result into the parent
26
+ # session as a synthetic user turn, which fires UserPromptSubmit.
27
+ _SYNTHETIC_PROMPT_PREFIXES = ('<task-notification>',)
28
+
25
29
  _USER_HOOKS_DIR = Path.home() / '.claude'
26
30
  _HOOKS_FILE_NAME = 'settings.json'
27
31
  _REPO_SUBDIR = '.claude'
@@ -284,6 +288,12 @@ class ClaudeCode(IDE):
284
288
  # processed as Claude Code events.
285
289
  return raw_payload.get('hook_event_name', '') in _CLAUDE_CODE_EVENT_NAMES and 'transcript_path' in raw_payload
286
290
 
291
+ def is_synthetic_prompt(self, raw_payload: dict) -> bool:
292
+ if raw_payload.get('hook_event_name') != 'UserPromptSubmit':
293
+ return False
294
+ prompt = raw_payload.get('prompt') or ''
295
+ return prompt.lstrip().startswith(_SYNTHETIC_PROMPT_PREFIXES)
296
+
287
297
  def parse_hook_payload(self, raw_payload: dict) -> AIHookPayload:
288
298
  hook_event_name = raw_payload.get('hook_event_name', '')
289
299
  tool_name = raw_payload.get('tool_name', '')
@@ -26,6 +26,7 @@ from cycode.cli.apps.ai_guardrails.scan.utils import is_denied_path, truncate_ut
26
26
  from cycode.cli.apps.scan.code_scanner import _get_scan_documents_thread_func
27
27
  from cycode.cli.apps.scan.scan_parameters import get_scan_parameters
28
28
  from cycode.cli.cli_types import ScanTypeOption, SeverityOption
29
+ from cycode.cli.files_collector.file_excluder import is_path_configured_in_exclusions
29
30
  from cycode.cli.models import Document
30
31
  from cycode.cli.utils.progress_bar import DummyProgressBar, ScanProgressBarSection
31
32
  from cycode.cli.utils.scan_utils import build_violation_summary
@@ -337,7 +338,7 @@ def _perform_scan(
337
338
 
338
339
  scan_id = local_scan_result.scan_id
339
340
 
340
- if local_scan_result.detections_count > 0:
341
+ if local_scan_result.issue_detected:
341
342
  violation_summary = build_violation_summary([local_scan_result])
342
343
  return violation_summary, scan_id
343
344
 
@@ -360,6 +361,10 @@ def _scan_path_for_secrets(ctx: typer.Context, file_path: str, policy: dict) ->
360
361
  if not file_path or not os.path.isfile(file_path):
361
362
  return None, None
362
363
 
364
+ if is_path_configured_in_exclusions(str(ScanTypeOption.SECRET), os.path.abspath(file_path)):
365
+ logger.debug('Skipping scan; the path is in the ignore paths list, %s', {'file_path': file_path})
366
+ return None, None
367
+
363
368
  max_bytes = get_policy_value(policy, 'secrets', 'max_bytes', default=200000)
364
369
 
365
370
  with open(file_path, encoding='utf-8', errors='replace') as f:
@@ -116,6 +116,14 @@ def scan_command(
116
116
  output_json(ide_integration.build_hook_response(HookDecision.allow(AiHookEventType.PROMPT)))
117
117
  return
118
118
 
119
+ # Fork/subagent completions arrive as synthetic user turns (e.g. Claude Code's
120
+ # <task-notification>); they are agent-generated, not user prompts - skip before
121
+ # parse_hook_payload, which reads the transcript and IDE config from disk.
122
+ if ide_integration.is_synthetic_prompt(payload):
123
+ logger.debug('Synthetic prompt detected, skipping scan')
124
+ output_json(ide_integration.build_hook_response(HookDecision.allow(AiHookEventType.PROMPT)))
125
+ return
126
+
119
127
  unified_payload = ide_integration.parse_hook_payload(payload)
120
128
  event_name = unified_payload.event_name
121
129
  logger.debug(
@@ -25,7 +25,7 @@ def _is_subpath_of_cycode_configuration_folder(filename: str) -> bool:
25
25
  )
26
26
 
27
27
 
28
- def _is_path_configured_in_exclusions(scan_type: str, file_path: str) -> bool:
28
+ def is_path_configured_in_exclusions(scan_type: str, file_path: str) -> bool:
29
29
  exclusions_by_path = configuration_manager.get_exclusions_by_scan_type(scan_type).get(
30
30
  consts.EXCLUSIONS_BY_PATH_SECTION_NAME, []
31
31
  )
@@ -106,7 +106,7 @@ class Excluder:
106
106
  )
107
107
  return False
108
108
 
109
- if _is_path_configured_in_exclusions(scan_type, filename):
109
+ if is_path_configured_in_exclusions(scan_type, filename):
110
110
  logger.debug(
111
111
  'The document is irrelevant because its path is in the ignore paths list, %s', {'filename': filename}
112
112
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycode
3
- Version: 3.17.3.dev3
3
+ Version: 3.17.3.dev5
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=rgVcASSONng6midnbKoXWeT9KedU31Q1WW54byov1rQ,396
1
+ cycode/__init__.py,sha256=HP3KMMTPFR7n7VwPC3UoqpE7xT3Z_U1i5cZUD1fUUqo,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
@@ -10,18 +10,18 @@ cycode/cli/apps/ai_guardrails/consts.py,sha256=Js2QtSNYG9Kt0eo3vepRd5TFciCeJHEC9
10
10
  cycode/cli/apps/ai_guardrails/hooks_manager.py,sha256=_8EjjpaDoeUrlh6gDXechWyev0LIGEZgcA9YJBl21xw,9314
11
11
  cycode/cli/apps/ai_guardrails/ides/__init__.py,sha256=9FPz984poZWPX6S6abuo-PThiXgJ_WpoUv47wiSXnKQ,2639
12
12
  cycode/cli/apps/ai_guardrails/ides/_plugin_utils.py,sha256=XPIc9pZFEgdGVTSSAl9yqI48F88GKlFnJ5FsLUhHjCE,3981
13
- cycode/cli/apps/ai_guardrails/ides/base.py,sha256=EvlAgGMkc9FlQehh_0XMhMOisuOGB8NGp-_GI7nj444,7860
14
- cycode/cli/apps/ai_guardrails/ides/claude_code.py,sha256=kjFoLRAJLZjhJdxpdU8HZgpJhVDvhyp9fwsfN_NzfwQ,14608
13
+ cycode/cli/apps/ai_guardrails/ides/base.py,sha256=RZintDpwWgl0l1cBVKccG4ek1jkTMuzRJ-hq91V5ehc,8224
14
+ cycode/cli/apps/ai_guardrails/ides/claude_code.py,sha256=ejLGzuVxrnVNOToJl--7HaTFTDI_N3jru8ZC8K0iIo8,15086
15
15
  cycode/cli/apps/ai_guardrails/ides/codex.py,sha256=1nI0TPeCgg2zI1PCVmLi0GouD8HGwGoa6RsIshDDa9c,11972
16
16
  cycode/cli/apps/ai_guardrails/ides/copilot.py,sha256=HYPoLd__CslG6z0LtfGshli-nJa-2ebiVuwM_tSM6ls,19109
17
17
  cycode/cli/apps/ai_guardrails/ides/cursor.py,sha256=-Jr76dD8m2xwvb0i93LtwjaloB_oon0OjBUPkv1K6f0,5633
18
18
  cycode/cli/apps/ai_guardrails/install_command.py,sha256=vGZSIvHHVMS9_zhV_6lEhxqtmr5H6uykSq4AS5nxQYw,4278
19
19
  cycode/cli/apps/ai_guardrails/scan/__init__.py,sha256=qJc82XiQGiAuc1sYY8Ij_A-qXpxgLPuayQq8xWlouMA,48
20
20
  cycode/cli/apps/ai_guardrails/scan/consts.py,sha256=drAslw6vW3kxmbCs2qPCUbUPR7PJouT2lsXtu5sD-lQ,1094
21
- cycode/cli/apps/ai_guardrails/scan/handlers.py,sha256=pf5PrUIVnGLEEE6QKPny9at5V6Ms5u2IEtFP72hKgqA,15523
21
+ cycode/cli/apps/ai_guardrails/scan/handlers.py,sha256=JDdBMFfJrd9o7Rrjv5CmwL7t8s408gIfKc-S5xe8ovA,15833
22
22
  cycode/cli/apps/ai_guardrails/scan/payload.py,sha256=pvT3UUqNMvdK3EVzzPjy4JMlOrF-WgxZ3fHN2AtN5eA,1126
23
23
  cycode/cli/apps/ai_guardrails/scan/policy.py,sha256=BZoNNdDQ9tqnfwhB4X1-bDtudaOQc_gXizm3IVwa28o,3351
24
- cycode/cli/apps/ai_guardrails/scan/scan_command.py,sha256=1qvPIdMlm8B5bW67sOA7qTS_dARkiUZcIpn4yNSAGh4,6606
24
+ cycode/cli/apps/ai_guardrails/scan/scan_command.py,sha256=G4pJ-ctTezft55pC0-AGf4HG3gtNp_EhoTiBX1_YP7w,7088
25
25
  cycode/cli/apps/ai_guardrails/scan/types.py,sha256=lDttkYFBfOkdMEEaRbq1IT2QTK0R-7Ht3T8vZdyB3b4,1038
26
26
  cycode/cli/apps/ai_guardrails/scan/utils.py,sha256=QzR_zmivDYwg2-F8g4bFfsycHhNo-pPuJly0P_l0gm8,2879
27
27
  cycode/cli/apps/ai_guardrails/session_start_command.py,sha256=05Li-ON2U1BU_8CR2YYw1y5HVvoWPTf19ne--EgPqmQ,5921
@@ -106,7 +106,7 @@ cycode/cli/exceptions/handle_scan_errors.py,sha256=1KkBFb7LniflYRr0vMl1FPIZDALPZ
106
106
  cycode/cli/files_collector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
107
107
  cycode/cli/files_collector/commit_range_documents.py,sha256=ZAU9er6m8_IF9y9KxZoiEaDOiZC35SEfv5VtqKp4AZc,20484
108
108
  cycode/cli/files_collector/documents_walk_ignore.py,sha256=G4e-3vfP4WZ7wa9-VbZ66xCKCioTXnPBfbrs4_hh8xY,4705
109
- cycode/cli/files_collector/file_excluder.py,sha256=YSMzmsv1qJFwOIWk6JzXLYPOd2YNHZGqf854n_DSnWI,8233
109
+ cycode/cli/files_collector/file_excluder.py,sha256=atua_L2qDbmhFXj4nB6rDqSn5--MubLGtUPSOXwXUqE,8231
110
110
  cycode/cli/files_collector/iac/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
111
  cycode/cli/files_collector/iac/tf_content_generator.py,sha256=a65zA0Ejv_LSA5jac2omHck4IKoNS5MX6v6ltF2wo4E,2873
112
112
  cycode/cli/files_collector/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -210,8 +210,8 @@ cycode/cyclient/report_client.py,sha256=Scq30NeJPzgXv0hPLO1U05AdE9i_2iu6cIrSKpEJ
210
210
  cycode/cyclient/scan_client.py,sha256=6TK5FQkfrvV7PHqRnUzEn1PBNd2oPYVamvIixcUfe3c,16755
211
211
  cycode/cyclient/scan_config_base.py,sha256=mXsPZGYCtp85rv5GIige40yQZXuRcEKUW-VQJ0vgFzk,1201
212
212
  cycode/logger.py,sha256=EfZGRK6VC5rE_LAjIcRrHFiQCueylCDXoG6bvGkrIME,2111
213
- cycode-3.17.3.dev3.dist-info/METADATA,sha256=N5ucWK2_MHWg5DJn0tHPJvGXG3L5Qnn55ed36wPL_eI,89246
214
- cycode-3.17.3.dev3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
215
- cycode-3.17.3.dev3.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
216
- cycode-3.17.3.dev3.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
217
- cycode-3.17.3.dev3.dist-info/RECORD,,
213
+ cycode-3.17.3.dev5.dist-info/METADATA,sha256=hGWAlg9KapbSf67D5ObeiMKEDtX5FNJxejSH6e0AvFM,89246
214
+ cycode-3.17.3.dev5.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
215
+ cycode-3.17.3.dev5.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
216
+ cycode-3.17.3.dev5.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
217
+ cycode-3.17.3.dev5.dist-info/RECORD,,