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
patchi/web/app.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FastAPI app factory for Patchi Web UI.
|
|
3
|
+
|
|
4
|
+
Exposes:
|
|
5
|
+
GET / → dashboard (Brain Map + security overview)
|
|
6
|
+
GET /findings → findings list with filters
|
|
7
|
+
GET /review → patch review with diffs
|
|
8
|
+
GET /guard → hosted guard monitoring
|
|
9
|
+
GET /chat → security AI chat
|
|
10
|
+
GET /brain → brain knowledge viewer
|
|
11
|
+
WS /ws → WebSocket for live events
|
|
12
|
+
/api/* → REST + htmx endpoints
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
import os as _os
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
from fastapi import FastAPI
|
|
21
|
+
from fastapi.responses import HTMLResponse
|
|
22
|
+
from fastapi.staticfiles import StaticFiles
|
|
23
|
+
|
|
24
|
+
_log = logging.getLogger("patchi.web.app")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_app(root: Path) -> FastAPI:
|
|
28
|
+
"""Build and return the FastAPI application."""
|
|
29
|
+
app = FastAPI(title="Patchi", docs_url=None, redoc_url=None)
|
|
30
|
+
|
|
31
|
+
# Restrict CORS to localhost for security - allow_origins can be configured via env var
|
|
32
|
+
import os
|
|
33
|
+
|
|
34
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
35
|
+
|
|
36
|
+
allowed_origins = os.environ.get(
|
|
37
|
+
"PATCHI_CORS_ORIGINS", "http://localhost:3000,http://localhost:8000"
|
|
38
|
+
).split(",")
|
|
39
|
+
app.add_middleware(
|
|
40
|
+
CORSMiddleware,
|
|
41
|
+
allow_origins=allowed_origins,
|
|
42
|
+
allow_credentials=False,
|
|
43
|
+
allow_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
|
|
44
|
+
allow_headers=["*"],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Store project root
|
|
48
|
+
app.state.root = root
|
|
49
|
+
|
|
50
|
+
# Initialize cost tracker (was only in dead server.py — now wired here)
|
|
51
|
+
try:
|
|
52
|
+
from patchi.core.ai.cost_tracker import init_cost
|
|
53
|
+
|
|
54
|
+
init_cost(root)
|
|
55
|
+
except Exception as e:
|
|
56
|
+
import logging
|
|
57
|
+
|
|
58
|
+
logging.getLogger("patchi.web").warning("Cost tracker init failed: %s", e)
|
|
59
|
+
|
|
60
|
+
# Initialize tenant manager for multi-project isolation
|
|
61
|
+
try:
|
|
62
|
+
from patchi.core.tenant import get_tenant_manager
|
|
63
|
+
|
|
64
|
+
tenant_mgr = get_tenant_manager()
|
|
65
|
+
tenant_mgr.register_project(root)
|
|
66
|
+
tenant_mgr.switch_project(root)
|
|
67
|
+
app.state.tenant_manager = tenant_mgr
|
|
68
|
+
except Exception as e:
|
|
69
|
+
import logging
|
|
70
|
+
|
|
71
|
+
logging.getLogger("patchi.web").warning("Tenant manager init failed: %s", e)
|
|
72
|
+
|
|
73
|
+
# Initialize SpawnManager (was only in dead server.py — now wired here)
|
|
74
|
+
try:
|
|
75
|
+
from patchi.web.spawn import SpawnManager
|
|
76
|
+
|
|
77
|
+
app.state.spawner = SpawnManager(root)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
import logging
|
|
80
|
+
|
|
81
|
+
logging.getLogger("patchi.web").warning("SpawnManager init failed: %s", e)
|
|
82
|
+
app.state.spawner = None
|
|
83
|
+
|
|
84
|
+
# Wire RequestInterceptor as ASGI middleware for runtime threat detection
|
|
85
|
+
try:
|
|
86
|
+
from patchi.core import config as _cfg
|
|
87
|
+
from patchi.core.security.request_interceptor import RequestInterceptor
|
|
88
|
+
|
|
89
|
+
_conf = _cfg.load(root)
|
|
90
|
+
interceptor = RequestInterceptor(root, _conf)
|
|
91
|
+
interceptor.enabled = _conf.get("pipeline", {}).get("interceptor", {}).get("enabled", False)
|
|
92
|
+
app.state.interceptor = interceptor
|
|
93
|
+
if interceptor.enabled:
|
|
94
|
+
|
|
95
|
+
@app.middleware("http")
|
|
96
|
+
async def security_interceptor(request, call_next):
|
|
97
|
+
result = interceptor.inspect_request(
|
|
98
|
+
request.method,
|
|
99
|
+
str(request.url.path),
|
|
100
|
+
dict(request.headers),
|
|
101
|
+
)
|
|
102
|
+
if result["should_block"]:
|
|
103
|
+
from fastapi.responses import JSONResponse
|
|
104
|
+
|
|
105
|
+
return JSONResponse(
|
|
106
|
+
status_code=403,
|
|
107
|
+
content={"error": "Request blocked", "reason": result["reason"]},
|
|
108
|
+
)
|
|
109
|
+
return await call_next(request)
|
|
110
|
+
|
|
111
|
+
import logging as _lg
|
|
112
|
+
|
|
113
|
+
_lg.getLogger("patchi.web").info(
|
|
114
|
+
"RequestInterceptor enabled — %d paths excluded", len(interceptor.exclude_paths)
|
|
115
|
+
)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
import logging
|
|
118
|
+
|
|
119
|
+
logging.getLogger("patchi.web").warning("RequestInterceptor init failed: %s", e)
|
|
120
|
+
app.state.interceptor = None
|
|
121
|
+
|
|
122
|
+
# ── Tenant context middleware ──────────────────────────────────────────
|
|
123
|
+
# Wraps every request so get_current_tenant_root() returns the active
|
|
124
|
+
# project, and call_ai() can resolve the model router's profiler data.
|
|
125
|
+
try:
|
|
126
|
+
from patchi.core.tenant import tenant_context
|
|
127
|
+
|
|
128
|
+
@app.middleware("http")
|
|
129
|
+
async def tenant_middleware(request, call_next):
|
|
130
|
+
root = request.app.state.root
|
|
131
|
+
with tenant_context(root):
|
|
132
|
+
return await call_next(request)
|
|
133
|
+
except Exception as _exc:
|
|
134
|
+
_log.debug("tenant middleware not wired: %s", _exc)
|
|
135
|
+
|
|
136
|
+
# Mount static files
|
|
137
|
+
import sys as _sys
|
|
138
|
+
|
|
139
|
+
if getattr(_sys, "frozen", False):
|
|
140
|
+
_base = Path(_sys._MEIPASS) / "patchi" / "web"
|
|
141
|
+
else:
|
|
142
|
+
_base = Path(__file__).parent
|
|
143
|
+
static_dir = _base / "static"
|
|
144
|
+
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
|
|
145
|
+
|
|
146
|
+
# Performance: cache static assets with versioned URLs
|
|
147
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
148
|
+
|
|
149
|
+
class StaticCacheMiddleware(BaseHTTPMiddleware):
|
|
150
|
+
async def dispatch(self, request, call_next):
|
|
151
|
+
response = await call_next(request)
|
|
152
|
+
if request.url.path.startswith("/static/"):
|
|
153
|
+
# Long cache for static assets (they have ?v=N cache-busting)
|
|
154
|
+
response.headers["Cache-Control"] = "public, max-age=86400, stale-while-revalidate=604800"
|
|
155
|
+
return response
|
|
156
|
+
|
|
157
|
+
app.add_middleware(StaticCacheMiddleware)
|
|
158
|
+
|
|
159
|
+
# Import and register routes
|
|
160
|
+
from patchi.web.api.brain_map import router as brain_map_router
|
|
161
|
+
from patchi.web.api.charts import router as charts_router
|
|
162
|
+
from patchi.web.api.chat import router as chat_api_router
|
|
163
|
+
from patchi.web.api.fix import router as fix_router
|
|
164
|
+
from patchi.web.api.guard import router as guard_api_router
|
|
165
|
+
from patchi.web.api.hosted import router as hosted_router
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
from patchi.web.api.hosted_v2 import router as hosted_v2_router
|
|
169
|
+
except Exception as e:
|
|
170
|
+
_logging = __import__("logging")
|
|
171
|
+
_logging.getLogger("patchi.web").warning("Hosted v2 API not available: %s", e)
|
|
172
|
+
hosted_v2_router = None
|
|
173
|
+
from patchi.web.api.dev_check import router as dev_check_router
|
|
174
|
+
from patchi.web.api.scan import router as scan_router
|
|
175
|
+
from patchi.web.api_legacy import router as legacy_router
|
|
176
|
+
from patchi.web.routes.brain import router as brain_router
|
|
177
|
+
from patchi.web.routes.chat import router as chat_router
|
|
178
|
+
from patchi.web.routes.dashboard import router as dashboard_router
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
from patchi.web.routes.dashboard_v2 import router as dashboard_v2_router
|
|
182
|
+
except Exception as e: # v2 dashboard is additive — never break core UI
|
|
183
|
+
import logging as _logging
|
|
184
|
+
|
|
185
|
+
_logging.getLogger("patchi.web").warning("Dashboard v2 not available: %s", e)
|
|
186
|
+
dashboard_v2_router = None
|
|
187
|
+
from patchi.web.api.cicd import router as cicd_router
|
|
188
|
+
from patchi.web.api.dast_evidence import router as dast_evidence_router
|
|
189
|
+
from patchi.web.api.live_testing import router as live_testing_api_router
|
|
190
|
+
from patchi.web.api.smart import router as smart_api_router
|
|
191
|
+
from patchi.web.api.tenant import router as tenant_router
|
|
192
|
+
from patchi.web.routes.assurance import router as assurance_router
|
|
193
|
+
from patchi.web.routes.charter import router as charter_router
|
|
194
|
+
from patchi.web.routes.findings import router as findings_router
|
|
195
|
+
from patchi.web.routes.guard import router as guard_router
|
|
196
|
+
from patchi.web.routes.history import router as history_router
|
|
197
|
+
from patchi.web.routes.live_testing import router as live_testing_router
|
|
198
|
+
from patchi.web.routes.review import router as review_router
|
|
199
|
+
from patchi.web.routes.self_improvement import router as self_improvement_router
|
|
200
|
+
from patchi.web.routes.settings import router as settings_router
|
|
201
|
+
from patchi.web.routes.tokens import router as tokens_router
|
|
202
|
+
|
|
203
|
+
app.include_router(legacy_router)
|
|
204
|
+
app.include_router(dashboard_router)
|
|
205
|
+
app.include_router(findings_router)
|
|
206
|
+
app.include_router(charter_router)
|
|
207
|
+
app.include_router(review_router)
|
|
208
|
+
app.include_router(guard_router)
|
|
209
|
+
app.include_router(chat_router)
|
|
210
|
+
app.include_router(brain_router)
|
|
211
|
+
app.include_router(settings_router)
|
|
212
|
+
app.include_router(history_router)
|
|
213
|
+
app.include_router(brain_map_router)
|
|
214
|
+
app.include_router(dev_check_router)
|
|
215
|
+
app.include_router(scan_router)
|
|
216
|
+
app.include_router(charts_router)
|
|
217
|
+
app.include_router(fix_router)
|
|
218
|
+
app.include_router(hosted_router)
|
|
219
|
+
if hosted_v2_router is not None:
|
|
220
|
+
app.include_router(hosted_v2_router)
|
|
221
|
+
app.include_router(assurance_router)
|
|
222
|
+
app.include_router(chat_api_router)
|
|
223
|
+
app.include_router(guard_api_router)
|
|
224
|
+
app.include_router(tokens_router)
|
|
225
|
+
app.include_router(live_testing_router)
|
|
226
|
+
app.include_router(self_improvement_router)
|
|
227
|
+
app.include_router(cicd_router)
|
|
228
|
+
app.include_router(live_testing_api_router)
|
|
229
|
+
app.include_router(smart_api_router)
|
|
230
|
+
app.include_router(tenant_router)
|
|
231
|
+
app.include_router(dast_evidence_router)
|
|
232
|
+
if dashboard_v2_router is not None:
|
|
233
|
+
app.include_router(dashboard_v2_router)
|
|
234
|
+
|
|
235
|
+
# WebSocket endpoint - use unified handler from dashboard
|
|
236
|
+
from patchi.web.routes.dashboard import websocket_endpoint as unified_ws_endpoint
|
|
237
|
+
|
|
238
|
+
app.websocket("/ws")(unified_ws_endpoint)
|
|
239
|
+
|
|
240
|
+
# Error handlers
|
|
241
|
+
@app.exception_handler(404)
|
|
242
|
+
async def not_found(request, exc):
|
|
243
|
+
return HTMLResponse(
|
|
244
|
+
"""<!DOCTYPE html><html lang="en">
|
|
245
|
+
<head><meta charset="UTF-8"><title>404 — Patchi</title>
|
|
246
|
+
<link rel="stylesheet" href="/static/dashboard_v2.css?v=10"></head>
|
|
247
|
+
<body style="display:flex;align-items:center;justify-content:center;height:100vh;background:var(--bg-primary)">
|
|
248
|
+
<div style="text-align:center">
|
|
249
|
+
<h1 style="font-size:72px;color:var(--accent);margin:0">404</h1>
|
|
250
|
+
<p style="color:var(--text-secondary);margin:16px 0 24px">This page doesn't exist.</p>
|
|
251
|
+
<a href="/" class="btn btn-primary" style="text-decoration:none">← Back to Dashboard</a>
|
|
252
|
+
</div></body></html>""",
|
|
253
|
+
status_code=404,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
@app.exception_handler(500)
|
|
257
|
+
async def server_error(request, exc):
|
|
258
|
+
return HTMLResponse(
|
|
259
|
+
"""<!DOCTYPE html><html lang="en">
|
|
260
|
+
<head><meta charset="UTF-8"><title>500 — Patchi</title>
|
|
261
|
+
<link rel="stylesheet" href="/static/dashboard_v2.css?v=10"></head>
|
|
262
|
+
<body style="display:flex;align-items:center;justify-content:center;height:100vh;background:var(--bg-primary)">
|
|
263
|
+
<div style="text-align:center">
|
|
264
|
+
<h1 style="font-size:72px;color:var(--critical);margin:0">500</h1>
|
|
265
|
+
<p style="color:var(--text-secondary);margin:16px 0 24px">Something went wrong on our end.</p>
|
|
266
|
+
<a href="/" class="btn btn-primary" style="text-decoration:none">← Back to Dashboard</a>
|
|
267
|
+
</div></body></html>""",
|
|
268
|
+
status_code=500,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
# Favicon
|
|
272
|
+
from fastapi.responses import FileResponse
|
|
273
|
+
|
|
274
|
+
@app.get("/favicon.ico")
|
|
275
|
+
async def favicon():
|
|
276
|
+
fav = static_dir / "favicon.ico"
|
|
277
|
+
if fav.exists():
|
|
278
|
+
return FileResponse(str(fav), media_type="image/x-icon")
|
|
279
|
+
return HTMLResponse("")
|
|
280
|
+
|
|
281
|
+
# Fast health endpoint — always responds in <10ms
|
|
282
|
+
@app.get("/health")
|
|
283
|
+
async def health():
|
|
284
|
+
from fastapi.responses import JSONResponse
|
|
285
|
+
return JSONResponse({"status": "ok"})
|
|
286
|
+
|
|
287
|
+
# Warm caches at startup so first dashboard request is fast
|
|
288
|
+
@app.on_event("startup")
|
|
289
|
+
async def _warm_caches():
|
|
290
|
+
import asyncio
|
|
291
|
+
_r = root
|
|
292
|
+
def _do():
|
|
293
|
+
try:
|
|
294
|
+
from patchi.core.security.domain_loader import DomainLoader
|
|
295
|
+
dl = DomainLoader(_r)
|
|
296
|
+
dl.load_all()
|
|
297
|
+
_log.info("Domain cache warmed: %d domains", len(dl._domains))
|
|
298
|
+
except Exception as exc:
|
|
299
|
+
_log.debug("Domain cache warm-up skipped: %s", exc)
|
|
300
|
+
try:
|
|
301
|
+
from patchi.core.health import compute as ch
|
|
302
|
+
ch(_r)
|
|
303
|
+
except Exception as _exc:
|
|
304
|
+
_log.debug('suppressed: %s', _exc)
|
|
305
|
+
await asyncio.to_thread(_do)
|
|
306
|
+
|
|
307
|
+
return app
|
|
308
|
+
|
|
309
|
+
# Module-level app for uvicorn discovery
|
|
310
|
+
app = create_app(Path(_os.getcwd()))
|