patchi 0.7.5__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.
- patchi/__init__.py +1 -0
- patchi/__main__.py +13 -0
- patchi/cli/__init__.py +0 -0
- patchi/cli/command_families.py +235 -0
- patchi/cli/commands/__init__.py +0 -0
- patchi/cli/commands/access_cmd.py +65 -0
- patchi/cli/commands/agent_stats_cmd.py +273 -0
- patchi/cli/commands/agents_cmd.py +187 -0
- patchi/cli/commands/ai_cmd.py +308 -0
- patchi/cli/commands/assure_cmd.py +538 -0
- patchi/cli/commands/audit_cmd.py +286 -0
- patchi/cli/commands/auto_cmd.py +110 -0
- patchi/cli/commands/blame_cmd.py +53 -0
- patchi/cli/commands/chains_cmd.py +327 -0
- patchi/cli/commands/charter_cmd.py +173 -0
- patchi/cli/commands/chat_cmd.py +597 -0
- patchi/cli/commands/check_cmd.py +232 -0
- patchi/cli/commands/cleanup_cmd.py +328 -0
- patchi/cli/commands/cockpit_cmd.py +208 -0
- patchi/cli/commands/commands_cmd.py +160 -0
- patchi/cli/commands/cross_repo_cmd.py +113 -0
- patchi/cli/commands/deps_cmd.py +110 -0
- patchi/cli/commands/dev_check_cmd.py +342 -0
- patchi/cli/commands/dev_cmd.py +445 -0
- patchi/cli/commands/doctor_cmd.py +457 -0
- patchi/cli/commands/findings_cmd.py +187 -0
- patchi/cli/commands/fix_cmd.py +648 -0
- patchi/cli/commands/fix_review_cmd.py +273 -0
- patchi/cli/commands/heatmap_cmd.py +62 -0
- patchi/cli/commands/help_cmd.py +159 -0
- patchi/cli/commands/hosted_cmd.py +980 -0
- patchi/cli/commands/init.py +456 -0
- patchi/cli/commands/key_cmd.py +571 -0
- patchi/cli/commands/learn_cmd.py +140 -0
- patchi/cli/commands/link_cmd.py +104 -0
- patchi/cli/commands/log_cmd.py +57 -0
- patchi/cli/commands/memory_cmd.py +215 -0
- patchi/cli/commands/model_cmd.py +207 -0
- patchi/cli/commands/notify_cmd.py +213 -0
- patchi/cli/commands/notify_prompts.py +29 -0
- patchi/cli/commands/patch_cmd.py +231 -0
- patchi/cli/commands/plan_cmd.py +128 -0
- patchi/cli/commands/plugins_cmd.py +307 -0
- patchi/cli/commands/queue_cmd.py +152 -0
- patchi/cli/commands/quick_cmd.py +159 -0
- patchi/cli/commands/ready_cmd.py +292 -0
- patchi/cli/commands/report_cmd.py +416 -0
- patchi/cli/commands/restrict_cmd.py +127 -0
- patchi/cli/commands/review_cmd.py +225 -0
- patchi/cli/commands/rules_cmd.py +233 -0
- patchi/cli/commands/scan_cmd.py +1908 -0
- patchi/cli/commands/settings_cmd.py +45 -0
- patchi/cli/commands/status_cmd.py +679 -0
- patchi/cli/commands/test_cmd.py +1052 -0
- patchi/cli/commands/trend_cmd.py +296 -0
- patchi/cli/commands/undo_cmd.py +235 -0
- patchi/cli/commands/update_cmd.py +345 -0
- patchi/cli/commands/verify_cmd.py +56 -0
- patchi/cli/commands/vr_cmd.py +440 -0
- patchi/cli/commands/watch_cmd.py +304 -0
- patchi/cli/commands/web_cmd.py +114 -0
- patchi/cli/console.py +101 -0
- patchi/cli/display/__init__.py +1 -0
- patchi/cli/display/live_audit.py +269 -0
- patchi/cli/display/live_progress.py +169 -0
- patchi/cli/framework.py +241 -0
- patchi/cli/logo.py +128 -0
- patchi/cli/main.py +222 -0
- patchi/cli/registry.py +1171 -0
- patchi/cli/style.py +68 -0
- patchi/cli/themes.py +187 -0
- patchi/cli/ux.py +444 -0
- patchi/core/__init__.py +0 -0
- patchi/core/agents/__init__.py +0 -0
- patchi/core/agents/api_fuzzer_agent.py +141 -0
- patchi/core/agents/attack_agent.py +242 -0
- patchi/core/agents/base.py +1012 -0
- patchi/core/agents/bug_predictor_agent.py +58 -0
- patchi/core/agents/build_tool_validator.py +150 -0
- patchi/core/agents/cache.py +192 -0
- patchi/core/agents/chaos_agent.py +133 -0
- patchi/core/agents/cicd_generator.py +240 -0
- patchi/core/agents/comment_scanner.py +280 -0
- patchi/core/agents/console_logging_agent.py +156 -0
- patchi/core/agents/coordinator.py +858 -0
- patchi/core/agents/core_scanner.py +269 -0
- patchi/core/agents/coverage_prioritizer.py +181 -0
- patchi/core/agents/dead_code_hygiene.py +296 -0
- patchi/core/agents/dead_code_scanner.py +692 -0
- patchi/core/agents/dependency_scanner.py +725 -0
- patchi/core/agents/doc_claim_agent.py +573 -0
- patchi/core/agents/duplicate_scanner.py +568 -0
- patchi/core/agents/env_scanner.py +410 -0
- patchi/core/agents/feature_flag_agent.py +89 -0
- patchi/core/agents/frontend_framework_agent.py +133 -0
- patchi/core/agents/goroutine_agent.py +82 -0
- patchi/core/agents/governor.py +1972 -0
- patchi/core/agents/i18n_agent.py +95 -0
- patchi/core/agents/license_compliance.py +247 -0
- patchi/core/agents/linking_agent.py +251 -0
- patchi/core/agents/memory_profiler_agent.py +102 -0
- patchi/core/agents/modernization_agent.py +84 -0
- patchi/core/agents/mutation_agent.py +174 -0
- patchi/core/agents/nl_query_agent.py +74 -0
- patchi/core/agents/promise_rejection_agent.py +100 -0
- patchi/core/agents/refactoring_agent.py +286 -0
- patchi/core/agents/resource_leak_agent.py +91 -0
- patchi/core/agents/route_graph_scanner.py +951 -0
- patchi/core/agents/run_agent.py +106 -0
- patchi/core/agents/rust_unwrap_agent.py +100 -0
- patchi/core/agents/sbom_generator.py +284 -0
- patchi/core/agents/scanners.py +67 -0
- patchi/core/agents/side/__init__.py +1 -0
- patchi/core/agents/side/build_agent.py +65 -0
- patchi/core/agents/side/format_agent.py +50 -0
- patchi/core/agents/side/install_agent.py +63 -0
- patchi/core/agents/side_file_scanner.py +549 -0
- patchi/core/agents/snapshot_drift_detector.py +146 -0
- patchi/core/agents/spa_route_inventory.py +203 -0
- patchi/core/agents/test_scanner.py +442 -0
- patchi/core/agents/tool_health.py +109 -0
- patchi/core/agents/tool_runner.py +162 -0
- patchi/core/agents/type_scanner.py +168 -0
- patchi/core/agents/ui_scanner.py +558 -0
- patchi/core/ai/__init__.py +20 -0
- patchi/core/ai/agent_audit.py +153 -0
- patchi/core/ai/agent_profiler.py +277 -0
- patchi/core/ai/client.py +499 -0
- patchi/core/ai/cost_tracker.py +107 -0
- patchi/core/ai/model_router.py +318 -0
- patchi/core/ai/orchestrator.py +625 -0
- patchi/core/ai/prompts.py +681 -0
- patchi/core/ai/smart.py +302 -0
- patchi/core/ai/tool_executor.py +24 -0
- patchi/core/ai/tools/__init__.py +10 -0
- patchi/core/ai/tools/executor.py +621 -0
- patchi/core/ai/tools/realize.py +1160 -0
- patchi/core/ai/tools/registry.py +1577 -0
- patchi/core/assurance/__init__.py +33 -0
- patchi/core/assurance/builder.py +211 -0
- patchi/core/assurance/graph.py +342 -0
- patchi/core/assurance/invariants.py +168 -0
- patchi/core/atomic.py +61 -0
- patchi/core/attackers/__init__.py +17 -0
- patchi/core/attackers/api_abuse.py +89 -0
- patchi/core/attackers/auth_bypass.py +73 -0
- patchi/core/attackers/base.py +91 -0
- patchi/core/attackers/business_logic.py +88 -0
- patchi/core/attackers/planner.py +108 -0
- patchi/core/attackers/priv_escalation.py +88 -0
- patchi/core/attackers/recon.py +87 -0
- patchi/core/brain/__init__.py +0 -0
- patchi/core/brain/ast_utils/__init__.py +81 -0
- patchi/core/brain/ast_utils/assignments.py +219 -0
- patchi/core/brain/ast_utils/calls.py +139 -0
- patchi/core/brain/ast_utils/config.py +132 -0
- patchi/core/brain/ast_utils/control_flow.py +74 -0
- patchi/core/brain/ast_utils/dead_symbols.py +205 -0
- patchi/core/brain/ast_utils/decorators.py +108 -0
- patchi/core/brain/ast_utils/helpers.py +144 -0
- patchi/core/brain/ast_utils/imports.py +169 -0
- patchi/core/brain/ast_utils/scan.py +143 -0
- patchi/core/brain/ast_utils/taint.py +310 -0
- patchi/core/brain/audit.py +379 -0
- patchi/core/brain/baseline.py +195 -0
- patchi/core/brain/blast_radius.py +312 -0
- patchi/core/brain/body_tags.py +144 -0
- patchi/core/brain/brain.py +1161 -0
- patchi/core/brain/brain_context.py +393 -0
- patchi/core/brain/brain_watcher.py +340 -0
- patchi/core/brain/charter.py +473 -0
- patchi/core/brain/classifier.py +214 -0
- patchi/core/brain/cockpit.py +350 -0
- patchi/core/brain/code_query.py +710 -0
- patchi/core/brain/contract.py +889 -0
- patchi/core/brain/contract_diff.py +155 -0
- patchi/core/brain/council.py +800 -0
- patchi/core/brain/cross_repo.py +104 -0
- patchi/core/brain/dead_code_tools.py +157 -0
- patchi/core/brain/doc_validator.py +197 -0
- patchi/core/brain/domain_activator.py +2183 -0
- patchi/core/brain/enriched_context.py +220 -0
- patchi/core/brain/file_corpus.py +220 -0
- patchi/core/brain/framework.py +953 -0
- patchi/core/brain/freshness.py +273 -0
- patchi/core/brain/git_aware.py +206 -0
- patchi/core/brain/heatmap.py +104 -0
- patchi/core/brain/ignore_parser.py +153 -0
- patchi/core/brain/import_graph.py +486 -0
- patchi/core/brain/languages.py +397 -0
- patchi/core/brain/layered_brain.py +419 -0
- patchi/core/brain/learning.py +229 -0
- patchi/core/brain/orphaned_endpoints.py +313 -0
- patchi/core/brain/personas/__init__.py +648 -0
- patchi/core/brain/personas/bad_user.py +165 -0
- patchi/core/brain/personas/base.py +349 -0
- patchi/core/brain/proactive.py +807 -0
- patchi/core/brain/project_context.py +121 -0
- patchi/core/brain/project_reader.py +521 -0
- patchi/core/brain/reasoning.py +269 -0
- patchi/core/brain/route_detector/__init__.py +15 -0
- patchi/core/brain/route_detector/base.py +31 -0
- patchi/core/brain/route_detector/csharp.py +209 -0
- patchi/core/brain/route_detector/file_based.py +81 -0
- patchi/core/brain/route_detector/go.py +152 -0
- patchi/core/brain/route_detector/java.py +195 -0
- patchi/core/brain/route_detector/javascript.py +197 -0
- patchi/core/brain/route_detector/php.py +158 -0
- patchi/core/brain/route_detector/python.py +193 -0
- patchi/core/brain/route_detector/registry.py +25 -0
- patchi/core/brain/route_detector/ruby.py +134 -0
- patchi/core/brain/route_detector/rust.py +216 -0
- patchi/core/brain/route_detector/swift.py +118 -0
- patchi/core/brain/route_mapper.py +265 -0
- patchi/core/brain/scanner.py +2136 -0
- patchi/core/brain/secrets.py +280 -0
- patchi/core/brain/symbol_graph.py +1955 -0
- patchi/core/brain/team.py +28 -0
- patchi/core/brain/trace_log.py +132 -0
- patchi/core/brain/type_checker/__init__.py +65 -0
- patchi/core/brain/type_checker/base.py +60 -0
- patchi/core/brain/type_checker/csharp.py +59 -0
- patchi/core/brain/type_checker/dart.py +59 -0
- patchi/core/brain/type_checker/go.py +81 -0
- patchi/core/brain/type_checker/java.py +75 -0
- patchi/core/brain/type_checker/kotlin.py +75 -0
- patchi/core/brain/type_checker/php.py +88 -0
- patchi/core/brain/type_checker/python.py +87 -0
- patchi/core/brain/type_checker/rust.py +81 -0
- patchi/core/brain/type_checker/swift.py +59 -0
- patchi/core/brain/type_checker/typescript.py +298 -0
- patchi/core/brain/understander.py +130 -0
- patchi/core/brain/verify.py +379 -0
- patchi/core/campaigns/__init__.py +14 -0
- patchi/core/campaigns/base.py +62 -0
- patchi/core/campaigns/data_flow_abuse.py +153 -0
- patchi/core/campaigns/orchestrator.py +140 -0
- patchi/core/campaigns/state_transitions.py +178 -0
- patchi/core/ci_bundle.py +104 -0
- patchi/core/config.py +311 -0
- patchi/core/constants.py +245 -0
- patchi/core/debug/__init__.py +25 -0
- patchi/core/debug/adapters/__init__.py +11 -0
- patchi/core/debug/adapters/codelldb.py +379 -0
- patchi/core/debug/adapters/node.py +222 -0
- patchi/core/debug/adapters/powershell.py +210 -0
- patchi/core/debug/adapters/python.py +244 -0
- patchi/core/debug/capture.py +210 -0
- patchi/core/debug/dap_client.py +268 -0
- patchi/core/detector/__init__.py +0 -0
- patchi/core/detector/audit.py +194 -0
- patchi/core/detector/bus.py +226 -0
- patchi/core/detector/dispatcher.py +275 -0
- patchi/core/detector/event.py +254 -0
- patchi/core/detector/sigma_engine.py +378 -0
- patchi/core/detector/triage.py +289 -0
- patchi/core/export/sarif.py +113 -0
- patchi/core/fix/__init__.py +17 -0
- patchi/core/fix/applier.py +574 -0
- patchi/core/fix/base.py +510 -0
- patchi/core/fix/code_fixer.py +169 -0
- patchi/core/fix/dead_code_remover.py +131 -0
- patchi/core/fix/fix_agents.py +775 -0
- patchi/core/fix/patch.py +444 -0
- patchi/core/fix/risk_gate.py +383 -0
- patchi/core/fix/security_fixer.py +93 -0
- patchi/core/fix/verify_loop.py +204 -0
- patchi/core/fuzz/__init__.py +8 -0
- patchi/core/fuzz/corpus.py +137 -0
- patchi/core/fuzz/input_fuzzer.py +256 -0
- patchi/core/fuzz/sequence_fuzzer.py +162 -0
- patchi/core/fuzz/state_fuzzer.py +236 -0
- patchi/core/health.py +407 -0
- patchi/core/hosted/__init__.py +1 -0
- patchi/core/hosted/anomaly.py +298 -0
- patchi/core/hosted/audit_log.py +102 -0
- patchi/core/hosted/compliance_report.py +148 -0
- patchi/core/hosted/ip_reputation.py +169 -0
- patchi/core/hosted/log_parsers.py +251 -0
- patchi/core/hosted/tokens.py +127 -0
- patchi/core/hosted/watchlist.py +164 -0
- patchi/core/hosted/webhooks.py +156 -0
- patchi/core/memory.py +437 -0
- patchi/core/notifications/__init__.py +18 -0
- patchi/core/notifications/channels.py +192 -0
- patchi/core/notifications/digest.py +141 -0
- patchi/core/notifications/escalation.py +158 -0
- patchi/core/notifications/notifier.py +182 -0
- patchi/core/notifications/quiet_hours.py +69 -0
- patchi/core/plugins/__init__.py +48 -0
- patchi/core/plugins/analyzer.py +326 -0
- patchi/core/plugins/analyzers/__init__.py +6 -0
- patchi/core/plugins/analyzers/dead_code_analyzer.py +120 -0
- patchi/core/plugins/analyzers/secret_scanner.py +158 -0
- patchi/core/plugins/analyzers/todo_scanner.py +115 -0
- patchi/core/plugins/registry.py +335 -0
- patchi/core/queue.py +375 -0
- patchi/core/reliability/__init__.py +13 -0
- patchi/core/reliability/chaos.py +163 -0
- patchi/core/reliability/fault_injector.py +172 -0
- patchi/core/reliability/idempotency.py +128 -0
- patchi/core/reliability/recovery.py +147 -0
- patchi/core/runtime/__init__.py +5 -0
- patchi/core/runtime/tracer.py +230 -0
- patchi/core/scan_bus.py +156 -0
- patchi/core/security/__init__.py +1 -0
- patchi/core/security/ai_validator.py +462 -0
- patchi/core/security/app_mapper.py +216 -0
- patchi/core/security/app_profile.py +464 -0
- patchi/core/security/attack_feedback.py +141 -0
- patchi/core/security/attack_scenarios/__init__.py +1 -0
- patchi/core/security/attack_tree.py +176 -0
- patchi/core/security/auth_audit_agent.py +344 -0
- patchi/core/security/authz_agent.py +602 -0
- patchi/core/security/auto_fix_proactive.py +620 -0
- patchi/core/security/auto_fixer.py +660 -0
- patchi/core/security/auto_ticket.py +53 -0
- patchi/core/security/bandit_agent.py +152 -0
- patchi/core/security/blast_radius.py +226 -0
- patchi/core/security/browser_tester.py +333 -0
- patchi/core/security/business_logic_agent.py +263 -0
- patchi/core/security/catch_block_auditor.py +395 -0
- patchi/core/security/cdn_cache_agent.py +357 -0
- patchi/core/security/chain_analyzer.py +321 -0
- patchi/core/security/chain_to_assurance.py +168 -0
- patchi/core/security/charter.py +510 -0
- patchi/core/security/cloud_waf_detector.py +295 -0
- patchi/core/security/codeql_agent.py +233 -0
- patchi/core/security/compliance_agent.py +348 -0
- patchi/core/security/confidence_gate.py +423 -0
- patchi/core/security/container_scanner.py +282 -0
- patchi/core/security/crypto_agent.py +378 -0
- patchi/core/security/cve_monitor.py +262 -0
- patchi/core/security/dast_agent.py +865 -0
- patchi/core/security/defectdojo.py +238 -0
- patchi/core/security/defenders/__init__.py +75 -0
- patchi/core/security/defenders/auth_middleware.py +115 -0
- patchi/core/security/defenders/base.py +97 -0
- patchi/core/security/defenders/block_ip.py +71 -0
- patchi/core/security/defenders/block_ws_origin.py +36 -0
- patchi/core/security/defenders/crypto_fix.py +118 -0
- patchi/core/security/defenders/enforce_rate_limit.py +108 -0
- patchi/core/security/defenders/fix_code.py +93 -0
- patchi/core/security/defenders/invalidate_session.py +40 -0
- patchi/core/security/defenders/patch_config.py +70 -0
- patchi/core/security/defenders/rotate_secret.py +54 -0
- patchi/core/security/defenders/suspend_account.py +41 -0
- patchi/core/security/defenders/update_dependency.py +160 -0
- patchi/core/security/defense_layer.py +217 -0
- patchi/core/security/dependency_vulnerability_agent.py +616 -0
- patchi/core/security/detection_pipeline.py +289 -0
- patchi/core/security/dns_security_agent.py +497 -0
- patchi/core/security/domain_activator_v2.py +913 -0
- patchi/core/security/domain_loader.py +1004 -0
- patchi/core/security/domains/__init__.py +0 -0
- patchi/core/security/email_authentication_agent.py +417 -0
- patchi/core/security/env_var_validator.py +304 -0
- patchi/core/security/evidence.py +100 -0
- patchi/core/security/falco_runtime_agent.py +387 -0
- patchi/core/security/fix-playbooks/__init__.py +0 -0
- patchi/core/security/gated_finding.py +85 -0
- patchi/core/security/git_diff_activator.py +367 -0
- patchi/core/security/governance.py +208 -0
- patchi/core/security/gradual_gate.py +34 -0
- patchi/core/security/history.py +315 -0
- patchi/core/security/iac_scanner.py +250 -0
- patchi/core/security/ignore_expiry.py +111 -0
- patchi/core/security/ignore_learner.py +416 -0
- patchi/core/security/injection_agent.py +319 -0
- patchi/core/security/insecure_randomness_agent.py +288 -0
- patchi/core/security/intent_analyzer.py +326 -0
- patchi/core/security/jwt_agent.py +453 -0
- patchi/core/security/kubernetes_agent.py +638 -0
- patchi/core/security/layer2_orchestrator.py +341 -0
- patchi/core/security/llm_security_agent.py +252 -0
- patchi/core/security/misconfig_agent.py +600 -0
- patchi/core/security/mobile_security_agent.py +474 -0
- patchi/core/security/network_agent.py +376 -0
- patchi/core/security/noise_filter.py +274 -0
- patchi/core/security/orchestrator.py +313 -0
- patchi/core/security/pattern_context.py +125 -0
- patchi/core/security/pattern_loader.py +101 -0
- patchi/core/security/pentest/__init__.py +4 -0
- patchi/core/security/pentest/base.py +58 -0
- patchi/core/security/pentest/dalfox_adapter.py +40 -0
- patchi/core/security/pentest/ffuf_adapter.py +48 -0
- patchi/core/security/pentest/nuclei_adapter.py +50 -0
- patchi/core/security/pentest/registry.py +80 -0
- patchi/core/security/pentest/shannon_adapter.py +107 -0
- patchi/core/security/pentest/sqlmap_adapter.py +56 -0
- patchi/core/security/pentest/zap_adapter.py +52 -0
- patchi/core/security/plan_auditor.py +276 -0
- patchi/core/security/policy_engine.py +272 -0
- patchi/core/security/prechecks.py +172 -0
- patchi/core/security/precommit_hook.py +247 -0
- patchi/core/security/privacy_agent.py +361 -0
- patchi/core/security/push_notification_agent.py +417 -0
- patchi/core/security/pysa_agent.py +143 -0
- patchi/core/security/reasoning.py +442 -0
- patchi/core/security/red_team_agent.py +184 -0
- patchi/core/security/red_team_engine.py +1142 -0
- patchi/core/security/remediation.py +360 -0
- patchi/core/security/request_interceptor.py +294 -0
- patchi/core/security/runtime_validator.py +245 -0
- patchi/core/security/saml_sso_agent.py +401 -0
- patchi/core/security/sast_agent.py +213 -0
- patchi/core/security/sast_gate.py +95 -0
- patchi/core/security/scheduler.py +287 -0
- patchi/core/security/secrets_runtime_agent.py +476 -0
- patchi/core/security/security_agents.py +175 -0
- patchi/core/security/security_config.py +551 -0
- patchi/core/security/security_probe.py +762 -0
- patchi/core/security/security_taint.py +1005 -0
- patchi/core/security/sensitive_data_agent.py +271 -0
- patchi/core/security/service_mesh_agent.py +412 -0
- patchi/core/security/session_management_agent.py +245 -0
- patchi/core/security/ssrf_agent.py +422 -0
- patchi/core/security/supply_chain.py +449 -0
- patchi/core/security/threat_model_generator.py +378 -0
- patchi/core/security/threat_model_updater.py +196 -0
- patchi/core/security/tool_adapters.py +135 -0
- patchi/core/security/tool_verify.py +173 -0
- patchi/core/security/websocket_security_agent.py +188 -0
- patchi/core/snapshot.py +242 -0
- patchi/core/tenant.py +386 -0
- patchi/core/testing/__init__.py +17 -0
- patchi/core/testing/_browser.py +147 -0
- patchi/core/testing/ads_agent.py +141 -0
- patchi/core/testing/api_contract_agent.py +450 -0
- patchi/core/testing/app_discovery_agent.py +641 -0
- patchi/core/testing/app_launcher.py +184 -0
- patchi/core/testing/browser_test_agent.py +516 -0
- patchi/core/testing/e2e_flow_agent.py +354 -0
- patchi/core/testing/flake_detector_agent.py +292 -0
- patchi/core/testing/gate.py +31 -0
- patchi/core/testing/live_test_runner.py +304 -0
- patchi/core/testing/live_v2/__init__.py +1 -0
- patchi/core/testing/live_v2/browser_pool.py +349 -0
- patchi/core/testing/live_v2/browser_test_runner.py +313 -0
- patchi/core/testing/live_v2/runner.py +626 -0
- patchi/core/testing/live_v2/screenshot_manager.py +474 -0
- patchi/core/testing/live_v2/stress_orchestrator.py +523 -0
- patchi/core/testing/live_v2/video_recorder.py +303 -0
- patchi/core/testing/regression_agent.py +302 -0
- patchi/core/testing/security_test_agent.py +253 -0
- patchi/core/testing/stress_test_agent.py +203 -0
- patchi/core/testing/test_agents.py +50 -0
- patchi/core/testing/test_config.py +194 -0
- patchi/core/testing/ui_accessibility_agent.py +324 -0
- patchi/core/testing/ui_button_agent.py +294 -0
- patchi/core/testing/ui_layout_agent.py +330 -0
- patchi/core/testing/unit_test_agent.py +1149 -0
- patchi/core/testing/visual_regression_agent.py +260 -0
- patchi/web/__init__.py +1 -0
- patchi/web/api/__init__.py +1 -0
- patchi/web/api/brain_map.py +114 -0
- patchi/web/api/charts.py +47 -0
- patchi/web/api/chat.py +224 -0
- patchi/web/api/cicd.py +576 -0
- patchi/web/api/dast_evidence.py +49 -0
- patchi/web/api/dev_check.py +320 -0
- patchi/web/api/fix.py +134 -0
- patchi/web/api/guard.py +65 -0
- patchi/web/api/hosted.py +128 -0
- patchi/web/api/hosted_v2.py +234 -0
- patchi/web/api/live_testing.py +699 -0
- patchi/web/api/scan.py +582 -0
- patchi/web/api/smart.py +111 -0
- patchi/web/api/tenant.py +117 -0
- patchi/web/api/tools.py +85 -0
- patchi/web/api_legacy.py +2401 -0
- patchi/web/app.py +310 -0
- patchi/web/events.py +483 -0
- patchi/web/routes/__init__.py +1 -0
- patchi/web/routes/assurance.py +541 -0
- patchi/web/routes/brain.py +36 -0
- patchi/web/routes/charter.py +227 -0
- patchi/web/routes/chat.py +23 -0
- patchi/web/routes/dashboard.py +558 -0
- patchi/web/routes/dashboard_v2.py +402 -0
- patchi/web/routes/findings.py +330 -0
- patchi/web/routes/guard.py +35 -0
- patchi/web/routes/history.py +126 -0
- patchi/web/routes/landing.py +52 -0
- patchi/web/routes/live_testing.py +24 -0
- patchi/web/routes/review.py +57 -0
- patchi/web/routes/self_improvement.py +110 -0
- patchi/web/routes/settings.py +49 -0
- patchi/web/routes/tokens.py +29 -0
- patchi/web/spawn.py +139 -0
- patchi/web/ws.py +141 -0
- patchi-0.7.5.dist-info/METADATA +315 -0
- patchi-0.7.5.dist-info/RECORD +496 -0
- patchi-0.7.5.dist-info/WHEEL +5 -0
- patchi-0.7.5.dist-info/licenses/LICENSE +60 -0
- patchi-0.7.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Detection Pipeline — orchestrates the full pipeline:
|
|
3
|
+
SecurityReport -> ConfidenceGate -> Layer2Orchestrator -> GatedReport
|
|
4
|
+
|
|
5
|
+
Stages:
|
|
6
|
+
1. Gate every finding through ConfidenceGate
|
|
7
|
+
2. Run Sigma rule matching against findings (context-aware correlation)
|
|
8
|
+
3. Partition by routing tier (defend / ai_analyze / human_review / discard)
|
|
9
|
+
4. Send medium-confidence findings to Layer 2 AI for confirmation
|
|
10
|
+
5. Promote AI-confirmed findings to 'defend', dismiss dismissed ones
|
|
11
|
+
6. Return final GatedReport
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from patchi.core.security.confidence_gate import ConfidenceGate
|
|
20
|
+
from patchi.core.security.gated_finding import GatedReport
|
|
21
|
+
from patchi.core.security.layer2_orchestrator import Layer2Orchestrator
|
|
22
|
+
from patchi.core.security.orchestrator import CorrelatedFinding, SecurityReport
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _as_correlated(finding) -> CorrelatedFinding:
|
|
26
|
+
"""Wrap a raw Finding as a single-agent CorrelatedFinding."""
|
|
27
|
+
if isinstance(finding, CorrelatedFinding):
|
|
28
|
+
return finding
|
|
29
|
+
return CorrelatedFinding(
|
|
30
|
+
finding=finding,
|
|
31
|
+
confirmed_by=[getattr(finding, "agent", "") or "unknown"],
|
|
32
|
+
composite_score=0.0,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class DetectionPipeline:
|
|
37
|
+
"""Wires ConfidenceGate + Layer2Orchestrator + Sigma into a single pipeline."""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self, root: Path, config: dict | None = None,
|
|
41
|
+
component_types=None, brain_context=None,
|
|
42
|
+
):
|
|
43
|
+
self.root = root
|
|
44
|
+
self.config = config or {}
|
|
45
|
+
self.gate = ConfidenceGate(root, config)
|
|
46
|
+
self.layer2 = Layer2Orchestrator(root, config)
|
|
47
|
+
self._sigma_set = None
|
|
48
|
+
self._domain_loader = None
|
|
49
|
+
self._noise_filter = None
|
|
50
|
+
self._component_types = component_types
|
|
51
|
+
self._brain = brain_context # BrainContext for context-aware classification
|
|
52
|
+
# Pre-load DomainLoader in background to avoid blocking on first use
|
|
53
|
+
self._domain_loader_future = None
|
|
54
|
+
try:
|
|
55
|
+
import concurrent.futures as _cf
|
|
56
|
+
|
|
57
|
+
from patchi.core.security.domain_loader import DomainLoader
|
|
58
|
+
pool = _cf.ThreadPoolExecutor(max_workers=1, thread_name_prefix="dl-pipeline")
|
|
59
|
+
|
|
60
|
+
def _preload() -> DomainLoader:
|
|
61
|
+
# Construct + force the (lazy) load in this background thread.
|
|
62
|
+
_ldr = DomainLoader(root, component_types=component_types)
|
|
63
|
+
_ldr.list_domains() # parses + caches taxonomy off the hot path
|
|
64
|
+
return _ldr
|
|
65
|
+
|
|
66
|
+
self._domain_loader_future = pool.submit(_preload)
|
|
67
|
+
pool.shutdown(wait=False)
|
|
68
|
+
except Exception as _exc:
|
|
69
|
+
logging.getLogger("patchi").debug('suppressed: %s', _exc)
|
|
70
|
+
|
|
71
|
+
def _get_sigma_set(self):
|
|
72
|
+
if self._sigma_set is None:
|
|
73
|
+
from patchi.core.detector.sigma_engine import SigmaRuleSet
|
|
74
|
+
|
|
75
|
+
sigma_dir = self.root / (
|
|
76
|
+
self.config.get("pipeline", {}).get("sigma_rules_dir", ".patchi/sigma")
|
|
77
|
+
)
|
|
78
|
+
self._sigma_set = SigmaRuleSet.load_directory(sigma_dir)
|
|
79
|
+
if self._sigma_set.count > 0:
|
|
80
|
+
import logging
|
|
81
|
+
|
|
82
|
+
logging.getLogger("patchi.detection").info(
|
|
83
|
+
"Loaded %d Sigma rules from %s", self._sigma_set.count, sigma_dir
|
|
84
|
+
)
|
|
85
|
+
return self._sigma_set
|
|
86
|
+
|
|
87
|
+
def _findings_to_events(self, findings):
|
|
88
|
+
from patchi.core.detector.event import Event, EventSeverity, EventSource
|
|
89
|
+
|
|
90
|
+
events = []
|
|
91
|
+
for cf in findings:
|
|
92
|
+
sev_map = {
|
|
93
|
+
"critical": EventSeverity.CRITICAL,
|
|
94
|
+
"high": EventSeverity.HIGH,
|
|
95
|
+
"medium": EventSeverity.MEDIUM,
|
|
96
|
+
"low": EventSeverity.LOW,
|
|
97
|
+
}
|
|
98
|
+
event = Event(
|
|
99
|
+
title=cf.finding.message[:200] if cf.finding.message else cf.finding.type,
|
|
100
|
+
severity=sev_map.get(cf.finding.severity, EventSeverity.INFO),
|
|
101
|
+
source=EventSource.SECURITY_SCAN,
|
|
102
|
+
source_details={
|
|
103
|
+
"file": cf.finding.file or "",
|
|
104
|
+
"line": cf.finding.line or 0,
|
|
105
|
+
"agent": cf.finding.agent or "",
|
|
106
|
+
"cwe": cf.finding.cwe or "",
|
|
107
|
+
"category": "security_scan",
|
|
108
|
+
},
|
|
109
|
+
)
|
|
110
|
+
events.append(event)
|
|
111
|
+
return events
|
|
112
|
+
|
|
113
|
+
def process(self, report: SecurityReport) -> GatedReport:
|
|
114
|
+
if not report.findings:
|
|
115
|
+
return GatedReport(
|
|
116
|
+
stats={"total": 0, "defend": 0, "ai_analyze": 0, "human_review": 0, "discarded": 0}
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Stage 0: Noise filter — findings from tests/lockfiles/generated/docs
|
|
120
|
+
# are severity-capped (or discarded) before scoring. This kills the
|
|
121
|
+
# bulk of false-positive volume at the cheapest possible point.
|
|
122
|
+
noise_stats = None
|
|
123
|
+
try:
|
|
124
|
+
from patchi.core.security.noise_filter import NoiseFilter
|
|
125
|
+
|
|
126
|
+
if self._noise_filter is None:
|
|
127
|
+
self._noise_filter = NoiseFilter(self.root, self.config)
|
|
128
|
+
if self._noise_filter.enabled:
|
|
129
|
+
kept, nf_report = self._noise_filter.apply(report.findings)
|
|
130
|
+
noise_stats = nf_report.to_dict()
|
|
131
|
+
gated_list = [self.gate.gate(_as_correlated(f)) for f in kept]
|
|
132
|
+
else:
|
|
133
|
+
gated_list = [self.gate.gate(cf) for cf in report.findings]
|
|
134
|
+
except Exception as e:
|
|
135
|
+
import logging
|
|
136
|
+
|
|
137
|
+
logging.getLogger("patchi.detection").warning(
|
|
138
|
+
"Noise filter failed (non-fatal, scanning all): %s", e
|
|
139
|
+
)
|
|
140
|
+
gated_list = [self.gate.gate(cf) for cf in report.findings]
|
|
141
|
+
|
|
142
|
+
# Stage 1a: Domain taxonomy matching — enrich findings with ASVS/domain context
|
|
143
|
+
try:
|
|
144
|
+
# Use pre-loaded DomainLoader if available, else create new
|
|
145
|
+
if self._domain_loader is None:
|
|
146
|
+
if self._domain_loader_future is not None:
|
|
147
|
+
try:
|
|
148
|
+
self._domain_loader = self._domain_loader_future.result(timeout=0)
|
|
149
|
+
except Exception as _exc:
|
|
150
|
+
logging.getLogger("patchi").debug('suppressed: %s', _exc)
|
|
151
|
+
if self._domain_loader is None:
|
|
152
|
+
from patchi.core.security.domain_loader import DomainLoader
|
|
153
|
+
self._domain_loader = DomainLoader(
|
|
154
|
+
self.root, component_types=self._component_types,
|
|
155
|
+
)
|
|
156
|
+
loader = self._domain_loader
|
|
157
|
+
for gf in gated_list:
|
|
158
|
+
ctrl_matches = loader.match_finding_to_controls(
|
|
159
|
+
gf.finding.type, gf.finding.file or "", gf.finding.message
|
|
160
|
+
)
|
|
161
|
+
if ctrl_matches:
|
|
162
|
+
gf.domain_controls = [
|
|
163
|
+
{"control_id": c.control_id, "name": c.name, "severity": c.severity}
|
|
164
|
+
for c in ctrl_matches
|
|
165
|
+
]
|
|
166
|
+
playbook = loader.get_playbook(ctrl_matches[0].control_id)
|
|
167
|
+
if playbook:
|
|
168
|
+
gf.playbook_ref = playbook.control_id
|
|
169
|
+
gf.fix_strategy = playbook.fix_strategy
|
|
170
|
+
except Exception as e:
|
|
171
|
+
import logging
|
|
172
|
+
|
|
173
|
+
logging.getLogger("patchi.detection").warning(
|
|
174
|
+
"Domain taxonomy enrichment failed: %s", e
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Stage 1a½: Brain context — context-aware false-positive reduction
|
|
178
|
+
if self._brain and self._brain.is_loaded():
|
|
179
|
+
for gf in gated_list:
|
|
180
|
+
fctx = self._brain.get_finding_context(
|
|
181
|
+
gf.finding.file or "", gf.finding.type, gf.finding.message
|
|
182
|
+
)
|
|
183
|
+
# Demote test fixture findings (they contain intentional vulns)
|
|
184
|
+
if fctx["is_test_fixture"] and gf.routing == "defend":
|
|
185
|
+
gf.routing = "ai_analyze"
|
|
186
|
+
gf.routing_reason = (
|
|
187
|
+
f"Test fixture — demoted for AI review ({gf.routing_reason})"
|
|
188
|
+
)
|
|
189
|
+
gf.confidence_score = min(gf.confidence_score, 0.5)
|
|
190
|
+
# Boost findings in critical directories
|
|
191
|
+
if fctx["project_relevance"] == "high":
|
|
192
|
+
gf.confidence_score = min(1.0, gf.confidence_score + 0.1)
|
|
193
|
+
# Add domain context to finding message for downstream use
|
|
194
|
+
if fctx["domain_matches"]:
|
|
195
|
+
domains_str = ', '.join(fctx['domain_matches'][:3])
|
|
196
|
+
gf.routing_reason = (
|
|
197
|
+
f"[domains: {domains_str}] {gf.routing_reason}"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Stage 1b: Sigma rule matching — boosts confidence for known attack patterns
|
|
201
|
+
sigma_set = self._get_sigma_set()
|
|
202
|
+
if sigma_set and sigma_set.count > 0:
|
|
203
|
+
events = self._findings_to_events(report.findings)
|
|
204
|
+
for event in events:
|
|
205
|
+
matches = sigma_set.match(event)
|
|
206
|
+
for match in matches:
|
|
207
|
+
for gf in gated_list:
|
|
208
|
+
# Noise-capped findings are never Sigma-promoted:
|
|
209
|
+
# test fixtures etc. legitimately contain attack
|
|
210
|
+
# patterns and must not be re-escalated to defend.
|
|
211
|
+
if getattr(gf.finding, "noise_category", None):
|
|
212
|
+
continue
|
|
213
|
+
if match.technique_id and str(match.technique_id) != "unknown":
|
|
214
|
+
tid = (
|
|
215
|
+
match.technique_id.value
|
|
216
|
+
if hasattr(match.technique_id, "value")
|
|
217
|
+
else str(match.technique_id)
|
|
218
|
+
)
|
|
219
|
+
if tid in gf.finding.message or (
|
|
220
|
+
gf.finding.cwe and tid in gf.finding.cwe
|
|
221
|
+
):
|
|
222
|
+
gf.confidence_tier = "high"
|
|
223
|
+
gf.routing = "defend"
|
|
224
|
+
gf.routing_reason = f"Sigma rule match: {match.rule_name} ({tid})"
|
|
225
|
+
gf.sigma_matches = getattr(gf, "sigma_matches", []) + [match]
|
|
226
|
+
|
|
227
|
+
# Stage 2: Partition
|
|
228
|
+
high = [g for g in gated_list if g.routing == "defend"]
|
|
229
|
+
medium = [g for g in gated_list if g.routing == "ai_analyze"]
|
|
230
|
+
low = [g for g in gated_list if g.routing == "human_review"]
|
|
231
|
+
discarded = [g for g in gated_list if g.routing == "discard"]
|
|
232
|
+
|
|
233
|
+
# Stage 3: AI analysis for medium-confidence findings
|
|
234
|
+
if medium:
|
|
235
|
+
ai_results = self.layer2.analyze(medium)
|
|
236
|
+
for gf, ai_res in zip(medium, ai_results, strict=False):
|
|
237
|
+
if ai_res.confirmed:
|
|
238
|
+
# Graded calibration: blend the model's confidence
|
|
239
|
+
# adjustment into the heuristic score, not just a binary
|
|
240
|
+
# yes/no. adjustment is roughly [-1, 1] -> map to [0, 1].
|
|
241
|
+
if ai_res.confidence_adjustment:
|
|
242
|
+
ai_conf = max(0.0, min(1.0, 0.5 + float(ai_res.confidence_adjustment) / 2))
|
|
243
|
+
recalc = self.gate.gate(_as_correlated(gf.finding), ai_confidence=ai_conf)
|
|
244
|
+
gf.confidence_score = recalc.confidence_score
|
|
245
|
+
if recalc.confidence_score >= 0.7:
|
|
246
|
+
gf.confidence_tier = "high"
|
|
247
|
+
gf.routing = "defend"
|
|
248
|
+
gf.routing_reason = (
|
|
249
|
+
f"AI confirmed ({gf.confidence_score:.2f}): {ai_res.summary}"
|
|
250
|
+
)
|
|
251
|
+
high.append(gf)
|
|
252
|
+
else:
|
|
253
|
+
gf.routing = "discard"
|
|
254
|
+
gf.routing_reason = f"AI dismissed: {ai_res.summary}"
|
|
255
|
+
discarded.append(gf)
|
|
256
|
+
|
|
257
|
+
# Stage 4: Noise learning loop — persist every rejected finding as a
|
|
258
|
+
# known false positive so future scans pre-penalize (or, with
|
|
259
|
+
# fp_auto_discard, drop it outright). This is what stops the same
|
|
260
|
+
# noise from resurfacing thousands of times.
|
|
261
|
+
try:
|
|
262
|
+
learned = self.gate.learn_from_dismissed(GatedReport(findings=discarded, stats={}))
|
|
263
|
+
if learned:
|
|
264
|
+
import logging
|
|
265
|
+
|
|
266
|
+
logging.getLogger("patchi.detection").info(
|
|
267
|
+
"Learned %d new false positive(s) from rejected findings", learned
|
|
268
|
+
)
|
|
269
|
+
except Exception as e:
|
|
270
|
+
import logging
|
|
271
|
+
|
|
272
|
+
logging.getLogger("patchi.detection").warning(
|
|
273
|
+
"FP learning loop failed (non-fatal): %s", e
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
stats = {
|
|
277
|
+
"total": len(gated_list),
|
|
278
|
+
"defend": len(high),
|
|
279
|
+
"ai_analyze": len([g for g in medium if g.routing == "ai_analyze"]),
|
|
280
|
+
"human_review": len(low),
|
|
281
|
+
"discarded": len(discarded),
|
|
282
|
+
}
|
|
283
|
+
if noise_stats is not None:
|
|
284
|
+
stats["noise"] = noise_stats
|
|
285
|
+
|
|
286
|
+
return GatedReport(
|
|
287
|
+
findings=high + [g for g in medium if g.routing == "ai_analyze"] + low + discarded,
|
|
288
|
+
stats=stats,
|
|
289
|
+
)
|