cycode 3.25.1.dev6__py3-none-any.whl → 3.25.2.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.
Files changed (125) hide show
  1. cycode/__init__.py +1 -1
  2. cycode/cli/app.py +9 -10
  3. cycode/cli/apps/activation_manager.py +6 -6
  4. cycode/cli/apps/ai_guardrails/command_utils.py +1 -2
  5. cycode/cli/apps/ai_guardrails/hooks_manager.py +6 -7
  6. cycode/cli/apps/ai_guardrails/ides/__init__.py +8 -9
  7. cycode/cli/apps/ai_guardrails/ides/_plugin_utils.py +11 -10
  8. cycode/cli/apps/ai_guardrails/ides/_skill_utils.py +1 -2
  9. cycode/cli/apps/ai_guardrails/ides/base.py +19 -21
  10. cycode/cli/apps/ai_guardrails/ides/claude_code.py +54 -16
  11. cycode/cli/apps/ai_guardrails/ides/codex.py +54 -20
  12. cycode/cli/apps/ai_guardrails/ides/copilot.py +23 -25
  13. cycode/cli/apps/ai_guardrails/ides/cursor.py +48 -10
  14. cycode/cli/apps/ai_guardrails/install_command.py +3 -3
  15. cycode/cli/apps/ai_guardrails/scan/guardrail_config.py +44 -22
  16. cycode/cli/apps/ai_guardrails/scan/handlers.py +79 -14
  17. cycode/cli/apps/ai_guardrails/scan/mcp_server_status.py +103 -0
  18. cycode/cli/apps/ai_guardrails/scan/payload.py +13 -14
  19. cycode/cli/apps/ai_guardrails/scan/policy.py +3 -3
  20. cycode/cli/apps/ai_guardrails/scan/scan_command.py +4 -4
  21. cycode/cli/apps/ai_guardrails/scan/types.py +1 -0
  22. cycode/cli/apps/ai_guardrails/session_start_command.py +46 -21
  23. cycode/cli/apps/ai_guardrails/status_command.py +2 -2
  24. cycode/cli/apps/ai_guardrails/uninstall_command.py +2 -2
  25. cycode/cli/apps/api/__init__.py +3 -3
  26. cycode/cli/apps/api/api_command.py +6 -6
  27. cycode/cli/apps/api/openapi_spec.py +4 -5
  28. cycode/cli/apps/auth/auth_common.py +4 -4
  29. cycode/cli/apps/configure/configure_command.py +2 -4
  30. cycode/cli/apps/configure/messages.py +2 -4
  31. cycode/cli/apps/configure/prompts.py +5 -7
  32. cycode/cli/apps/ignore/ignore_command.py +7 -7
  33. cycode/cli/apps/mcp/mcp_command.py +11 -11
  34. cycode/cli/apps/report/sbom/common.py +5 -5
  35. cycode/cli/apps/report/sbom/sbom_command.py +2 -2
  36. cycode/cli/apps/report/sbom/sbom_report_file.py +1 -2
  37. cycode/cli/apps/report_import/sbom/sbom_command.py +3 -3
  38. cycode/cli/apps/sca_options.py +3 -3
  39. cycode/cli/apps/scan/aggregation_report.py +4 -4
  40. cycode/cli/apps/scan/code_scanner.py +8 -7
  41. cycode/cli/apps/scan/commit_range_scanner.py +10 -10
  42. cycode/cli/apps/scan/detection_excluder.py +2 -4
  43. cycode/cli/apps/scan/pre_commit/pre_commit_command.py +3 -3
  44. cycode/cli/apps/scan/pre_push/pre_push_command.py +3 -3
  45. cycode/cli/apps/scan/pre_receive/pre_receive_command.py +2 -2
  46. cycode/cli/apps/scan/remote_url_resolver.py +6 -8
  47. cycode/cli/apps/scan/repository/repository_command.py +2 -2
  48. cycode/cli/apps/scan/scan_command.py +2 -2
  49. cycode/cli/apps/scan/scan_parameters.py +1 -3
  50. cycode/cli/apps/scan/scan_result.py +5 -5
  51. cycode/cli/console.py +2 -2
  52. cycode/cli/exceptions/custom_exceptions.py +1 -1
  53. cycode/cli/exceptions/handle_errors.py +1 -3
  54. cycode/cli/exceptions/handle_scan_errors.py +1 -2
  55. cycode/cli/files_collector/commit_range_documents.py +14 -14
  56. cycode/cli/files_collector/models/in_memory_zip.py +3 -3
  57. cycode/cli/files_collector/repository_documents.py +3 -3
  58. cycode/cli/files_collector/sca/base_restore_dependencies.py +7 -8
  59. cycode/cli/files_collector/sca/go/restore_go_dependencies.py +1 -2
  60. cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py +2 -3
  61. cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py +3 -4
  62. cycode/cli/files_collector/sca/npm/restore_bun_dependencies.py +3 -4
  63. cycode/cli/files_collector/sca/npm/restore_deno_dependencies.py +1 -2
  64. cycode/cli/files_collector/sca/npm/restore_pnpm_dependencies.py +2 -3
  65. cycode/cli/files_collector/sca/npm/restore_yarn_dependencies.py +2 -3
  66. cycode/cli/files_collector/sca/npm/workspace/coverage.py +5 -5
  67. cycode/cli/files_collector/sca/npm/workspace/files.py +2 -3
  68. cycode/cli/files_collector/sca/npm/workspace/globs.py +1 -2
  69. cycode/cli/files_collector/sca/npm/workspace/resolvers.py +14 -16
  70. cycode/cli/files_collector/sca/php/restore_composer_dependencies.py +1 -2
  71. cycode/cli/files_collector/sca/python/restore_pip_dependencies.py +2 -3
  72. cycode/cli/files_collector/sca/python/restore_pipenv_dependencies.py +1 -2
  73. cycode/cli/files_collector/sca/python/restore_poetry_dependencies.py +2 -3
  74. cycode/cli/files_collector/sca/python/restore_uv_dependencies.py +2 -3
  75. cycode/cli/files_collector/sca/sca_file_collector.py +5 -5
  76. cycode/cli/files_collector/zip_documents.py +1 -2
  77. cycode/cli/models.py +8 -8
  78. cycode/cli/printers/console_printer.py +9 -9
  79. cycode/cli/printers/json_printer.py +2 -2
  80. cycode/cli/printers/printer_base.py +3 -3
  81. cycode/cli/printers/rich_printer.py +2 -2
  82. cycode/cli/printers/tables/table.py +4 -4
  83. cycode/cli/printers/tables/table_models.py +2 -2
  84. cycode/cli/printers/tables/table_printer_base.py +2 -2
  85. cycode/cli/printers/text_printer.py +4 -4
  86. cycode/cli/printers/utils/code_snippet_syntax.py +1 -1
  87. cycode/cli/printers/utils/detection_data.py +3 -3
  88. cycode/cli/printers/utils/sca_ossf.py +4 -4
  89. cycode/cli/printers/utils/sca_policy_details.py +2 -1
  90. cycode/cli/user_settings/config_file_manager.py +10 -10
  91. cycode/cli/user_settings/configuration_manager.py +6 -6
  92. cycode/cli/user_settings/credentials_manager.py +5 -6
  93. cycode/cli/utils/get_api_client.py +5 -5
  94. cycode/cli/utils/git_proxy.py +8 -8
  95. cycode/cli/utils/host_info.py +21 -38
  96. cycode/cli/utils/ignore_utils.py +13 -15
  97. cycode/cli/utils/jwt_utils.py +2 -4
  98. cycode/cli/utils/path_utils.py +6 -6
  99. cycode/cli/utils/progress_bar.py +4 -4
  100. cycode/cli/utils/scan_batch.py +2 -1
  101. cycode/cli/utils/scan_utils.py +2 -2
  102. cycode/cli/utils/shell_executor.py +3 -4
  103. cycode/cli/utils/task_timer.py +4 -4
  104. cycode/cli/utils/trust_store.py +0 -17
  105. cycode/cli/utils/url_utils.py +1 -2
  106. cycode/cli/utils/version_checker.py +4 -5
  107. cycode/cli/utils/yaml_utils.py +1 -1
  108. cycode/config.py +1 -2
  109. cycode/cyclient/ai_security_manager_client.py +27 -21
  110. cycode/cyclient/auth_client.py +2 -4
  111. cycode/cyclient/base_token_auth_client.py +2 -2
  112. cycode/cyclient/client_creator.py +4 -6
  113. cycode/cyclient/cycode_client_base.py +10 -9
  114. cycode/cyclient/cycode_dev_based_client.py +1 -3
  115. cycode/cyclient/headers.py +1 -2
  116. cycode/cyclient/import_sbom_client.py +3 -4
  117. cycode/cyclient/models.py +88 -30
  118. cycode/cyclient/report_client.py +1 -2
  119. cycode/cyclient/scan_client.py +8 -7
  120. cycode/logger.py +4 -4
  121. {cycode-3.25.1.dev6.dist-info → cycode-3.25.2.dev2.dist-info}/METADATA +12 -19
  122. {cycode-3.25.1.dev6.dist-info → cycode-3.25.2.dev2.dist-info}/RECORD +125 -124
  123. {cycode-3.25.1.dev6.dist-info → cycode-3.25.2.dev2.dist-info}/WHEEL +1 -1
  124. {cycode-3.25.1.dev6.dist-info → cycode-3.25.2.dev2.dist-info}/entry_points.txt +0 -0
  125. {cycode-3.25.1.dev6.dist-info → cycode-3.25.2.dev2.dist-info}/licenses/LICENCE +0 -0
@@ -4,7 +4,6 @@ import json
4
4
  import os
5
5
  import time
6
6
  from pathlib import Path
7
- from typing import Optional
8
7
 
9
8
  from cycode.cli.consts import CYCODE_CONFIGURATION_DIRECTORY
10
9
  from cycode.cli.user_settings.credentials_manager import CredentialsManager
@@ -20,7 +19,7 @@ _CACHE_TTL_SECONDS = int(os.getenv('CYCODE_SPEC_CACHE_TTL', str(24 * 60 * 60)))
20
19
  _OPENAPI_SPEC_PATH = '/v4/api-docs/cycode-api-swagger.json'
21
20
 
22
21
 
23
- def get_openapi_spec(client_id: Optional[str] = None, client_secret: Optional[str] = None) -> dict:
22
+ def get_openapi_spec(client_id: str | None = None, client_secret: str | None = None) -> dict:
24
23
  """Get the OpenAPI spec, using cache if fresh, otherwise fetching from API.
25
24
 
26
25
  The spec is only fetched when the user actually invokes `cycode platform ...`.
@@ -45,7 +44,7 @@ def get_openapi_spec(client_id: Optional[str] = None, client_secret: Optional[st
45
44
  return _fetch_and_cache_spec(client_id, client_secret)
46
45
 
47
46
 
48
- def _load_cached_spec() -> Optional[dict]:
47
+ def _load_cached_spec() -> dict | None:
49
48
  """Load spec from local cache if it exists and is fresh."""
50
49
  if not _CACHE_FILE.exists():
51
50
  return None
@@ -64,7 +63,7 @@ def _load_cached_spec() -> Optional[dict]:
64
63
  return None
65
64
 
66
65
 
67
- def resolve_credentials(client_id: Optional[str] = None, client_secret: Optional[str] = None) -> tuple[str, str]:
66
+ def resolve_credentials(client_id: str | None = None, client_secret: str | None = None) -> tuple[str, str]:
68
67
  """Resolve credentials from args or the CLI's standard credential chain."""
69
68
  if not client_id or not client_secret:
70
69
  credentials_manager = CredentialsManager()
@@ -81,7 +80,7 @@ def resolve_credentials(client_id: Optional[str] = None, client_secret: Optional
81
80
  return client_id, client_secret
82
81
 
83
82
 
84
- def _fetch_and_cache_spec(client_id: Optional[str] = None, client_secret: Optional[str] = None) -> dict:
83
+ def _fetch_and_cache_spec(client_id: str | None = None, client_secret: str | None = None) -> dict:
85
84
  """Fetch OpenAPI spec from API and cache to disk.
86
85
 
87
86
  Uses CycodeTokenBasedClient for auth and retries. The spec is served from the app URL,
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Optional
1
+ from typing import TYPE_CHECKING
2
2
 
3
3
  from cycode.cli.apps.auth.models import AuthInfo
4
4
  from cycode.cli.exceptions.custom_exceptions import HttpUnauthorizedError, RequestHttpError
@@ -11,7 +11,7 @@ if TYPE_CHECKING:
11
11
  from typer import Context
12
12
 
13
13
 
14
- def get_authorization_info(ctx: 'Context') -> Optional[AuthInfo]:
14
+ def get_authorization_info(ctx: 'Context') -> AuthInfo | None:
15
15
  printer = ctx.obj.get('console_printer')
16
16
 
17
17
  client_id = ctx.obj.get('client_id')
@@ -50,8 +50,8 @@ def get_authorization_info(ctx: 'Context') -> Optional[AuthInfo]:
50
50
 
51
51
 
52
52
  def _try_oidc_authorization(
53
- ctx: 'Context', printer: any, client_id: Optional[str], id_token: Optional[str]
54
- ) -> Optional[AuthInfo]:
53
+ ctx: 'Context', printer: any, client_id: str | None, id_token: str | None
54
+ ) -> AuthInfo | None:
55
55
  if not client_id or not id_token:
56
56
  return None
57
57
 
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  from cycode.cli.apps.configure.consts import CONFIGURATION_MANAGER, CREDENTIALS_MANAGER
4
2
  from cycode.cli.apps.configure.messages import (
5
3
  get_credentials_environment_variables_override_warning,
@@ -18,8 +16,8 @@ from cycode.cli.console import console
18
16
 
19
17
 
20
18
  def _should_update_value(
21
- old_value: Optional[str],
22
- new_value: Optional[str],
19
+ old_value: str | None,
20
+ new_value: str | None,
23
21
  ) -> bool:
24
22
  if not new_value:
25
23
  return False
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  from cycode.cli.apps.configure.consts import (
4
2
  CONFIGURATION_MANAGER,
5
3
  CREDENTIALS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE,
@@ -19,7 +17,7 @@ def get_credentials_update_result_message() -> str:
19
17
  return CREDENTIALS_UPDATED_SUCCESSFULLY_MESSAGE.format(filename=CREDENTIALS_MANAGER.get_filename())
20
18
 
21
19
 
22
- def get_credentials_environment_variables_override_warning() -> Optional[str]:
20
+ def get_credentials_environment_variables_override_warning() -> str | None:
23
21
  if _are_credentials_exist_in_environment_variables():
24
22
  return CREDENTIALS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE
25
23
 
@@ -38,7 +36,7 @@ def get_urls_update_result_message() -> str:
38
36
  )
39
37
 
40
38
 
41
- def get_urls_environment_variables_override_warning() -> Optional[str]:
39
+ def get_urls_environment_variables_override_warning() -> str | None:
42
40
  if _are_urls_exist_in_environment_variables():
43
41
  return URLS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE
44
42
 
@@ -1,12 +1,10 @@
1
- from typing import Optional
2
-
3
1
  import typer
4
2
 
5
3
  from cycode.cli import consts
6
4
  from cycode.cli.utils.string_utils import obfuscate_text
7
5
 
8
6
 
9
- def get_client_id_input(current_client_id: Optional[str]) -> Optional[str]:
7
+ def get_client_id_input(current_client_id: str | None) -> str | None:
10
8
  prompt_text = 'Cycode Client ID'
11
9
 
12
10
  prompt_suffix = ' []: '
@@ -17,7 +15,7 @@ def get_client_id_input(current_client_id: Optional[str]) -> Optional[str]:
17
15
  return new_client_id or current_client_id
18
16
 
19
17
 
20
- def get_client_secret_input(current_client_secret: Optional[str]) -> Optional[str]:
18
+ def get_client_secret_input(current_client_secret: str | None) -> str | None:
21
19
  prompt_text = 'Cycode Client Secret'
22
20
 
23
21
  prompt_suffix = ' []: '
@@ -28,7 +26,7 @@ def get_client_secret_input(current_client_secret: Optional[str]) -> Optional[st
28
26
  return new_client_secret or current_client_secret
29
27
 
30
28
 
31
- def get_app_url_input(current_app_url: Optional[str]) -> str:
29
+ def get_app_url_input(current_app_url: str | None) -> str:
32
30
  prompt_text = 'Cycode APP URL'
33
31
 
34
32
  default = consts.DEFAULT_CYCODE_APP_URL
@@ -38,7 +36,7 @@ def get_app_url_input(current_app_url: Optional[str]) -> str:
38
36
  return typer.prompt(text=prompt_text, default=default, type=str)
39
37
 
40
38
 
41
- def get_api_url_input(current_api_url: Optional[str]) -> str:
39
+ def get_api_url_input(current_api_url: str | None) -> str:
42
40
  prompt_text = 'Cycode API URL'
43
41
 
44
42
  default = consts.DEFAULT_CYCODE_API_URL
@@ -48,7 +46,7 @@ def get_api_url_input(current_api_url: Optional[str]) -> str:
48
46
  return typer.prompt(text=prompt_text, default=default, type=str)
49
47
 
50
48
 
51
- def get_id_token_input(current_id_token: Optional[str]) -> Optional[str]:
49
+ def get_id_token_input(current_id_token: str | None) -> str | None:
52
50
  prompt_text = 'Cycode ID Token'
53
51
 
54
52
  prompt_suffix = ' []: '
@@ -1,5 +1,5 @@
1
1
  import re
2
- from typing import Annotated, Optional
2
+ from typing import Annotated
3
3
 
4
4
  import click
5
5
  import typer
@@ -22,7 +22,7 @@ def _is_package_pattern_valid(package: str) -> bool:
22
22
 
23
23
  def ignore_command( # noqa: C901
24
24
  by_path: Annotated[
25
- Optional[str],
25
+ str | None,
26
26
  typer.Option(
27
27
  help='Ignore a specific file or directory while scanning.',
28
28
  show_default=False,
@@ -30,7 +30,7 @@ def ignore_command( # noqa: C901
30
30
  ),
31
31
  ] = None,
32
32
  by_rule: Annotated[
33
- Optional[str],
33
+ str | None,
34
34
  typer.Option(
35
35
  help='Ignore scanning a specific Secrets rule ID or IaC rule ID.',
36
36
  show_default=False,
@@ -38,7 +38,7 @@ def ignore_command( # noqa: C901
38
38
  ),
39
39
  ] = None,
40
40
  by_value: Annotated[
41
- Optional[str],
41
+ str | None,
42
42
  typer.Option(
43
43
  help='Ignore a specific value.',
44
44
  show_default=False,
@@ -46,7 +46,7 @@ def ignore_command( # noqa: C901
46
46
  ),
47
47
  ] = None,
48
48
  by_sha: Annotated[
49
- Optional[str],
49
+ str | None,
50
50
  typer.Option(
51
51
  help='Ignore a specific SHA512 representation of a string.',
52
52
  show_default=False,
@@ -54,7 +54,7 @@ def ignore_command( # noqa: C901
54
54
  ),
55
55
  ] = None,
56
56
  by_package: Annotated[
57
- Optional[str],
57
+ str | None,
58
58
  typer.Option(
59
59
  help='Ignore scanning a specific package version. Expected pattern: [cyan]name@version[/].',
60
60
  show_default=False,
@@ -62,7 +62,7 @@ def ignore_command( # noqa: C901
62
62
  ),
63
63
  ] = None,
64
64
  by_cve: Annotated[
65
- Optional[str],
65
+ str | None,
66
66
  typer.Option(
67
67
  help='Ignore scanning a specific CVE. Expected pattern: [cyan]CVE-YYYY-NNN[/].',
68
68
  show_default=False,
@@ -6,7 +6,7 @@ import shutil
6
6
  import sys
7
7
  import tempfile
8
8
  import uuid
9
- from typing import Annotated, Any, Optional
9
+ from typing import Annotated, Any
10
10
 
11
11
  import anyio
12
12
  import typer
@@ -229,8 +229,8 @@ def _build_scan_summary(result: dict[str, Any]) -> str:
229
229
 
230
230
  async def _cycode_scan_tool(
231
231
  scan_type: ScanTypeOption,
232
- files: Optional[dict[str, str]] = None,
233
- paths: Optional[list[str]] = None,
232
+ files: dict[str, str] | None = None,
233
+ paths: list[str] | None = None,
234
234
  ) -> str:
235
235
  _tool_call_id = _gen_random_id()
236
236
  _logger.info('Scan tool called, %s', {'scan_type': scan_type, 'call_id': _tool_call_id})
@@ -288,8 +288,8 @@ async def _cycode_scan_tool(
288
288
 
289
289
 
290
290
  async def cycode_secret_scan(
291
- paths: Optional[list[str]] = _PATHS_TOOL_FIELD,
292
- files: Optional[dict[str, str]] = _FILES_TOOL_FIELD,
291
+ paths: list[str] | None = _PATHS_TOOL_FIELD,
292
+ files: dict[str, str] | None = _FILES_TOOL_FIELD,
293
293
  ) -> str:
294
294
  """Scan for hardcoded secrets.
295
295
 
@@ -309,8 +309,8 @@ async def cycode_secret_scan(
309
309
 
310
310
 
311
311
  async def cycode_sca_scan(
312
- paths: Optional[list[str]] = _PATHS_TOOL_FIELD,
313
- files: Optional[dict[str, str]] = _FILES_TOOL_FIELD,
312
+ paths: list[str] | None = _PATHS_TOOL_FIELD,
313
+ files: dict[str, str] | None = _FILES_TOOL_FIELD,
314
314
  ) -> str:
315
315
  """Scan for Software Composition Analysis (SCA) - vulnerabilities and license issues.
316
316
 
@@ -337,8 +337,8 @@ async def cycode_sca_scan(
337
337
 
338
338
 
339
339
  async def cycode_iac_scan(
340
- paths: Optional[list[str]] = _PATHS_TOOL_FIELD,
341
- files: Optional[dict[str, str]] = _FILES_TOOL_FIELD,
340
+ paths: list[str] | None = _PATHS_TOOL_FIELD,
341
+ files: dict[str, str] | None = _FILES_TOOL_FIELD,
342
342
  ) -> str:
343
343
  """Scan for Infrastructure as Code (IaC) misconfigurations.
344
344
 
@@ -360,8 +360,8 @@ async def cycode_iac_scan(
360
360
 
361
361
 
362
362
  async def cycode_sast_scan(
363
- paths: Optional[list[str]] = _PATHS_TOOL_FIELD,
364
- files: Optional[dict[str, str]] = _FILES_TOOL_FIELD,
363
+ paths: list[str] | None = _PATHS_TOOL_FIELD,
364
+ files: dict[str, str] | None = _FILES_TOOL_FIELD,
365
365
  ) -> str:
366
366
  """Scan for Static Application Security Testing (SAST) - code quality and security flaws.
367
367
 
@@ -1,7 +1,7 @@
1
1
  import pathlib
2
2
  import time
3
3
  from platform import platform
4
- from typing import TYPE_CHECKING, Optional
4
+ from typing import TYPE_CHECKING
5
5
 
6
6
  from cycode.cli import consts
7
7
  from cycode.cli.apps.report.sbom.sbom_report_file import SbomReportFile
@@ -20,7 +20,7 @@ def _poll_report_execution_until_completed(
20
20
  progress_bar: 'BaseProgressBar',
21
21
  client: 'ReportClient',
22
22
  report_execution_id: int,
23
- polling_timeout: Optional[int] = None,
23
+ polling_timeout: int | None = None,
24
24
  ) -> ReportExecutionSchema:
25
25
  if polling_timeout is None:
26
26
  polling_timeout = configuration_manager.get_report_polling_timeout_in_seconds()
@@ -50,8 +50,8 @@ def send_report_feedback(
50
50
  report_command_type: str,
51
51
  request_report_parameters: dict,
52
52
  report_execution_id: int,
53
- error_message: Optional[str] = None,
54
- request_zip_file_size: Optional[int] = None,
53
+ error_message: str | None = None,
54
+ request_zip_file_size: int | None = None,
55
55
  **kwargs,
56
56
  ) -> None:
57
57
  try:
@@ -77,7 +77,7 @@ def create_sbom_report(
77
77
  progress_bar: 'BaseProgressBar',
78
78
  client: 'ReportClient',
79
79
  report_execution_id: int,
80
- output_file: Optional[pathlib.Path],
80
+ output_file: pathlib.Path | None,
81
81
  output_format: str,
82
82
  ) -> None:
83
83
  report_execution = _poll_report_execution_until_completed(progress_bar, client, report_execution_id)
@@ -1,5 +1,5 @@
1
1
  from pathlib import Path
2
- from typing import Annotated, Optional
2
+ from typing import Annotated
3
3
 
4
4
  import click
5
5
  import typer
@@ -32,7 +32,7 @@ def sbom_command(
32
32
  ),
33
33
  ] = SbomOutputFormatOption.JSON,
34
34
  output_file: Annotated[
35
- Optional[Path],
35
+ Path | None,
36
36
  typer.Option(
37
37
  help='Output file.',
38
38
  show_default='Autogenerated filename saved to the current directory',
@@ -1,7 +1,6 @@
1
1
  import os
2
2
  import pathlib
3
3
  import re
4
- from typing import Optional
5
4
 
6
5
  import typer
7
6
 
@@ -9,7 +8,7 @@ from cycode.cli.console import console
9
8
 
10
9
 
11
10
  class SbomReportFile:
12
- def __init__(self, storage_path: str, output_format: str, output_file: Optional[pathlib.Path]) -> None:
11
+ def __init__(self, storage_path: str, output_format: str, output_file: pathlib.Path | None) -> None:
13
12
  if output_file is None:
14
13
  output_file = pathlib.Path(storage_path)
15
14
 
@@ -1,5 +1,5 @@
1
1
  from pathlib import Path
2
- from typing import Annotated, Optional
2
+ from typing import Annotated
3
3
 
4
4
  import typer
5
5
 
@@ -24,13 +24,13 @@ def sbom_command(
24
24
  str, typer.Option('--vendor', '-v', help='Vendor Name.', case_sensitive=False, show_default=False)
25
25
  ],
26
26
  labels: Annotated[
27
- Optional[list[str]],
27
+ list[str] | None,
28
28
  typer.Option(
29
29
  '--label', '-l', help='Label, can be specified multiple times.', case_sensitive=False, show_default=False
30
30
  ),
31
31
  ] = None,
32
32
  owners: Annotated[
33
- Optional[list[str]],
33
+ list[str] | None,
34
34
  typer.Option(
35
35
  '--owner',
36
36
  '-o',
@@ -1,5 +1,5 @@
1
1
  from pathlib import Path
2
- from typing import Annotated, Optional
2
+ from typing import Annotated
3
3
 
4
4
  import typer
5
5
 
@@ -25,7 +25,7 @@ GradleAllSubProjectsOption = Annotated[
25
25
  ]
26
26
 
27
27
  MavenSettingsFileOption = Annotated[
28
- Optional[Path],
28
+ Path | None,
29
29
  typer.Option(
30
30
  '--maven-settings-file',
31
31
  show_default=False,
@@ -49,7 +49,7 @@ def apply_sca_restore_options_to_context(
49
49
  ctx: typer.Context,
50
50
  no_restore: bool,
51
51
  gradle_all_sub_projects: bool,
52
- maven_settings_file: Optional[Path],
52
+ maven_settings_file: Path | None,
53
53
  stop_on_error: bool = False,
54
54
  ) -> None:
55
55
  ctx.obj['no_restore'] = no_restore
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Optional
1
+ from typing import TYPE_CHECKING
2
2
 
3
3
  import typer
4
4
 
@@ -10,13 +10,13 @@ if TYPE_CHECKING:
10
10
  logger = get_logger('Aggregation Report URL')
11
11
 
12
12
 
13
- def _set_aggregation_report_url(ctx: typer.Context, aggregation_report_url: Optional[str] = None) -> None:
13
+ def _set_aggregation_report_url(ctx: typer.Context, aggregation_report_url: str | None = None) -> None:
14
14
  ctx.obj['aggregation_report_url'] = aggregation_report_url
15
15
 
16
16
 
17
17
  def try_get_aggregation_report_url_if_needed(
18
18
  scan_parameters: dict, cycode_client: 'ScanClient', scan_type: str
19
- ) -> Optional[str]:
19
+ ) -> str | None:
20
20
  if not scan_parameters.get('report', False):
21
21
  return None
22
22
 
@@ -37,6 +37,6 @@ def try_set_aggregation_report_url_if_needed(
37
37
  aggregation_report_url = try_get_aggregation_report_url_if_needed(scan_parameters, cycode_client, scan_type)
38
38
  if aggregation_report_url:
39
39
  _set_aggregation_report_url(ctx, aggregation_report_url)
40
- logger.debug('Aggregation report URL set successfully', {'aggregation_report_url': aggregation_report_url})
40
+ logger.debug('Aggregation report URL set successfully, %s', {'aggregation_report_url': aggregation_report_url})
41
41
  else:
42
42
  logger.debug('No aggregation report URL found or report generation is disabled')
@@ -1,8 +1,9 @@
1
1
  import os
2
2
  import time
3
3
  import zipfile
4
+ from collections.abc import Callable
4
5
  from platform import platform
5
- from typing import TYPE_CHECKING, Callable, Optional
6
+ from typing import TYPE_CHECKING
6
7
 
7
8
  import requests
8
9
  import typer
@@ -147,7 +148,7 @@ def _get_scan_documents_thread_func(
147
148
  is_git_diff: bool,
148
149
  is_commit_range: bool,
149
150
  scan_parameters: dict,
150
- prezipped: Optional['InMemoryZip'] = None,
151
+ prezipped: 'InMemoryZip | None' = None,
151
152
  ) -> Callable[[list[Document]], tuple[str, CliError, LocalScanResult]]:
152
153
  cycode_client = ctx.obj['client']
153
154
  scan_type = ctx.obj['scan_type']
@@ -363,7 +364,7 @@ def _perform_scan_v4_async(
363
364
  scan_parameters: dict,
364
365
  is_git_diff: bool,
365
366
  is_commit_range: bool,
366
- on_upload_progress: Optional[Callable] = None,
367
+ on_upload_progress: Callable | None = None,
367
368
  ) -> ZippedFileScanResult:
368
369
  upload_link = cycode_client.get_upload_link(scan_type)
369
370
  logger.debug('Got upload link, %s', {'upload_id': upload_link.upload_id})
@@ -390,7 +391,7 @@ def _perform_scan_async(
390
391
  scan_type: str,
391
392
  scan_parameters: dict,
392
393
  is_commit_range: bool,
393
- on_upload_progress: Optional[Callable] = None,
394
+ on_upload_progress: Callable | None = None,
394
395
  ) -> ZippedFileScanResult:
395
396
  scan_async_result = cycode_client.zipped_file_scan_async(
396
397
  zipped_documents,
@@ -429,7 +430,7 @@ def _perform_scan(
429
430
  is_commit_range: bool,
430
431
  scan_parameters: dict,
431
432
  should_use_sync_flow: bool = False,
432
- on_upload_progress: Optional[Callable] = None,
433
+ on_upload_progress: Callable | None = None,
433
434
  ) -> ZippedFileScanResult:
434
435
  if should_use_sync_flow:
435
436
  # it does not support commit range scans; should_use_sync_flow handles it
@@ -463,7 +464,7 @@ def poll_scan_results(
463
464
  scan_id: str,
464
465
  scan_type: str,
465
466
  scan_parameters: dict,
466
- polling_timeout: Optional[int] = None,
467
+ polling_timeout: int | None = None,
467
468
  ) -> 'ZippedFileScanResult':
468
469
  if polling_timeout is None:
469
470
  polling_timeout = configuration_manager.get_scan_polling_timeout_in_seconds()
@@ -504,7 +505,7 @@ def report_scan_status(
504
505
  files_to_scan_count: int,
505
506
  zip_size: int,
506
507
  command_scan_type: str,
507
- error_message: Optional[str],
508
+ error_message: str | None,
508
509
  ) -> None:
509
510
  try:
510
511
  end_scan_time = time.time()
@@ -1,5 +1,5 @@
1
1
  import os
2
- from typing import TYPE_CHECKING, Optional
2
+ from typing import TYPE_CHECKING
3
3
 
4
4
  import click
5
5
  import requests
@@ -72,7 +72,7 @@ def _perform_commit_range_scan_async(
72
72
  to_commit_zipped_documents: 'InMemoryZip',
73
73
  scan_type: str,
74
74
  scan_parameters: dict,
75
- timeout: Optional[int] = None,
75
+ timeout: int | None = None,
76
76
  ) -> ZippedFileScanResult:
77
77
  scan_async_result = cycode_client.commit_range_scan_async(
78
78
  from_commit_zipped_documents, to_commit_zipped_documents, scan_type, scan_parameters
@@ -90,7 +90,7 @@ def _perform_commit_range_scan_v4_async(
90
90
  to_commit_zipped_documents: 'InMemoryZip',
91
91
  scan_type: str,
92
92
  scan_parameters: dict,
93
- timeout: Optional[int] = None,
93
+ timeout: int | None = None,
94
94
  ) -> ZippedFileScanResult:
95
95
  from_upload_link = cycode_client.get_upload_link(scan_type)
96
96
  logger.debug('Got from-commit upload link, %s', {'upload_id': from_upload_link.upload_id})
@@ -120,8 +120,8 @@ def _scan_commit_range_documents(
120
120
  ctx: typer.Context,
121
121
  from_documents_to_scan: list[Document],
122
122
  to_documents_to_scan: list[Document],
123
- scan_parameters: Optional[dict] = None,
124
- timeout: Optional[int] = None,
123
+ scan_parameters: dict | None = None,
124
+ timeout: int | None = None,
125
125
  ) -> None:
126
126
  cycode_client = ctx.obj['client']
127
127
  scan_type = ctx.obj['scan_type']
@@ -265,7 +265,7 @@ def _scan_sca_commit_range(ctx: typer.Context, repo_path: str, commit_range: str
265
265
 
266
266
 
267
267
  def _scan_secret_commit_range(
268
- ctx: typer.Context, repo_path: str, commit_range: str, max_commits_count: Optional[int] = None
268
+ ctx: typer.Context, repo_path: str, commit_range: str, max_commits_count: int | None = None
269
269
  ) -> None:
270
270
  commit_diff_documents_to_scan = collect_commit_range_diff_documents(ctx, repo_path, commit_range, max_commits_count)
271
271
  diff_documents_to_scan = excluder.exclude_irrelevant_documents_to_scan(
@@ -329,7 +329,7 @@ def _scan_sca_pre_commit(
329
329
  repo_path: str,
330
330
  base_ref: str = consts.GIT_HEAD_COMMIT_REV,
331
331
  include_unstaged: bool = False,
332
- paths: Optional[list[str]] = None,
332
+ paths: list[str] | None = None,
333
333
  ) -> None:
334
334
  scan_parameters = get_scan_parameters(ctx, (repo_path,))
335
335
 
@@ -367,7 +367,7 @@ def _scan_secret_pre_commit(
367
367
  repo_path: str,
368
368
  base_ref: str = consts.GIT_HEAD_COMMIT_REV,
369
369
  include_unstaged: bool = False,
370
- paths: Optional[list[str]] = None,
370
+ paths: list[str] | None = None,
371
371
  ) -> None:
372
372
  # collect_file_contents=False: the secret scan only ever uses diff_documents below, so skip
373
373
  # building from_ref_documents/working_copy_documents (a disk read per changed file it would
@@ -395,7 +395,7 @@ def _scan_sast_pre_commit(
395
395
  repo_path: str,
396
396
  base_ref: str = consts.GIT_HEAD_COMMIT_REV,
397
397
  include_unstaged: bool = False,
398
- paths: Optional[list[str]] = None,
398
+ paths: list[str] | None = None,
399
399
  **_,
400
400
  ) -> None:
401
401
  scan_parameters = get_scan_parameters(ctx, (repo_path,))
@@ -435,7 +435,7 @@ def scan_pre_commit(
435
435
  repo_path: str,
436
436
  base_ref: str = consts.GIT_HEAD_COMMIT_REV,
437
437
  include_unstaged: bool = False,
438
- paths: Optional[list[str]] = None,
438
+ paths: list[str] | None = None,
439
439
  ) -> None:
440
440
  scan_type = ctx.obj['scan_type']
441
441
  if scan_type not in _SCAN_TYPE_TO_PRE_COMMIT_HANDLER:
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  from cycode.cli import consts
4
2
  from cycode.cli.cli_types import SeverityOption
5
3
  from cycode.cli.config import configuration_manager
@@ -116,7 +114,7 @@ def _is_detection_sha_configured_in_exclusions(detection: Detection, exclusions:
116
114
  return detection_sha in exclusions
117
115
 
118
116
 
119
- def _get_package_name(detection: Detection) -> Optional[str]:
117
+ def _get_package_name(detection: Detection) -> str | None:
120
118
  package_name = detection.detection_details.get('vulnerable_component')
121
119
  package_version = detection.detection_details.get('vulnerable_component_version')
122
120
 
@@ -130,7 +128,7 @@ def _get_package_name(detection: Detection) -> Optional[str]:
130
128
  return None
131
129
 
132
130
 
133
- def _get_cve_identifier(detection: Detection) -> Optional[str]:
131
+ def _get_cve_identifier(detection: Detection) -> str | None:
134
132
  return detection.detection_details.get('alert', {}).get('cve_identifier')
135
133
 
136
134
 
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from pathlib import Path
3
- from typing import Annotated, Optional
3
+ from typing import Annotated
4
4
 
5
5
  import typer
6
6
 
@@ -47,7 +47,7 @@ def _validate_base_ref(repo_path: str, base_ref: str) -> None:
47
47
 
48
48
  def pre_commit_command(
49
49
  ctx: typer.Context,
50
- _: Annotated[Optional[list[str]], typer.Argument(help='Ignored arguments', hidden=True)] = None,
50
+ _: Annotated[list[str] | None, typer.Argument(help='Ignored arguments', hidden=True)] = None,
51
51
  base_ref: Annotated[
52
52
  str,
53
53
  typer.Option(
@@ -66,7 +66,7 @@ def pre_commit_command(
66
66
  ),
67
67
  ] = False,
68
68
  paths: Annotated[
69
- Optional[list[Path]],
69
+ list[Path] | None,
70
70
  typer.Option(
71
71
  '--path',
72
72
  help='Optional paths to scope the diff scan to (e.g. the file currently open in an IDE). '
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import os
3
- from typing import Annotated, Optional
3
+ from typing import Annotated
4
4
 
5
5
  import typer
6
6
 
@@ -28,7 +28,7 @@ from cycode.logger import set_logging_level
28
28
 
29
29
  def pre_push_command(
30
30
  ctx: typer.Context,
31
- _: Annotated[Optional[list[str]], typer.Argument(help='Ignored arguments', hidden=True)] = None,
31
+ _: Annotated[list[str] | None, typer.Argument(help='Ignored arguments', hidden=True)] = None,
32
32
  ) -> None:
33
33
  try:
34
34
  if should_skip_pre_receive_scan():
@@ -63,7 +63,7 @@ def pre_push_command(
63
63
  handle_scan_exception(ctx, e)
64
64
 
65
65
 
66
- def _get_pre_push_commit_range() -> Optional[str]:
66
+ def _get_pre_push_commit_range() -> str | None:
67
67
  commit_range = get_pre_commit_framework_push_range()
68
68
  if commit_range:
69
69
  logger.debug('Using push details from the pre-commit framework, %s', {'commit_range': commit_range})
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import os
3
- from typing import Annotated, Optional
3
+ from typing import Annotated
4
4
 
5
5
  import typer
6
6
 
@@ -25,7 +25,7 @@ from cycode.logger import set_logging_level
25
25
 
26
26
  def pre_receive_command(
27
27
  ctx: typer.Context,
28
- _: Annotated[Optional[list[str]], typer.Argument(help='Ignored arguments', hidden=True)] = None,
28
+ _: Annotated[list[str] | None, typer.Argument(help='Ignored arguments', hidden=True)] = None,
29
29
  ) -> None:
30
30
  try:
31
31
  if should_skip_pre_receive_scan():