syntax = "proto3";

// If you make any changes make sure you run: make regenerate-proto

package gitlab.agent.agentcfg;

option go_package = "gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/pkg/agentcfg";
import "buf/validate/validate.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";

// CF suffix stands for Configuration File, meaning a message is
// part of ConfigurationFile.

message ObservabilityCF {
  LoggingCF logging = 1 [json_name = "logging"];
  GoogleProfilerCF google_profiler = 2 [json_name = "google_profiler"];
}

enum log_level_enum {
  info = 0; // default value must be 0
  debug = 1;
  warn = 2;
  error = 3;
}

message LoggingCF {
  log_level_enum level = 1 [json_name = "level"];
  optional log_level_enum grpc_level = 2 [json_name = "grpc_level"]; // optional to be able to tell when not set and use a different default value.
}

message GoogleProfilerCF {
  bool enabled = 1 [json_name = "enabled"];
  string project_id = 2 [json_name = "project_id"];
  string credentials_file = 3 [json_name = "credentials_file"];
  bool debug_logging = 4 [json_name = "debug_logging"];
}

message CiAccessInstanceCF {
  string default_namespace = 1 [json_name = "default_namespace"];
  CiAccessAsCF access_as = 2 [json_name = "access_as"];
  repeated string environments = 3 [json_name = "environments", (buf.validate.field).repeated.items.string.min_bytes = 1];
  google.protobuf.Struct annotations = 4 [json_name = "annotations"];
  bool protected_branches_only = 5 [json_name = "protected_branches_only"];
  ResourceManagementCF resource_management = 6 [json_name = "resource_management"];
}

// TODO for https://gitlab.com/gitlab-org/gitlab/-/issues/357516.
//message CiAccessOrganizationCF {
//  string default_namespace = 1 [json_name = "default_namespace"];
//  CiAccessAsCF access_as = 2 [json_name = "access_as"];
//  repeated string environments = 3 [json_name = "environments", (buf.validate.field).repeated.items.string.min_bytes = 1];
//  google.protobuf.Struct annotations = 4 [json_name = "annotations"];
//  bool protected_branches_only = 5 [json_name = "protected_branches_only"];
//  ResourceManagementCF resource_management = 6 [json_name = "resource_management"];
//}

// https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_ci_access.md
message CiAccessCF {
  repeated CiAccessProjectCF projects = 1 [json_name = "projects"];
  repeated CiAccessGroupCF groups = 2 [json_name = "groups"];
  oneof orgOrInstance {
    CiAccessInstanceCF instance = 3 [json_name = "instance"];
    // CiAccessOrganizationCF organization = 4 [json_name = "organization"];
  }
}

message CiAccessProjectCF {
  string id = 1 [json_name = "id", (buf.validate.field).string.min_bytes = 1];
  string default_namespace = 2 [json_name = "default_namespace"];
  CiAccessAsCF access_as = 3 [json_name = "access_as"];
  repeated string environments = 4 [json_name = "environments", (buf.validate.field).repeated.items.string.min_bytes = 1];
  google.protobuf.Struct annotations = 5 [json_name = "annotations"];
  bool protected_branches_only = 6 [json_name = "protected_branches_only"];
  ResourceManagementCF resource_management = 7 [json_name = "resource_management"];
}

message CiAccessGroupCF {
  string id = 1 [json_name = "id", (buf.validate.field).string.min_bytes = 1];
  string default_namespace = 2 [json_name = "default_namespace"];
  CiAccessAsCF access_as = 3 [json_name = "access_as"];
  repeated string environments = 4 [json_name = "environments", (buf.validate.field).repeated.items.string.min_bytes = 1];
  google.protobuf.Struct annotations = 5 [json_name = "annotations"];
  bool protected_branches_only = 6 [json_name = "protected_branches_only"];
  ResourceManagementCF resource_management = 7 [json_name = "resource_management"];
}

message ResourceManagementCF {
  bool enabled = 1 [json_name = "enabled"];
}

message CiAccessAsCF {
  oneof as {
    option (buf.validate.oneof).required = true;

    CiAccessAsAgentCF agent = 1 [json_name = "agent"];
    CiAccessAsImpersonateCF impersonate = 2 [json_name = "impersonate"];
    CiAccessAsCiJobCF ci_job = 3 [json_name = "ci_job"];
  }
}

message CiAccessAsAgentCF {
}

message CiAccessAsCiJobCF {
}

message CiAccessAsImpersonateCF {
  string username = 1 [json_name = "username", (buf.validate.field).string.min_bytes = 1];
  repeated string groups = 2 [json_name = "groups", (buf.validate.field).repeated.items.string.min_bytes = 1];
  string uid = 3 [json_name = "uid"];
  repeated ExtraKeyValCF extra = 4 [json_name = "extra"];
}

message ExtraKeyValCF {
  string key = 1 [json_name = "key", (buf.validate.field).string.min_bytes = 1];
  // Empty elements are allowed by Kubernetes.
  repeated string val = 2 [json_name = "val", (buf.validate.field).repeated.min_items = 1, (buf.validate.field).repeated.items.string.min_bytes = 1];
}

// https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_user_access.md
message UserAccessCF {
  UserAccessAsCF access_as = 1 [json_name = "access_as"];
  repeated UserAccessProjectCF projects = 2 [json_name = "projects"];
  repeated UserAccessGroupCF groups = 3 [json_name = "groups"];
  oneof orgOrInstance {
    UserAccessInstanceCF instance = 4 [json_name = "instance"];
    // UserAccessOrganizationCF organization = 5 [json_name = "organization"];
  }
}

message UserAccessProjectCF {
  string id = 1 [json_name = "id", (buf.validate.field).string.min_bytes = 1];
}

message UserAccessGroupCF {
  string id = 1 [json_name = "id", (buf.validate.field).string.min_bytes = 1];
}

message UserAccessInstanceCF {
}

message UserAccessAsCF {
  oneof as {
    option (buf.validate.oneof).required = true;

    UserAccessAsAgentCF agent = 1 [json_name = "agent"];
    UserAccessAsUserCF user = 3 [json_name = "user"];
  }
}

message UserAccessAsAgentCF {
}

message UserAccessAsUserCF {
}

message ContainerScanningCF {
  VulnerabilityReport vulnerability_report = 1 [json_name = "vulnerability_report"];
  string cadence = 2 [json_name = "cadence", (buf.validate.field).string.min_bytes = 1];
  ResourceRequirements resource_requirements = 3 [json_name = "resource_requirements"];
  TrivyK8sWrapperImage trivy_k8s_wrapper_image = 4 [json_name = "trivy_k8s_wrapper_image"];
  optional bool persist_ocs_status = 5 [json_name = "persist_ocs_status"];
  google.protobuf.Duration scanner_timeout = 6 [json_name = "scanner_timeout"];
  // The maximum size of the generated Trivy Report, in bytes
  uint64 report_max_size = 7 [json_name = "report_max_size"];
  // Determines whether the Trivy Report ConfigMap is deleted after a Vulnerability Scan.
  // Defaults to true
  optional bool delete_report_artifact = 8 [json_name = "delete_report_artifact"];
}

message VulnerabilityReport {
  repeated string namespaces = 1 [json_name = "namespaces"];
  repeated ContainerScanningFilter filters = 2 [json_name = "filters"];
  // The Kubernetes Resource Types to inspect to identify Container Images to scan.
  // Allowed Values: Pod, ReplicaSet, ReplicationController, StatefulSet, DaemonSet, CronJob, Job, Deployment
  repeated string resource_types = 3 [
    json_name = "resource_types",
    (buf.validate.field).repeated = {
      unique: true,
      items: {
        string: {
          in: ["Pod", "ReplicaSet", "ReplicationController", "StatefulSet", "DaemonSet", "CronJob", "Job", "Deployment"]
        }
      }
    }
  ];
}

message ContainerScanningFilter {
  repeated string namespaces = 1 [json_name = "namespaces"];
  repeated string resources = 2 [json_name = "resources"];
  repeated string containers = 3 [json_name = "containers"];
  repeated string kinds = 4 [json_name = "kinds"];
}

message ResourceRequirements {
  Resource limits = 1 [json_name = "limits"];
  Resource requests = 2 [json_name = "requests"];
}

message TrivyK8sWrapperImage {
  string repository = 1 [json_name = "repository", (buf.validate.field).string.min_bytes = 1];
  string tag = 2 [json_name = "tag"];
}

message Resource {
  string cpu = 1 [json_name = "cpu"];
  string memory = 2 [json_name = "memory"];
  string ephemeral_storage = 3 [json_name = "ephemeral_storage"];
}

// ConfigurationFile represents user-facing configuration file.
message ConfigurationFile {
  reserved 1;
  reserved "gitops";

  // Configuration related to all things observability. This is about the
  // agent itself, not any observability-related features.
  ObservabilityCF observability = 2 [json_name = "observability"];
  reserved 3;
  CiAccessCF ci_access = 4 [json_name = "ci_access"];
  ContainerScanningCF container_scanning = 5 [json_name = "container_scanning"];
  UserAccessCF user_access = 6 [json_name = "user_access"];
  RemoteDevelopmentCF remote_development = 7 [json_name = "remote_development"];
  FluxCF flux = 8 [json_name = "flux"];
}

// AgentConfiguration represents configuration for agentk.
// Note that agentk configuration is not exactly the whole file as the file
// may contain bits that are not relevant for the agent. For example, some
// additional config for kas.
message AgentConfiguration {
  reserved 1;
  reserved "gitops";

  ObservabilityCF observability = 2;
  reserved 3;
  // GitLab-wide unique id of the agent for the given agent_type.
  int64 agent_id = 4;
  // Id of the configuration project.
  int64 project_id = 5;
  CiAccessCF ci_access = 6;
  ContainerScanningCF container_scanning = 7;
  // Path of the configuration project
  string project_path = 8;
  RemoteDevelopmentCF remote_development = 9;
  FluxCF flux = 10;
  string gitlab_external_url = 11;
}

// GitLabWorkspacesProxy represents the gitlab workspaces proxy configuration for the remote development module
message GitLabWorkspacesProxy {
  string namespace = 1 [json_name = "namespace"];
}

// WorkspaceNetworkPolicyEgress represent the firewall rules for the remote development workspaces
message WorkspaceNetworkPolicyEgress {
  string allow = 1 [json_name = "allow"];
  repeated string except = 2 [json_name = "except"];
}

// WorkspaceNetworkPolicy represents the firewall configuration for the remote development workspaces
message WorkspaceNetworkPolicy {
  optional bool enabled = 1 [json_name = "enabled"];
  repeated WorkspaceNetworkPolicyEgress egress = 2 [json_name = "egress"];
}

// WorkspaceImagePullSecret represents an image pull secret and the namespace it is located
message WorkspaceImagePullSecret {
  string name = 1 [json_name = "name"];
  string namespace = 2 [json_name = "namespace"];
}

// RemoteDevelopmentCF represents configurations for Workspaces for agentk.
// Only the `enabled` field is used by the agentk.
// Remaining fields are used in Rails to drive the workspace behaviour.
// Note that we use integers instead of duration fields for time values, to match types stored in Rails.
message RemoteDevelopmentCF {
  reserved 3, 4, 11, 12;
  reserved "partial_sync_interval", "full_sync_interval", "default_max_hours_before_termination", "max_hours_before_termination_limit";
  bool enabled = 1 [json_name = "enabled"];
  string dns_zone = 2 [json_name = "dns_zone"];
  GitLabWorkspacesProxy gitlab_workspaces_proxy = 5 [json_name = "gitlab_workspaces_proxy"];
  WorkspaceNetworkPolicy network_policy = 6 [json_name = "network_policy"];
  ResourceRequirements default_resources_per_workspace_container = 7 [json_name = "default_resources_per_workspace_container"];
  ResourceRequirements max_resources_per_workspace = 8 [json_name = "max_resources_per_workspace"];
  optional int32 workspaces_quota = 9 [json_name = "workspaces_quota"];
  optional int32 workspaces_per_user_quota = 10 [json_name = "workspaces_per_user_quota"];
  repeated WorkspaceImagePullSecret image_pull_secrets = 13 [json_name = "image_pull_secrets"];
  map<string, string> annotations = 14 [json_name = "annotations"];
  map<string, string> labels = 15 [json_name = "labels"];
  bool allow_privilege_escalation = 16 [json_name = "allow_privilege_escalation"];
  bool use_kubernetes_user_namespaces = 17 [json_name = "use_kubernetes_user_namespaces"];
  string default_runtime_class = 18 [json_name = "default_runtime_class"];
  optional int32 max_active_hours_before_stop = 19 [json_name = "max_active_hours_before_stop"];
  optional int32 max_stopped_hours_before_termination = 20 [json_name = "max_stopped_hours_before_termination"];
  optional string shared_namespace = 21 [json_name = "shared_namespace"];
}

message FluxCF {
  string webhook_receiver_url = 1 [json_name = "webhook_receiver_url"];
  optional bool enabled = 2 [json_name = "enabled"];
}
