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,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`p quick` — Fast readiness check with subset of agents.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
p quick — fast readiness check
|
|
6
|
+
p quick --json — JSON output
|
|
7
|
+
|
|
8
|
+
Runs a minimal set of agents to quickly check if code is ready:
|
|
9
|
+
- Unit tests
|
|
10
|
+
- Secret scanning
|
|
11
|
+
- Basic security check
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
import sys
|
|
19
|
+
import time
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
from rich.table import Table
|
|
23
|
+
|
|
24
|
+
from patchi.cli.console import con
|
|
25
|
+
from patchi.cli.ux import (
|
|
26
|
+
format_error,
|
|
27
|
+
format_header,
|
|
28
|
+
format_step,
|
|
29
|
+
spinner,
|
|
30
|
+
status_icon,
|
|
31
|
+
status_style,
|
|
32
|
+
summary_panel,
|
|
33
|
+
)
|
|
34
|
+
from patchi.core.config import require_project_root
|
|
35
|
+
|
|
36
|
+
_log = logging.getLogger("patchi.cli.quick")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _run_agent_safe(agent_cls, root: Path, brain: dict, config: dict):
|
|
40
|
+
"""Run an agent and return results, catching exceptions."""
|
|
41
|
+
from patchi.core.agents.base import AgentInput
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
inp = AgentInput(root=root, scope=[], brain=brain, config=config, extra={})
|
|
45
|
+
return agent_cls().run(inp)
|
|
46
|
+
except Exception as e:
|
|
47
|
+
_log.debug("Agent %s failed: %s", agent_cls.name, e)
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def run(
|
|
52
|
+
json_output: bool = False,
|
|
53
|
+
root: Path | None = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Entry point for `p quick`."""
|
|
56
|
+
try:
|
|
57
|
+
r = root or require_project_root()
|
|
58
|
+
except RuntimeError as e:
|
|
59
|
+
con.print(format_error(str(e)))
|
|
60
|
+
if json_output:
|
|
61
|
+
print(json.dumps({"ready": False, "error": str(e)}))
|
|
62
|
+
sys.exit(1)
|
|
63
|
+
|
|
64
|
+
from patchi.core.agents.base import discover_agent_modules
|
|
65
|
+
discover_agent_modules()
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
from patchi.core import config as cfg
|
|
69
|
+
from patchi.core import memory as mem
|
|
70
|
+
|
|
71
|
+
brain = mem.get_brain(r)
|
|
72
|
+
config = cfg.load(r)
|
|
73
|
+
except Exception:
|
|
74
|
+
brain, config = {}, {}
|
|
75
|
+
|
|
76
|
+
con.print()
|
|
77
|
+
con.print(format_header("Quick Readiness Check", "Fast verification of critical checks"))
|
|
78
|
+
con.print()
|
|
79
|
+
|
|
80
|
+
results = {}
|
|
81
|
+
start_time = time.time()
|
|
82
|
+
|
|
83
|
+
# Define the quick check agents (subset for speed)
|
|
84
|
+
quick_checks = [
|
|
85
|
+
("unit_test", "patchi.core.testing.unit_test_agent", "UnitTestAgent"),
|
|
86
|
+
("secrets", "patchi.core.security.secrets_runtime_agent", "SecretsRuntimeAgent"),
|
|
87
|
+
("bandit", "patchi.core.agents.scanners.bandit_agent", "BanditAgent"),
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
with spinner("Running quick checks...") as update:
|
|
91
|
+
for i, (name, module_path, class_name) in enumerate(quick_checks, 1):
|
|
92
|
+
update(f"Step {i}/{len(quick_checks)}: Running {name}...")
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
import importlib
|
|
96
|
+
module = importlib.import_module(module_path)
|
|
97
|
+
agent_cls = getattr(module, class_name)
|
|
98
|
+
result = _run_agent_safe(agent_cls, r, brain, config)
|
|
99
|
+
if result:
|
|
100
|
+
results[name] = {
|
|
101
|
+
"status": result.status.value,
|
|
102
|
+
"findings": result.finding_count,
|
|
103
|
+
"files_scanned": result.files_scanned,
|
|
104
|
+
}
|
|
105
|
+
else:
|
|
106
|
+
results[name] = {"status": "error", "findings": 0, "files_scanned": 0}
|
|
107
|
+
except Exception as e:
|
|
108
|
+
_log.debug("Failed to load %s: %s", name, e)
|
|
109
|
+
results[name] = {"status": "error", "findings": 0, "files_scanned": 0}
|
|
110
|
+
|
|
111
|
+
elapsed = time.time() - start_time
|
|
112
|
+
|
|
113
|
+
# Compute readiness
|
|
114
|
+
is_ready = all(r.get("status") == "done" for r in results.values())
|
|
115
|
+
total_findings = sum(r.get("findings", 0) for r in results.values())
|
|
116
|
+
|
|
117
|
+
# Display results
|
|
118
|
+
con.print()
|
|
119
|
+
|
|
120
|
+
if json_output:
|
|
121
|
+
output = {
|
|
122
|
+
"ready": is_ready,
|
|
123
|
+
"elapsed_seconds": round(elapsed, 2),
|
|
124
|
+
"total_findings": total_findings,
|
|
125
|
+
"results": results,
|
|
126
|
+
}
|
|
127
|
+
con.print(json.dumps(output, indent=2))
|
|
128
|
+
else:
|
|
129
|
+
# Show results table
|
|
130
|
+
table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
|
|
131
|
+
table.add_column("Check", style="cyan")
|
|
132
|
+
table.add_column("Status", justify="center")
|
|
133
|
+
table.add_column("Findings", justify="right")
|
|
134
|
+
table.add_column("Files", justify="right")
|
|
135
|
+
|
|
136
|
+
for name, data in results.items():
|
|
137
|
+
s = data["status"]
|
|
138
|
+
icon = status_icon(s)
|
|
139
|
+
style = status_style(s)
|
|
140
|
+
status_str = f"[{style}]{icon} {s}[/{style}]"
|
|
141
|
+
|
|
142
|
+
findings = data["findings"]
|
|
143
|
+
if findings > 0:
|
|
144
|
+
findings_style = f"[red]{findings}[/red]"
|
|
145
|
+
else:
|
|
146
|
+
findings_style = "[green]0[/green]"
|
|
147
|
+
|
|
148
|
+
table.add_row(name, status_str, findings_style, str(data["files_scanned"]))
|
|
149
|
+
|
|
150
|
+
con.print(table)
|
|
151
|
+
con.print()
|
|
152
|
+
|
|
153
|
+
# Summary
|
|
154
|
+
items = {name: data["status"] == "done" for name, data in results.items()}
|
|
155
|
+
con.print(summary_panel("Quick Check", items, elapsed))
|
|
156
|
+
con.print()
|
|
157
|
+
|
|
158
|
+
if not is_ready:
|
|
159
|
+
sys.exit(1)
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ready command — Ship Readiness Check.
|
|
3
|
+
|
|
4
|
+
Runs a comprehensive check across all domains to determine if the code is
|
|
5
|
+
ready to ship. Outputs a detailed report with pass/fail status.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
p ready → full ship readiness check
|
|
9
|
+
p ready --json → JSON output
|
|
10
|
+
p ready --quick → fast check (subset of agents)
|
|
11
|
+
p ready --ci → CI-friendly output (exit code 1 on failure)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
import sys
|
|
19
|
+
import time
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
from rich.panel import Panel
|
|
23
|
+
from rich.table import Table
|
|
24
|
+
|
|
25
|
+
from patchi.cli.console import con
|
|
26
|
+
from patchi.cli.ux import (
|
|
27
|
+
format_header,
|
|
28
|
+
format_step,
|
|
29
|
+
progress_bar,
|
|
30
|
+
spinner,
|
|
31
|
+
status_icon,
|
|
32
|
+
status_style,
|
|
33
|
+
summary_panel,
|
|
34
|
+
)
|
|
35
|
+
from patchi.core.config import require_project_root
|
|
36
|
+
|
|
37
|
+
_log = logging.getLogger("patchi.cli.ready")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _run_agent_safe(agent_cls, root: Path, brain: dict, config: dict, extra: dict | None = None):
|
|
41
|
+
"""Run an agent and return results, catching exceptions."""
|
|
42
|
+
from patchi.core.agents.base import AgentInput
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
inp = AgentInput(root=root, scope=[], brain=brain, config=config, extra=extra or {})
|
|
46
|
+
return agent_cls().run(inp)
|
|
47
|
+
except Exception as e:
|
|
48
|
+
_log.debug("Agent %s failed: %s", agent_cls.name, e)
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _check_testing(root: Path, brain: dict, config: dict) -> dict:
|
|
53
|
+
"""Run testing agents and return results."""
|
|
54
|
+
from patchi.core.testing.unit_test_agent import UnitTestAgent
|
|
55
|
+
from patchi.core.testing.regression_agent import RegressionAgent
|
|
56
|
+
from patchi.core.testing.flake_detector_agent import FlakeDetectorAgent
|
|
57
|
+
|
|
58
|
+
results = {}
|
|
59
|
+
agents = [
|
|
60
|
+
("unit_test", UnitTestAgent),
|
|
61
|
+
("regression", RegressionAgent),
|
|
62
|
+
("flake_detector", FlakeDetectorAgent),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
for name, cls in agents:
|
|
66
|
+
res = _run_agent_safe(cls, root, brain, config)
|
|
67
|
+
if res:
|
|
68
|
+
results[name] = {
|
|
69
|
+
"status": res.status.value,
|
|
70
|
+
"findings": res.finding_count,
|
|
71
|
+
"files_scanned": res.files_scanned,
|
|
72
|
+
}
|
|
73
|
+
else:
|
|
74
|
+
results[name] = {"status": "error", "findings": 0, "files_scanned": 0}
|
|
75
|
+
|
|
76
|
+
return results
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _check_code_quality(root: Path, brain: dict, config: dict) -> dict:
|
|
80
|
+
"""Run code quality agents and return results."""
|
|
81
|
+
from patchi.core.agents.base import list_agents, AgentGroup
|
|
82
|
+
|
|
83
|
+
results = {}
|
|
84
|
+
# Get scanner agents for code quality
|
|
85
|
+
scanners = [a for a in list_agents(AgentGroup.SCANNER) if a.name in (
|
|
86
|
+
"BanditAgent", "SemgrepAgent", "CatchBlockAuditor",
|
|
87
|
+
)]
|
|
88
|
+
|
|
89
|
+
for cls in scanners:
|
|
90
|
+
res = _run_agent_safe(cls, root, brain, config)
|
|
91
|
+
if res:
|
|
92
|
+
results[cls.name] = {
|
|
93
|
+
"status": res.status.value,
|
|
94
|
+
"findings": res.finding_count,
|
|
95
|
+
"files_scanned": res.files_scanned,
|
|
96
|
+
}
|
|
97
|
+
else:
|
|
98
|
+
results[cls.name] = {"status": "error", "findings": 0, "files_scanned": 0}
|
|
99
|
+
|
|
100
|
+
return results
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _check_security(root: Path, brain: dict, config: dict) -> dict:
|
|
104
|
+
"""Run security agents and return results."""
|
|
105
|
+
from patchi.core.security.secrets_runtime_agent import SecretsRuntimeAgent
|
|
106
|
+
from patchi.core.security.misconfig_agent import MisconfigAgent
|
|
107
|
+
from patchi.core.agents.base import list_agents, AgentGroup
|
|
108
|
+
|
|
109
|
+
results = {}
|
|
110
|
+
|
|
111
|
+
# Core security agents
|
|
112
|
+
core_agents = [
|
|
113
|
+
("secrets", SecretsRuntimeAgent),
|
|
114
|
+
("misconfig", MisconfigAgent),
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
for name, cls in core_agents:
|
|
118
|
+
res = _run_agent_safe(cls, root, brain, config)
|
|
119
|
+
if res:
|
|
120
|
+
results[name] = {
|
|
121
|
+
"status": res.status.value,
|
|
122
|
+
"findings": res.finding_count,
|
|
123
|
+
"files_scanned": res.files_scanned,
|
|
124
|
+
}
|
|
125
|
+
else:
|
|
126
|
+
results[name] = {"status": "error", "findings": 0, "files_scanned": 0}
|
|
127
|
+
|
|
128
|
+
return results
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _check_integration(root: Path, brain: dict, config: dict) -> dict:
|
|
132
|
+
"""Run integration agents and return results."""
|
|
133
|
+
from patchi.core.testing.api_contract_agent import APIContractAgent
|
|
134
|
+
|
|
135
|
+
results = {}
|
|
136
|
+
res = _run_agent_safe(APIContractAgent, root, brain, config)
|
|
137
|
+
if res:
|
|
138
|
+
results["api_contract"] = {
|
|
139
|
+
"status": res.status.value,
|
|
140
|
+
"findings": res.finding_count,
|
|
141
|
+
"files_scanned": res.files_scanned,
|
|
142
|
+
}
|
|
143
|
+
else:
|
|
144
|
+
results["api_contract"] = {"status": "error", "findings": 0, "files_scanned": 0}
|
|
145
|
+
|
|
146
|
+
return results
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _format_results_table(results: dict, title: str) -> Table:
|
|
150
|
+
"""Format results as a Rich table."""
|
|
151
|
+
table = Table(title=title, show_header=True, header_style="bold")
|
|
152
|
+
table.add_column("Check", style="cyan")
|
|
153
|
+
table.add_column("Status", justify="center")
|
|
154
|
+
table.add_column("Findings", justify="right")
|
|
155
|
+
table.add_column("Files", justify="right")
|
|
156
|
+
|
|
157
|
+
for name, data in results.items():
|
|
158
|
+
s = data["status"]
|
|
159
|
+
icon = status_icon(s)
|
|
160
|
+
style = status_style(s)
|
|
161
|
+
status_str = f"[{style}]{icon} {s}[/{style}]"
|
|
162
|
+
|
|
163
|
+
findings = data["findings"]
|
|
164
|
+
if findings > 0:
|
|
165
|
+
findings_style = f"[red]{findings}[/red]"
|
|
166
|
+
else:
|
|
167
|
+
findings_style = "[green]0[/green]"
|
|
168
|
+
|
|
169
|
+
table.add_row(name, status_str, findings_style, str(data["files_scanned"]))
|
|
170
|
+
|
|
171
|
+
return table
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _compute_readiness(results: dict) -> tuple[bool, dict]:
|
|
175
|
+
"""Compute overall readiness from results."""
|
|
176
|
+
total_findings = 0
|
|
177
|
+
critical_findings = 0
|
|
178
|
+
failed_checks = 0
|
|
179
|
+
|
|
180
|
+
for category, checks in results.items():
|
|
181
|
+
for name, data in checks.items():
|
|
182
|
+
total_findings += data.get("findings", 0)
|
|
183
|
+
if data.get("status") == "error":
|
|
184
|
+
failed_checks += 1
|
|
185
|
+
|
|
186
|
+
# Readiness criteria:
|
|
187
|
+
# - No critical findings
|
|
188
|
+
# - All checks completed
|
|
189
|
+
is_ready = critical_findings == 0 and failed_checks == 0
|
|
190
|
+
|
|
191
|
+
return is_ready, {
|
|
192
|
+
"total_findings": total_findings,
|
|
193
|
+
"critical_findings": critical_findings,
|
|
194
|
+
"failed_checks": failed_checks,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def run(
|
|
199
|
+
json_output: bool = False,
|
|
200
|
+
quick: bool = False,
|
|
201
|
+
ci: bool = False,
|
|
202
|
+
root: Path | None = None,
|
|
203
|
+
) -> None:
|
|
204
|
+
"""Run the ship readiness check."""
|
|
205
|
+
try:
|
|
206
|
+
r = root or require_project_root()
|
|
207
|
+
except RuntimeError as e:
|
|
208
|
+
con.print(f"[red]{e}[/red]")
|
|
209
|
+
if ci:
|
|
210
|
+
sys.exit(1)
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
from patchi.core.agents.base import discover_agent_modules
|
|
214
|
+
discover_agent_modules()
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
from patchi.core import config as cfg
|
|
218
|
+
from patchi.core import memory as mem
|
|
219
|
+
|
|
220
|
+
brain = mem.get_brain(r)
|
|
221
|
+
config = cfg.load(r)
|
|
222
|
+
except Exception:
|
|
223
|
+
brain, config = {}, {}
|
|
224
|
+
|
|
225
|
+
con.print()
|
|
226
|
+
con.print(format_header("Ship Readiness Check", "Verifying your code is ready to ship"))
|
|
227
|
+
con.print()
|
|
228
|
+
|
|
229
|
+
# Run checks with progress
|
|
230
|
+
all_results = {}
|
|
231
|
+
start_time = time.time()
|
|
232
|
+
|
|
233
|
+
steps = [
|
|
234
|
+
("testing", "Running unit tests & regression checks"),
|
|
235
|
+
("code_quality", "Analyzing code quality"),
|
|
236
|
+
("integration", "Checking API contracts"),
|
|
237
|
+
("security", "Scanning for security issues"),
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
if quick:
|
|
241
|
+
steps = [steps[0], steps[3]] # Only testing and security
|
|
242
|
+
|
|
243
|
+
total_steps = len(steps)
|
|
244
|
+
|
|
245
|
+
with spinner("Initializing checks...") as update:
|
|
246
|
+
for i, (category, description) in enumerate(steps, 1):
|
|
247
|
+
update(f"Step {i}/{total_steps}: {description}")
|
|
248
|
+
|
|
249
|
+
if category == "testing":
|
|
250
|
+
all_results["testing"] = _check_testing(r, brain, config)
|
|
251
|
+
elif category == "code_quality" and not quick:
|
|
252
|
+
all_results["code_quality"] = _check_code_quality(r, brain, config)
|
|
253
|
+
elif category == "integration" and not quick:
|
|
254
|
+
all_results["integration"] = _check_integration(r, brain, config)
|
|
255
|
+
elif category == "security":
|
|
256
|
+
all_results["security"] = _check_security(r, brain, config)
|
|
257
|
+
|
|
258
|
+
elapsed = time.time() - start_time
|
|
259
|
+
|
|
260
|
+
# Compute readiness
|
|
261
|
+
is_ready, summary = _compute_readiness(all_results)
|
|
262
|
+
|
|
263
|
+
# Display results
|
|
264
|
+
con.print()
|
|
265
|
+
|
|
266
|
+
if json_output:
|
|
267
|
+
output = {
|
|
268
|
+
"ready": is_ready,
|
|
269
|
+
"elapsed_seconds": round(elapsed, 2),
|
|
270
|
+
"summary": summary,
|
|
271
|
+
"results": all_results,
|
|
272
|
+
}
|
|
273
|
+
con.print(json.dumps(output, indent=2))
|
|
274
|
+
else:
|
|
275
|
+
# Show tables for each category
|
|
276
|
+
for category, checks in all_results.items():
|
|
277
|
+
title = category.replace("_", " ").title()
|
|
278
|
+
table = _format_results_table(checks, title)
|
|
279
|
+
con.print(table)
|
|
280
|
+
con.print()
|
|
281
|
+
|
|
282
|
+
# Show summary
|
|
283
|
+
items = {}
|
|
284
|
+
for category, checks in all_results.items():
|
|
285
|
+
for name, data in checks.items():
|
|
286
|
+
items[f"{category}/{name}"] = data.get("status") == "done"
|
|
287
|
+
|
|
288
|
+
con.print(summary_panel("Ship Readiness", items, elapsed))
|
|
289
|
+
con.print()
|
|
290
|
+
|
|
291
|
+
if ci and not is_ready:
|
|
292
|
+
sys.exit(1)
|