raxe 0.4.6__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.
- raxe/__init__.py +101 -0
- raxe/application/__init__.py +48 -0
- raxe/application/ab_testing.py +170 -0
- raxe/application/analytics/__init__.py +30 -0
- raxe/application/analytics/achievement_service.py +444 -0
- raxe/application/analytics/repositories.py +172 -0
- raxe/application/analytics/retention_service.py +267 -0
- raxe/application/analytics/statistics_service.py +419 -0
- raxe/application/analytics/streak_service.py +283 -0
- raxe/application/apply_policy.py +291 -0
- raxe/application/eager_l2.py +503 -0
- raxe/application/preloader.py +353 -0
- raxe/application/scan_merger.py +321 -0
- raxe/application/scan_pipeline.py +1059 -0
- raxe/application/scan_pipeline_async.py +403 -0
- raxe/application/session_tracker.py +458 -0
- raxe/application/telemetry_manager.py +357 -0
- raxe/application/telemetry_orchestrator.py +1210 -0
- raxe/async_sdk/__init__.py +34 -0
- raxe/async_sdk/cache.py +286 -0
- raxe/async_sdk/client.py +556 -0
- raxe/async_sdk/wrappers/__init__.py +23 -0
- raxe/async_sdk/wrappers/openai.py +238 -0
- raxe/cli/__init__.py +21 -0
- raxe/cli/auth.py +1047 -0
- raxe/cli/branding.py +235 -0
- raxe/cli/config.py +334 -0
- raxe/cli/custom_rules.py +458 -0
- raxe/cli/doctor.py +686 -0
- raxe/cli/error_handler.py +665 -0
- raxe/cli/event.py +648 -0
- raxe/cli/exit_codes.py +57 -0
- raxe/cli/expiry_warning.py +302 -0
- raxe/cli/export.py +183 -0
- raxe/cli/history.py +247 -0
- raxe/cli/l2_formatter.py +872 -0
- raxe/cli/main.py +1137 -0
- raxe/cli/models.py +590 -0
- raxe/cli/output.py +403 -0
- raxe/cli/privacy.py +84 -0
- raxe/cli/profiler.py +262 -0
- raxe/cli/progress.py +379 -0
- raxe/cli/progress_context.py +101 -0
- raxe/cli/repl.py +394 -0
- raxe/cli/rules.py +542 -0
- raxe/cli/setup_wizard.py +721 -0
- raxe/cli/stats.py +292 -0
- raxe/cli/suppress.py +501 -0
- raxe/cli/telemetry.py +1384 -0
- raxe/cli/test.py +130 -0
- raxe/cli/tune.py +315 -0
- raxe/cli/validate.py +218 -0
- raxe/domain/__init__.py +30 -0
- raxe/domain/analytics/__init__.py +97 -0
- raxe/domain/analytics/achievements.py +306 -0
- raxe/domain/analytics/models.py +120 -0
- raxe/domain/analytics/retention.py +168 -0
- raxe/domain/analytics/statistics.py +207 -0
- raxe/domain/analytics/streaks.py +173 -0
- raxe/domain/engine/__init__.py +15 -0
- raxe/domain/engine/executor.py +396 -0
- raxe/domain/engine/matcher.py +212 -0
- raxe/domain/inline_suppression.py +176 -0
- raxe/domain/ml/__init__.py +133 -0
- raxe/domain/ml/embedding_cache.py +309 -0
- raxe/domain/ml/gemma_detector.py +921 -0
- raxe/domain/ml/gemma_models.py +346 -0
- raxe/domain/ml/l2_config.py +428 -0
- raxe/domain/ml/l2_output_schema.py +443 -0
- raxe/domain/ml/manifest_loader.py +309 -0
- raxe/domain/ml/manifest_schema.py +345 -0
- raxe/domain/ml/model_metadata.py +263 -0
- raxe/domain/ml/model_registry.py +786 -0
- raxe/domain/ml/protocol.py +282 -0
- raxe/domain/ml/scoring_models.py +419 -0
- raxe/domain/ml/stub_detector.py +397 -0
- raxe/domain/ml/threat_scorer.py +757 -0
- raxe/domain/ml/tokenizer_registry.py +372 -0
- raxe/domain/ml/voting/__init__.py +89 -0
- raxe/domain/ml/voting/config.py +595 -0
- raxe/domain/ml/voting/engine.py +465 -0
- raxe/domain/ml/voting/head_voters.py +378 -0
- raxe/domain/ml/voting/models.py +222 -0
- raxe/domain/models.py +82 -0
- raxe/domain/packs/__init__.py +17 -0
- raxe/domain/packs/models.py +304 -0
- raxe/domain/policies/__init__.py +20 -0
- raxe/domain/policies/evaluator.py +212 -0
- raxe/domain/policies/models.py +223 -0
- raxe/domain/rules/__init__.py +32 -0
- raxe/domain/rules/custom.py +286 -0
- raxe/domain/rules/models.py +273 -0
- raxe/domain/rules/schema.py +166 -0
- raxe/domain/rules/validator.py +556 -0
- raxe/domain/suppression.py +801 -0
- raxe/domain/suppression_factory.py +174 -0
- raxe/domain/telemetry/__init__.py +116 -0
- raxe/domain/telemetry/backpressure.py +424 -0
- raxe/domain/telemetry/event_creator.py +362 -0
- raxe/domain/telemetry/events.py +1282 -0
- raxe/domain/telemetry/priority.py +263 -0
- raxe/domain/telemetry/scan_telemetry_builder.py +670 -0
- raxe/infrastructure/__init__.py +25 -0
- raxe/infrastructure/analytics/__init__.py +18 -0
- raxe/infrastructure/analytics/aggregator.py +484 -0
- raxe/infrastructure/analytics/aggregator_optimized.py +184 -0
- raxe/infrastructure/analytics/engine.py +748 -0
- raxe/infrastructure/analytics/repository.py +409 -0
- raxe/infrastructure/analytics/streaks.py +467 -0
- raxe/infrastructure/analytics/views.py +178 -0
- raxe/infrastructure/cloud/__init__.py +9 -0
- raxe/infrastructure/config/__init__.py +56 -0
- raxe/infrastructure/config/endpoints.py +641 -0
- raxe/infrastructure/config/scan_config.py +352 -0
- raxe/infrastructure/config/yaml_config.py +459 -0
- raxe/infrastructure/database/__init__.py +10 -0
- raxe/infrastructure/database/connection.py +200 -0
- raxe/infrastructure/database/models.py +325 -0
- raxe/infrastructure/database/scan_history.py +764 -0
- raxe/infrastructure/ml/__init__.py +0 -0
- raxe/infrastructure/ml/download_progress.py +438 -0
- raxe/infrastructure/ml/model_downloader.py +457 -0
- raxe/infrastructure/models/__init__.py +16 -0
- raxe/infrastructure/models/discovery.py +461 -0
- raxe/infrastructure/packs/__init__.py +13 -0
- raxe/infrastructure/packs/loader.py +407 -0
- raxe/infrastructure/packs/registry.py +381 -0
- raxe/infrastructure/policies/__init__.py +16 -0
- raxe/infrastructure/policies/api_client.py +256 -0
- raxe/infrastructure/policies/validator.py +227 -0
- raxe/infrastructure/policies/yaml_loader.py +250 -0
- raxe/infrastructure/rules/__init__.py +18 -0
- raxe/infrastructure/rules/custom_loader.py +224 -0
- raxe/infrastructure/rules/versioning.py +222 -0
- raxe/infrastructure/rules/yaml_loader.py +286 -0
- raxe/infrastructure/security/__init__.py +31 -0
- raxe/infrastructure/security/auth.py +145 -0
- raxe/infrastructure/security/policy_validator.py +124 -0
- raxe/infrastructure/security/signatures.py +171 -0
- raxe/infrastructure/suppression/__init__.py +36 -0
- raxe/infrastructure/suppression/composite_repository.py +154 -0
- raxe/infrastructure/suppression/sqlite_repository.py +231 -0
- raxe/infrastructure/suppression/yaml_composite_repository.py +156 -0
- raxe/infrastructure/suppression/yaml_repository.py +510 -0
- raxe/infrastructure/telemetry/__init__.py +79 -0
- raxe/infrastructure/telemetry/acquisition.py +179 -0
- raxe/infrastructure/telemetry/config.py +254 -0
- raxe/infrastructure/telemetry/credential_store.py +947 -0
- raxe/infrastructure/telemetry/dual_queue.py +1123 -0
- raxe/infrastructure/telemetry/flush_helper.py +343 -0
- raxe/infrastructure/telemetry/flush_scheduler.py +776 -0
- raxe/infrastructure/telemetry/health_client.py +394 -0
- raxe/infrastructure/telemetry/hook.py +347 -0
- raxe/infrastructure/telemetry/queue.py +520 -0
- raxe/infrastructure/telemetry/sender.py +476 -0
- raxe/infrastructure/tracking/__init__.py +13 -0
- raxe/infrastructure/tracking/usage.py +389 -0
- raxe/integrations/__init__.py +55 -0
- raxe/integrations/availability.py +143 -0
- raxe/integrations/registry.py +122 -0
- raxe/integrations/utils.py +135 -0
- raxe/mcp/__init__.py +62 -0
- raxe/mcp/cli.py +97 -0
- raxe/mcp/server.py +409 -0
- raxe/monitoring/__init__.py +51 -0
- raxe/monitoring/metrics.py +372 -0
- raxe/monitoring/profiler.py +388 -0
- raxe/monitoring/server.py +136 -0
- raxe/packs/core/v1.0.0/pack.yaml +1394 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-001@1.0.0.yaml +49 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-006@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-014@1.0.0.yaml +54 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-017@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-022@1.0.0.yaml +67 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-023@1.0.0.yaml +91 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-024@1.0.0.yaml +80 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-025@1.0.0.yaml +81 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-026@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-027@1.0.0.yaml +77 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-028@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-029@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-030@1.0.0.yaml +55 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-033@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-034@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-035@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-046@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-047@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-048@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-049@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-050@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-068@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-078@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-2001@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-2004@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-201@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-202@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-203@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3007@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3016@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3026@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3027@1.0.0.yaml +64 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3028@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3029@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3030@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3031@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3032@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3033@1.0.0.yaml +56 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-3034@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-79@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-80@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-81@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-82@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-83@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-84@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-85@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-86@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-87@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-88@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-89@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-90@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-91@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-92@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-93@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-94@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-95@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-96@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-97@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/PI/pi-98@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-001@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-007@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-015@1.0.0.yaml +56 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-016@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-017@1.0.0.yaml +57 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-021@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-022@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-023@1.0.0.yaml +78 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-024@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-025@1.0.0.yaml +93 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-026@1.0.0.yaml +81 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-027@1.0.0.yaml +82 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-028@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-033@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-036@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-037@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-052@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-054@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-056@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-065@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-075@1.0.0.yaml +45 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-079@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-1080@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-1090@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-1104@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-1105@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-1112@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-201@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-202@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-203@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-204@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-205@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-206@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-207@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-208@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-209@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-210@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-211@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-212@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-213@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-214@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-215@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-216@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-217@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-218@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-219@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-220@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-221@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-222@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-223@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-224@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-225@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-226@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-227@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-228@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-229@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-230@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-231@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-232@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-233@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-234@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-235@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-236@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-237@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/cmd/cmd-238@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-001@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-013@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-019@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-020@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-024@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-029@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-038@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-044@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-067@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-069@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-100@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-101@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-102@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-103@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-104@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-105@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-106@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-107@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-108@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-109@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-110@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-111@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-112@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-113@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-114@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-115@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-116@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-117@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-118@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-119@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-120@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-201@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-202@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-203@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-3004@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-3006@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-3011@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-5016@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-6001@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-6002@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-70@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-71@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-72@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-73@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-74@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-75@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-76@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-77@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-78@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-79@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-80@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-81@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-82@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-83@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-84@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-85@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-86@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-87@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-88@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-89@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-90@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-91@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-92@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-93@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-94@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-95@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-96@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-97@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-98@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/enc/enc-99@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-001@1.0.0.yaml +73 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-002@1.0.0.yaml +71 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-003@1.0.0.yaml +65 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-004@1.0.0.yaml +73 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-101@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-102@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-103@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-104@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-105@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-106@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-107@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-108@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-109@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-110@1.0.0.yaml +56 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-111@1.0.0.yaml +49 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-112@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-113@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-114@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-115@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-116@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-117@1.0.0.yaml +54 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-118@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-119@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-120@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-121@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-122@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-123@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-124@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-125@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-126@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-127@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-128@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-129@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-130@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-131@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-132@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-133@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-134@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-135@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-136@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-137@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-138@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-139@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-140@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-141@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-142@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-143@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-144@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-145@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-146@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-147@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-148@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-149@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-150@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-151@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-152@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-153@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-154@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-155@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-156@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-157@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-158@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-159@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-160@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/hc/hc-161@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-001@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-009@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-020@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-021@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-022@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-028@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-033@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-034@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-036@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-039@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-056@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-066@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-076@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-098@1.0.0.yaml +46 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-103@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-104@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-105@1.0.0.yaml +56 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-110@1.0.0.yaml +56 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-111@1.0.0.yaml +57 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-112@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-113@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-114@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-115@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-116@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-117@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-118@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-119@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-120@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-121@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-122@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-123@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-124@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-125@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-126@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-127@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-128@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-129@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-130@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-131@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-132@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-133@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-134@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-135@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-136@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-137@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-138@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-139@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-140@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-141@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-142@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-143@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-144@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-145@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-146@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-147@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-148@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-149@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-150@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-151@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-152@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-153@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-154@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-155@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-156@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-157@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-158@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-159@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-160@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-161@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-162@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-201@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-202@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-203@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-204@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-205@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-206@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/jb/jb-207@1.0.0.yaml +49 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-001@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-009@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-012@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-017@1.0.0.yaml +48 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-022@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-025@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-027@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-028@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-034@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-037@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-040@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-041@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-044@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-050@1.0.0.yaml +57 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-051@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-052@1.0.0.yaml +52 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-053@1.0.0.yaml +56 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-054@1.0.0.yaml +53 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-055@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-056@1.0.0.yaml +51 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-058@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-2015@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-2025@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-2026@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-2035@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-2037@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-2042@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3001@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3002@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3003@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3004@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3005@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3006@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3007@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3008@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3009@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3010@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3011@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3012@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3013@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3014@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3015@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3016@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3017@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3018@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3019@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3020@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3021@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3022@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3023@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3024@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3025@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3026@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3027@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3028@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3029@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3030@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3031@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3032@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3033@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3034@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3035@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3036@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3037@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3038@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3039@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3040@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3041@1.0.0.yaml +39 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3042@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3043@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3044@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3045@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3046@1.0.0.yaml +37 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3047@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3048@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3049@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3050@1.0.0.yaml +44 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3051@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3052@1.0.0.yaml +36 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3053@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3054@1.0.0.yaml +35 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3055@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3056@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3057@1.0.0.yaml +40 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3058@1.0.0.yaml +43 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3059@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3060@1.0.0.yaml +42 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3061@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3062@1.0.0.yaml +50 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3063@1.0.0.yaml +54 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3064@1.0.0.yaml +78 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3065@1.0.0.yaml +84 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3066@1.0.0.yaml +84 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3067@1.0.0.yaml +88 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3068@1.0.0.yaml +94 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3069@1.0.0.yaml +90 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3070@1.0.0.yaml +99 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3071@1.0.0.yaml +91 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3072@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3073@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3074@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3075@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3076@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3077@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3078@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3079@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3080@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3081@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3082@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3083@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3084@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/pii/pii-3085@1.0.0.yaml +38 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-016@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-028@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-042@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-044@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-045@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-050@1.0.0.yaml +47 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-201@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-202@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-3001@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-3006@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-3009@1.0.0.yaml +41 -0
- raxe/packs/core/v1.0.0/rules/rag/rag-3012@1.0.0.yaml +41 -0
- raxe/plugins/__init__.py +98 -0
- raxe/plugins/custom_rules.py +380 -0
- raxe/plugins/loader.py +389 -0
- raxe/plugins/manager.py +538 -0
- raxe/plugins/protocol.py +428 -0
- raxe/py.typed +0 -0
- raxe/sdk/__init__.py +77 -0
- raxe/sdk/agent_scanner.py +1918 -0
- raxe/sdk/client.py +1603 -0
- raxe/sdk/decorator.py +175 -0
- raxe/sdk/exceptions.py +859 -0
- raxe/sdk/integrations/__init__.py +277 -0
- raxe/sdk/integrations/agent_scanner.py +71 -0
- raxe/sdk/integrations/autogen.py +872 -0
- raxe/sdk/integrations/crewai.py +1368 -0
- raxe/sdk/integrations/dspy.py +845 -0
- raxe/sdk/integrations/extractors.py +363 -0
- raxe/sdk/integrations/huggingface.py +395 -0
- raxe/sdk/integrations/langchain.py +948 -0
- raxe/sdk/integrations/litellm.py +484 -0
- raxe/sdk/integrations/llamaindex.py +1049 -0
- raxe/sdk/integrations/portkey.py +831 -0
- raxe/sdk/suppression_context.py +215 -0
- raxe/sdk/wrappers/__init__.py +163 -0
- raxe/sdk/wrappers/anthropic.py +310 -0
- raxe/sdk/wrappers/openai.py +221 -0
- raxe/sdk/wrappers/vertexai.py +484 -0
- raxe/utils/__init__.py +12 -0
- raxe/utils/error_sanitizer.py +135 -0
- raxe/utils/logging.py +241 -0
- raxe/utils/performance.py +414 -0
- raxe/utils/profiler.py +339 -0
- raxe/utils/validators.py +170 -0
- raxe-0.4.6.dist-info/METADATA +471 -0
- raxe-0.4.6.dist-info/RECORD +668 -0
- raxe-0.4.6.dist-info/WHEEL +5 -0
- raxe-0.4.6.dist-info/entry_points.txt +2 -0
- raxe-0.4.6.dist-info/licenses/LICENSE +56 -0
- raxe-0.4.6.dist-info/top_level.txt +1 -0
raxe/cli/l2_formatter.py
ADDED
|
@@ -0,0 +1,872 @@
|
|
|
1
|
+
"""L2 result formatting with rich WHY explanations.
|
|
2
|
+
|
|
3
|
+
This module provides comprehensive formatting for L2 ML detection results,
|
|
4
|
+
including:
|
|
5
|
+
- Hierarchical risk scoring (0-100 scale)
|
|
6
|
+
- Classification levels (SAFE, FP_LIKELY, REVIEW, LIKELY_THREAT, THREAT, HIGH_THREAT)
|
|
7
|
+
- Final decision recommendations (ALLOW, BLOCK, BLOCK_WITH_REVIEW, etc.)
|
|
8
|
+
- Clear WHY explanations for each detection
|
|
9
|
+
- Detailed confidence breakdown (binary, family, subfamily)
|
|
10
|
+
- Signal quality indicators
|
|
11
|
+
- Matched patterns and features
|
|
12
|
+
- Recommended actions and remediation advice
|
|
13
|
+
- User-friendly threat descriptions
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
from raxe.cli.l2_formatter import L2ResultFormatter
|
|
17
|
+
|
|
18
|
+
formatter = L2ResultFormatter()
|
|
19
|
+
formatter.format_predictions(l2_result, console, explain=False)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from typing import ClassVar
|
|
23
|
+
|
|
24
|
+
from rich.console import Console
|
|
25
|
+
from rich.panel import Panel
|
|
26
|
+
from rich.table import Table
|
|
27
|
+
from rich.text import Text
|
|
28
|
+
|
|
29
|
+
from raxe.domain.ml.protocol import L2Prediction, L2Result
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class L2ResultFormatter:
|
|
33
|
+
"""Formatter for L2 detection results with comprehensive WHY explanations."""
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _get_confidence_indicator(confidence: float) -> tuple[str, str]:
|
|
37
|
+
"""Get visual indicator for confidence level.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
confidence: Confidence value (0.0-1.0)
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Tuple of (indicator emoji, strength label)
|
|
44
|
+
"""
|
|
45
|
+
if confidence >= 0.8:
|
|
46
|
+
return ("✓", "Strong")
|
|
47
|
+
elif confidence >= 0.5:
|
|
48
|
+
return ("⚠️", "Medium")
|
|
49
|
+
elif confidence >= 0.3:
|
|
50
|
+
return ("⚠️", "Weak")
|
|
51
|
+
else:
|
|
52
|
+
return ("❌", "Very weak")
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def _get_classification_display(classification: str) -> tuple[str, str]:
|
|
56
|
+
"""Get display styling for classification level.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
classification: Classification level
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Tuple of (icon, color)
|
|
63
|
+
"""
|
|
64
|
+
classification_map = {
|
|
65
|
+
"SAFE": ("🟢", "green"),
|
|
66
|
+
"FP_LIKELY": ("🟡", "yellow"),
|
|
67
|
+
"REVIEW": ("🟠", "yellow"),
|
|
68
|
+
"LIKELY_THREAT": ("🔶", "dark_orange"),
|
|
69
|
+
"THREAT": ("🔴", "red"),
|
|
70
|
+
"HIGH_THREAT": ("🔴", "red bold"),
|
|
71
|
+
}
|
|
72
|
+
return classification_map.get(classification, ("⚪", "white"))
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def _get_action_display(action: str) -> tuple[str, str]:
|
|
76
|
+
"""Get display styling for action.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
action: Action recommendation
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Tuple of (icon, color)
|
|
83
|
+
"""
|
|
84
|
+
action_map = {
|
|
85
|
+
"ALLOW": ("✓", "green"),
|
|
86
|
+
"ALLOW_WITH_LOG": ("✓", "yellow"),
|
|
87
|
+
"MANUAL_REVIEW": ("👁️", "yellow"),
|
|
88
|
+
"BLOCK_WITH_REVIEW": ("🔍", "dark_orange"),
|
|
89
|
+
"BLOCK": ("🛡️", "red"),
|
|
90
|
+
"BLOCK_ALERT": ("🚨", "red bold"),
|
|
91
|
+
}
|
|
92
|
+
return action_map.get(action, ("•", "white"))
|
|
93
|
+
|
|
94
|
+
# User-friendly threat type descriptions (Gemma 5-head model)
|
|
95
|
+
THREAT_DESCRIPTIONS: ClassVar[dict[str, dict[str, str]]] = {
|
|
96
|
+
"benign": {
|
|
97
|
+
"title": "Benign",
|
|
98
|
+
"description": "No threat detected",
|
|
99
|
+
"icon": "✅",
|
|
100
|
+
},
|
|
101
|
+
"data_exfiltration": {
|
|
102
|
+
"title": "Data Exfiltration",
|
|
103
|
+
"description": "Attempt to extract sensitive data or information",
|
|
104
|
+
"icon": "📤",
|
|
105
|
+
},
|
|
106
|
+
"encoding_or_obfuscation_attack": {
|
|
107
|
+
"title": "Encoding/Obfuscation Attack",
|
|
108
|
+
"description": "Malicious content hidden using encoding or obfuscation",
|
|
109
|
+
"icon": "🔐",
|
|
110
|
+
},
|
|
111
|
+
"jailbreak": {
|
|
112
|
+
"title": "Jailbreak",
|
|
113
|
+
"description": "Attempt to bypass AI safety guidelines",
|
|
114
|
+
"icon": "🔓",
|
|
115
|
+
},
|
|
116
|
+
"other_security": {
|
|
117
|
+
"title": "Security Threat",
|
|
118
|
+
"description": "General security threat detected",
|
|
119
|
+
"icon": "🛡️",
|
|
120
|
+
},
|
|
121
|
+
"prompt_injection": {
|
|
122
|
+
"title": "Prompt Injection",
|
|
123
|
+
"description": "Attempt to override or manipulate system instructions",
|
|
124
|
+
"icon": "💉",
|
|
125
|
+
},
|
|
126
|
+
"rag_or_context_attack": {
|
|
127
|
+
"title": "RAG/Context Attack",
|
|
128
|
+
"description": "Attempt to manipulate retrieval or context",
|
|
129
|
+
"icon": "🎭",
|
|
130
|
+
},
|
|
131
|
+
"tool_or_command_abuse": {
|
|
132
|
+
"title": "Tool/Command Abuse",
|
|
133
|
+
"description": "Attempt to misuse tools or execute commands",
|
|
134
|
+
"icon": "⚙️",
|
|
135
|
+
},
|
|
136
|
+
"toxic_or_policy_violating_content": {
|
|
137
|
+
"title": "Toxic Content",
|
|
138
|
+
"description": "Content violating safety or policy guidelines",
|
|
139
|
+
"icon": "☠️",
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# Remediation advice per threat type (Gemma model)
|
|
144
|
+
REMEDIATION_ADVICE: ClassVar[dict[str, str]] = {
|
|
145
|
+
"benign": (
|
|
146
|
+
"No action required. The content appears safe."
|
|
147
|
+
),
|
|
148
|
+
"data_exfiltration": (
|
|
149
|
+
"Review data access controls and implement DLP policies. "
|
|
150
|
+
"Block requests attempting to extract sensitive information."
|
|
151
|
+
),
|
|
152
|
+
"encoding_or_obfuscation_attack": (
|
|
153
|
+
"Decode and validate all user inputs before processing. "
|
|
154
|
+
"Block obfuscated payloads and implement input sanitization."
|
|
155
|
+
),
|
|
156
|
+
"jailbreak": (
|
|
157
|
+
"Block the request and log for security review. "
|
|
158
|
+
"This prompt attempts to bypass AI safety guidelines."
|
|
159
|
+
),
|
|
160
|
+
"other_security": (
|
|
161
|
+
"Review the prompt manually for security concerns. "
|
|
162
|
+
"Consider updating detection rules."
|
|
163
|
+
),
|
|
164
|
+
"prompt_injection": (
|
|
165
|
+
"Block the request. This is an attempt to override system instructions. "
|
|
166
|
+
"Validate instruction boundaries and sanitize inputs."
|
|
167
|
+
),
|
|
168
|
+
"rag_or_context_attack": (
|
|
169
|
+
"Reset conversation context and re-validate user intent. "
|
|
170
|
+
"Monitor for patterns of context manipulation."
|
|
171
|
+
),
|
|
172
|
+
"tool_or_command_abuse": (
|
|
173
|
+
"Block tool/command execution and validate all user-provided inputs. "
|
|
174
|
+
"Implement strict command whitelisting."
|
|
175
|
+
),
|
|
176
|
+
"toxic_or_policy_violating_content": (
|
|
177
|
+
"Block the content immediately. This violates safety policies. "
|
|
178
|
+
"Log for compliance review."
|
|
179
|
+
),
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Documentation URLs per threat type (Gemma model)
|
|
183
|
+
DOCS_URLS: ClassVar[dict] = {
|
|
184
|
+
"benign": "https://docs.raxe.ai/threats/overview",
|
|
185
|
+
"data_exfiltration": "https://docs.raxe.ai/threats/data-exfiltration",
|
|
186
|
+
"encoding_or_obfuscation_attack": "https://docs.raxe.ai/threats/encoding-attacks",
|
|
187
|
+
"jailbreak": "https://docs.raxe.ai/threats/jailbreak",
|
|
188
|
+
"other_security": "https://docs.raxe.ai/threats/overview",
|
|
189
|
+
"prompt_injection": "https://docs.raxe.ai/threats/prompt-injection",
|
|
190
|
+
"rag_or_context_attack": "https://docs.raxe.ai/threats/rag-attacks",
|
|
191
|
+
"tool_or_command_abuse": "https://docs.raxe.ai/threats/tool-abuse",
|
|
192
|
+
"toxic_or_policy_violating_content": "https://docs.raxe.ai/threats/toxic-content",
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def _make_progress_bar(value: float, width: int = 20, filled: str = "█", empty: str = "░") -> str:
|
|
197
|
+
"""Create a text-based progress bar.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
value: Value between 0.0 and 1.0
|
|
201
|
+
width: Total width of the bar
|
|
202
|
+
filled: Character for filled portion
|
|
203
|
+
empty: Character for empty portion
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Progress bar string like "████████░░░░░░░░░░░░"
|
|
207
|
+
"""
|
|
208
|
+
filled_count = int(value * width)
|
|
209
|
+
empty_count = width - filled_count
|
|
210
|
+
return filled * filled_count + empty * empty_count
|
|
211
|
+
|
|
212
|
+
@staticmethod
|
|
213
|
+
def format_predictions(
|
|
214
|
+
l2_result: L2Result,
|
|
215
|
+
console: Console,
|
|
216
|
+
*,
|
|
217
|
+
explain: bool = False,
|
|
218
|
+
show_below_threshold: bool = False,
|
|
219
|
+
) -> None:
|
|
220
|
+
"""Format all L2 predictions with rich output.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
l2_result: L2 detection result
|
|
224
|
+
console: Rich console instance
|
|
225
|
+
explain: Show detailed explain mode with scoring breakdown (default: False)
|
|
226
|
+
show_below_threshold: Show L2 analysis even when below threshold (default: False)
|
|
227
|
+
"""
|
|
228
|
+
if not l2_result:
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
# If below threshold but we want to show analysis anyway
|
|
232
|
+
if show_below_threshold and not l2_result.has_predictions:
|
|
233
|
+
L2ResultFormatter._format_below_threshold(l2_result, console)
|
|
234
|
+
return
|
|
235
|
+
|
|
236
|
+
if not l2_result.has_predictions:
|
|
237
|
+
return
|
|
238
|
+
|
|
239
|
+
# Show default or explain mode
|
|
240
|
+
if explain:
|
|
241
|
+
# Detailed explain mode with full scoring breakdown
|
|
242
|
+
L2ResultFormatter._format_explain_mode(l2_result, console)
|
|
243
|
+
else:
|
|
244
|
+
# Compact default mode with key metrics
|
|
245
|
+
L2ResultFormatter._format_default_mode(l2_result, console)
|
|
246
|
+
|
|
247
|
+
@staticmethod
|
|
248
|
+
def _format_below_threshold(l2_result: L2Result, console: Console) -> None:
|
|
249
|
+
"""Format L2 analysis when below detection threshold.
|
|
250
|
+
|
|
251
|
+
Shows the ML analysis even when no detection was triggered,
|
|
252
|
+
useful for understanding why L2 didn't flag something.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
l2_result: L2 detection result (with metadata but no predictions)
|
|
256
|
+
console: Rich console instance
|
|
257
|
+
"""
|
|
258
|
+
console.print()
|
|
259
|
+
console.print("─" * 60, style="dim cyan")
|
|
260
|
+
console.print(" 📊 ML ANALYSIS (Below Threshold)", style="cyan")
|
|
261
|
+
console.print("─" * 60, style="dim cyan")
|
|
262
|
+
console.print()
|
|
263
|
+
|
|
264
|
+
# Get metadata from the result
|
|
265
|
+
metadata = l2_result.metadata or {}
|
|
266
|
+
classification_result = metadata.get("classification_result", {})
|
|
267
|
+
|
|
268
|
+
if not classification_result:
|
|
269
|
+
console.print(" No L2 analysis available", style="dim")
|
|
270
|
+
return
|
|
271
|
+
|
|
272
|
+
# Extract all 5 heads from classification_result
|
|
273
|
+
threat_prob = classification_result.get("threat_probability", 0)
|
|
274
|
+
classification_result.get("safe_probability", 1)
|
|
275
|
+
family = classification_result.get("threat_family", "unknown")
|
|
276
|
+
family_conf = classification_result.get("family_confidence", 0)
|
|
277
|
+
severity = classification_result.get("severity", "none")
|
|
278
|
+
severity_conf = classification_result.get("severity_confidence", 0)
|
|
279
|
+
technique = classification_result.get("primary_technique", "none")
|
|
280
|
+
technique_conf = classification_result.get("technique_confidence", 0)
|
|
281
|
+
harm_types = classification_result.get("harm_types", {})
|
|
282
|
+
|
|
283
|
+
# Main threat score
|
|
284
|
+
threat_bar = L2ResultFormatter._make_progress_bar(threat_prob, width=20)
|
|
285
|
+
threat_color = "yellow" if threat_prob >= 0.3 else "green"
|
|
286
|
+
|
|
287
|
+
threat_line = Text()
|
|
288
|
+
threat_line.append(" Threat Score ")
|
|
289
|
+
threat_line.append(threat_bar, style=threat_color)
|
|
290
|
+
threat_line.append(f" {threat_prob * 100:4.0f}% ", style=threat_color + " bold")
|
|
291
|
+
threat_line.append("Below threshold", style="dim")
|
|
292
|
+
console.print(threat_line)
|
|
293
|
+
console.print()
|
|
294
|
+
|
|
295
|
+
# Classification (what it would be if triggered)
|
|
296
|
+
console.print(" If triggered, classified as:", style="dim")
|
|
297
|
+
family_display = family.replace("_", " ").title()
|
|
298
|
+
severity_display = severity.replace("_", " ").title()
|
|
299
|
+
technique_display = technique.replace("_", " ").title() if technique and technique != "none" else "Unknown"
|
|
300
|
+
|
|
301
|
+
console.print(f" Family {family_display}", style="dim")
|
|
302
|
+
console.print(f" Severity {severity_display}", style="dim")
|
|
303
|
+
console.print(f" Technique {technique_display}", style="dim")
|
|
304
|
+
console.print()
|
|
305
|
+
|
|
306
|
+
# Confidence breakdown
|
|
307
|
+
console.print(" Confidence:", style="white bold")
|
|
308
|
+
|
|
309
|
+
def print_conf_row(label: str, value: float, color: str) -> None:
|
|
310
|
+
bar = L2ResultFormatter._make_progress_bar(value, width=12)
|
|
311
|
+
line = Text()
|
|
312
|
+
line.append(f" {label:<16}")
|
|
313
|
+
line.append(bar, style=color)
|
|
314
|
+
line.append(f" {value * 100:4.0f}%", style=color)
|
|
315
|
+
console.print(line)
|
|
316
|
+
|
|
317
|
+
print_conf_row("Threat", threat_prob, "yellow" if threat_prob >= 0.3 else "dim")
|
|
318
|
+
print_conf_row("Family", family_conf, "dim")
|
|
319
|
+
print_conf_row("Severity", severity_conf, "dim")
|
|
320
|
+
print_conf_row("Technique", technique_conf, "dim")
|
|
321
|
+
console.print()
|
|
322
|
+
|
|
323
|
+
# Harm Types (if any notable)
|
|
324
|
+
if harm_types and harm_types.get("probabilities"):
|
|
325
|
+
probs = harm_types.get("probabilities", {})
|
|
326
|
+
thresholds = harm_types.get("thresholds_used", {})
|
|
327
|
+
sorted_harms = sorted(probs.items(), key=lambda x: x[1], reverse=True)
|
|
328
|
+
|
|
329
|
+
# Only show if any are notable (>30%)
|
|
330
|
+
notable = [(h, p) for h, p in sorted_harms if p >= 0.3]
|
|
331
|
+
if notable:
|
|
332
|
+
console.print(" Notable Harm Signals:", style="white bold")
|
|
333
|
+
for harm_name, prob in notable[:3]:
|
|
334
|
+
threshold = thresholds.get(harm_name, 0.5)
|
|
335
|
+
bar = L2ResultFormatter._make_progress_bar(prob, width=10)
|
|
336
|
+
harm_display = harm_name.replace("_", " ").title()
|
|
337
|
+
color = "yellow" if prob >= threshold * 0.7 else "dim"
|
|
338
|
+
line = Text()
|
|
339
|
+
line.append(f" {harm_display:<24}")
|
|
340
|
+
line.append(bar, style=color)
|
|
341
|
+
line.append(f" {prob * 100:4.0f}%", style=color)
|
|
342
|
+
console.print(line)
|
|
343
|
+
console.print()
|
|
344
|
+
|
|
345
|
+
# Footer - simplified
|
|
346
|
+
console.print(f" Model: {l2_result.model_version}", style="dim")
|
|
347
|
+
|
|
348
|
+
@staticmethod
|
|
349
|
+
def _format_default_mode(l2_result: L2Result, console: Console) -> None:
|
|
350
|
+
"""Format L2 predictions in compact default mode.
|
|
351
|
+
|
|
352
|
+
Shows a clean, minimal summary - one line per detection.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
l2_result: L2 detection result
|
|
356
|
+
console: Rich console instance
|
|
357
|
+
"""
|
|
358
|
+
console.print()
|
|
359
|
+
|
|
360
|
+
for prediction in l2_result.predictions:
|
|
361
|
+
# Extract scoring metadata
|
|
362
|
+
metadata = prediction.metadata
|
|
363
|
+
classification = metadata.get("classification", "THREAT")
|
|
364
|
+
action = metadata.get("action", "BLOCK")
|
|
365
|
+
hierarchical_score = metadata.get("hierarchical_score", prediction.confidence)
|
|
366
|
+
|
|
367
|
+
# Get family info for display
|
|
368
|
+
family = metadata.get("family", "unknown")
|
|
369
|
+
family_display = family.replace("_", " ").title()
|
|
370
|
+
|
|
371
|
+
# Get display styling
|
|
372
|
+
class_icon, class_color = L2ResultFormatter._get_classification_display(classification)
|
|
373
|
+
action_icon, action_color = L2ResultFormatter._get_action_display(action)
|
|
374
|
+
|
|
375
|
+
# Single clean line: 🤖 ML: Prompt Injection (55%) → MANUAL_REVIEW
|
|
376
|
+
ml_line = Text()
|
|
377
|
+
ml_line.append("🤖 ML: ", style="cyan bold")
|
|
378
|
+
ml_line.append(f"{family_display}", style="white bold")
|
|
379
|
+
ml_line.append(f" ({hierarchical_score * 100:.0f}%)", style="dim")
|
|
380
|
+
ml_line.append(" → ", style="dim")
|
|
381
|
+
ml_line.append(f"{action_icon} {action}", style=f"{action_color}")
|
|
382
|
+
console.print(ml_line)
|
|
383
|
+
console.print()
|
|
384
|
+
|
|
385
|
+
@staticmethod
|
|
386
|
+
def _format_explain_mode(l2_result: L2Result, console: Console) -> None:
|
|
387
|
+
"""Format L2 predictions in detailed explain mode.
|
|
388
|
+
|
|
389
|
+
Shows:
|
|
390
|
+
- Complete scoring breakdown
|
|
391
|
+
- Classification reasoning
|
|
392
|
+
- Confidence signals with strength indicators
|
|
393
|
+
- Hierarchical score calculation
|
|
394
|
+
- Signal quality metrics
|
|
395
|
+
- Decision rationale
|
|
396
|
+
- Recommended actions
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
l2_result: L2 detection result
|
|
400
|
+
console: Rich console instance
|
|
401
|
+
"""
|
|
402
|
+
console.print()
|
|
403
|
+
console.print("─" * 60, style="cyan")
|
|
404
|
+
console.print(" 📊 ML DETECTION ANALYSIS", style="bold cyan")
|
|
405
|
+
console.print("─" * 60, style="cyan")
|
|
406
|
+
console.print()
|
|
407
|
+
|
|
408
|
+
for prediction in l2_result.predictions:
|
|
409
|
+
# Extract scoring metadata
|
|
410
|
+
metadata = prediction.metadata
|
|
411
|
+
classification = metadata.get("classification", "THREAT")
|
|
412
|
+
action = metadata.get("action", "BLOCK")
|
|
413
|
+
metadata.get("risk_score", prediction.confidence * 100)
|
|
414
|
+
hierarchical_score = metadata.get("hierarchical_score", prediction.confidence)
|
|
415
|
+
|
|
416
|
+
# Get confidence scores
|
|
417
|
+
scores = metadata.get("scores", {})
|
|
418
|
+
binary_conf = scores.get("attack_probability", prediction.confidence)
|
|
419
|
+
family_conf = scores.get("family_confidence", 0.0)
|
|
420
|
+
subfamily_conf = scores.get("subfamily_confidence", 0.0)
|
|
421
|
+
|
|
422
|
+
# Get signal quality
|
|
423
|
+
is_consistent = metadata.get("is_consistent", True)
|
|
424
|
+
metadata.get("variance", 0.0)
|
|
425
|
+
metadata.get("weak_margins_count", 0)
|
|
426
|
+
metadata.get("margins", {})
|
|
427
|
+
|
|
428
|
+
# Get family info
|
|
429
|
+
family = metadata.get("family", "UNKNOWN")
|
|
430
|
+
subfamily = metadata.get("sub_family", "unknown")
|
|
431
|
+
|
|
432
|
+
# Classification header - simplified
|
|
433
|
+
class_icon, class_color = L2ResultFormatter._get_classification_display(classification)
|
|
434
|
+
header_line = Text()
|
|
435
|
+
header_line.append(f" {class_icon} ", style=class_color)
|
|
436
|
+
header_line.append(classification, style=f"{class_color} bold")
|
|
437
|
+
header_line.append(f" ({hierarchical_score * 100:.0f}% confidence)", style="dim")
|
|
438
|
+
console.print(header_line)
|
|
439
|
+
console.print()
|
|
440
|
+
|
|
441
|
+
# Why This Was Flagged - cleaner format
|
|
442
|
+
why_it_hit = metadata.get("why_it_hit", [])
|
|
443
|
+
if why_it_hit:
|
|
444
|
+
console.print(" Why Flagged:", style="yellow bold")
|
|
445
|
+
for reason_item in why_it_hit:
|
|
446
|
+
console.print(f" • {reason_item}", style="white")
|
|
447
|
+
console.print()
|
|
448
|
+
|
|
449
|
+
# ─────────────────────────────────────────────────────────────
|
|
450
|
+
# ML Confidence Breakdown - Clean aligned display
|
|
451
|
+
# ─────────────────────────────────────────────────────────────
|
|
452
|
+
|
|
453
|
+
console.print("ML Confidence:", style="cyan bold")
|
|
454
|
+
console.print()
|
|
455
|
+
|
|
456
|
+
# Main threat score with large progress bar
|
|
457
|
+
threat_bar = L2ResultFormatter._make_progress_bar(binary_conf, width=20)
|
|
458
|
+
threat_color = "green" if binary_conf >= 0.8 else "yellow" if binary_conf >= 0.5 else "red"
|
|
459
|
+
threat_label = "High" if binary_conf >= 0.8 else "Medium" if binary_conf >= 0.5 else "Low"
|
|
460
|
+
|
|
461
|
+
threat_line = Text()
|
|
462
|
+
threat_line.append(" Threat Score ")
|
|
463
|
+
threat_line.append(threat_bar, style=threat_color)
|
|
464
|
+
threat_line.append(f" {binary_conf * 100:4.0f}% ", style=threat_color + " bold")
|
|
465
|
+
threat_line.append(threat_label, style=threat_color)
|
|
466
|
+
console.print(threat_line)
|
|
467
|
+
console.print()
|
|
468
|
+
|
|
469
|
+
# Classification details in clean table format
|
|
470
|
+
console.print(" Classification:", style="white bold")
|
|
471
|
+
severity = metadata.get("severity", "unknown")
|
|
472
|
+
severity_conf = scores.get("severity_confidence", 0.0)
|
|
473
|
+
|
|
474
|
+
# Format family name nicely
|
|
475
|
+
family_display = family.replace("_", " ").title()
|
|
476
|
+
subfamily_display = subfamily.replace("_", " ").title() if subfamily else "Unknown"
|
|
477
|
+
severity_display = severity.replace("_", " ").title()
|
|
478
|
+
|
|
479
|
+
# Use consistent column widths
|
|
480
|
+
console.print(f" Family {family_display}", style="dim")
|
|
481
|
+
console.print(f" Technique {subfamily_display}", style="dim")
|
|
482
|
+
console.print(f" Severity {severity_display}", style="dim")
|
|
483
|
+
console.print()
|
|
484
|
+
|
|
485
|
+
# Confidence breakdown as simple bars (all aligned)
|
|
486
|
+
console.print(" Confidence Breakdown:", style="white bold")
|
|
487
|
+
|
|
488
|
+
# Helper for aligned confidence rows
|
|
489
|
+
def print_conf_row(label: str, value: float, color: str) -> None:
|
|
490
|
+
bar = L2ResultFormatter._make_progress_bar(value, width=12)
|
|
491
|
+
line = Text()
|
|
492
|
+
line.append(f" {label:<16}")
|
|
493
|
+
line.append(bar, style=color)
|
|
494
|
+
line.append(f" {value * 100:4.0f}%", style=color)
|
|
495
|
+
console.print(line)
|
|
496
|
+
|
|
497
|
+
# All confidence signals with consistent alignment
|
|
498
|
+
print_conf_row("Threat", binary_conf,
|
|
499
|
+
"green" if binary_conf >= 0.7 else "yellow" if binary_conf >= 0.4 else "red")
|
|
500
|
+
print_conf_row("Family", family_conf,
|
|
501
|
+
"green" if family_conf >= 0.6 else "yellow" if family_conf >= 0.3 else "dim")
|
|
502
|
+
print_conf_row("Severity", severity_conf,
|
|
503
|
+
"green" if severity_conf >= 0.6 else "yellow" if severity_conf >= 0.3 else "dim")
|
|
504
|
+
print_conf_row("Technique", subfamily_conf,
|
|
505
|
+
"green" if subfamily_conf >= 0.6 else "yellow" if subfamily_conf >= 0.3 else "dim")
|
|
506
|
+
|
|
507
|
+
console.print()
|
|
508
|
+
|
|
509
|
+
# Signal quality - simplified to single line
|
|
510
|
+
quality_icon = "✓" if is_consistent else "⚠"
|
|
511
|
+
quality_color = "green" if is_consistent else "yellow"
|
|
512
|
+
quality_text = "Consistent" if is_consistent else "Mixed signals"
|
|
513
|
+
console.print(f" Signal Quality {quality_icon} {quality_text}", style=quality_color)
|
|
514
|
+
console.print()
|
|
515
|
+
|
|
516
|
+
# Recommended Action - prominent display
|
|
517
|
+
action_icon, action_color = L2ResultFormatter._get_action_display(action)
|
|
518
|
+
action_line = Text()
|
|
519
|
+
action_line.append(" Recommended ", style="white bold")
|
|
520
|
+
action_line.append(f"{action_icon} {action}", style=f"{action_color} bold")
|
|
521
|
+
console.print(action_line)
|
|
522
|
+
console.print()
|
|
523
|
+
|
|
524
|
+
# Harm Types (if available) - simplified display
|
|
525
|
+
harm_types = metadata.get("harm_types")
|
|
526
|
+
if harm_types and isinstance(harm_types, dict):
|
|
527
|
+
active_labels = harm_types.get("active_labels", [])
|
|
528
|
+
probabilities = harm_types.get("probabilities", {})
|
|
529
|
+
|
|
530
|
+
if active_labels:
|
|
531
|
+
console.print(" Harm Categories:", style="white bold")
|
|
532
|
+
for label in active_labels:
|
|
533
|
+
prob = probabilities.get(label, 0)
|
|
534
|
+
bar = L2ResultFormatter._make_progress_bar(prob, width=10)
|
|
535
|
+
label_display = label.replace("_", " ").title()
|
|
536
|
+
line = Text()
|
|
537
|
+
line.append(f" ⚠ {label_display:<26}")
|
|
538
|
+
line.append(bar, style="red")
|
|
539
|
+
line.append(f" {prob * 100:4.0f}%", style="red")
|
|
540
|
+
console.print(line)
|
|
541
|
+
console.print()
|
|
542
|
+
|
|
543
|
+
# Separator between predictions
|
|
544
|
+
if len(l2_result.predictions) > 1:
|
|
545
|
+
console.print("─" * 80, style="dim")
|
|
546
|
+
console.print()
|
|
547
|
+
|
|
548
|
+
# ─────────────────────────────────────────────────────────────
|
|
549
|
+
# Voting Engine Breakdown (if available)
|
|
550
|
+
# ─────────────────────────────────────────────────────────────
|
|
551
|
+
voting = getattr(l2_result, "voting", None)
|
|
552
|
+
if voting and isinstance(voting, dict):
|
|
553
|
+
L2ResultFormatter._format_voting_breakdown(voting, console)
|
|
554
|
+
|
|
555
|
+
@staticmethod
|
|
556
|
+
def _format_voting_breakdown(voting: dict, console: Console) -> None:
|
|
557
|
+
"""Format voting engine breakdown for --explain output.
|
|
558
|
+
|
|
559
|
+
Shows how each of the 5 heads voted and the final decision.
|
|
560
|
+
|
|
561
|
+
Args:
|
|
562
|
+
voting: Voting result dictionary from L2Result.voting
|
|
563
|
+
console: Rich console instance
|
|
564
|
+
"""
|
|
565
|
+
console.print("─" * 60, style="magenta")
|
|
566
|
+
console.print(" 🗳️ VOTING ENGINE BREAKDOWN", style="bold magenta")
|
|
567
|
+
console.print("─" * 60, style="magenta")
|
|
568
|
+
console.print()
|
|
569
|
+
|
|
570
|
+
# Decision summary
|
|
571
|
+
decision = voting.get("decision", "unknown").upper()
|
|
572
|
+
confidence = voting.get("confidence", 0.0)
|
|
573
|
+
preset = voting.get("preset_used", "balanced")
|
|
574
|
+
rule = voting.get("decision_rule_triggered", "unknown")
|
|
575
|
+
|
|
576
|
+
# Color based on decision
|
|
577
|
+
decision_color = "red" if decision == "THREAT" else "yellow" if decision == "REVIEW" else "green"
|
|
578
|
+
decision_icon = "🔴" if decision == "THREAT" else "🟡" if decision == "REVIEW" else "🟢"
|
|
579
|
+
|
|
580
|
+
console.print(f" {decision_icon} Decision: ", style=decision_color + " bold", end="")
|
|
581
|
+
console.print(f"{decision}", style=decision_color + " bold", end="")
|
|
582
|
+
console.print(f" ({confidence * 100:.0f}% confidence)", style="dim")
|
|
583
|
+
console.print(f" Preset: {preset} • Rule: {rule}", style="dim")
|
|
584
|
+
console.print()
|
|
585
|
+
|
|
586
|
+
# Vote counts
|
|
587
|
+
threat_votes = voting.get("threat_vote_count", 0)
|
|
588
|
+
safe_votes = voting.get("safe_vote_count", 0)
|
|
589
|
+
abstain_votes = voting.get("abstain_vote_count", 0)
|
|
590
|
+
|
|
591
|
+
console.print(" Vote Summary:", style="white bold")
|
|
592
|
+
console.print(f" 🔴 THREAT: {threat_votes} • 🟢 SAFE: {safe_votes} • ⚪ ABSTAIN: {abstain_votes}", style="dim")
|
|
593
|
+
console.print()
|
|
594
|
+
|
|
595
|
+
# Per-head votes
|
|
596
|
+
per_head = voting.get("per_head_votes", {})
|
|
597
|
+
if per_head:
|
|
598
|
+
console.print(" Per-Head Votes:", style="white bold")
|
|
599
|
+
|
|
600
|
+
# Define head display order
|
|
601
|
+
head_order = ["binary", "family", "severity", "technique", "harm"]
|
|
602
|
+
head_labels = {
|
|
603
|
+
"binary": "Binary ",
|
|
604
|
+
"family": "Family ",
|
|
605
|
+
"severity": "Severity ",
|
|
606
|
+
"technique": "Technique ",
|
|
607
|
+
"harm": "Harm Types ",
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
for head in head_order:
|
|
611
|
+
vote_data = per_head.get(head, {})
|
|
612
|
+
if not vote_data:
|
|
613
|
+
continue
|
|
614
|
+
|
|
615
|
+
vote = vote_data.get("vote", "unknown")
|
|
616
|
+
conf = vote_data.get("confidence", 0.0)
|
|
617
|
+
weight = vote_data.get("weight", 1.0)
|
|
618
|
+
prediction = vote_data.get("prediction", "")
|
|
619
|
+
raw_prob = vote_data.get("raw_probability", 0.0)
|
|
620
|
+
|
|
621
|
+
# Vote icon and color
|
|
622
|
+
if vote == "threat":
|
|
623
|
+
vote_icon = "🔴"
|
|
624
|
+
vote_color = "red"
|
|
625
|
+
elif vote == "safe":
|
|
626
|
+
vote_icon = "🟢"
|
|
627
|
+
vote_color = "green"
|
|
628
|
+
else:
|
|
629
|
+
vote_icon = "⚪"
|
|
630
|
+
vote_color = "dim"
|
|
631
|
+
|
|
632
|
+
# Format prediction for display
|
|
633
|
+
pred_display = prediction.replace("_", " ").title() if prediction else "-"
|
|
634
|
+
if len(pred_display) > 20:
|
|
635
|
+
pred_display = pred_display[:18] + ".."
|
|
636
|
+
|
|
637
|
+
line = Text()
|
|
638
|
+
line.append(f" {head_labels.get(head, head)}")
|
|
639
|
+
line.append(f"{vote_icon} {vote.upper():<7}", style=vote_color + " bold")
|
|
640
|
+
line.append(f" w={weight:.1f} ", style="dim")
|
|
641
|
+
line.append(f"prob={raw_prob * 100:4.0f}% ", style="dim")
|
|
642
|
+
line.append(f"→ {pred_display}", style="cyan")
|
|
643
|
+
console.print(line)
|
|
644
|
+
|
|
645
|
+
console.print()
|
|
646
|
+
|
|
647
|
+
# Weighted scores
|
|
648
|
+
weighted_threat = voting.get("weighted_threat_score", 0)
|
|
649
|
+
weighted_safe = voting.get("weighted_safe_score", 0)
|
|
650
|
+
ratio = voting.get("weighted_ratio", 0) if weighted_safe > 0 else 0
|
|
651
|
+
|
|
652
|
+
console.print(" Weighted Scores:", style="white bold")
|
|
653
|
+
console.print(f" Threat: {weighted_threat:.1f} • Safe: {weighted_safe:.1f} • Ratio: {ratio:.2f}", style="dim")
|
|
654
|
+
console.print()
|
|
655
|
+
|
|
656
|
+
@staticmethod
|
|
657
|
+
def format_prediction_detail(
|
|
658
|
+
prediction: L2Prediction,
|
|
659
|
+
console: Console,
|
|
660
|
+
) -> None:
|
|
661
|
+
"""Format a single L2 prediction with full WHY explanation.
|
|
662
|
+
|
|
663
|
+
Args:
|
|
664
|
+
prediction: L2 prediction to format
|
|
665
|
+
console: Rich console instance
|
|
666
|
+
"""
|
|
667
|
+
threat_key = prediction.threat_type.value
|
|
668
|
+
threat_info = L2ResultFormatter.THREAT_DESCRIPTIONS.get(
|
|
669
|
+
threat_key,
|
|
670
|
+
{
|
|
671
|
+
"title": threat_key.replace("_", " ").title(),
|
|
672
|
+
"description": "Detected threat",
|
|
673
|
+
"icon": "⚠️",
|
|
674
|
+
}
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
# Create detailed explanation panel
|
|
678
|
+
content = Text()
|
|
679
|
+
|
|
680
|
+
# Header with icon and title
|
|
681
|
+
icon = threat_info["icon"]
|
|
682
|
+
title = threat_info["title"]
|
|
683
|
+
content.append(f"\n{icon} {title}\n", style="red bold")
|
|
684
|
+
content.append(f"{threat_info['description']}\n\n", style="white")
|
|
685
|
+
|
|
686
|
+
# NEW: Display ML model metadata fields if available (is_attack, family, sub_family)
|
|
687
|
+
family = prediction.metadata.get("family")
|
|
688
|
+
sub_family = prediction.metadata.get("sub_family")
|
|
689
|
+
if family:
|
|
690
|
+
content.append("Attack Classification:\n", style="cyan bold")
|
|
691
|
+
content.append(f" Family: {family}\n", style="white")
|
|
692
|
+
if sub_family:
|
|
693
|
+
content.append(f" Sub-family: {sub_family}\n", style="white")
|
|
694
|
+
content.append("\n")
|
|
695
|
+
|
|
696
|
+
# Confidence with detailed scores from bundle
|
|
697
|
+
scores = prediction.metadata.get("scores", {})
|
|
698
|
+
if scores:
|
|
699
|
+
content.append("Confidence Scores:\n", style="cyan bold")
|
|
700
|
+
attack_prob = scores.get("attack_probability", prediction.confidence)
|
|
701
|
+
family_conf = scores.get("family_confidence")
|
|
702
|
+
subfamily_conf = scores.get("subfamily_confidence")
|
|
703
|
+
|
|
704
|
+
confidence_pct = f"{attack_prob * 100:.1f}%"
|
|
705
|
+
confidence_color = "red" if attack_prob >= 0.8 else "yellow"
|
|
706
|
+
content.append(" Attack Probability: ", style="white")
|
|
707
|
+
content.append(f"{confidence_pct}\n", style=confidence_color)
|
|
708
|
+
|
|
709
|
+
if family_conf is not None:
|
|
710
|
+
content.append(" Family Confidence: ", style="white")
|
|
711
|
+
content.append(f"{family_conf * 100:.1f}%\n", style="white")
|
|
712
|
+
|
|
713
|
+
if subfamily_conf is not None:
|
|
714
|
+
content.append(" Subfamily Confidence: ", style="white")
|
|
715
|
+
content.append(f"{subfamily_conf * 100:.1f}%\n", style="white")
|
|
716
|
+
|
|
717
|
+
content.append("\n")
|
|
718
|
+
else:
|
|
719
|
+
# Fallback to simple confidence
|
|
720
|
+
confidence_pct = f"{prediction.confidence * 100:.1f}%"
|
|
721
|
+
confidence_color = "red" if prediction.confidence >= 0.8 else "yellow"
|
|
722
|
+
content.append("Confidence: ", style="bold")
|
|
723
|
+
content.append(f"{confidence_pct}\n\n", style=confidence_color)
|
|
724
|
+
|
|
725
|
+
# WHY - Use why_it_hit from bundle if available, otherwise use explanation
|
|
726
|
+
why_it_hit = prediction.metadata.get("why_it_hit", [])
|
|
727
|
+
if why_it_hit:
|
|
728
|
+
content.append("Why This Was Flagged:\n", style="cyan bold")
|
|
729
|
+
for reason in why_it_hit:
|
|
730
|
+
content.append(f" • {reason}\n", style="white")
|
|
731
|
+
content.append("\n")
|
|
732
|
+
elif prediction.explanation:
|
|
733
|
+
content.append("Why This Was Flagged:\n", style="cyan bold")
|
|
734
|
+
content.append(f"{prediction.explanation}\n\n", style="white")
|
|
735
|
+
|
|
736
|
+
# Trigger matches from bundle
|
|
737
|
+
trigger_matches = prediction.metadata.get("trigger_matches", [])
|
|
738
|
+
if trigger_matches:
|
|
739
|
+
content.append("Trigger Matches:\n", style="yellow bold")
|
|
740
|
+
for trigger in trigger_matches[:5]: # Limit to top 5
|
|
741
|
+
content.append(f" • {trigger}\n", style="yellow")
|
|
742
|
+
content.append("\n")
|
|
743
|
+
|
|
744
|
+
# Features used (if available and not redundant with why_it_hit)
|
|
745
|
+
if prediction.features_used and not why_it_hit:
|
|
746
|
+
content.append("Features Detected:\n", style="cyan bold")
|
|
747
|
+
for feature in prediction.features_used[:5]: # Limit to top 5
|
|
748
|
+
content.append(f" • {feature}\n", style="white")
|
|
749
|
+
content.append("\n")
|
|
750
|
+
|
|
751
|
+
# Matched patterns (from metadata - legacy support)
|
|
752
|
+
matched_patterns = prediction.metadata.get("matched_patterns", [])
|
|
753
|
+
if matched_patterns and not trigger_matches:
|
|
754
|
+
content.append("Detected Patterns:\n", style="cyan bold")
|
|
755
|
+
for pattern in matched_patterns:
|
|
756
|
+
content.append(f" • {pattern}\n", style="white")
|
|
757
|
+
content.append("\n")
|
|
758
|
+
|
|
759
|
+
# Similar attacks from bundle
|
|
760
|
+
similar_attacks = prediction.metadata.get("similar_attacks", [])
|
|
761
|
+
if similar_attacks:
|
|
762
|
+
content.append("Similar Known Attacks:\n", style="magenta bold")
|
|
763
|
+
for i, attack in enumerate(similar_attacks[:3], 1): # Top 3
|
|
764
|
+
if isinstance(attack, dict):
|
|
765
|
+
text = attack.get("text", "")
|
|
766
|
+
similarity = attack.get("similarity", 0)
|
|
767
|
+
if text:
|
|
768
|
+
# Truncate if too long
|
|
769
|
+
text_preview = text[:60] + "..." if len(text) > 60 else text
|
|
770
|
+
content.append(f" {i}. {text_preview} ", style="white")
|
|
771
|
+
content.append(f"({similarity:.0%} similar)\n", style="dim")
|
|
772
|
+
content.append("\n")
|
|
773
|
+
|
|
774
|
+
# Recommended action from bundle (list of strings)
|
|
775
|
+
recommended_actions = prediction.metadata.get("recommended_action", [])
|
|
776
|
+
if recommended_actions:
|
|
777
|
+
content.append("Recommended Actions:\n", style="yellow bold")
|
|
778
|
+
for action in recommended_actions:
|
|
779
|
+
# Determine color based on action content
|
|
780
|
+
if "BLOCK" in action.upper() or "HIGH" in action.upper():
|
|
781
|
+
action_color = "red bold"
|
|
782
|
+
elif "WARN" in action.upper() or "MEDIUM" in action.upper():
|
|
783
|
+
action_color = "yellow"
|
|
784
|
+
else:
|
|
785
|
+
action_color = "green"
|
|
786
|
+
content.append(f" • {action}\n", style=action_color)
|
|
787
|
+
content.append("\n")
|
|
788
|
+
else:
|
|
789
|
+
# Fallback to legacy recommended_action
|
|
790
|
+
recommended_action = prediction.metadata.get("recommended_action", "review")
|
|
791
|
+
if isinstance(recommended_action, str):
|
|
792
|
+
content.append("Recommended Action: ", style="yellow bold")
|
|
793
|
+
action_color = "red bold" if recommended_action == "block" else "yellow"
|
|
794
|
+
content.append(f"{recommended_action.upper()}\n\n", style=action_color)
|
|
795
|
+
|
|
796
|
+
# Severity (if available)
|
|
797
|
+
severity = prediction.metadata.get("severity", "unknown")
|
|
798
|
+
if severity != "unknown":
|
|
799
|
+
content.append("Severity: ", style="yellow bold")
|
|
800
|
+
severity_color = "red" if severity in ("critical", "high") else "yellow"
|
|
801
|
+
content.append(f"{severity.upper()}\n\n", style=severity_color)
|
|
802
|
+
|
|
803
|
+
# Uncertainty flag from bundle
|
|
804
|
+
uncertain = prediction.metadata.get("uncertain", False)
|
|
805
|
+
if uncertain:
|
|
806
|
+
content.append("⚠️ ", style="yellow bold")
|
|
807
|
+
content.append("Model Uncertainty: ", style="yellow bold")
|
|
808
|
+
content.append("Low confidence - manual review recommended\n\n", style="yellow")
|
|
809
|
+
|
|
810
|
+
# What to do - Remediation advice
|
|
811
|
+
remediation = L2ResultFormatter.REMEDIATION_ADVICE.get(
|
|
812
|
+
threat_key,
|
|
813
|
+
"Review the prompt and apply appropriate security controls."
|
|
814
|
+
)
|
|
815
|
+
content.append("What To Do:\n", style="green bold")
|
|
816
|
+
content.append(f"{remediation}\n\n", style="white")
|
|
817
|
+
|
|
818
|
+
# Documentation link
|
|
819
|
+
docs_url = L2ResultFormatter.DOCS_URLS.get(threat_key, "")
|
|
820
|
+
if docs_url:
|
|
821
|
+
content.append("Learn More: ", style="blue bold")
|
|
822
|
+
content.append(f"{docs_url}\n", style="blue underline")
|
|
823
|
+
|
|
824
|
+
# Display panel with appropriate border color
|
|
825
|
+
border_color = "red" if prediction.confidence >= 0.8 else "yellow"
|
|
826
|
+
panel_title = "L2 ML Detection"
|
|
827
|
+
if family:
|
|
828
|
+
panel_title += f" [{family}]"
|
|
829
|
+
|
|
830
|
+
console.print(Panel(
|
|
831
|
+
content,
|
|
832
|
+
border_style=border_color,
|
|
833
|
+
title=panel_title,
|
|
834
|
+
title_align="left",
|
|
835
|
+
padding=(1, 2),
|
|
836
|
+
))
|
|
837
|
+
|
|
838
|
+
@staticmethod
|
|
839
|
+
def format_prediction_compact(
|
|
840
|
+
prediction: L2Prediction,
|
|
841
|
+
console: Console,
|
|
842
|
+
) -> None:
|
|
843
|
+
"""Format a single L2 prediction in compact format (for tables).
|
|
844
|
+
|
|
845
|
+
Args:
|
|
846
|
+
prediction: L2 prediction to format
|
|
847
|
+
console: Rich console instance
|
|
848
|
+
"""
|
|
849
|
+
threat_key = prediction.threat_type.value
|
|
850
|
+
threat_info = L2ResultFormatter.THREAT_DESCRIPTIONS.get(
|
|
851
|
+
threat_key,
|
|
852
|
+
{"title": threat_key.replace("_", " ").title(), "icon": "⚠️"}
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
icon = threat_info["icon"]
|
|
856
|
+
title = threat_info["title"]
|
|
857
|
+
confidence_pct = f"{prediction.confidence * 100:.1f}%"
|
|
858
|
+
|
|
859
|
+
# Single line format
|
|
860
|
+
line = Text()
|
|
861
|
+
line.append(f"{icon} ", style="red bold")
|
|
862
|
+
line.append(f"{title} ", style="red")
|
|
863
|
+
line.append(f"({confidence_pct})", style="yellow")
|
|
864
|
+
|
|
865
|
+
if prediction.explanation:
|
|
866
|
+
# Truncate explanation if too long
|
|
867
|
+
explanation = prediction.explanation[:60]
|
|
868
|
+
if len(prediction.explanation) > 60:
|
|
869
|
+
explanation += "..."
|
|
870
|
+
line.append(f" - {explanation}", style="dim")
|
|
871
|
+
|
|
872
|
+
console.print(line)
|