initial-commit

This commit is contained in:
Guillaume GRABÉ
2026-05-12 17:06:43 +02:00
commit 051a080dfa
110 changed files with 26377 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
syntax = "proto3";
package charybdis.core;
import "core/common.proto";
// APIMetadata represents identifying information for an API entity
// An API is a contract for data exchange between software components
message APIMetadata {
// Required: The name of the API
string name = 1;
// Optional: Namespace for organizational grouping (default: "default")
string namespace = 2;
// Optional: Human-readable description of the API
string description = 3;
// Optional: Labels for categorization and filtering
// Key-value pairs (e.g., "protocol": "rest", "version": "v1")
map<string, string> labels = 4;
// Optional: Tags for additional classification
repeated string tags = 5;
// Optional: Links to external resources
repeated Link links = 6;
}
// APISpec represents configuration for an API entity
message APISpec {
// Required: Type of API definition
// Standard types: "openapi", "grpc", "graphql", "asyncapi", "rest"
string type = 1;
// Required: Lifecycle stage (e.g., "production", "experimental", "deprecated")
string lifecycle = 2;
// Required: Owner team or individual (references a Group or User entity)
string owner = 3;
// Optional: System this API belongs to (references a System entity)
string system = 4;
// Required: The API definition itself
// For OpenAPI: the full OpenAPI spec in YAML or JSON
// For gRPC: the .proto file content or reference
// For GraphQL: the schema definition
string definition = 5;
}
+19
View File
@@ -0,0 +1,19 @@
syntax = "proto3";
package charybdis.core;
// Link represents an external URL reference
// Used across all entity types for documentation, dashboards, etc.
message Link {
// URL to the external resource
string url = 1;
// Human-readable title for the link
string title = 2;
// Optional: Icon identifier (e.g., "github", "dashboard", "docs")
string icon = 3;
// Optional: Type of link (e.g., "documentation", "monitoring", "repository")
string type = 4;
}
+55
View File
@@ -0,0 +1,55 @@
syntax = "proto3";
package charybdis.core;
import "core/common.proto";
// ComponentMetadata represents identifying information for a component entity
// A component is a software component (service, website, library, etc.)
message ComponentMetadata {
// Required: The name of the component
string name = 1;
// Optional: Namespace for organizational grouping (default: "default")
string namespace = 2;
// Optional: Human-readable description of the component
string description = 3;
// Optional: Labels for categorization and filtering
// Key-value pairs (e.g., "environment": "production", "team": "payments")
map<string, string> labels = 4;
// Optional: Tags for additional classification
repeated string tags = 5;
// Optional: Links to external resources
repeated Link links = 6;
}
// ComponentSpec represents configuration for a component entity
message ComponentSpec {
// Required: Type of component (e.g., "service", "website", "library", "documentation")
string type = 1;
// Required: Lifecycle stage (e.g., "production", "experimental", "deprecated")
string lifecycle = 2;
// Required: Owner team or individual (references a Group or User entity)
string owner = 3;
// Optional: Parent system this component belongs to (references a System entity)
string system = 4;
// Optional: Sub-component of another component (references a Component entity)
string subcomponent_of = 5;
// Optional: Components this component depends on (references Component entities)
repeated string depends_on = 6;
// Optional: APIs this component provides (references API entities)
repeated string provides_apis = 7;
// Optional: APIs this component consumes (references API entities)
repeated string consumes_apis = 8;
}
+34
View File
@@ -0,0 +1,34 @@
syntax = "proto3";
package charybdis.core;
import "core/common.proto";
// DomainMetadata represents identifying information for a domain entity
// A domain is a high-level organizational boundary (e.g., "payments", "identity")
message DomainMetadata {
// Required: The domain name
string name = 1;
// Optional: Namespace for organizational grouping (default: "default")
string namespace = 2;
// Optional: Human-readable description of the domain
string description = 3;
// Optional: Labels for categorization and filtering
// Key-value pairs (e.g., "business-unit": "platform", "priority": "high")
map<string, string> labels = 4;
// Optional: Tags for additional classification
repeated string tags = 5;
// Optional: Links to external resources
repeated Link links = 6;
}
// DomainSpec represents configuration for a domain entity
message DomainSpec {
// Required: Owner team or individual (references a Group or User entity)
string owner = 1;
}
+114
View File
@@ -0,0 +1,114 @@
syntax = "proto3";
package charybdis.core;
import "google/protobuf/timestamp.proto";
// FindingMetadata represents identifying information for a security finding
message FindingMetadata {
// Required: Title of the finding (e.g., "SQL Injection in login handler")
string title = 1;
// Optional: Namespace (default: "default")
string namespace = 2;
// Optional: Detailed description of the vulnerability
string description = 3;
// Optional: Labels for categorization and filtering
map<string, string> labels = 4;
// Optional: Tags (e.g., "owasp-top-10", "cwe-89")
repeated string tags = 5;
}
// FindingSpec contains the security-relevant data for a finding
message FindingSpec {
// Required: Reference to the component this finding belongs to (entity name or UUID)
string component_ref = 1;
// Required: Lifecycle/environment scope (e.g., "production", "integration", "development")
string lifecycle = 2;
// Required: Severity level
Severity severity = 3;
// Required: Current state of the finding
FindingState state = 4;
// Required: Scanner that produced this finding
string scanner = 5;
// Required: Rule/check identifier from the scanner (e.g., "CWE-89", "RUSTSEC-2024-001")
string rule_id = 6;
// Computed: Fingerprint for deduplication (set by reconciliation engine)
string fingerprint = 7;
// Optional: File path where the vulnerability was found
string file_path = 8;
// Optional: Line number in the file
uint32 line_start = 9;
// Optional: End line number (for multi-line findings)
uint32 line_end = 10;
// Optional: CWE identifier (e.g., "CWE-89")
string cwe = 11;
// Optional: CVE identifier (e.g., "CVE-2024-1234")
string cve = 12;
// Optional: CVSS score (0.0 - 10.0)
float cvss_score = 13;
// Optional: Affected package/dependency name
string package_name = 14;
// Optional: Affected package version
string package_version = 15;
// Optional: Fixed version (if known)
string fixed_version = 16;
// Optional: URL to more details (advisory, documentation)
string details_url = 17;
// Timestamp of first detection
google.protobuf.Timestamp first_seen = 18;
// Timestamp of most recent detection
google.protobuf.Timestamp last_seen = 19;
// Optional: Timestamp when the finding was resolved
google.protobuf.Timestamp resolved_at = 20;
// Optional: Scan identifier that produced this finding (for tracing back to CI run)
string scan_id = 21;
}
// Severity levels aligned with CVSS qualitative ratings
enum Severity {
SEVERITY_UNSPECIFIED = 0;
SEVERITY_INFO = 1;
SEVERITY_LOW = 2;
SEVERITY_MEDIUM = 3;
SEVERITY_HIGH = 4;
SEVERITY_CRITICAL = 5;
}
// Finding lifecycle states
enum FindingState {
FINDING_STATE_UNSPECIFIED = 0;
// Active: currently detected by scanner
FINDING_STATE_ACTIVE = 1;
// Resolved: no longer detected by scanner (auto-closed on reimport)
FINDING_STATE_RESOLVED = 2;
// Accepted: risk accepted by human decision
FINDING_STATE_ACCEPTED = 3;
// False positive: marked as not a real issue
FINDING_STATE_FALSE_POSITIVE = 4;
// Reopened: was resolved but detected again
FINDING_STATE_REOPENED = 5;
}
+60
View File
@@ -0,0 +1,60 @@
syntax = "proto3";
package charybdis.core;
import "core/common.proto";
// GroupMetadata represents identifying information for a group entity
// A group represents a team or organizational unit
message GroupMetadata {
// Required: The group name (e.g., "team-a", "engineering")
string name = 1;
// Optional: Namespace for organizational grouping (default: "default")
string namespace = 2;
// Optional: Human-readable description of the group
string description = 3;
// Optional: Labels for categorization and filtering
// Key-value pairs (e.g., "department": "engineering", "cost-center": "1234")
map<string, string> labels = 4;
// Optional: Tags for additional classification
repeated string tags = 5;
// Optional: Links to external resources (e.g., team page, Slack channel)
repeated Link links = 6;
}
// GroupSpec represents configuration for a group entity
message GroupSpec {
// Required: Type of group
// Standard types: "team", "business-unit", "product-area", "root", "department"
string type = 1;
// Optional: Group profile information
GroupProfile profile = 2;
// Optional: Parent group for hierarchy (references a Group entity)
// Leave empty for root-level groups
string parent = 3;
// Optional: Child groups in the hierarchy (references Group entities)
repeated string children = 4;
// Optional: Direct members of this group (references User entities)
repeated string members = 5;
}
// GroupProfile contains detailed profile information
message GroupProfile {
// Display name (e.g., "Engineering Team")
string display_name = 1;
// Group email address
string email = 2;
// Group picture/logo URL
string picture = 3;
}
+44
View File
@@ -0,0 +1,44 @@
syntax = "proto3";
package charybdis.core;
import "core/common.proto";
// ResourceMetadata represents identifying information for a resource entity
// A resource is infrastructure or operational component (database, S3 bucket, cluster, etc.)
message ResourceMetadata {
// Required: The resource name
string name = 1;
// Optional: Namespace for organizational grouping (default: "default")
string namespace = 2;
// Optional: Human-readable description of the resource
string description = 3;
// Optional: Labels for categorization and filtering
// Key-value pairs (e.g., "cloud": "aws", "region": "us-west-2")
map<string, string> labels = 4;
// Optional: Tags for additional classification
repeated string tags = 5;
// Optional: Links to external resources (e.g., AWS console, monitoring dashboard)
repeated Link links = 6;
}
// ResourceSpec represents configuration for a resource entity
message ResourceSpec {
// Required: Type of resource
// Standard types: "database", "s3-bucket", "cluster", "pipeline", "queue", "cache"
string type = 1;
// Required: Owner team or individual (references a Group or User entity)
string owner = 2;
// Optional: System this resource belongs to (references a System entity)
string system = 3;
// Optional: Resources this resource depends on (references other Resource entities)
repeated string depends_on = 4;
}
+55
View File
@@ -0,0 +1,55 @@
syntax = "proto3";
package charybdis.core;
import "core/common.proto";
// ServiceMetadata represents identifying information for a service entity
// Compatible with Backstage Component metadata structure
message ServiceMetadata {
// Required: The name of the service
string name = 1;
// Optional: Namespace for organizational grouping (e.g., "production", "staging")
string namespace = 2;
// Optional: Human-readable description of what this service does
string description = 3;
// Optional: Labels for categorization and filtering
repeated string labels = 4;
// Optional: Tags for additional classification
repeated string tags = 5;
// Optional: Links to external resources
repeated Link links = 6;
}
// ServiceSpec represents configuration and behavior for a service entity
// Compatible with Backstage Component spec structure
message ServiceSpec {
// Type of service (e.g., "backend-service", "frontend", "api", "website")
string type = 1;
// Lifecycle stage (e.g., "production", "experimental", "deprecated")
string lifecycle = 2;
// Owner team or individual (e.g., "team-platform", "john.doe@company.com")
string owner = 3;
// Optional: Parent system this service belongs to
string system = 4;
// Optional: Sub-component of another service
string subcomponent_of = 5;
// Optional: Services this service depends on
repeated string depends_on = 6;
// Optional: Services that provide APIs this service consumes
repeated string consumes_apis = 7;
// Optional: APIs that this service provides
repeated string provides_apis = 8;
}
+37
View File
@@ -0,0 +1,37 @@
syntax = "proto3";
package charybdis.core;
import "core/common.proto";
// SystemMetadata represents identifying information for a system entity
// A system is a collection of services and resources that work together
message SystemMetadata {
// Required: The name of the system
string name = 1;
// Optional: Namespace for organizational grouping (default: "default")
string namespace = 2;
// Optional: Human-readable description of the system
string description = 3;
// Optional: Labels for categorization and filtering
// Key-value pairs (e.g., "environment": "production", "criticality": "high")
map<string, string> labels = 4;
// Optional: Tags for additional classification
repeated string tags = 5;
// Optional: Links to external resources
repeated Link links = 6;
}
// SystemSpec represents configuration for a system entity
message SystemSpec {
// Required: Owner team or individual responsible for this system (references a Group or User entity)
string owner = 1;
// Optional: Domain this system belongs to (references a Domain entity)
string domain = 2;
}
+49
View File
@@ -0,0 +1,49 @@
syntax = "proto3";
package charybdis.core;
import "core/common.proto";
// UserMetadata represents identifying information for a user entity
// A user represents a person in the organization
message UserMetadata {
// Required: The username (e.g., "jdoe", "john.doe")
string name = 1;
// Optional: Namespace for organizational grouping (default: "default")
string namespace = 2;
// Optional: Full name or description
string description = 3;
// Optional: Labels for categorization and filtering
// Key-value pairs (e.g., "department": "engineering", "location": "SF")
map<string, string> labels = 4;
// Optional: Tags for additional classification
repeated string tags = 5;
// Optional: Links to external resources (e.g., GitHub profile, LinkedIn)
repeated Link links = 6;
}
// UserSpec represents configuration for a user entity
message UserSpec {
// Optional: User profile information
UserProfile profile = 1;
// Optional: Groups this user is a member of (references Group entities)
repeated string member_of = 2;
}
// UserProfile contains detailed profile information
message UserProfile {
// Display name (e.g., "John Doe")
string display_name = 1;
// Email address
string email = 2;
// Avatar/picture URL
string picture = 3;
}
+200
View File
@@ -0,0 +1,200 @@
syntax = "proto3";
package charybdis.entities;
import "google/protobuf/timestamp.proto";
import "google/protobuf/field_mask.proto";
import "core/service.proto";
import "core/system.proto";
import "core/component.proto";
import "core/api.proto";
import "core/user.proto";
import "core/group.proto";
import "core/domain.proto";
import "core/resource.proto";
import "core/finding.proto";
// Plugin imports will be inserted here by build.rs
import "plugins/defectdojo/proto/defectdojo.proto";
import "plugins/keycloak/proto/keycloak.proto";
import "plugins/dependencytrack/proto/dependencytrack.proto";
// GENERATED FILE - DO NOT EDIT MANUALLY
// This file is generated by build.rs based on plugins.toml configuration
// To add new entity types, configure plugins in plugins.toml and rebuild
// Main entity structure
// This represents any cataloged entity in Charybdis
message Entity {
// Unique identifier (UUID)
string id = 1;
// Entity kind (e.g., "Service", "System", "Component")
// This determines which metadata/spec variant is populated
string kind = 2;
// Polymorphic metadata - identifying information
// Each kind has its own metadata structure
oneof metadata {
charybdis.core.ServiceMetadata service_metadata = 10;
charybdis.core.SystemMetadata system_metadata = 11;
charybdis.core.ComponentMetadata component_metadata = 12;
charybdis.core.APIMetadata api_metadata = 13;
charybdis.core.UserMetadata user_metadata = 14;
charybdis.core.GroupMetadata group_metadata = 15;
charybdis.core.DomainMetadata domain_metadata = 16;
charybdis.core.ResourceMetadata resource_metadata = 17;
charybdis.core.FindingMetadata finding_metadata = 24;
// Plugin metadata types will be inserted here by build.rs
// Example:
// charybdis.plugins.defectdojo.DefectDojoProductMetadata defectdojo_product_metadata = 100;
// charybdis.plugins.dependencytrack.DependencyTrackProjectMetadata dependencytrack_project_metadata = 101;
charybdis.plugins.defectdojo.DefectdojoMetadata defectdojo_metadata = 100;
charybdis.plugins.keycloak.KeycloakMetadata keycloak_metadata = 102;
charybdis.plugins.dependencytrack.DependencytrackMetadata dependencytrack_metadata = 101;
}
// Polymorphic spec - configuration and behavior
// Each kind has its own spec structure
oneof spec {
charybdis.core.ServiceSpec service_spec = 4;
charybdis.core.SystemSpec system_spec = 5;
charybdis.core.ComponentSpec component_spec = 6;
charybdis.core.APISpec api_spec = 7;
charybdis.core.UserSpec user_spec = 8;
charybdis.core.GroupSpec group_spec = 9;
charybdis.core.DomainSpec domain_spec = 18;
charybdis.core.ResourceSpec resource_spec = 19;
charybdis.core.FindingSpec finding_spec = 25;
// Plugin spec types will be inserted here by build.rs
// Example:
// charybdis.plugins.defectdojo.DefectDojoProductSpec defectdojo_product_spec = 100;
// charybdis.plugins.dependencytrack.DependencyTrackProjectSpec dependencytrack_project_spec = 101;
charybdis.plugins.defectdojo.DefectdojoSpec defectdojo_spec = 200;
charybdis.plugins.keycloak.KeycloakSpec keycloak_spec = 202;
charybdis.plugins.dependencytrack.DependencytrackSpec dependencytrack_spec = 201;
}
// Annotations - arbitrary string key-value pairs
// This is where plugins store external tool IDs and references
// Examples:
// "defectdojo.com/product-id": "12345"
// "dependencytrack.com/project-uuid": "550e8400-e29b-41d4-a716-446655440000"
// "github.com/repo-slug": "myorg/myrepo"
map<string, string> annotations = 20;
// Timestamps (managed by the system)
google.protobuf.Timestamp created_at = 21;
google.protobuf.Timestamp updated_at = 22;
}
// Request to create a new entity
message CreateEntityRequest {
// Entity data (id, created_at, updated_at will be set by server)
Entity entity = 1;
}
// Response after creating an entity
message CreateEntityResponse {
// The created entity with server-assigned fields
Entity entity = 1;
}
// Request to get an entity by ID
message GetEntityRequest {
// The UUID of the entity to retrieve
string id = 1;
}
// Response containing a single entity
message GetEntityResponse {
Entity entity = 1;
}
// Request to update an existing entity
message UpdateEntityRequest {
// The UUID of the entity to update
string id = 1;
// Updated entity data (id, created_at will be ignored)
Entity entity = 2;
// Optional: Field mask for partial updates
// If not provided, performs a full update
// If provided, only updates the fields specified in the mask
// Example paths: "kind", "annotations", "metadata", "spec",
// "annotations.github.com/repo-slug",
// "component_metadata.name", "component_spec.lifecycle"
google.protobuf.FieldMask update_mask = 3;
}
// Response after updating an entity
message UpdateEntityResponse {
// The updated entity
Entity entity = 1;
}
// Request to delete an entity by ID
message DeleteEntityRequest {
// The UUID of the entity to delete
string id = 1;
}
// Response after deleting an entity
message DeleteEntityResponse {
// Whether the deletion was successful
bool success = 1;
}
// Request to list entities
message ListEntitiesRequest {
// Optional: Filter by kind
string kind = 1;
// Optional: Filter by annotation key-value pairs
map<string, string> annotations = 2;
// Page size (default: 100, max: 1000)
int32 page_size = 3;
// Cursor for next page (opaque token from previous response)
string page_token = 4;
// Optional: Filter by name
string name = 5;
}
// Response containing a list of entities
message ListEntitiesResponse {
// The list of entities matching the filter
repeated Entity entities = 1;
// Cursor for next page (empty if no more results)
string next_page_token = 2;
// Total count of matching entities
int32 total_count = 3;
}
// Service definition for managing entities
service EntityService {
// Creates a new entity
rpc CreateEntity (CreateEntityRequest) returns (CreateEntityResponse);
// Gets an entity by its ID
rpc GetEntity (GetEntityRequest) returns (GetEntityResponse);
// Updates an existing entity
rpc UpdateEntity (UpdateEntityRequest) returns (UpdateEntityResponse);
// Deletes an entity by its ID
rpc DeleteEntity (DeleteEntityRequest) returns (DeleteEntityResponse);
// Lists entities with optional filtering
rpc ListEntities (ListEntitiesRequest) returns (ListEntitiesResponse);
}
+191
View File
@@ -0,0 +1,191 @@
syntax = "proto3";
package charybdis.entities;
import "google/protobuf/timestamp.proto";
import "google/protobuf/field_mask.proto";
import "core/service.proto";
import "core/system.proto";
import "core/component.proto";
import "core/api.proto";
import "core/user.proto";
import "core/group.proto";
import "core/domain.proto";
import "core/resource.proto";
import "core/finding.proto";
// Plugin imports will be inserted here by build.rs
{{PLUGIN_IMPORTS}}
// GENERATED FILE - DO NOT EDIT MANUALLY
// This file is generated by build.rs based on plugins.toml configuration
// To add new entity types, configure plugins in plugins.toml and rebuild
// Main entity structure
// This represents any cataloged entity in Charybdis
message Entity {
// Unique identifier (UUID)
string id = 1;
// Entity kind (e.g., "Service", "System", "Component")
// This determines which metadata/spec variant is populated
string kind = 2;
// Polymorphic metadata - identifying information
// Each kind has its own metadata structure
oneof metadata {
charybdis.core.ServiceMetadata service_metadata = 10;
charybdis.core.SystemMetadata system_metadata = 11;
charybdis.core.ComponentMetadata component_metadata = 12;
charybdis.core.APIMetadata api_metadata = 13;
charybdis.core.UserMetadata user_metadata = 14;
charybdis.core.GroupMetadata group_metadata = 15;
charybdis.core.DomainMetadata domain_metadata = 16;
charybdis.core.ResourceMetadata resource_metadata = 17;
charybdis.core.FindingMetadata finding_metadata = 24;
// Plugin metadata types will be inserted here by build.rs
// Example:
// charybdis.plugins.defectdojo.DefectDojoProductMetadata defectdojo_product_metadata = 100;
// charybdis.plugins.dependencytrack.DependencyTrackProjectMetadata dependencytrack_project_metadata = 101;
{{PLUGIN_METADATA_FIELDS}}
}
// Polymorphic spec - configuration and behavior
// Each kind has its own spec structure
oneof spec {
charybdis.core.ServiceSpec service_spec = 4;
charybdis.core.SystemSpec system_spec = 5;
charybdis.core.ComponentSpec component_spec = 6;
charybdis.core.APISpec api_spec = 7;
charybdis.core.UserSpec user_spec = 8;
charybdis.core.GroupSpec group_spec = 9;
charybdis.core.DomainSpec domain_spec = 18;
charybdis.core.ResourceSpec resource_spec = 19;
charybdis.core.FindingSpec finding_spec = 25;
// Plugin spec types will be inserted here by build.rs
// Example:
// charybdis.plugins.defectdojo.DefectDojoProductSpec defectdojo_product_spec = 100;
// charybdis.plugins.dependencytrack.DependencyTrackProjectSpec dependencytrack_project_spec = 101;
{{PLUGIN_SPEC_FIELDS}}
}
// Annotations - arbitrary string key-value pairs
// This is where plugins store external tool IDs and references
// Examples:
// "defectdojo.com/product-id": "12345"
// "dependencytrack.com/project-uuid": "550e8400-e29b-41d4-a716-446655440000"
// "github.com/repo-slug": "myorg/myrepo"
map<string, string> annotations = 20;
// Timestamps (managed by the system)
google.protobuf.Timestamp created_at = 21;
google.protobuf.Timestamp updated_at = 22;
}
// Request to create a new entity
message CreateEntityRequest {
// Entity data (id, created_at, updated_at will be set by server)
Entity entity = 1;
}
// Response after creating an entity
message CreateEntityResponse {
// The created entity with server-assigned fields
Entity entity = 1;
}
// Request to get an entity by ID
message GetEntityRequest {
// The UUID of the entity to retrieve
string id = 1;
}
// Response containing a single entity
message GetEntityResponse {
Entity entity = 1;
}
// Request to update an existing entity
message UpdateEntityRequest {
// The UUID of the entity to update
string id = 1;
// Updated entity data (id, created_at will be ignored)
Entity entity = 2;
// Optional: Field mask for partial updates
// If not provided, performs a full update
// If provided, only updates the fields specified in the mask
// Example paths: "kind", "annotations", "metadata", "spec",
// "annotations.github.com/repo-slug",
// "component_metadata.name", "component_spec.lifecycle"
google.protobuf.FieldMask update_mask = 3;
}
// Response after updating an entity
message UpdateEntityResponse {
// The updated entity
Entity entity = 1;
}
// Request to delete an entity by ID
message DeleteEntityRequest {
// The UUID of the entity to delete
string id = 1;
}
// Response after deleting an entity
message DeleteEntityResponse {
// Whether the deletion was successful
bool success = 1;
}
// Request to list entities
message ListEntitiesRequest {
// Optional: Filter by kind
string kind = 1;
// Optional: Filter by annotation key-value pairs
map<string, string> annotations = 2;
// Page size (default: 100, max: 1000)
int32 page_size = 3;
// Cursor for next page (opaque token from previous response)
string page_token = 4;
// Optional: Filter by name
string name = 5;
}
// Response containing a list of entities
message ListEntitiesResponse {
// The list of entities matching the filter
repeated Entity entities = 1;
// Cursor for next page (empty if no more results)
string next_page_token = 2;
// Total count of matching entities
int32 total_count = 3;
}
// Service definition for managing entities
service EntityService {
// Creates a new entity
rpc CreateEntity (CreateEntityRequest) returns (CreateEntityResponse);
// Gets an entity by its ID
rpc GetEntity (GetEntityRequest) returns (GetEntityResponse);
// Updates an existing entity
rpc UpdateEntity (UpdateEntityRequest) returns (UpdateEntityResponse);
// Deletes an entity by its ID
rpc DeleteEntity (DeleteEntityRequest) returns (DeleteEntityResponse);
// Lists entities with optional filtering
rpc ListEntities (ListEntitiesRequest) returns (ListEntitiesResponse);
}
+127
View File
@@ -0,0 +1,127 @@
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;
}