cycode 3.24.3.dev2__tar.gz → 3.25.0__tar.gz
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-3.24.3.dev2 → cycode-3.25.0}/PKG-INFO +38 -7
- {cycode-3.24.3.dev2 → cycode-3.25.0}/README.md +37 -6
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/__init__.py +1 -1
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/__init__.py +2 -1
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/commit_range_scanner.py +70 -48
- cycode-3.25.0/cycode/cli/apps/scan/pre_commit/pre_commit_command.py +100 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/exceptions/custom_exceptions.py +19 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/exceptions/handle_scan_errors.py +10 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/commit_range_documents.py +87 -13
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/sca_file_collector.py +11 -4
- {cycode-3.24.3.dev2 → cycode-3.25.0}/pyproject.toml +1 -1
- cycode-3.24.3.dev2/cycode/cli/apps/scan/pre_commit/pre_commit_command.py +0 -18
- {cycode-3.24.3.dev2 → cycode-3.25.0}/LICENCE +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/__main__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/app.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/activation_manager.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/command_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/consts.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/hooks_manager.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/ides/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/ides/_plugin_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/ides/_skill_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/ides/base.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/ides/claude_code.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/ides/codex.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/ides/copilot.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/ides/cursor.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/install_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/consts.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/detach.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/guardrail_config.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/handlers.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/payload.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/policy.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/scan_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/types.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/scan/utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/session_start_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/status_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_guardrails/uninstall_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_remediation/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_remediation/ai_remediation_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_remediation/apply_fix.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ai_remediation/print_remediation.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/api/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/api/api_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/api/openapi_spec.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/auth/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/auth/auth_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/auth/auth_common.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/auth/auth_manager.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/auth/models.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/configure/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/configure/configure_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/configure/consts.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/configure/messages.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/configure/prompts.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ignore/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/ignore/ignore_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/mcp/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/mcp/mcp_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/report_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/sbom/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/sbom/common.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/sbom/path/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/sbom/path/path_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/sbom/repository_url/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/sbom/repository_url/repository_url_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/sbom/sbom_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report/sbom/sbom_report_file.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report_import/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report_import/report_import_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report_import/sbom/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/report_import/sbom/sbom_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/sca_options.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/aggregation_report.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/code_scanner.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/commit_history/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/commit_history/commit_history_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/detection_excluder.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/path/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/path/path_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/pre_commit/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/pre_push/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/pre_push/pre_push_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/pre_receive/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/pre_receive/pre_receive_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/remote_url_resolver.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/repository/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/repository/repository_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/scan_ci/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/scan_ci/ci_integrations.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/scan_ci/scan_ci_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/scan_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/scan_parameters.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/scan/scan_result.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/status/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/status/get_cli_status.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/status/models.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/status/status_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/apps/status/version_command.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/cli_types.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/config.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/console.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/consts.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/exceptions/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/exceptions/handle_ai_remediation_errors.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/exceptions/handle_auth_errors.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/exceptions/handle_errors.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/exceptions/handle_report_sbom_errors.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/documents_walk_ignore.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/file_excluder.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/iac/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/iac/tf_content_generator.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/models/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/models/in_memory_zip.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/path_documents.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/repository_documents.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/base_restore_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/go/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/go/restore_go_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/maven/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/npm/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/npm/restore_bun_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/npm/restore_deno_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/npm/restore_pnpm_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/npm/restore_yarn_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/nuget/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/php/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/php/restore_composer_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/python/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/python/restore_pip_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/python/restore_pipenv_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/python/restore_poetry_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/python/restore_uv_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/ruby/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/sbt/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/walk_ignore.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/files_collector/zip_documents.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/logger.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/main.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/models.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/console_printer.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/json_printer.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/printer_base.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/rich_printer.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/tables/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/tables/sca_table_printer.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/tables/table.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/tables/table_models.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/tables/table_printer.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/tables/table_printer_base.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/text_printer.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/code_snippet_syntax.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/detection_data.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/detection_ordering/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/detection_ordering/common_ordering.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/detection_ordering/sca_ordering.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/rich_helpers.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/sca_ossf.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/printers/utils/sca_policy_details.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/user_settings/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/user_settings/base_file_manager.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/user_settings/config_file_manager.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/user_settings/configuration_manager.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/user_settings/credentials_manager.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/user_settings/jwt_creator.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/binary_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/enum_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/get_api_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/git_proxy.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/host_info.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/ignore_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/jwt_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/path_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/progress_bar.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/scan_batch.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/scan_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/shell_executor.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/string_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/task_timer.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/trust_store.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/url_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/version_checker.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cli/utils/yaml_utils.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/config.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/__init__.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/ai_security_manager_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/ai_security_manager_service_config.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/auth_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/base_token_auth_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/cli_activation_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/client_creator.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/config.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/config_dev.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/cycode_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/cycode_client_base.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/cycode_dev_based_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/cycode_oidc_based_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/cycode_token_based_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/headers.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/import_sbom_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/logger.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/models.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/report_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/scan_client.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/cyclient/scan_config_base.py +0 -0
- {cycode-3.24.3.dev2 → cycode-3.25.0}/cycode/logger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cycode
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.25.0
|
|
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
|
|
@@ -94,6 +94,7 @@ This guide walks you through both installation and usage.
|
|
|
94
94
|
4. [Commit History Scan](#commit-history-scan)
|
|
95
95
|
1. [Commit Range Option (Diff Scanning)](#commit-range-option-diff-scanning)
|
|
96
96
|
5. [Pre-Commit Scan](#pre-commit-scan)
|
|
97
|
+
1. [Local Diff Scanning (IDE Integrations)](#local-diff-scanning-ide-integrations)
|
|
97
98
|
6. [Pre-Push Scan](#pre-push-scan)
|
|
98
99
|
2. [Scan Results](#scan-results)
|
|
99
100
|
1. [Show/Hide Secrets](#showhide-secrets)
|
|
@@ -844,12 +845,12 @@ The Cycode CLI application offers several types of scans so that you can choose
|
|
|
844
845
|
| `--maven-settings-file` | For Maven only, allows using a custom [settings.xml](https://maven.apache.org/settings.html) file when scanning for dependencies |
|
|
845
846
|
| `--help` | Show options for given command. |
|
|
846
847
|
|
|
847
|
-
| Command | Description
|
|
848
|
-
|
|
849
|
-
| [commit-history](#commit-history-scan) | Scan commit history or perform diff scanning between specific commits
|
|
850
|
-
| [path](#path-scan) | Scan the files in the path supplied in the command
|
|
851
|
-
| [pre-commit](#pre-commit-scan) |
|
|
852
|
-
| [repository](#repository-scan) | Scan git repository including its history
|
|
848
|
+
| Command | Description |
|
|
849
|
+
|-----------------------------------------|----------------------------------------------------------------------------------------------------|
|
|
850
|
+
| [commit-history](#commit-history-scan) | Scan commit history or perform diff scanning between specific commits |
|
|
851
|
+
| [path](#path-scan) | Scan the files in the path supplied in the command |
|
|
852
|
+
| [pre-commit](#pre-commit-scan) | Scan content that was not committed yet; also supports local diff scanning via flags (IDE-friendly) |
|
|
853
|
+
| [repository](#repository-scan) | Scan git repository including its history |
|
|
853
854
|
|
|
854
855
|
### Options
|
|
855
856
|
|
|
@@ -1131,6 +1132,36 @@ After installing the pre-commit hook, you may occasionally wish to skip scanning
|
|
|
1131
1132
|
SKIP=cycode git commit -m <your commit message>`
|
|
1132
1133
|
```
|
|
1133
1134
|
|
|
1135
|
+
The following options are available for use with this command:
|
|
1136
|
+
|
|
1137
|
+
| Option | Description |
|
|
1138
|
+
|-----------------------|---------------------------------------------------------------------------------------------------------------------|
|
|
1139
|
+
| `-b, --base-ref TEXT` | Git ref (commit, branch, or tag) to diff against; defaults to `HEAD`, matching the pre-commit hook behavior |
|
|
1140
|
+
| `--include-unstaged` | Also scan unstaged changes to tracked files, not just what is staged; off by default |
|
|
1141
|
+
| `--path PATH` | Optional path(s) to scope the diff scan to; repeatable; defaults to the entire working directory |
|
|
1142
|
+
|
|
1143
|
+
#### Local Diff Scanning (IDE Integrations)
|
|
1144
|
+
|
|
1145
|
+
`--base-ref` and `--include-unstaged` turn `pre-commit` into a general-purpose **local diff scan**: comparing any commit (default `HEAD`) against your current working directory — including edits that aren't staged yet. This is intended for IDE plugins and other tools that need continuous, real-time feedback as you work, rather than the git hook flow. Combined with `--include-unstaged`, `--path` lets an IDE scope the scan to just the file currently open in the editor.
|
|
1146
|
+
|
|
1147
|
+
> [!NOTE]
|
|
1148
|
+
> Local diff scanning (via these flags) is not available for IaC scans.
|
|
1149
|
+
|
|
1150
|
+
**Scan everything currently changed (staged + unstaged) against the last commit:**
|
|
1151
|
+
```bash
|
|
1152
|
+
cycode scan pre-commit --include-unstaged
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
**Scan changes against a specific commit or branch:**
|
|
1156
|
+
```bash
|
|
1157
|
+
cycode scan pre-commit --include-unstaged --base-ref main
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
**Scan only a specific file (e.g., the file currently open in your IDE):**
|
|
1161
|
+
```bash
|
|
1162
|
+
cycode scan pre-commit --include-unstaged --path src/app.py
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1134
1165
|
### Pre-Push Scan
|
|
1135
1166
|
|
|
1136
1167
|
A pre-push scan automatically identifies any issues before you push changes to the remote repository. This hook runs on the client side and scans only the commits that are about to be pushed, making it efficient for catching issues before they reach the remote repository.
|
|
@@ -48,6 +48,7 @@ This guide walks you through both installation and usage.
|
|
|
48
48
|
4. [Commit History Scan](#commit-history-scan)
|
|
49
49
|
1. [Commit Range Option (Diff Scanning)](#commit-range-option-diff-scanning)
|
|
50
50
|
5. [Pre-Commit Scan](#pre-commit-scan)
|
|
51
|
+
1. [Local Diff Scanning (IDE Integrations)](#local-diff-scanning-ide-integrations)
|
|
51
52
|
6. [Pre-Push Scan](#pre-push-scan)
|
|
52
53
|
2. [Scan Results](#scan-results)
|
|
53
54
|
1. [Show/Hide Secrets](#showhide-secrets)
|
|
@@ -798,12 +799,12 @@ The Cycode CLI application offers several types of scans so that you can choose
|
|
|
798
799
|
| `--maven-settings-file` | For Maven only, allows using a custom [settings.xml](https://maven.apache.org/settings.html) file when scanning for dependencies |
|
|
799
800
|
| `--help` | Show options for given command. |
|
|
800
801
|
|
|
801
|
-
| Command | Description
|
|
802
|
-
|
|
803
|
-
| [commit-history](#commit-history-scan) | Scan commit history or perform diff scanning between specific commits
|
|
804
|
-
| [path](#path-scan) | Scan the files in the path supplied in the command
|
|
805
|
-
| [pre-commit](#pre-commit-scan) |
|
|
806
|
-
| [repository](#repository-scan) | Scan git repository including its history
|
|
802
|
+
| Command | Description |
|
|
803
|
+
|-----------------------------------------|----------------------------------------------------------------------------------------------------|
|
|
804
|
+
| [commit-history](#commit-history-scan) | Scan commit history or perform diff scanning between specific commits |
|
|
805
|
+
| [path](#path-scan) | Scan the files in the path supplied in the command |
|
|
806
|
+
| [pre-commit](#pre-commit-scan) | Scan content that was not committed yet; also supports local diff scanning via flags (IDE-friendly) |
|
|
807
|
+
| [repository](#repository-scan) | Scan git repository including its history |
|
|
807
808
|
|
|
808
809
|
### Options
|
|
809
810
|
|
|
@@ -1085,6 +1086,36 @@ After installing the pre-commit hook, you may occasionally wish to skip scanning
|
|
|
1085
1086
|
SKIP=cycode git commit -m <your commit message>`
|
|
1086
1087
|
```
|
|
1087
1088
|
|
|
1089
|
+
The following options are available for use with this command:
|
|
1090
|
+
|
|
1091
|
+
| Option | Description |
|
|
1092
|
+
|-----------------------|---------------------------------------------------------------------------------------------------------------------|
|
|
1093
|
+
| `-b, --base-ref TEXT` | Git ref (commit, branch, or tag) to diff against; defaults to `HEAD`, matching the pre-commit hook behavior |
|
|
1094
|
+
| `--include-unstaged` | Also scan unstaged changes to tracked files, not just what is staged; off by default |
|
|
1095
|
+
| `--path PATH` | Optional path(s) to scope the diff scan to; repeatable; defaults to the entire working directory |
|
|
1096
|
+
|
|
1097
|
+
#### Local Diff Scanning (IDE Integrations)
|
|
1098
|
+
|
|
1099
|
+
`--base-ref` and `--include-unstaged` turn `pre-commit` into a general-purpose **local diff scan**: comparing any commit (default `HEAD`) against your current working directory — including edits that aren't staged yet. This is intended for IDE plugins and other tools that need continuous, real-time feedback as you work, rather than the git hook flow. Combined with `--include-unstaged`, `--path` lets an IDE scope the scan to just the file currently open in the editor.
|
|
1100
|
+
|
|
1101
|
+
> [!NOTE]
|
|
1102
|
+
> Local diff scanning (via these flags) is not available for IaC scans.
|
|
1103
|
+
|
|
1104
|
+
**Scan everything currently changed (staged + unstaged) against the last commit:**
|
|
1105
|
+
```bash
|
|
1106
|
+
cycode scan pre-commit --include-unstaged
|
|
1107
|
+
```
|
|
1108
|
+
|
|
1109
|
+
**Scan changes against a specific commit or branch:**
|
|
1110
|
+
```bash
|
|
1111
|
+
cycode scan pre-commit --include-unstaged --base-ref main
|
|
1112
|
+
```
|
|
1113
|
+
|
|
1114
|
+
**Scan only a specific file (e.g., the file currently open in your IDE):**
|
|
1115
|
+
```bash
|
|
1116
|
+
cycode scan pre-commit --include-unstaged --path src/app.py
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1088
1119
|
### Pre-Push Scan
|
|
1089
1120
|
|
|
1090
1121
|
A pre-push scan automatically identifies any issues before you push changes to the remote repository. This hook runs on the client side and scans only the commits that are about to be pushed, making it efficient for catching issues before they reach the remote repository.
|
|
@@ -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.
|
|
8
|
+
__version__ = '3.25.0' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
|
|
@@ -28,7 +28,8 @@ app.command(name='commit-history', short_help='Scan commit history or perform di
|
|
|
28
28
|
)
|
|
29
29
|
app.command(
|
|
30
30
|
name='pre-commit',
|
|
31
|
-
short_help='Use this command in pre-commit hook to scan any content that was not committed yet.'
|
|
31
|
+
short_help='Use this command in pre-commit hook to scan any content that was not committed yet. '
|
|
32
|
+
'Also supports IDE-style local diff scanning via --base-ref/--include-unstaged/--path.',
|
|
32
33
|
rich_help_panel=_AUTOMATION_COMMANDS_RICH_HELP_PANEL,
|
|
33
34
|
)(pre_commit_command)
|
|
34
35
|
app.command(
|
|
@@ -24,10 +24,7 @@ from cycode.cli.exceptions.handle_scan_errors import handle_scan_exception
|
|
|
24
24
|
from cycode.cli.files_collector.commit_range_documents import (
|
|
25
25
|
collect_commit_range_diff_documents,
|
|
26
26
|
get_commit_range_modified_documents,
|
|
27
|
-
get_diff_file_content,
|
|
28
|
-
get_diff_file_path,
|
|
29
27
|
get_pre_commit_modified_documents,
|
|
30
|
-
get_staged_diff_index,
|
|
31
28
|
parse_commit_range,
|
|
32
29
|
)
|
|
33
30
|
from cycode.cli.files_collector.documents_walk_ignore import filter_documents_with_cycodeignore
|
|
@@ -35,12 +32,10 @@ from cycode.cli.files_collector.file_excluder import excluder
|
|
|
35
32
|
from cycode.cli.files_collector.models.in_memory_zip import InMemoryZip
|
|
36
33
|
from cycode.cli.files_collector.sca.sca_file_collector import (
|
|
37
34
|
perform_sca_pre_commit_range_scan_actions,
|
|
38
|
-
|
|
35
|
+
perform_sca_pre_commit_scan_actions,
|
|
39
36
|
)
|
|
40
37
|
from cycode.cli.files_collector.zip_documents import zip_documents
|
|
41
38
|
from cycode.cli.models import Document
|
|
42
|
-
from cycode.cli.utils.git_proxy import git_proxy
|
|
43
|
-
from cycode.cli.utils.path_utils import get_path_by_os
|
|
44
39
|
from cycode.cli.utils.progress_bar import ScanProgressBarSection
|
|
45
40
|
from cycode.cli.utils.scan_utils import (
|
|
46
41
|
generate_unique_scan_id,
|
|
@@ -329,84 +324,103 @@ def scan_commit_range(ctx: typer.Context, repo_path: str, commit_range: str, **k
|
|
|
329
324
|
_SCAN_TYPE_TO_COMMIT_RANGE_HANDLER[scan_type](ctx, repo_path, commit_range, **kwargs)
|
|
330
325
|
|
|
331
326
|
|
|
332
|
-
def _scan_sca_pre_commit(
|
|
333
|
-
|
|
327
|
+
def _scan_sca_pre_commit(
|
|
328
|
+
ctx: typer.Context,
|
|
329
|
+
repo_path: str,
|
|
330
|
+
base_ref: str = consts.GIT_HEAD_COMMIT_REV,
|
|
331
|
+
include_unstaged: bool = False,
|
|
332
|
+
paths: Optional[list[str]] = None,
|
|
333
|
+
) -> None:
|
|
334
|
+
scan_parameters = get_scan_parameters(ctx, (repo_path,))
|
|
334
335
|
|
|
335
|
-
|
|
336
|
+
from_ref_documents, working_copy_documents, _diff_documents = get_pre_commit_modified_documents(
|
|
336
337
|
progress_bar=ctx.obj['progress_bar'],
|
|
337
338
|
progress_bar_section=ScanProgressBarSection.PREPARE_LOCAL_FILES,
|
|
338
339
|
repo_path=repo_path,
|
|
340
|
+
base_ref=base_ref,
|
|
341
|
+
include_unstaged=include_unstaged,
|
|
342
|
+
paths=paths,
|
|
339
343
|
)
|
|
340
344
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
consts.SCA_SCAN_TYPE, pre_committed_documents
|
|
344
|
-
)
|
|
345
|
+
from_ref_documents = excluder.exclude_irrelevant_documents_to_scan(consts.SCA_SCAN_TYPE, from_ref_documents)
|
|
346
|
+
working_copy_documents = excluder.exclude_irrelevant_documents_to_scan(consts.SCA_SCAN_TYPE, working_copy_documents)
|
|
345
347
|
|
|
346
348
|
is_cycodeignore_allowed = is_cycodeignore_allowed_by_scan_config(ctx)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
349
|
+
from_ref_documents = filter_documents_with_cycodeignore(from_ref_documents, repo_path, is_cycodeignore_allowed)
|
|
350
|
+
working_copy_documents = filter_documents_with_cycodeignore(
|
|
351
|
+
working_copy_documents, repo_path, is_cycodeignore_allowed
|
|
350
352
|
)
|
|
351
353
|
|
|
352
|
-
|
|
354
|
+
perform_sca_pre_commit_scan_actions(repo_path, from_ref_documents, base_ref, working_copy_documents)
|
|
353
355
|
|
|
354
356
|
_scan_commit_range_documents(
|
|
355
357
|
ctx,
|
|
356
|
-
|
|
357
|
-
|
|
358
|
+
from_ref_documents,
|
|
359
|
+
working_copy_documents,
|
|
358
360
|
scan_parameters,
|
|
359
361
|
configuration_manager.get_sca_pre_commit_timeout_in_seconds(),
|
|
360
362
|
)
|
|
361
363
|
|
|
362
364
|
|
|
363
|
-
def _scan_secret_pre_commit(
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
365
|
+
def _scan_secret_pre_commit(
|
|
366
|
+
ctx: typer.Context,
|
|
367
|
+
repo_path: str,
|
|
368
|
+
base_ref: str = consts.GIT_HEAD_COMMIT_REV,
|
|
369
|
+
include_unstaged: bool = False,
|
|
370
|
+
paths: Optional[list[str]] = None,
|
|
371
|
+
) -> None:
|
|
372
|
+
# collect_file_contents=False: the secret scan only ever uses diff_documents below, so skip
|
|
373
|
+
# building from_ref_documents/working_copy_documents (a disk read per changed file it would
|
|
374
|
+
# otherwise discard immediately).
|
|
375
|
+
_from_ref_documents, _working_copy_documents, diff_documents = get_pre_commit_modified_documents(
|
|
376
|
+
progress_bar=ctx.obj['progress_bar'],
|
|
377
|
+
progress_bar_section=ScanProgressBarSection.PREPARE_LOCAL_FILES,
|
|
378
|
+
repo_path=repo_path,
|
|
379
|
+
base_ref=base_ref,
|
|
380
|
+
include_unstaged=include_unstaged,
|
|
381
|
+
paths=paths,
|
|
382
|
+
collect_file_contents=False,
|
|
383
|
+
)
|
|
380
384
|
|
|
381
|
-
|
|
385
|
+
diff_documents = excluder.exclude_irrelevant_documents_to_scan(consts.SECRET_SCAN_TYPE, diff_documents)
|
|
382
386
|
|
|
383
387
|
is_cycodeignore_allowed = is_cycodeignore_allowed_by_scan_config(ctx)
|
|
384
|
-
|
|
388
|
+
diff_documents = filter_documents_with_cycodeignore(diff_documents, repo_path, is_cycodeignore_allowed)
|
|
385
389
|
|
|
386
|
-
scan_documents(ctx,
|
|
390
|
+
scan_documents(ctx, diff_documents, get_scan_parameters(ctx, (repo_path,)), is_git_diff=True)
|
|
387
391
|
|
|
388
392
|
|
|
389
|
-
def _scan_sast_pre_commit(
|
|
393
|
+
def _scan_sast_pre_commit(
|
|
394
|
+
ctx: typer.Context,
|
|
395
|
+
repo_path: str,
|
|
396
|
+
base_ref: str = consts.GIT_HEAD_COMMIT_REV,
|
|
397
|
+
include_unstaged: bool = False,
|
|
398
|
+
paths: Optional[list[str]] = None,
|
|
399
|
+
**_,
|
|
400
|
+
) -> None:
|
|
390
401
|
scan_parameters = get_scan_parameters(ctx, (repo_path,))
|
|
391
402
|
|
|
392
|
-
|
|
403
|
+
_from_ref_documents, working_copy_documents, diff_documents = get_pre_commit_modified_documents(
|
|
393
404
|
progress_bar=ctx.obj['progress_bar'],
|
|
394
405
|
progress_bar_section=ScanProgressBarSection.PREPARE_LOCAL_FILES,
|
|
395
406
|
repo_path=repo_path,
|
|
407
|
+
base_ref=base_ref,
|
|
408
|
+
include_unstaged=include_unstaged,
|
|
409
|
+
paths=paths,
|
|
396
410
|
)
|
|
397
411
|
|
|
398
|
-
|
|
399
|
-
consts.SAST_SCAN_TYPE,
|
|
412
|
+
working_copy_documents = excluder.exclude_irrelevant_documents_to_scan(
|
|
413
|
+
consts.SAST_SCAN_TYPE, working_copy_documents
|
|
400
414
|
)
|
|
401
415
|
diff_documents = excluder.exclude_irrelevant_documents_to_scan(consts.SAST_SCAN_TYPE, diff_documents)
|
|
402
416
|
|
|
403
417
|
is_cycodeignore_allowed = is_cycodeignore_allowed_by_scan_config(ctx)
|
|
404
|
-
|
|
405
|
-
|
|
418
|
+
working_copy_documents = filter_documents_with_cycodeignore(
|
|
419
|
+
working_copy_documents, repo_path, is_cycodeignore_allowed
|
|
406
420
|
)
|
|
407
421
|
diff_documents = filter_documents_with_cycodeignore(diff_documents, repo_path, is_cycodeignore_allowed)
|
|
408
422
|
|
|
409
|
-
_scan_commit_range_documents(ctx,
|
|
423
|
+
_scan_commit_range_documents(ctx, working_copy_documents, diff_documents, scan_parameters=scan_parameters)
|
|
410
424
|
|
|
411
425
|
|
|
412
426
|
_SCAN_TYPE_TO_PRE_COMMIT_HANDLER = {
|
|
@@ -416,10 +430,18 @@ _SCAN_TYPE_TO_PRE_COMMIT_HANDLER = {
|
|
|
416
430
|
}
|
|
417
431
|
|
|
418
432
|
|
|
419
|
-
def scan_pre_commit(
|
|
433
|
+
def scan_pre_commit(
|
|
434
|
+
ctx: typer.Context,
|
|
435
|
+
repo_path: str,
|
|
436
|
+
base_ref: str = consts.GIT_HEAD_COMMIT_REV,
|
|
437
|
+
include_unstaged: bool = False,
|
|
438
|
+
paths: Optional[list[str]] = None,
|
|
439
|
+
) -> None:
|
|
420
440
|
scan_type = ctx.obj['scan_type']
|
|
421
441
|
if scan_type not in _SCAN_TYPE_TO_PRE_COMMIT_HANDLER:
|
|
422
442
|
raise click.ClickException(f'Pre-commit scanning for {scan_type.upper()} is not supported')
|
|
423
443
|
|
|
424
|
-
_SCAN_TYPE_TO_PRE_COMMIT_HANDLER[scan_type](
|
|
444
|
+
_SCAN_TYPE_TO_PRE_COMMIT_HANDLER[scan_type](
|
|
445
|
+
ctx, repo_path, base_ref=base_ref, include_unstaged=include_unstaged, paths=paths
|
|
446
|
+
)
|
|
425
447
|
logger.debug('Pre-commit scan completed successfully')
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Annotated, Optional
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from cycode.cli import consts
|
|
8
|
+
from cycode.cli.apps.scan.commit_range_scanner import scan_pre_commit
|
|
9
|
+
from cycode.cli.exceptions.custom_exceptions import ScanPathOutsideRepositoryError, UnresolvedGitRefError
|
|
10
|
+
from cycode.cli.exceptions.handle_scan_errors import handle_scan_exception
|
|
11
|
+
from cycode.cli.logger import logger
|
|
12
|
+
from cycode.cli.utils.git_proxy import git_proxy
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _resolve_repo_root(cwd: str) -> str:
|
|
16
|
+
"""Resolve the repository root from `cwd`, which may be any subdirectory of the repo.
|
|
17
|
+
|
|
18
|
+
`git_proxy.get_repo()` requires an exact match (the root or a `.git` dir) unless told to
|
|
19
|
+
search parent directories, so without this, running the command from anywhere but the repo
|
|
20
|
+
root raises a misleading "not a git repository" error. The git pre-commit hook framework
|
|
21
|
+
always invokes from the repo root, so this is a no-op there; it matters for IDE-style
|
|
22
|
+
invocations (--include-unstaged etc.), which may run from any subdirectory.
|
|
23
|
+
"""
|
|
24
|
+
repo = git_proxy.get_repo(cwd, search_parent_directories=True)
|
|
25
|
+
return repo.working_tree_dir or cwd
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _validate_base_ref(repo_path: str, base_ref: str) -> None:
|
|
29
|
+
"""Raise a clear, user-facing error for an unresolvable `--base-ref`.
|
|
30
|
+
|
|
31
|
+
A repository with no commits at all is a valid state (the diff falls back to comparing
|
|
32
|
+
against the empty tree), so validation is skipped in that case.
|
|
33
|
+
"""
|
|
34
|
+
repo = git_proxy.get_repo(repo_path)
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
repo.rev_parse(consts.GIT_HEAD_COMMIT_REV)
|
|
38
|
+
except Exception as e:
|
|
39
|
+
logger.debug('Repository has no commits yet; skipping --base-ref validation', exc_info=e)
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
repo.commit(base_ref)
|
|
44
|
+
except Exception as e:
|
|
45
|
+
raise UnresolvedGitRefError(base_ref) from e
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def pre_commit_command(
|
|
49
|
+
ctx: typer.Context,
|
|
50
|
+
_: Annotated[Optional[list[str]], typer.Argument(help='Ignored arguments', hidden=True)] = None,
|
|
51
|
+
base_ref: Annotated[
|
|
52
|
+
str,
|
|
53
|
+
typer.Option(
|
|
54
|
+
'--base-ref',
|
|
55
|
+
'-b',
|
|
56
|
+
help='Git ref (commit, branch, or tag) to diff against. Defaults to HEAD, matching the '
|
|
57
|
+
'pre-commit hook behavior. Combine with --include-unstaged for IDE-style local diff scanning.',
|
|
58
|
+
),
|
|
59
|
+
] = consts.GIT_HEAD_COMMIT_REV,
|
|
60
|
+
include_unstaged: Annotated[
|
|
61
|
+
bool,
|
|
62
|
+
typer.Option(
|
|
63
|
+
'--include-unstaged',
|
|
64
|
+
help='Also scan unstaged changes to tracked files, not just what is staged. '
|
|
65
|
+
'Off by default, so the pre-commit hook flow is unaffected.',
|
|
66
|
+
),
|
|
67
|
+
] = False,
|
|
68
|
+
paths: Annotated[
|
|
69
|
+
Optional[list[Path]],
|
|
70
|
+
typer.Option(
|
|
71
|
+
'--path',
|
|
72
|
+
help='Optional paths to scope the diff scan to (e.g. the file currently open in an IDE). '
|
|
73
|
+
'Defaults to the entire working directory. Repeatable.',
|
|
74
|
+
show_default=False,
|
|
75
|
+
resolve_path=True,
|
|
76
|
+
),
|
|
77
|
+
] = None,
|
|
78
|
+
) -> None:
|
|
79
|
+
try:
|
|
80
|
+
repo_path = _resolve_repo_root(os.getcwd())
|
|
81
|
+
_validate_base_ref(repo_path, base_ref)
|
|
82
|
+
str_paths = [str(path) for path in paths] if paths else None
|
|
83
|
+
# realpath both sides: repo_path (from GitPython) and str_path (from Click's
|
|
84
|
+
# resolve_path=True) can disagree on 8.3 short-name vs long-name form on Windows,
|
|
85
|
+
# which would otherwise make an in-repo path look like it's outside the repo.
|
|
86
|
+
repo_path_real = os.path.realpath(repo_path)
|
|
87
|
+
for str_path in str_paths or []:
|
|
88
|
+
if os.path.commonpath([repo_path_real, os.path.realpath(str_path)]) != repo_path_real:
|
|
89
|
+
raise ScanPathOutsideRepositoryError(str_path, repo_path)
|
|
90
|
+
except Exception as e:
|
|
91
|
+
handle_scan_exception(ctx, e)
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
progress_bar = ctx.obj['progress_bar']
|
|
95
|
+
progress_bar.start()
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
scan_pre_commit(ctx, repo_path, base_ref=base_ref, include_unstaged=include_unstaged, paths=str_paths)
|
|
99
|
+
except Exception as e:
|
|
100
|
+
handle_scan_exception(ctx, e)
|
|
@@ -103,6 +103,25 @@ class TfplanKeyError(CycodeError):
|
|
|
103
103
|
return f'Error occurred while parsing terraform plan file. Path: {self.file_path}'
|
|
104
104
|
|
|
105
105
|
|
|
106
|
+
class ScanPathOutsideRepositoryError(CycodeError):
|
|
107
|
+
def __init__(self, path: str, repo_path: str) -> None:
|
|
108
|
+
self.path = path
|
|
109
|
+
self.repo_path = repo_path
|
|
110
|
+
super().__init__()
|
|
111
|
+
|
|
112
|
+
def __str__(self) -> str:
|
|
113
|
+
return f'The path {self.path!r} is outside the repository {self.repo_path!r}'
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class UnresolvedGitRefError(CycodeError):
|
|
117
|
+
def __init__(self, ref: str) -> None:
|
|
118
|
+
self.ref = ref
|
|
119
|
+
super().__init__()
|
|
120
|
+
|
|
121
|
+
def __str__(self) -> str:
|
|
122
|
+
return f'Could not resolve git ref: {self.ref!r}'
|
|
123
|
+
|
|
124
|
+
|
|
106
125
|
_SSL_ERROR_CA_BUNDLE_HINT = (
|
|
107
126
|
'set the REQUESTS_CA_BUNDLE (or CURL_CA_BUNDLE) environment variable to the path of a valid .pem or similar'
|
|
108
127
|
)
|
|
@@ -60,6 +60,16 @@ def handle_scan_exception(ctx: typer.Context, err: Exception, *, return_exceptio
|
|
|
60
60
|
message='The path you supplied does not correlate to a Git repository. '
|
|
61
61
|
'If you still wish to scan this path, use: `cycode scan path <path>`',
|
|
62
62
|
),
|
|
63
|
+
custom_exceptions.ScanPathOutsideRepositoryError: CliError(
|
|
64
|
+
soft_fail=False,
|
|
65
|
+
code='invalid_scan_path_error',
|
|
66
|
+
message=f'\n{err!s}\n--path must point to a location inside the scanned repository',
|
|
67
|
+
),
|
|
68
|
+
custom_exceptions.UnresolvedGitRefError: CliError(
|
|
69
|
+
soft_fail=False,
|
|
70
|
+
code='invalid_git_ref_error',
|
|
71
|
+
message=f'\n{err!s}\nPass a commit, branch, or tag that exists in this repository',
|
|
72
|
+
),
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
return handle_errors(ctx, err, errors, return_exception=return_exception)
|
|
@@ -15,7 +15,7 @@ from cycode.cli.utils.progress_bar import ScanProgressBarSection
|
|
|
15
15
|
from cycode.logger import get_logger
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
|
-
from git import Diff, DiffIndex, Repo
|
|
18
|
+
from git import Blob, Diff, DiffIndex, Repo
|
|
19
19
|
|
|
20
20
|
from cycode.cli.utils.progress_bar import BaseProgressBar, ProgressBarSection
|
|
21
21
|
|
|
@@ -47,7 +47,7 @@ def get_safe_head_reference_for_diff(repo: 'Repo') -> str:
|
|
|
47
47
|
return consts.GIT_EMPTY_TREE_OBJECT
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def get_staged_diff_index(repo: 'Repo') -> tuple[str, 'DiffIndex']:
|
|
50
|
+
def get_staged_diff_index(repo: 'Repo', paths: Optional[list[str]] = None) -> tuple[str, 'DiffIndex']:
|
|
51
51
|
"""Diff the index against HEAD, or against the empty tree in repositories with no commits.
|
|
52
52
|
|
|
53
53
|
GitPython only inverts the `R` flag for HEAD, so `R` must be off for the empty tree to keep
|
|
@@ -55,13 +55,14 @@ def get_staged_diff_index(repo: 'Repo') -> tuple[str, 'DiffIndex']:
|
|
|
55
55
|
|
|
56
56
|
Args:
|
|
57
57
|
repo: Git repository object
|
|
58
|
+
paths: Optional pathspec to scope the diff to
|
|
58
59
|
|
|
59
60
|
Returns:
|
|
60
61
|
The reference that was diffed against, and the resulting diff index
|
|
61
62
|
"""
|
|
62
63
|
head_reference = get_safe_head_reference_for_diff(repo)
|
|
63
64
|
reverse = head_reference == consts.GIT_HEAD_COMMIT_REV
|
|
64
|
-
return head_reference, repo.index.diff(head_reference, create_patch=True, R=reverse)
|
|
65
|
+
return head_reference, repo.index.diff(head_reference, create_patch=True, R=reverse, paths=paths or None)
|
|
65
66
|
|
|
66
67
|
|
|
67
68
|
def _does_reach_to_max_commits_to_scan_limit(commit_ids: list[str], max_commits_count: Optional[int]) -> bool:
|
|
@@ -185,6 +186,20 @@ def _get_file_content_from_commit_diff(repo: 'Repo', commit: str, diff: 'Diff')
|
|
|
185
186
|
return get_file_content_from_commit_path(repo, commit, file_path)
|
|
186
187
|
|
|
187
188
|
|
|
189
|
+
def _get_blob_content(blob: Optional['Blob']) -> Optional[str]:
|
|
190
|
+
"""Read a diff-side blob's content in-process, with no subprocess spawn.
|
|
191
|
+
|
|
192
|
+
`diff.a_blob`/`diff.b_blob` already hold whatever git loaded to compute the patch, so this is
|
|
193
|
+
the same content `git show <ref>:<path>` would return -- for every `Diffable.diff()` variant
|
|
194
|
+
(`index.diff(HEAD, R=True)`, `commit.diff()`, `commit.diff(None)`), `a_blob` is exactly the
|
|
195
|
+
"before" side, and it's `None` precisely when the file didn't exist there (e.g. diffed against
|
|
196
|
+
the empty tree for a brand-new repo/file) -- verified against a scratch repo for each variant.
|
|
197
|
+
"""
|
|
198
|
+
if blob is None:
|
|
199
|
+
return None
|
|
200
|
+
return blob.data_stream.read().decode('UTF-8', errors='replace')
|
|
201
|
+
|
|
202
|
+
|
|
188
203
|
def get_commit_range_modified_documents(
|
|
189
204
|
progress_bar: 'BaseProgressBar',
|
|
190
205
|
progress_bar_section: 'ProgressBarSection',
|
|
@@ -453,13 +468,65 @@ def get_pre_commit_modified_documents(
|
|
|
453
468
|
progress_bar: 'BaseProgressBar',
|
|
454
469
|
progress_bar_section: 'ProgressBarSection',
|
|
455
470
|
repo_path: str,
|
|
471
|
+
base_ref: str = consts.GIT_HEAD_COMMIT_REV,
|
|
472
|
+
include_unstaged: bool = False,
|
|
473
|
+
paths: Optional[list[str]] = None,
|
|
474
|
+
collect_file_contents: bool = True,
|
|
456
475
|
) -> tuple[list[Document], list[Document], list[Document]]:
|
|
457
|
-
|
|
458
|
-
|
|
476
|
+
"""Diffs `base_ref` against the staged index (default) or the full working tree.
|
|
477
|
+
|
|
478
|
+
Args:
|
|
479
|
+
base_ref: Git ref to diff against. Defaults to HEAD, matching the pre-commit hook's
|
|
480
|
+
historical behavior exactly.
|
|
481
|
+
include_unstaged: If False (default), diffs the staged index only -- this is the exact
|
|
482
|
+
pre-commit hook flow. If True, diffs the full working tree (staged + unstaged).
|
|
483
|
+
paths: Optional pathspec to scope the diff to.
|
|
484
|
+
collect_file_contents: If False, skip building `from_ref_documents`/`working_copy_documents`
|
|
485
|
+
entirely -- only `diff_documents` (the patch itself) is produced. The secret scan path
|
|
486
|
+
only ever uses `diff_documents`, so this avoids a disk read per changed file (and,
|
|
487
|
+
before the `a_blob` fix below, a subprocess spawn per file) that it would otherwise
|
|
488
|
+
discard immediately. Defaults to True so existing callers (SCA/SAST) are unaffected.
|
|
489
|
+
|
|
490
|
+
Returns:
|
|
491
|
+
(from_ref_documents, working_copy_documents, diff_documents). `from_ref_documents` holds
|
|
492
|
+
each changed file's content at `base_ref` (skipped if it didn't exist there, or was empty);
|
|
493
|
+
`working_copy_documents` holds each changed file's current on-disk content (skipped if
|
|
494
|
+
the file no longer exists, or is empty); `diff_documents` holds the unified diff per
|
|
495
|
+
changed file.
|
|
496
|
+
"""
|
|
497
|
+
from_ref_documents = []
|
|
498
|
+
working_copy_documents = []
|
|
459
499
|
diff_documents = []
|
|
460
500
|
|
|
461
501
|
repo = git_proxy.get_repo(repo_path)
|
|
462
|
-
|
|
502
|
+
|
|
503
|
+
if base_ref == consts.GIT_HEAD_COMMIT_REV and not include_unstaged:
|
|
504
|
+
# The exact pre-commit hook flow, byte-for-byte unchanged: diff the staged index against
|
|
505
|
+
# HEAD (or the empty tree in a brand-new repo), via get_staged_diff_index()'s proven
|
|
506
|
+
# R-flag handling. Keeping this as its own branch (rather than folding it into the
|
|
507
|
+
# `diff_target.diff(...)` calls below) means this default, most-used path can't regress.
|
|
508
|
+
_, diff_index = get_staged_diff_index(repo, paths=paths)
|
|
509
|
+
else:
|
|
510
|
+
try:
|
|
511
|
+
diff_target = repo.commit(base_ref)
|
|
512
|
+
except Exception as e:
|
|
513
|
+
# Repository has no commits yet, or base_ref doesn't resolve; diff against the empty
|
|
514
|
+
# tree instead. (git_proxy.get_null_tree() is only a sentinel usable as the `other`
|
|
515
|
+
# side of a diff, so we resolve the well-known empty tree object itself to diff from.)
|
|
516
|
+
logger.debug(
|
|
517
|
+
'Could not resolve base_ref, falling back to the empty tree, %s', {'base_ref': base_ref}, exc_info=e
|
|
518
|
+
)
|
|
519
|
+
diff_target = repo.tree(consts.GIT_EMPTY_TREE_OBJECT)
|
|
520
|
+
|
|
521
|
+
if include_unstaged:
|
|
522
|
+
diff_index = diff_target.diff(None, create_patch=True, paths=paths or None)
|
|
523
|
+
else:
|
|
524
|
+
# `Diffable.diff()` defaults `other` to the staged index, so omitting it here diffs
|
|
525
|
+
# `base_ref` against the index only -- the same "staged changes against an arbitrary
|
|
526
|
+
# ref" semantics as `git diff --cached <base_ref>`, verified to produce identical,
|
|
527
|
+
# correctly-directed patches.
|
|
528
|
+
diff_index = diff_target.diff(create_patch=True, paths=paths or None)
|
|
529
|
+
|
|
463
530
|
progress_bar.set_section_length(progress_bar_section, len(diff_index))
|
|
464
531
|
for diff in diff_index:
|
|
465
532
|
progress_bar.update(progress_bar_section)
|
|
@@ -474,18 +541,25 @@ def get_pre_commit_modified_documents(
|
|
|
474
541
|
)
|
|
475
542
|
)
|
|
476
543
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
544
|
+
if not collect_file_contents:
|
|
545
|
+
continue
|
|
546
|
+
|
|
547
|
+
# `a_blob` is exactly the content at `base_ref` -- see `_get_blob_content`'s docstring.
|
|
548
|
+
# Deliberately `if file_content:` (skip empty string) rather than `is not None`: this
|
|
549
|
+
# matches the working_copy branch immediately below, treating an empty file the same as
|
|
550
|
+
# a nonexistent one. `get_commit_range_modified_documents` uses `is not None` instead, but
|
|
551
|
+
# for a different reason (there, `None` only ever means "no such commit"); don't "fix"
|
|
552
|
+
# this one to match it.
|
|
553
|
+
file_content = _get_blob_content(diff.a_blob)
|
|
554
|
+
if file_content:
|
|
555
|
+
from_ref_documents.append(Document(file_path, file_content))
|
|
482
556
|
|
|
483
557
|
if os.path.exists(file_path):
|
|
484
558
|
file_content = get_file_content(file_path)
|
|
485
559
|
if file_content:
|
|
486
|
-
|
|
560
|
+
working_copy_documents.append(Document(file_path, file_content))
|
|
487
561
|
|
|
488
|
-
return
|
|
562
|
+
return from_ref_documents, working_copy_documents, diff_documents
|
|
489
563
|
|
|
490
564
|
|
|
491
565
|
def parse_commit_range(commit_range: str, path: str) -> tuple[Optional[str], Optional[str], Optional[str]]:
|