syntax = "proto3";

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

package gitlab.agent.kascfg;

option go_package = "gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/pkg/kascfg";

import "google/protobuf/duration.proto";
import "buf/validate/validate.proto";

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

message ListenAgentCF {
  // Network type to listen on. Supported values: tcp, tcp4, tcp6, unix.
  optional string network = 1 [json_name = "network", (buf.validate.field).string = {in: ["tcp", "tcp4", "tcp6", "unix"]}];
  // Address to listen on.
  string address = 2 [json_name = "address"];
  // Enable "gRPC through WebSocket" listening mode.
  // Rather than expecting gRPC directly, expect a WebSocket
  // connection, from which a gRPC stream is then unpacked.
  bool websocket = 3 [json_name = "websocket"];
  // X.509 certificate for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  string certificate_file = 4 [json_name = "certificate_file"];
  // X.509 key file for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  string key_file = 5 [json_name = "key_file"];
  // Maximum number of connections to allow per agent token per minute.
  uint32 connections_per_token_per_minute = 6 [json_name = "connections_per_token_per_minute"];
  // Max age of a connection. Connection is closed gracefully once it's
  // too old and there is no streaming happening.
  google.protobuf.Duration max_connection_age = 7 [json_name = "max_connection_age", (buf.validate.field).duration = {gt: {}}];
  // How much time to wait before stopping accepting new connections on shutdown.
  google.protobuf.Duration listen_grace_period = 8 [json_name = "listen_grace_period", (buf.validate.field).duration = {gt: {}}];
}

message PrometheusCF {
  // Expected URL path for requests.
  string url_path = 1 [json_name = "url_path"];
}

message ObservabilityListenCF {
  // Network type to listen on. Supported values: tcp, tcp4, tcp6, unix.
  optional string network = 1 [json_name = "network", (buf.validate.field).string = {in: ["tcp", "tcp4", "tcp6", "unix"]}];
  // Address to listen on.
  string address = 2 [json_name = "address"];
  // X.509 certificate for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  optional string certificate_file = 3 [json_name = "certificate_file", (buf.validate.field).string.min_bytes = 1];
  // X.509 key file for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  optional string key_file = 4 [json_name = "key_file", (buf.validate.field).string.min_bytes = 1];
}

message TracingCF {
  reserved 1, 5;
  reserved "connection_string", "otlp_legacy_endpoint";

  // URL to send traces to.
  // Supported protocols are: http, https. Traces are protobuf encoded.
  // Example: https://localhost:4317/traces/foo/bar
  string otlp_endpoint = 2 [json_name = "otlp_endpoint", (buf.validate.field).string.min_bytes = 1];

  // API token to set for authentication.
  optional string otlp_token_secret_file = 3 [json_name = "otlp_token_secret_file", (buf.validate.field).string.min_bytes = 1];

  // Custom CA certificate to use in order to verify the connection to OTLP collector
  optional string otlp_ca_certificate_file = 4 [json_name = "otlp_ca_certificate_file", (buf.validate.field).string.min_bytes = 1];

  bool http_server_enabled = 6 [json_name = "http_server_enabled"];
  bool http_client_enabled = 7 [json_name = "http_client_enabled"];
  bool grpc_server_enabled = 8 [json_name = "grpc_server_enabled"];
  bool grpc_client_enabled = 9 [json_name = "grpc_client_enabled"];
  bool redis_enabled = 10 [json_name = "redis_enabled"];
}

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 GitLabCF {
  // Address for calling GitLab APIs
  string address = 1 [json_name = "address", (buf.validate.field).string.min_bytes = 1, (buf.validate.field).string.uri = true];
  // External URL of GitLab in the format of `<scheme>://<domain>:<port>`. It is used to enable CORS (via Access-Control-Allow-Origin) for the Kubernetes API proxy.
  // This value can be omitted if KAS is hosted on the same domain than GitLab (frontend access)
  optional string external_url = 5 [json_name = "external_url", (buf.validate.field).string.min_bytes = 1, (buf.validate.field).string.uri = true];
  // Secret to generate JWT tokens to authenticate with GitLab.
  string authentication_secret_file = 2 [json_name = "authentication_secret_file", (buf.validate.field).string.min_bytes = 1];
  // Optional X.509 CA certificate for TLS in PEM format.
  // Should be set for self-signed certificates.
  string ca_certificate_file = 3 [json_name = "ca_certificate_file"];
  // Rate limiting configuration for talking to the GitLab API.
  TokenBucketRateLimitCF api_rate_limit = 4 [json_name = "api_rate_limit"];
}

message RemoteDevelopmentCF {
  // How often to poll RemoteDevelopment server module for changes.
  google.protobuf.Duration poll_period = 1 [json_name = "poll_period", (buf.validate.field).duration = {gt: {}}];
}

message SentryCF {
  // Sentry DSN https://docs.sentry.io/platforms/go/#configure
  string dsn = 1 [json_name = "dsn"];
  // Sentry environment
  // https://docs.sentry.io/product/sentry-basics/environments/
  string environment = 2 [json_name = "environment"];
}

message ListenCF {
  // Network type to listen on. Supported values: tcp, tcp4, tcp6, unix.
  optional string network = 1 [json_name = "network", (buf.validate.field).string = {in: ["tcp", "tcp4", "tcp6", "unix"]}];
  // Address to listen on.
  string address = 2 [json_name = "address"];
  // X.509 certificate for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  string certificate_file = 3 [json_name = "certificate_file"];
  // X.509 key file for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  string key_file = 4 [json_name = "key_file"];
  // How much time to wait before stopping accepting new connections on shutdown.
  google.protobuf.Duration listen_grace_period = 5 [json_name = "listen_grace_period", (buf.validate.field).duration = {gt: {}}];
  // How much time to wait before closing connections with in-flight requests.
  google.protobuf.Duration shutdown_grace_period = 6 [json_name = "shutdown_grace_period", (buf.validate.field).duration = {gt: {}}];
}

message KubernetesApiCF {
  // HTTP listener configuration for Kubernetes API connections.
  ListenCF listen = 1 [json_name = "listen"];
  // URL path prefix to remove from the incoming request URL.
  // Should be `/` if no prefix trimming is needed.
  string url_path_prefix = 2 [json_name = "url_path_prefix"];
  // TTL for successful allowed agent lookups.
  // /api/v4/job/allowed_agents
  // Set to zero to disable.
  google.protobuf.Duration allowed_agent_cache_ttl = 3 [json_name = "allowed_agent_cache_ttl", (buf.validate.field).duration = {gte: {}}];
  // TTL for failed allowed agent lookups.
  // /api/v4/job/allowed_agents
  google.protobuf.Duration allowed_agent_cache_error_ttl = 4 [json_name = "allowed_agent_cache_error_ttl", (buf.validate.field).duration = {gt: {}}];
  // Path to file containing the secret to sign and verify WebSocket tokens.
  string websocket_token_secret_file = 5 [json_name = "websocket_token_secret_file"];
  repeated string extra_allowed_response_headers = 6 [json_name = "extra_allowed_response_headers", (buf.validate.field).repeated.items.string.min_bytes = 1];
}

message AgentCF {
  reserved 3;
  reserved "gitops";

  option (buf.validate.message).cel = {
    id: "redis_conn_info",
    message: "redis_conn_info_refresh should be < redis_conn_info_ttl",
    expression: "this.redis_conn_info_refresh < this.redis_conn_info_ttl"
  };

  // RPC listener configuration for agentk connections.
  ListenAgentCF listen = 1 [json_name = "listen"];
  // Configuration for agent's configuration repository.
  AgentConfigurationCF configuration = 2 [json_name = "configuration"];
  // TTL for successful agent info lookups.
  // /api/v4/internal/agents/AGENT_TYPE/agent_info - where AGENT_TYPE is an enum.
  // Set to zero to disable.
  google.protobuf.Duration info_cache_ttl = 4 [json_name = "info_cache_ttl", (buf.validate.field).duration = {gte: {}}];
  // TTL for failed agent info lookups.
  // /api/v4/internal/agents/AGENT_TYPE/agent_info - where AGENT_TYPE is an enum.
  google.protobuf.Duration info_cache_error_ttl = 5 [json_name = "info_cache_error_ttl", (buf.validate.field).duration = {gt: {}}];
  // TTL for information about connected agents, stored in Redis.
  google.protobuf.Duration redis_conn_info_ttl = 7 [json_name = "redis_conn_info_ttl"];
  // Refresh period for information about connected agents, stored in Redis.
  google.protobuf.Duration redis_conn_info_refresh = 8 [json_name = "redis_conn_info_refresh"];
  // Garbage collection period for information about connected agents, stored in Redis.
  // If gitlab-kas crashes, another gitlab-kas instance will clean up stale data. This is how often this cleanup runs.
  google.protobuf.Duration redis_conn_info_gc = 9 [json_name = "redis_conn_info_gc"];
  // Configuration for exposing Kubernetes API.
  KubernetesApiCF kubernetes_api = 10 [json_name = "kubernetes_api"];
  // Configuration for RemoteDevelopment.
  RemoteDevelopmentCF remote_development = 11 [json_name = "remote_development"];
  // Configuration for the kas->agentk tunnel feature.
  ReceptiveAgentCF receptive_agent = 12 [json_name = "receptive_agent"];
}

message ReceptiveAgentCF {
  // How often to fetch the list of receptive agents from GitLab.
  google.protobuf.Duration poll_period = 1 [json_name = "poll_period", (buf.validate.field).duration = {gt: {}}];
}

message AgentConfigurationCF {
  // How often to poll agent's configuration repository for changes.
  google.protobuf.Duration poll_period = 1 [json_name = "poll_period", (buf.validate.field).duration = {gt: {}}];
  // Maximum file size of the agent configuration file.
  uint32 max_configuration_file_size = 2 [json_name = "max_configuration_file_size"];
}

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 LivenessProbeCF {
  // Expected URL path for requests.
  string url_path = 1 [json_name = "url_path"];
}

message ReadinessProbeCF {
  // Expected URL path for requests.
  string url_path = 1 [json_name = "url_path"];
}

message ObservabilityCF {
  // How often to send usage metrics to the main application.
  // /api/v4/internal/kubernetes/usage_ping
  // Set to zero to disable.
  google.protobuf.Duration usage_reporting_period = 1 [json_name = "usage_reporting_period", (buf.validate.field).duration = {gte: {}}];
  // Listener configuration for HTTP endpoint that exposes Prometheus,
  // pprof, liveness and readiness probes.
  ObservabilityListenCF listen = 2 [json_name = "listen"];
  PrometheusCF prometheus = 3 [json_name = "prometheus"];
  TracingCF tracing = 4 [json_name = "tracing"];
  SentryCF sentry = 5 [json_name = "sentry"];
  LoggingCF logging = 6 [json_name = "logging"];
  // Configuration for the Google Cloud Profiler.
  // See https://pkg.go.dev/cloud.google.com/go/profiler.
  GoogleProfilerCF google_profiler = 7 [json_name = "google_profiler"];
  LivenessProbeCF liveness_probe = 8 [json_name = "liveness_probe"];
  ReadinessProbeCF readiness_probe = 9 [json_name = "readiness_probe"];
  // How often to send events to the main application. (/api/v4/internal/kubernetes/agent_events)
  // Set to zero to disable.
  google.protobuf.Duration event_reporting_period = 10 [json_name = "event_reporting_period", (buf.validate.field).duration = {gte: {}}];
}

// See https://pkg.go.dev/golang.org/x/time/rate#Limiter.
message TokenBucketRateLimitCF {
  // Number of events per second. A zero allows no events.
  // How fast the "token bucket" is refilled.
  double refill_rate_per_second = 1 [json_name = "refill_rate_per_second", (buf.validate.field).double.gte = 0];
  // Maximum number of events that are allowed to happen in succession.
  // Size of the "token bucket".
  uint32 bucket_size = 2 [json_name = "bucket_size"];
}

message GitalyCF {
  // Rate limit that is enforced across all Gitaly servers.
  TokenBucketRateLimitCF global_api_rate_limit = 1 [json_name = "global_api_rate_limit"];
  // Rate limit that is enforced per each Gitaly server.
  TokenBucketRateLimitCF per_server_api_rate_limit = 2 [json_name = "per_server_api_rate_limit"];
}

message RedisCF {
  oneof redis_config {
    option (buf.validate.oneof).required = true;

    // Single-server Redis.
    RedisServerCF server = 1 [json_name = "server"];
    // Redis with Sentinel setup. See http://redis.io/topics/sentinel.
    RedisSentinelCF sentinel = 2 [json_name = "sentinel"];
  }
  // The max number of connections.
  // DEPRECATED, unused.
  uint32 pool_size = 4 [json_name = "pool_size"];
  // Dial timeout.
  google.protobuf.Duration dial_timeout = 5 [json_name = "dial_timeout", (buf.validate.field).duration = {gt: {}}];
  // Read timeout.
  // DEPRECATED, unused.
  google.protobuf.Duration read_timeout = 6 [json_name = "read_timeout", (buf.validate.field).duration = {gt: {}}];
  // Write timeout.
  google.protobuf.Duration write_timeout = 7 [json_name = "write_timeout", (buf.validate.field).duration = {gt: {}}];
  // How long to keep TCP connections alive before closing.
  // DEPRECATED, unused.
  google.protobuf.Duration idle_timeout = 8 [json_name = "idle_timeout", (buf.validate.field).duration = {gt: {}}];
  // Key prefix for everything gitlab-kas stores in Redis.
  string key_prefix = 9 [json_name = "key_prefix"];
  // Use the specified Username to authenticate the current connection
  // with one of the connections defined in the ACL list when connecting
  // to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
  string username = 10 [json_name = "username"];
  // Optional file with the password. Must match the password specified in the
  // requirepass server configuration option (if connecting to a Redis 5.0 instance, or lower),
  // or the User Password when connecting to a Redis 6.0 instance, or greater,
  // that is using the Redis ACL system.
  string password_file = 11 [json_name = "password_file"];
  // The network type, either tcp or unix.
  // Default is tcp.
  string network = 12 [json_name = "network", (buf.validate.field).string = {in: "", in: "tcp", in: "unix"}];

  RedisTLSCF tls = 13 [json_name = "tls"];
  // The logical zero-based numeric database index.
  int32 database_index = 14 [json_name = "database_index", (buf.validate.field).int32.gte = 0];
  // Optional password. Must match the password specified in the
  // requirepass server configuration option (if connecting to a Redis 5.0 instance, or lower),
  // or the User Password when connecting to a Redis 6.0 instance, or greater,
  // that is using the Redis ACL system.
  string password = 15 [json_name = "password"];
  // The number of tcp connections used to pipeline commands to one redis instance.
  // The default for single and sentinel clients is 2, which means 4 connections (2^2).
  // The default for cluster clients is 0, which means 1 connection (2^0).
  uint32 pipeline_multiplex = 16 [json_name = "pipeline_multiplex"];
}

message RedisTLSCF {
  // If true, uses TLS for the redis connection (only available if network is "tcp")
  bool enabled = 1 [json_name = "enabled"];
  // For mutual TLS, specify both certificate_file and key_file; otherwise, specify neither
  // Optional custom X.509 certificate file for TLS in PEM format
  string certificate_file = 2 [json_name = "certificate_file"];
  // Optional custom X.509 key file for TLS in PEM format
  string key_file = 3 [json_name = "key_file"];
  // Optional custom X.509 root CA file in PEM format, used to validate
  // the Redis server's certificate (e.g. if the server has a self-signed certificate)
  string ca_certificate_file = 4 [json_name = "ca_certificate_file"];
}

message RedisServerCF {
  // The host:port address of the node.
  string address = 1 [json_name = "address", (buf.validate.field).string.min_bytes = 1];
}

message RedisSentinelCF {
  // The name of the sentinel master.
  string master_name = 1 [json_name = "master_name", (buf.validate.field).string.min_bytes = 1];
  // The host:port addresses of the sentinels.
  repeated string addresses = 2 [json_name = "addresses", (buf.validate.field).repeated.min_items = 1, (buf.validate.field).repeated.items.string.min_bytes = 1];
  // Sentinel password from "requirepass <password>" (if enabled) in Sentinel configuration
  string sentinel_password_file = 3 [json_name = "sentinel_password_file"];
  // Sentinel username. If not set, Redis username is used.
  string username = 4 [json_name = "username"];
}

message ListenApiCF {
  // Network type to listen on. Supported values: tcp, tcp4, tcp6, unix.
  optional string network = 1 [json_name = "network", (buf.validate.field).string = {in: ["tcp", "tcp4", "tcp6", "unix"]}];
  // Address to listen on.
  string address = 2 [json_name = "address"];
  // Secret to verify JWT tokens.
  string authentication_secret_file = 3 [json_name = "authentication_secret_file", (buf.validate.field).string.min_bytes = 1];
  // X.509 certificate for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  string certificate_file = 4 [json_name = "certificate_file"];
  // X.509 key file for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  string key_file = 5 [json_name = "key_file"];
  // Max age of a connection. Connection is closed gracefully once it's
  // too old and there is no streaming happening.
  google.protobuf.Duration max_connection_age = 6 [json_name = "max_connection_age", (buf.validate.field).duration = {gt: {}}];
  // How much time to wait before stopping accepting new connections on shutdown.
  google.protobuf.Duration listen_grace_period = 7 [json_name = "listen_grace_period", (buf.validate.field).duration = {gt: {}}];
}

message ListenPrivateApiCF {
  // Network type to listen on. Supported values: tcp, tcp4, tcp6, unix.
  optional string network = 1 [json_name = "network", (buf.validate.field).string = {in: ["tcp", "tcp4", "tcp6", "unix"]}];
  // Address to listen on.
  string address = 2 [json_name = "address"];
  // Secret to verify JWT tokens.
  string authentication_secret_file = 3 [json_name = "authentication_secret_file", (buf.validate.field).string.min_bytes = 1];
  // X.509 certificate for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  string certificate_file = 4 [json_name = "certificate_file"];
  // X.509 key file for TLS in PEM format.
  // TLS is enabled iff both certificate_file and key_file are provided.
  string key_file = 5 [json_name = "key_file"];
  // Max age of a connection. Connection is closed gracefully once it's
  // too old and there is no streaming happening.
  google.protobuf.Duration max_connection_age = 6 [json_name = "max_connection_age", (buf.validate.field).duration = {gt: {}}];
  // Optional X.509 CA certificate for TLS in PEM format.
  // Should be set for self-signed certificates.
  string ca_certificate_file = 7 [json_name = "ca_certificate_file"];
  // How much time to wait before stopping accepting new connections on shutdown.
  google.protobuf.Duration listen_grace_period = 8 [json_name = "listen_grace_period", (buf.validate.field).duration = {gt: {}}];
}

message ApiCF {
  // RPC listener configuration for API connections.
  ListenApiCF listen = 1 [json_name = "listen", (buf.validate.field).required = true];
}

message PrivateApiCF {
  // RPC listener configuration for API connections.
  ListenPrivateApiCF listen = 1 [json_name = "listen", (buf.validate.field).required = true];
}

message ConfigCF {
  // Command to run to get configuration YAML that is merged on top of this configuration file.
  // File path resolution:
  // - Absolute file paths (e.g. "/opt/my_script.sh") are used as is.
  // - Relative file paths (e.g. "./my_script.sh") are resolved against the working directory of kas (not kas' binary directory).
  // - File names without the path component (e.g. "my_script.sh") are resolved using the PATH environment
  //   variable. See https://pkg.go.dev/os/exec for the details on how that works.
  // Command is split into pieces (binary and args) by splitting on the space character.
  // No quoting or escaping is supported.
  string command = 1 [json_name = "command"];
}

message AutoFlowCF {
  // Configuration related to Temporal.
  TemporalCF temporal = 1 [json_name = "temporal", (buf.validate.field).required = true];
  // TTL for successful project info lookups.
  // /api/v4/internal/kubernetes/project_info
  // Set to zero to disable.
  google.protobuf.Duration project_info_cache_ttl = 2 [json_name = "project_info_cache_ttl", (buf.validate.field).duration = {gte: {}}];
  // TTL for failed project info lookups.
  // /api/v4/internal/kubernetes/project_info
  google.protobuf.Duration project_info_cache_error_ttl = 3 [json_name = "project_info_cache_error_ttl", (buf.validate.field).duration = {gt: {}}];
  // Optional configuration for the HTTP client injected to the Flow script runtime.
  HTTPClientCF http_client = 4 [json_name = "http_client" ];
  // Workflow Runs per project ID and event type per minute
  uint32 workflows_per_project_id_event_type_per_minute = 5 [json_name = "workflows_per_project_id_event_type_per_minute"];
}

message TemporalCF {
  string host_port = 1 [json_name = "host_port", (buf.validate.field).string.min_bytes = 1];
  optional string namespace = 2 [json_name = "namespace", (buf.validate.field).string.min_bytes = 1];
  bool enable_tls = 3 [json_name = "enable_tls"];
  // Optional X.509 CA certificate for TLS in PEM format.
  // Should be set for self-signed certificates.
  optional string ca_certificate_file = 4 [json_name = "ca_certificate_file", (buf.validate.field).string.min_bytes = 1];
  // For mutual TLS, specify both certificate_file and key_file; otherwise, specify neither.
  // Optional custom X.509 certificate file for TLS in PEM format.
  optional string certificate_file = 5 [json_name = "certificate_file", (buf.validate.field).string.min_bytes = 1];
  // Optional custom X.509 key file for TLS in PEM format.
  optional string key_file = 6 [json_name = "key_file", (buf.validate.field).string.min_bytes = 1];
  // Optional Workflow Data encryption configuration. Encryption is enabled if this message is configured.
  WorkflowDataEncryptionCF workflow_data_encryption = 7 [json_name = "workflow_data_encryption"];
}

message WorkflowDataEncryptionCF {
  // Path to secret key to enable Workflow data encryption.
  string secret_key_file = 1 [json_name = "secret_key_file"];
  CodecServerCF codec_server = 2 [json_name = "codec_server", (buf.validate.field).required = true];
}

message CodecServerCF {
  // Listen configuration for the codec server endpoint.
  ListenCF listen = 1 [json_name = "listen", (buf.validate.field).required = true];
  // URL of the Temporal Web UI that issues codec server decode requests to allow CORS.
  string temporal_web_ui_url = 2 [json_name = "temporal_web_ui_url", (buf.validate.field).string.uri = true];
  // URL of the Temporal OIDC .well-known/openid-configuration endpoint. It's used to retrieve the OpenID configuration and discover the JWKS URIs.
  string temporal_oidc_url = 3 [json_name = "temporal_oidc_url", (buf.validate.field).string.uri = true];
  // Set of emails of users that are authorized to decode.
  // NOTE: Temporal doesn't yet sent the `permissions` claim in the access JWT with Temporal Cloud. They do it for Temporal self-hosted.
  // Therefore, this is a boring solution for minimal authorization of users. An alternative is to configure a Temporal API key
  // and use their Operations API to retrieve namespace RBAC information given the user email from the JWT.
  // To avoid yet another secret (Temporal API key) we use this static set of user emails only.
  repeated string authorized_user_emails = 4 [json_name = "authorized_user_emails", (buf.validate.field).repeated.items.string.email = true];
}

message HTTPClientCF {
  // Only allow a set of ports (defaults to [80, 443]).
  repeated uint32 allowed_ports = 1 [json_name = "allowed_ports", (buf.validate.field).repeated.items.uint32 = {gt: 0, lte: 65535}];
  // Additionally allow a set of IPs that are otherwise blocked, like a private address.
  repeated string allowed_ips = 2 [json_name = "allowed_ips"];
  // Additionally allow a set of IP CIDRs that are otherwise blocked, like a private network.
  repeated string allowed_ip_cidrs = 3 [json_name = "allowed_ip_cidrs"];
  // Additionally block a set of IPs that are otherwise allowed, like a private address. (takes precedence over allowed_ips).
  repeated string blocked_ips = 4 [json_name = "blocked_ips"];
  // Additionally block a set of IP CIDRs that are otherwise allowed, like a private network. (takes precedence over allowed_ip_cidrs).
  repeated string blocked_ip_cidrs = 5 [json_name = "blocked_ip_cidrs"];
}

message WorkspacesListenCF {
  // Network type to listen on. Supported values: tcp, tcp4, tcp6, unix.
  optional string network = 1 [json_name = "network", (buf.validate.field).string = {in: ["tcp", "tcp4", "tcp6", "unix"]}];
  // Address to listen on.
  string address = 2 [json_name = "address"];
  // How much time to wait before stopping accepting new connections on shutdown.
  google.protobuf.Duration listen_grace_period = 3 [json_name = "listen_grace_period", (buf.validate.field).duration = {gt: {}}];
  // How much time to wait before closing connections with in-flight requests.
  google.protobuf.Duration shutdown_grace_period = 4 [json_name = "shutdown_grace_period", (buf.validate.field).duration = {gt: {}}];
}

message WorkspacesCF {
  // Listen configuration for the Workspaces endpoint.
  WorkspacesListenCF listen = 1 [json_name = "listen", (buf.validate.field).required = true];
  bool Enabled = 2 [json_name = "enabled"];
}

// ConfigurationFile represents kas configuration file.
message ConfigurationFile {
  // Configuration related to interaction with GitLab.
  GitLabCF gitlab = 1 [json_name = "gitlab", (buf.validate.field).required = true];
  // Configuration related to the agent. Generally all configuration for
  // user-facing features should be here.
  AgentCF agent = 2 [json_name = "agent"];
  // Configuration related to all things observability: metrics, tracing,
  // monitoring, logging, usage metrics, profiling.
  ObservabilityCF observability = 3 [json_name = "observability"];
  // Configuration related to interaction with Gitaly.
  GitalyCF gitaly = 4 [json_name = "gitaly"];
  // Redis configurations available to kas.
  RedisCF redis = 5 [json_name = "redis", (buf.validate.field).required = true];
  // Public API.
  ApiCF api = 6 [json_name = "api", (buf.validate.field).required = true];
  // Private API for kas->kas communication.
  PrivateApiCF private_api = 7 [json_name = "private_api", (buf.validate.field).required = true];
  ConfigCF config = 8 [json_name = "config"];
  // Configuration related to GitLab AutoFlow
  AutoFlowCF autoflow = 9 [json_name = "autoflow"]; // not required YET
  // Configuration related to Workspaces.
  WorkspacesCF workspaces = 10 [json_name = "workspaces"];
}
