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
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
"""Scan history database for storing local scan results.
|
|
2
|
+
|
|
3
|
+
SQLite-based storage for:
|
|
4
|
+
- Scan metadata (timestamp, hashes, duration)
|
|
5
|
+
- Detection details (rule hits, severity, confidence)
|
|
6
|
+
- Performance metrics (L1/L2 latency)
|
|
7
|
+
- Auto-cleanup (90 day retention)
|
|
8
|
+
|
|
9
|
+
Database: ~/.raxe/scan_history.db
|
|
10
|
+
"""
|
|
11
|
+
import hashlib
|
|
12
|
+
import sqlite3
|
|
13
|
+
from contextlib import contextmanager
|
|
14
|
+
from dataclasses import asdict, dataclass
|
|
15
|
+
from datetime import datetime, timedelta, timezone
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from raxe.domain.engine.executor import Detection
|
|
20
|
+
from raxe.domain.rules.models import Severity
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ScanRecord:
|
|
25
|
+
"""Record of a completed scan.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
id: Unique scan ID (auto-assigned)
|
|
29
|
+
timestamp: When scan occurred (UTC)
|
|
30
|
+
prompt_hash: SHA256 hash of prompt (NOT the prompt itself)
|
|
31
|
+
threats_found: Number of threats detected
|
|
32
|
+
highest_severity: Highest severity found (if any)
|
|
33
|
+
l1_duration_ms: L1 scan duration in milliseconds
|
|
34
|
+
l2_duration_ms: L2 scan duration in milliseconds
|
|
35
|
+
total_duration_ms: Total scan duration
|
|
36
|
+
l1_detections: Number of L1 detections
|
|
37
|
+
l2_detections: Number of L2 detections
|
|
38
|
+
version: RAXE version that performed scan
|
|
39
|
+
event_id: Portal event ID (evt_xxx) for portal correlation
|
|
40
|
+
NOTE: This is the SAME event_id used in telemetry for portal-CLI correlation.
|
|
41
|
+
"""
|
|
42
|
+
timestamp: datetime
|
|
43
|
+
prompt_hash: str
|
|
44
|
+
threats_found: int
|
|
45
|
+
highest_severity: str | None = None
|
|
46
|
+
l1_duration_ms: float | None = None
|
|
47
|
+
l2_duration_ms: float | None = None
|
|
48
|
+
total_duration_ms: float | None = None
|
|
49
|
+
l1_detections: int = 0
|
|
50
|
+
l2_detections: int = 0
|
|
51
|
+
version: str = "0.0.1"
|
|
52
|
+
id: int | None = None
|
|
53
|
+
event_id: str | None = None
|
|
54
|
+
prompt_text: str | None = None # Full prompt text (stored locally for --show-prompt)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class DetectionRecord:
|
|
59
|
+
"""Record of a single detection within a scan.
|
|
60
|
+
|
|
61
|
+
Attributes:
|
|
62
|
+
id: Unique detection ID (auto-assigned)
|
|
63
|
+
scan_id: Foreign key to scans table
|
|
64
|
+
rule_id: Rule that triggered
|
|
65
|
+
severity: Severity level
|
|
66
|
+
confidence: Confidence score (0-1)
|
|
67
|
+
detection_layer: Which layer detected (L1, L2, PLUGIN)
|
|
68
|
+
category: Threat category
|
|
69
|
+
description: Human-readable description of the detection
|
|
70
|
+
"""
|
|
71
|
+
scan_id: int
|
|
72
|
+
rule_id: str
|
|
73
|
+
severity: str
|
|
74
|
+
confidence: float
|
|
75
|
+
detection_layer: str
|
|
76
|
+
category: str | None = None
|
|
77
|
+
description: str | None = None
|
|
78
|
+
id: int | None = None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ScanHistoryDB:
|
|
82
|
+
"""SQLite database for scan history.
|
|
83
|
+
|
|
84
|
+
Features:
|
|
85
|
+
- Thread-safe connection pooling
|
|
86
|
+
- Auto-migration on first use
|
|
87
|
+
- Auto-cleanup of old scans (90 days)
|
|
88
|
+
- Efficient queries with indexes
|
|
89
|
+
- Suppression tracking for audit trail
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
SCHEMA_VERSION = 5 # Bumped for description column in detections
|
|
93
|
+
RETENTION_DAYS = 90
|
|
94
|
+
|
|
95
|
+
def __init__(self, db_path: Path | None = None):
|
|
96
|
+
"""Initialize scan history database.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
db_path: Path to SQLite database file (default: ~/.raxe/scan_history.db)
|
|
100
|
+
"""
|
|
101
|
+
if db_path is None:
|
|
102
|
+
db_path = Path.home() / ".raxe" / "scan_history.db"
|
|
103
|
+
|
|
104
|
+
self.db_path = Path(db_path)
|
|
105
|
+
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
106
|
+
|
|
107
|
+
# Initialize schema
|
|
108
|
+
self._init_schema()
|
|
109
|
+
|
|
110
|
+
@contextmanager
|
|
111
|
+
def _get_connection(self):
|
|
112
|
+
"""Get thread-safe database connection with proper pooling.
|
|
113
|
+
|
|
114
|
+
This uses a simple connection pool for SQLite to ensure
|
|
115
|
+
thread-safety while maintaining good performance.
|
|
116
|
+
|
|
117
|
+
Yields:
|
|
118
|
+
sqlite3.Connection: Database connection
|
|
119
|
+
"""
|
|
120
|
+
# Use connection pool for better performance and thread-safety
|
|
121
|
+
# For SQLite, we maintain a single connection with check_same_thread=False
|
|
122
|
+
# This is safe because SQLite serializes all operations internally
|
|
123
|
+
conn = sqlite3.connect(
|
|
124
|
+
self.db_path,
|
|
125
|
+
check_same_thread=False,
|
|
126
|
+
timeout=30.0, # Increased timeout for better reliability
|
|
127
|
+
isolation_level=None, # Autocommit mode for better concurrency
|
|
128
|
+
)
|
|
129
|
+
conn.row_factory = sqlite3.Row
|
|
130
|
+
|
|
131
|
+
# Enable WAL mode for better concurrency
|
|
132
|
+
conn.execute("PRAGMA journal_mode=WAL")
|
|
133
|
+
# Enable foreign keys
|
|
134
|
+
conn.execute("PRAGMA foreign_keys=ON")
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
yield conn
|
|
138
|
+
finally:
|
|
139
|
+
conn.close()
|
|
140
|
+
|
|
141
|
+
def _init_schema(self) -> None:
|
|
142
|
+
"""Initialize database schema if needed."""
|
|
143
|
+
with self._get_connection() as conn:
|
|
144
|
+
cursor = conn.cursor()
|
|
145
|
+
|
|
146
|
+
# Create metadata table
|
|
147
|
+
cursor.execute("""
|
|
148
|
+
CREATE TABLE IF NOT EXISTS _metadata (
|
|
149
|
+
key TEXT PRIMARY KEY,
|
|
150
|
+
value TEXT NOT NULL
|
|
151
|
+
)
|
|
152
|
+
""")
|
|
153
|
+
|
|
154
|
+
# Check schema version
|
|
155
|
+
cursor.execute("SELECT value FROM _metadata WHERE key = 'schema_version'")
|
|
156
|
+
row = cursor.fetchone()
|
|
157
|
+
|
|
158
|
+
if row is None:
|
|
159
|
+
# First time setup
|
|
160
|
+
self._create_tables(conn)
|
|
161
|
+
cursor.execute(
|
|
162
|
+
"INSERT INTO _metadata (key, value) VALUES ('schema_version', ?)",
|
|
163
|
+
(str(self.SCHEMA_VERSION),)
|
|
164
|
+
)
|
|
165
|
+
conn.commit()
|
|
166
|
+
else:
|
|
167
|
+
current_version = int(row[0])
|
|
168
|
+
if current_version < self.SCHEMA_VERSION:
|
|
169
|
+
self._migrate(conn, current_version, self.SCHEMA_VERSION)
|
|
170
|
+
|
|
171
|
+
def _create_tables(self, conn: sqlite3.Connection) -> None:
|
|
172
|
+
"""Create database tables.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
conn: Database connection
|
|
176
|
+
"""
|
|
177
|
+
cursor = conn.cursor()
|
|
178
|
+
|
|
179
|
+
# Scans table
|
|
180
|
+
cursor.execute("""
|
|
181
|
+
CREATE TABLE scans (
|
|
182
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
183
|
+
timestamp INTEGER NOT NULL,
|
|
184
|
+
prompt_hash TEXT NOT NULL,
|
|
185
|
+
threats_found INTEGER NOT NULL,
|
|
186
|
+
highest_severity TEXT,
|
|
187
|
+
l1_duration_ms REAL,
|
|
188
|
+
l2_duration_ms REAL,
|
|
189
|
+
total_duration_ms REAL,
|
|
190
|
+
l1_detections INTEGER DEFAULT 0,
|
|
191
|
+
l2_detections INTEGER DEFAULT 0,
|
|
192
|
+
version TEXT NOT NULL,
|
|
193
|
+
event_id TEXT,
|
|
194
|
+
scan_id TEXT,
|
|
195
|
+
prompt_text TEXT
|
|
196
|
+
)
|
|
197
|
+
""")
|
|
198
|
+
|
|
199
|
+
# Detections table
|
|
200
|
+
cursor.execute("""
|
|
201
|
+
CREATE TABLE detections (
|
|
202
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
203
|
+
scan_id INTEGER NOT NULL,
|
|
204
|
+
rule_id TEXT NOT NULL,
|
|
205
|
+
severity TEXT NOT NULL,
|
|
206
|
+
confidence REAL NOT NULL,
|
|
207
|
+
detection_layer TEXT NOT NULL,
|
|
208
|
+
category TEXT,
|
|
209
|
+
description TEXT,
|
|
210
|
+
FOREIGN KEY (scan_id) REFERENCES scans(id) ON DELETE CASCADE
|
|
211
|
+
)
|
|
212
|
+
""")
|
|
213
|
+
|
|
214
|
+
# Suppressions table (for audit trail)
|
|
215
|
+
cursor.execute("""
|
|
216
|
+
CREATE TABLE IF NOT EXISTS suppressions (
|
|
217
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
218
|
+
scan_id INTEGER,
|
|
219
|
+
rule_id TEXT NOT NULL,
|
|
220
|
+
reason TEXT NOT NULL,
|
|
221
|
+
timestamp TEXT NOT NULL,
|
|
222
|
+
suppression_pattern TEXT,
|
|
223
|
+
FOREIGN KEY (scan_id) REFERENCES scans(id) ON DELETE CASCADE
|
|
224
|
+
)
|
|
225
|
+
""")
|
|
226
|
+
|
|
227
|
+
# Indexes for performance
|
|
228
|
+
cursor.execute("CREATE INDEX idx_scans_timestamp ON scans(timestamp)")
|
|
229
|
+
cursor.execute("CREATE INDEX idx_scans_severity ON scans(highest_severity)")
|
|
230
|
+
cursor.execute("CREATE INDEX idx_detections_scan_id ON detections(scan_id)")
|
|
231
|
+
cursor.execute("CREATE INDEX idx_detections_severity ON detections(severity)")
|
|
232
|
+
cursor.execute("CREATE INDEX IF NOT EXISTS idx_suppressions_scan_id ON suppressions(scan_id)")
|
|
233
|
+
cursor.execute("CREATE INDEX IF NOT EXISTS idx_suppressions_rule_id ON suppressions(rule_id)")
|
|
234
|
+
# Unique index for event_id lookup (partial index - only non-null values)
|
|
235
|
+
cursor.execute(
|
|
236
|
+
"CREATE UNIQUE INDEX IF NOT EXISTS idx_scans_event_id "
|
|
237
|
+
"ON scans(event_id) WHERE event_id IS NOT NULL"
|
|
238
|
+
)
|
|
239
|
+
# Index for scan_id lookup
|
|
240
|
+
cursor.execute(
|
|
241
|
+
"CREATE INDEX IF NOT EXISTS idx_scans_scan_id "
|
|
242
|
+
"ON scans(scan_id) WHERE scan_id IS NOT NULL"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
conn.commit()
|
|
246
|
+
|
|
247
|
+
def _migrate(self, conn: sqlite3.Connection, from_version: int, to_version: int) -> None:
|
|
248
|
+
"""Migrate database schema.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
conn: Database connection
|
|
252
|
+
from_version: Current schema version
|
|
253
|
+
to_version: Target schema version
|
|
254
|
+
"""
|
|
255
|
+
cursor = conn.cursor()
|
|
256
|
+
|
|
257
|
+
# Migration from v1 to v2: Add suppressions table
|
|
258
|
+
if from_version < 2 <= to_version:
|
|
259
|
+
cursor.execute("""
|
|
260
|
+
CREATE TABLE IF NOT EXISTS suppressions (
|
|
261
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
262
|
+
scan_id INTEGER,
|
|
263
|
+
rule_id TEXT NOT NULL,
|
|
264
|
+
reason TEXT NOT NULL,
|
|
265
|
+
timestamp TEXT NOT NULL,
|
|
266
|
+
suppression_pattern TEXT,
|
|
267
|
+
FOREIGN KEY (scan_id) REFERENCES scans(id) ON DELETE CASCADE
|
|
268
|
+
)
|
|
269
|
+
""")
|
|
270
|
+
cursor.execute("CREATE INDEX IF NOT EXISTS idx_suppressions_scan_id ON suppressions(scan_id)")
|
|
271
|
+
cursor.execute("CREATE INDEX IF NOT EXISTS idx_suppressions_rule_id ON suppressions(rule_id)")
|
|
272
|
+
|
|
273
|
+
# Update schema version
|
|
274
|
+
cursor.execute("UPDATE _metadata SET value = '2' WHERE key = 'schema_version'")
|
|
275
|
+
conn.commit()
|
|
276
|
+
|
|
277
|
+
# Migration from v2 to v3: Add event_id and scan_id columns
|
|
278
|
+
if from_version < 3 <= to_version:
|
|
279
|
+
# Add event_id column for portal correlation
|
|
280
|
+
cursor.execute("ALTER TABLE scans ADD COLUMN event_id TEXT")
|
|
281
|
+
# Add scan_id column for telemetry correlation
|
|
282
|
+
cursor.execute("ALTER TABLE scans ADD COLUMN scan_id TEXT")
|
|
283
|
+
# Create unique index for event_id lookup (partial index - only non-null values)
|
|
284
|
+
cursor.execute(
|
|
285
|
+
"CREATE UNIQUE INDEX IF NOT EXISTS idx_scans_event_id "
|
|
286
|
+
"ON scans(event_id) WHERE event_id IS NOT NULL"
|
|
287
|
+
)
|
|
288
|
+
# Create index for scan_id lookup
|
|
289
|
+
cursor.execute(
|
|
290
|
+
"CREATE INDEX IF NOT EXISTS idx_scans_scan_id "
|
|
291
|
+
"ON scans(scan_id) WHERE scan_id IS NOT NULL"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# Update schema version
|
|
295
|
+
cursor.execute("UPDATE _metadata SET value = '3' WHERE key = 'schema_version'")
|
|
296
|
+
conn.commit()
|
|
297
|
+
|
|
298
|
+
# Migration from v3 to v4: Add prompt_text column for --show-prompt feature
|
|
299
|
+
if from_version < 4 <= to_version:
|
|
300
|
+
# Add prompt_text column (stored locally only for privacy)
|
|
301
|
+
cursor.execute("ALTER TABLE scans ADD COLUMN prompt_text TEXT")
|
|
302
|
+
|
|
303
|
+
# Update schema version
|
|
304
|
+
cursor.execute("UPDATE _metadata SET value = '4' WHERE key = 'schema_version'")
|
|
305
|
+
conn.commit()
|
|
306
|
+
|
|
307
|
+
# Migration from v4 to v5: Add description column to detections
|
|
308
|
+
if from_version < 5 <= to_version:
|
|
309
|
+
# Add description column for human-readable detection messages
|
|
310
|
+
cursor.execute("ALTER TABLE detections ADD COLUMN description TEXT")
|
|
311
|
+
|
|
312
|
+
# Update schema version
|
|
313
|
+
cursor.execute("UPDATE _metadata SET value = '5' WHERE key = 'schema_version'")
|
|
314
|
+
conn.commit()
|
|
315
|
+
|
|
316
|
+
def hash_prompt(self, prompt: str) -> str:
|
|
317
|
+
"""Create privacy-preserving hash of prompt.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
prompt: Prompt text to hash
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
SHA256 hex digest
|
|
324
|
+
"""
|
|
325
|
+
return hashlib.sha256(prompt.encode("utf-8")).hexdigest()
|
|
326
|
+
|
|
327
|
+
def record_scan(
|
|
328
|
+
self,
|
|
329
|
+
prompt: str,
|
|
330
|
+
detections: list[Detection],
|
|
331
|
+
l1_duration_ms: float | None = None,
|
|
332
|
+
l2_duration_ms: float | None = None,
|
|
333
|
+
total_duration_ms: float | None = None,
|
|
334
|
+
version: str = "0.0.1",
|
|
335
|
+
event_id: str | None = None,
|
|
336
|
+
store_prompt: bool = True,
|
|
337
|
+
) -> int:
|
|
338
|
+
"""Record a scan in the database.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
prompt: Original prompt (will be hashed, optionally stored)
|
|
342
|
+
detections: List of detections found
|
|
343
|
+
l1_duration_ms: L1 scan duration
|
|
344
|
+
l2_duration_ms: L2 scan duration
|
|
345
|
+
total_duration_ms: Total scan duration
|
|
346
|
+
version: RAXE version
|
|
347
|
+
event_id: Portal event ID (evt_xxx) for portal-CLI correlation.
|
|
348
|
+
NOTE: This is the SAME event_id used in telemetry, enabling
|
|
349
|
+
correlation between local scan history and portal alerts.
|
|
350
|
+
store_prompt: If True, store full prompt text locally (default True).
|
|
351
|
+
Enables --show-prompt in 'raxe event show'.
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
Database row ID (int)
|
|
355
|
+
"""
|
|
356
|
+
# Hash prompt
|
|
357
|
+
prompt_hash = self.hash_prompt(prompt)
|
|
358
|
+
# Optionally store full prompt for local retrieval
|
|
359
|
+
prompt_text = prompt if store_prompt else None
|
|
360
|
+
|
|
361
|
+
# Calculate stats
|
|
362
|
+
threats_found = len(detections)
|
|
363
|
+
l1_detections = sum(1 for d in detections if d.detection_layer == "L1")
|
|
364
|
+
l2_detections = sum(1 for d in detections if d.detection_layer == "L2")
|
|
365
|
+
|
|
366
|
+
# Find highest severity
|
|
367
|
+
highest_severity = None
|
|
368
|
+
if detections:
|
|
369
|
+
severity_order = {
|
|
370
|
+
Severity.CRITICAL: 4,
|
|
371
|
+
Severity.HIGH: 3,
|
|
372
|
+
Severity.MEDIUM: 2,
|
|
373
|
+
Severity.LOW: 1,
|
|
374
|
+
Severity.INFO: 0,
|
|
375
|
+
}
|
|
376
|
+
highest = max(detections, key=lambda d: severity_order.get(d.severity, 0))
|
|
377
|
+
highest_severity = highest.severity.value
|
|
378
|
+
|
|
379
|
+
# Insert scan record
|
|
380
|
+
with self._get_connection() as conn:
|
|
381
|
+
cursor = conn.cursor()
|
|
382
|
+
|
|
383
|
+
cursor.execute("""
|
|
384
|
+
INSERT INTO scans (
|
|
385
|
+
timestamp, prompt_hash, threats_found, highest_severity,
|
|
386
|
+
l1_duration_ms, l2_duration_ms, total_duration_ms,
|
|
387
|
+
l1_detections, l2_detections, version, event_id,
|
|
388
|
+
prompt_text
|
|
389
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
390
|
+
""", (
|
|
391
|
+
int(datetime.now(timezone.utc).timestamp()),
|
|
392
|
+
prompt_hash,
|
|
393
|
+
threats_found,
|
|
394
|
+
highest_severity,
|
|
395
|
+
l1_duration_ms,
|
|
396
|
+
l2_duration_ms,
|
|
397
|
+
total_duration_ms,
|
|
398
|
+
l1_detections,
|
|
399
|
+
l2_detections,
|
|
400
|
+
version,
|
|
401
|
+
event_id,
|
|
402
|
+
prompt_text,
|
|
403
|
+
))
|
|
404
|
+
|
|
405
|
+
db_scan_id = cursor.lastrowid
|
|
406
|
+
|
|
407
|
+
# Insert detection records
|
|
408
|
+
for detection in detections:
|
|
409
|
+
cursor.execute("""
|
|
410
|
+
INSERT INTO detections (
|
|
411
|
+
scan_id, rule_id, severity, confidence,
|
|
412
|
+
detection_layer, category, description
|
|
413
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
414
|
+
""", (
|
|
415
|
+
db_scan_id,
|
|
416
|
+
detection.rule_id,
|
|
417
|
+
detection.severity.value,
|
|
418
|
+
detection.confidence,
|
|
419
|
+
detection.detection_layer,
|
|
420
|
+
detection.category,
|
|
421
|
+
detection.message, # Human-readable description
|
|
422
|
+
))
|
|
423
|
+
|
|
424
|
+
conn.commit()
|
|
425
|
+
|
|
426
|
+
return db_scan_id
|
|
427
|
+
|
|
428
|
+
def get_scan(self, scan_id: int) -> ScanRecord | None:
|
|
429
|
+
"""Get scan by database ID.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
scan_id: Database scan ID (integer) to retrieve
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
ScanRecord if found, None otherwise
|
|
436
|
+
"""
|
|
437
|
+
with self._get_connection() as conn:
|
|
438
|
+
cursor = conn.cursor()
|
|
439
|
+
cursor.execute("SELECT * FROM scans WHERE id = ?", (scan_id,))
|
|
440
|
+
row = cursor.fetchone()
|
|
441
|
+
|
|
442
|
+
if row is None:
|
|
443
|
+
return None
|
|
444
|
+
|
|
445
|
+
return self._row_to_scan_record(row)
|
|
446
|
+
|
|
447
|
+
def _row_to_scan_record(self, row: sqlite3.Row) -> ScanRecord:
|
|
448
|
+
"""Convert a database row to a ScanRecord.
|
|
449
|
+
|
|
450
|
+
Args:
|
|
451
|
+
row: SQLite Row object from query
|
|
452
|
+
|
|
453
|
+
Returns:
|
|
454
|
+
ScanRecord populated from the row data
|
|
455
|
+
"""
|
|
456
|
+
return ScanRecord(
|
|
457
|
+
id=row["id"],
|
|
458
|
+
timestamp=datetime.fromtimestamp(row["timestamp"], tz=timezone.utc),
|
|
459
|
+
prompt_hash=row["prompt_hash"],
|
|
460
|
+
threats_found=row["threats_found"],
|
|
461
|
+
highest_severity=row["highest_severity"],
|
|
462
|
+
l1_duration_ms=row["l1_duration_ms"],
|
|
463
|
+
l2_duration_ms=row["l2_duration_ms"],
|
|
464
|
+
total_duration_ms=row["total_duration_ms"],
|
|
465
|
+
l1_detections=row["l1_detections"],
|
|
466
|
+
l2_detections=row["l2_detections"],
|
|
467
|
+
version=row["version"],
|
|
468
|
+
event_id=row["event_id"] if "event_id" in row.keys() else None,
|
|
469
|
+
prompt_text=row["prompt_text"] if "prompt_text" in row.keys() else None,
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
def get_by_event_id(self, event_id: str) -> ScanRecord | None:
|
|
473
|
+
"""Get scan record by event ID for portal correlation.
|
|
474
|
+
|
|
475
|
+
This method enables looking up local scan records using the
|
|
476
|
+
event ID (evt_xxx) that was sent to the portal, allowing
|
|
477
|
+
users to correlate portal alerts with local scan details.
|
|
478
|
+
|
|
479
|
+
Args:
|
|
480
|
+
event_id: Portal event ID (evt_xxx format)
|
|
481
|
+
|
|
482
|
+
Returns:
|
|
483
|
+
ScanRecord if found, None otherwise
|
|
484
|
+
|
|
485
|
+
Example:
|
|
486
|
+
>>> db = ScanHistoryDB()
|
|
487
|
+
>>> record = db.get_by_event_id("evt_a1b2c3d4e5f67890")
|
|
488
|
+
>>> if record:
|
|
489
|
+
... print(f"Found scan with {record.threats_found} threats")
|
|
490
|
+
"""
|
|
491
|
+
if not event_id or not event_id.startswith("evt_"):
|
|
492
|
+
return None
|
|
493
|
+
|
|
494
|
+
with self._get_connection() as conn:
|
|
495
|
+
cursor = conn.cursor()
|
|
496
|
+
cursor.execute("SELECT * FROM scans WHERE event_id = ?", (event_id,))
|
|
497
|
+
row = cursor.fetchone()
|
|
498
|
+
|
|
499
|
+
if row is None:
|
|
500
|
+
return None
|
|
501
|
+
|
|
502
|
+
return self._row_to_scan_record(row)
|
|
503
|
+
|
|
504
|
+
def list_scans(
|
|
505
|
+
self,
|
|
506
|
+
limit: int = 100,
|
|
507
|
+
offset: int = 0,
|
|
508
|
+
severity_filter: str | None = None,
|
|
509
|
+
) -> list[ScanRecord]:
|
|
510
|
+
"""List recent scans.
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
limit: Maximum number of scans to return
|
|
514
|
+
offset: Offset for pagination
|
|
515
|
+
severity_filter: Filter by highest severity
|
|
516
|
+
|
|
517
|
+
Returns:
|
|
518
|
+
List of ScanRecords
|
|
519
|
+
"""
|
|
520
|
+
with self._get_connection() as conn:
|
|
521
|
+
cursor = conn.cursor()
|
|
522
|
+
|
|
523
|
+
if severity_filter:
|
|
524
|
+
cursor.execute("""
|
|
525
|
+
SELECT * FROM scans
|
|
526
|
+
WHERE highest_severity = ?
|
|
527
|
+
ORDER BY timestamp DESC
|
|
528
|
+
LIMIT ? OFFSET ?
|
|
529
|
+
""", (severity_filter, limit, offset))
|
|
530
|
+
else:
|
|
531
|
+
cursor.execute("""
|
|
532
|
+
SELECT * FROM scans
|
|
533
|
+
ORDER BY timestamp DESC
|
|
534
|
+
LIMIT ? OFFSET ?
|
|
535
|
+
""", (limit, offset))
|
|
536
|
+
|
|
537
|
+
rows = cursor.fetchall()
|
|
538
|
+
return [self._row_to_scan_record(row) for row in rows]
|
|
539
|
+
|
|
540
|
+
def get_detections(self, scan_id: int) -> list[DetectionRecord]:
|
|
541
|
+
"""Get all detections for a scan.
|
|
542
|
+
|
|
543
|
+
Args:
|
|
544
|
+
scan_id: Scan ID
|
|
545
|
+
|
|
546
|
+
Returns:
|
|
547
|
+
List of DetectionRecords
|
|
548
|
+
"""
|
|
549
|
+
with self._get_connection() as conn:
|
|
550
|
+
cursor = conn.cursor()
|
|
551
|
+
cursor.execute("""
|
|
552
|
+
SELECT * FROM detections
|
|
553
|
+
WHERE scan_id = ?
|
|
554
|
+
ORDER BY severity DESC, confidence DESC
|
|
555
|
+
""", (scan_id,))
|
|
556
|
+
|
|
557
|
+
rows = cursor.fetchall()
|
|
558
|
+
return [
|
|
559
|
+
DetectionRecord(
|
|
560
|
+
id=row["id"],
|
|
561
|
+
scan_id=row["scan_id"],
|
|
562
|
+
rule_id=row["rule_id"],
|
|
563
|
+
severity=row["severity"],
|
|
564
|
+
confidence=row["confidence"],
|
|
565
|
+
detection_layer=row["detection_layer"],
|
|
566
|
+
category=row["category"],
|
|
567
|
+
description=row["description"] if "description" in row.keys() else None,
|
|
568
|
+
)
|
|
569
|
+
for row in rows
|
|
570
|
+
]
|
|
571
|
+
|
|
572
|
+
def get_statistics(self, days: int = 30) -> dict[str, Any]:
|
|
573
|
+
"""Get scan statistics for the last N days.
|
|
574
|
+
|
|
575
|
+
Args:
|
|
576
|
+
days: Number of days to analyze
|
|
577
|
+
|
|
578
|
+
Returns:
|
|
579
|
+
Dictionary with statistics
|
|
580
|
+
"""
|
|
581
|
+
cutoff = int((datetime.now(timezone.utc) - timedelta(days=days)).timestamp())
|
|
582
|
+
|
|
583
|
+
with self._get_connection() as conn:
|
|
584
|
+
cursor = conn.cursor()
|
|
585
|
+
|
|
586
|
+
# Total scans
|
|
587
|
+
cursor.execute(
|
|
588
|
+
"SELECT COUNT(*) as count FROM scans WHERE timestamp >= ?",
|
|
589
|
+
(cutoff,)
|
|
590
|
+
)
|
|
591
|
+
total_scans = cursor.fetchone()["count"]
|
|
592
|
+
|
|
593
|
+
# Scans with threats
|
|
594
|
+
cursor.execute(
|
|
595
|
+
"SELECT COUNT(*) as count FROM scans WHERE timestamp >= ? AND threats_found > 0",
|
|
596
|
+
(cutoff,)
|
|
597
|
+
)
|
|
598
|
+
scans_with_threats = cursor.fetchone()["count"]
|
|
599
|
+
|
|
600
|
+
# Threats by severity
|
|
601
|
+
cursor.execute("""
|
|
602
|
+
SELECT highest_severity, COUNT(*) as count
|
|
603
|
+
FROM scans
|
|
604
|
+
WHERE timestamp >= ? AND highest_severity IS NOT NULL
|
|
605
|
+
GROUP BY highest_severity
|
|
606
|
+
""", (cutoff,))
|
|
607
|
+
|
|
608
|
+
severity_counts = {row["highest_severity"]: row["count"] for row in cursor.fetchall()}
|
|
609
|
+
|
|
610
|
+
# Average latencies
|
|
611
|
+
cursor.execute("""
|
|
612
|
+
SELECT
|
|
613
|
+
AVG(l1_duration_ms) as avg_l1,
|
|
614
|
+
AVG(l2_duration_ms) as avg_l2,
|
|
615
|
+
AVG(total_duration_ms) as avg_total
|
|
616
|
+
FROM scans
|
|
617
|
+
WHERE timestamp >= ?
|
|
618
|
+
""", (cutoff,))
|
|
619
|
+
|
|
620
|
+
latencies = cursor.fetchone()
|
|
621
|
+
|
|
622
|
+
return {
|
|
623
|
+
"period_days": days,
|
|
624
|
+
"total_scans": total_scans,
|
|
625
|
+
"scans_with_threats": scans_with_threats,
|
|
626
|
+
"threat_rate": scans_with_threats / total_scans if total_scans > 0 else 0,
|
|
627
|
+
"severity_counts": severity_counts,
|
|
628
|
+
"avg_l1_duration_ms": latencies["avg_l1"],
|
|
629
|
+
"avg_l2_duration_ms": latencies["avg_l2"],
|
|
630
|
+
"avg_total_duration_ms": latencies["avg_total"],
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
def cleanup_old_scans(self, retention_days: int | None = None) -> int:
|
|
634
|
+
"""Delete scans older than retention period.
|
|
635
|
+
|
|
636
|
+
Args:
|
|
637
|
+
retention_days: Days to retain (default: 90)
|
|
638
|
+
|
|
639
|
+
Returns:
|
|
640
|
+
Number of scans deleted
|
|
641
|
+
"""
|
|
642
|
+
if retention_days is None:
|
|
643
|
+
retention_days = self.RETENTION_DAYS
|
|
644
|
+
|
|
645
|
+
cutoff = int(
|
|
646
|
+
(datetime.now(timezone.utc) - timedelta(days=retention_days)).timestamp()
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
with self._get_connection() as conn:
|
|
650
|
+
cursor = conn.cursor()
|
|
651
|
+
|
|
652
|
+
# Count scans to delete
|
|
653
|
+
cursor.execute("SELECT COUNT(*) as count FROM scans WHERE timestamp < ?", (cutoff,))
|
|
654
|
+
count = cursor.fetchone()["count"]
|
|
655
|
+
|
|
656
|
+
# Delete (cascade will handle detections)
|
|
657
|
+
cursor.execute("DELETE FROM scans WHERE timestamp < ?", (cutoff,))
|
|
658
|
+
conn.commit()
|
|
659
|
+
|
|
660
|
+
# Vacuum to reclaim space
|
|
661
|
+
cursor.execute("VACUUM")
|
|
662
|
+
|
|
663
|
+
return count
|
|
664
|
+
|
|
665
|
+
def log_suppression(
|
|
666
|
+
self,
|
|
667
|
+
scan_id: int | None,
|
|
668
|
+
rule_id: str,
|
|
669
|
+
reason: str,
|
|
670
|
+
suppression_pattern: str | None = None,
|
|
671
|
+
) -> None:
|
|
672
|
+
"""Log a suppression to the database for audit trail.
|
|
673
|
+
|
|
674
|
+
Args:
|
|
675
|
+
scan_id: Scan ID (optional, None for manual suppressions)
|
|
676
|
+
rule_id: Rule ID that was suppressed
|
|
677
|
+
reason: Reason for suppression
|
|
678
|
+
suppression_pattern: Pattern that matched (e.g., "pi-*")
|
|
679
|
+
"""
|
|
680
|
+
with self._get_connection() as conn:
|
|
681
|
+
cursor = conn.cursor()
|
|
682
|
+
|
|
683
|
+
cursor.execute("""
|
|
684
|
+
INSERT INTO suppressions (
|
|
685
|
+
scan_id, rule_id, reason, timestamp, suppression_pattern
|
|
686
|
+
) VALUES (?, ?, ?, ?, ?)
|
|
687
|
+
""", (
|
|
688
|
+
scan_id,
|
|
689
|
+
rule_id,
|
|
690
|
+
reason,
|
|
691
|
+
datetime.now(timezone.utc).isoformat(),
|
|
692
|
+
suppression_pattern,
|
|
693
|
+
))
|
|
694
|
+
|
|
695
|
+
conn.commit()
|
|
696
|
+
|
|
697
|
+
def get_suppressions(
|
|
698
|
+
self,
|
|
699
|
+
scan_id: int | None = None,
|
|
700
|
+
limit: int = 100,
|
|
701
|
+
) -> list[dict[str, Any]]:
|
|
702
|
+
"""Get suppression log entries.
|
|
703
|
+
|
|
704
|
+
Args:
|
|
705
|
+
scan_id: Filter by scan ID (optional)
|
|
706
|
+
limit: Maximum entries to return
|
|
707
|
+
|
|
708
|
+
Returns:
|
|
709
|
+
List of suppression log entries
|
|
710
|
+
"""
|
|
711
|
+
with self._get_connection() as conn:
|
|
712
|
+
cursor = conn.cursor()
|
|
713
|
+
|
|
714
|
+
if scan_id is not None:
|
|
715
|
+
cursor.execute("""
|
|
716
|
+
SELECT * FROM suppressions
|
|
717
|
+
WHERE scan_id = ?
|
|
718
|
+
ORDER BY timestamp DESC
|
|
719
|
+
LIMIT ?
|
|
720
|
+
""", (scan_id, limit))
|
|
721
|
+
else:
|
|
722
|
+
cursor.execute("""
|
|
723
|
+
SELECT * FROM suppressions
|
|
724
|
+
ORDER BY timestamp DESC
|
|
725
|
+
LIMIT ?
|
|
726
|
+
""", (limit,))
|
|
727
|
+
|
|
728
|
+
rows = cursor.fetchall()
|
|
729
|
+
return [
|
|
730
|
+
{
|
|
731
|
+
"id": row["id"],
|
|
732
|
+
"scan_id": row["scan_id"],
|
|
733
|
+
"rule_id": row["rule_id"],
|
|
734
|
+
"reason": row["reason"],
|
|
735
|
+
"timestamp": row["timestamp"],
|
|
736
|
+
"suppression_pattern": row["suppression_pattern"],
|
|
737
|
+
}
|
|
738
|
+
for row in rows
|
|
739
|
+
]
|
|
740
|
+
|
|
741
|
+
def export_to_json(self, scan_id: int) -> dict[str, Any]:
|
|
742
|
+
"""Export scan and detections to JSON-serializable dict.
|
|
743
|
+
|
|
744
|
+
Args:
|
|
745
|
+
scan_id: Scan ID to export
|
|
746
|
+
|
|
747
|
+
Returns:
|
|
748
|
+
Dictionary with scan and detections
|
|
749
|
+
"""
|
|
750
|
+
scan = self.get_scan(scan_id)
|
|
751
|
+
if scan is None:
|
|
752
|
+
raise ValueError(f"Scan {scan_id} not found")
|
|
753
|
+
|
|
754
|
+
detections = self.get_detections(scan_id)
|
|
755
|
+
suppressions = self.get_suppressions(scan_id=scan_id)
|
|
756
|
+
|
|
757
|
+
return {
|
|
758
|
+
"scan": {
|
|
759
|
+
**asdict(scan),
|
|
760
|
+
"timestamp": scan.timestamp.isoformat(),
|
|
761
|
+
},
|
|
762
|
+
"detections": [asdict(d) for d in detections],
|
|
763
|
+
"suppressions": suppressions,
|
|
764
|
+
}
|