syntax = "proto3"; package charybdis.ingestion; import "google/protobuf/timestamp.proto"; import "core/finding.proto"; // Service for ingesting security scan results service IngestionService { // Import a scan report: parse, reconcile with existing findings, and persist rpc ImportScan (ImportScanRequest) returns (ImportScanResponse); // Dry-run a scan report: parse, reconcile, return diff without persisting // Useful for MR/PR comments: "this change introduces X new vulnerabilities" rpc DryRunScan (DryRunScanRequest) returns (DryRunScanResponse); } // Request to import a scan report message ImportScanRequest { // Required: Reference to the component (entity name or UUID) string component_ref = 1; // Required: Lifecycle/environment scope (e.g., "production", "integration") string lifecycle = 2; // Required: Format of the scan data (e.g., "sarif", "cyclonedx-vex") string format = 3; // Required: Raw scan report data (JSON/XML bytes) bytes data = 4; // Optional: Scanner name override (if not derivable from the report) string scanner_name = 5; // Optional: Identifier for this scan run (e.g., CI job ID) string scan_id = 6; } // Response after importing a scan message ImportScanResponse { // Summary of what happened during reconciliation ReconciliationSummary summary = 1; // New findings created during this import repeated FindingResult new_findings = 2; // Findings that were resolved (no longer detected) repeated FindingResult resolved_findings = 3; // Findings that were reopened (detected again after being resolved) repeated FindingResult reopened_findings = 4; } // Request for dry-run scan (same as import but no persistence) message DryRunScanRequest { // Required: Reference to the component (entity name or UUID) string component_ref = 1; // Required: Lifecycle/environment scope string lifecycle = 2; // Required: Format of the scan data string format = 3; // Required: Raw scan report data bytes data = 4; // Optional: Scanner name override string scanner_name = 5; } // Response for dry-run scan message DryRunScanResponse { // Summary of what would happen ReconciliationSummary summary = 1; // New findings that would be created repeated FindingResult new_findings = 2; // Findings that would be resolved repeated FindingResult resolved_findings = 3; // Findings that would be reopened repeated FindingResult reopened_findings = 4; } // Summary statistics of a reconciliation operation message ReconciliationSummary { // Total findings parsed from the scan report uint32 total_parsed = 1; // New findings (not previously seen) uint32 new_count = 2; // Existing findings still detected (unchanged) uint32 unchanged_count = 3; // Previously active findings no longer detected (resolved) uint32 resolved_count = 4; // Previously resolved findings detected again (reopened) uint32 reopened_count = 5; } // A finding result returned in import/dry-run responses message FindingResult { // Finding title string title = 1; // Severity charybdis.core.Severity severity = 2; // Scanner rule ID string rule_id = 3; // File path (if applicable) string file_path = 4; // Line number (if applicable) uint32 line_start = 5; // Fingerprint used for deduplication string fingerprint = 6; // Entity ID (set for existing findings, empty for dry-run new findings) string entity_id = 7; }