mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat(coderd): add retention policy configuration (#21021)
Add `RetentionConfig` with server flags for configuring data retention: - `--audit-logs-retention`: retention for audit log entries - `--connection-logs-retention`: retention for connection logs - `--api-keys-retention`: retention for expired API keys (default 7d) Updates #20743
This commit is contained in:
committed by
GitHub
parent
74d0c39cb3
commit
56e7858570
+21
@@ -696,6 +696,27 @@ updating, and deleting workspace resources.
|
||||
Number of provisioner daemons to create on start. If builds are stuck
|
||||
in queued state for a long time, consider increasing this.
|
||||
|
||||
RETENTION OPTIONS:
|
||||
Configure data retention policies for various database tables. Retention
|
||||
policies automatically purge old data to reduce database size and improve
|
||||
performance. Setting a retention duration to 0 disables automatic purging for
|
||||
that data type.
|
||||
|
||||
--api-keys-retention duration, $CODER_API_KEYS_RETENTION (default: 7d)
|
||||
How long expired API keys are retained before being deleted. Keeping
|
||||
expired keys allows the backend to return a more helpful error when a
|
||||
user tries to use an expired key. Set to 0 to disable automatic
|
||||
deletion of expired keys.
|
||||
|
||||
--audit-logs-retention duration, $CODER_AUDIT_LOGS_RETENTION (default: 0)
|
||||
How long audit log entries are retained. Set to 0 to disable (keep
|
||||
indefinitely). We advise keeping audit logs for at least a year, and
|
||||
in accordance with your compliance requirements.
|
||||
|
||||
--connection-logs-retention duration, $CODER_CONNECTION_LOGS_RETENTION (default: 0)
|
||||
How long connection log entries are retained. Set to 0 to disable
|
||||
(keep indefinitely).
|
||||
|
||||
TELEMETRY OPTIONS:
|
||||
Telemetry is critical to our ability to improve Coder. We strip all personal
|
||||
information before sending data to our servers. Please only disable telemetry
|
||||
|
||||
+19
@@ -742,3 +742,22 @@ aibridge:
|
||||
# (token, prompt, tool use).
|
||||
# (default: 60d, type: duration)
|
||||
retention: 1440h0m0s
|
||||
# Configure data retention policies for various database tables. Retention
|
||||
# policies automatically purge old data to reduce database size and improve
|
||||
# performance. Setting a retention duration to 0 disables automatic purging for
|
||||
# that data type.
|
||||
retention:
|
||||
# How long audit log entries are retained. Set to 0 to disable (keep
|
||||
# indefinitely). We advise keeping audit logs for at least a year, and in
|
||||
# accordance with your compliance requirements.
|
||||
# (default: 0, type: duration)
|
||||
audit_logs: 0s
|
||||
# How long connection log entries are retained. Set to 0 to disable (keep
|
||||
# indefinitely).
|
||||
# (default: 0, type: duration)
|
||||
connection_logs: 0s
|
||||
# How long expired API keys are retained before being deleted. Keeping expired
|
||||
# keys allows the backend to return a more helpful error when a user tries to use
|
||||
# an expired key. Set to 0 to disable automatic deletion of expired keys.
|
||||
# (default: 7d, type: duration)
|
||||
api_keys: 168h0m0s
|
||||
|
||||
Generated
+20
@@ -14302,6 +14302,9 @@ const docTemplate = `{
|
||||
"redirect_to_access_url": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"retention": {
|
||||
"$ref": "#/definitions/codersdk.RetentionConfig"
|
||||
},
|
||||
"scim_api_key": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -17728,6 +17731,23 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.RetentionConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"api_keys": {
|
||||
"description": "APIKeys controls how long expired API keys are retained before being deleted.\nKeys are only deleted if they have been expired for at least this duration.\nDefaults to 7 days to preserve existing behavior.",
|
||||
"type": "integer"
|
||||
},
|
||||
"audit_logs": {
|
||||
"description": "AuditLogs controls how long audit log entries are retained.\nSet to 0 to disable (keep indefinitely).",
|
||||
"type": "integer"
|
||||
},
|
||||
"connection_logs": {
|
||||
"description": "ConnectionLogs controls how long connection log entries are retained.\nSet to 0 to disable (keep indefinitely).",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.Role": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Generated
+20
@@ -12886,6 +12886,9 @@
|
||||
"redirect_to_access_url": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"retention": {
|
||||
"$ref": "#/definitions/codersdk.RetentionConfig"
|
||||
},
|
||||
"scim_api_key": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -16190,6 +16193,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.RetentionConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"api_keys": {
|
||||
"description": "APIKeys controls how long expired API keys are retained before being deleted.\nKeys are only deleted if they have been expired for at least this duration.\nDefaults to 7 days to preserve existing behavior.",
|
||||
"type": "integer"
|
||||
},
|
||||
"audit_logs": {
|
||||
"description": "AuditLogs controls how long audit log entries are retained.\nSet to 0 to disable (keep indefinitely).",
|
||||
"type": "integer"
|
||||
},
|
||||
"connection_logs": {
|
||||
"description": "ConnectionLogs controls how long connection log entries are retained.\nSet to 0 to disable (keep indefinitely).",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.Role": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -501,6 +501,7 @@ type DeploymentValues struct {
|
||||
WebTerminalRenderer serpent.String `json:"web_terminal_renderer,omitempty" typescript:",notnull"`
|
||||
AllowWorkspaceRenames serpent.Bool `json:"allow_workspace_renames,omitempty" typescript:",notnull"`
|
||||
Healthcheck HealthcheckConfig `json:"healthcheck,omitempty" typescript:",notnull"`
|
||||
Retention RetentionConfig `json:"retention,omitempty" typescript:",notnull"`
|
||||
CLIUpgradeMessage serpent.String `json:"cli_upgrade_message,omitempty" typescript:",notnull"`
|
||||
TermsOfServiceURL serpent.String `json:"terms_of_service_url,omitempty" typescript:",notnull"`
|
||||
Notifications NotificationsConfig `json:"notifications,omitempty" typescript:",notnull"`
|
||||
@@ -813,6 +814,23 @@ type HealthcheckConfig struct {
|
||||
ThresholdDatabase serpent.Duration `json:"threshold_database" typescript:",notnull"`
|
||||
}
|
||||
|
||||
// RetentionConfig contains configuration for data retention policies.
|
||||
// These settings control how long various types of data are retained in the database
|
||||
// before being automatically purged. Setting a value to 0 disables retention for that
|
||||
// data type (data is kept indefinitely).
|
||||
type RetentionConfig struct {
|
||||
// AuditLogs controls how long audit log entries are retained.
|
||||
// Set to 0 to disable (keep indefinitely).
|
||||
AuditLogs serpent.Duration `json:"audit_logs" typescript:",notnull"`
|
||||
// ConnectionLogs controls how long connection log entries are retained.
|
||||
// Set to 0 to disable (keep indefinitely).
|
||||
ConnectionLogs serpent.Duration `json:"connection_logs" typescript:",notnull"`
|
||||
// APIKeys controls how long expired API keys are retained before being deleted.
|
||||
// Keys are only deleted if they have been expired for at least this duration.
|
||||
// Defaults to 7 days to preserve existing behavior.
|
||||
APIKeys serpent.Duration `json:"api_keys" typescript:",notnull"`
|
||||
}
|
||||
|
||||
type NotificationsConfig struct {
|
||||
// The upper limit of attempts to send a notification.
|
||||
MaxSendAttempts serpent.Int64 `json:"max_send_attempts" typescript:",notnull"`
|
||||
@@ -1180,6 +1198,11 @@ func (c *DeploymentValues) Options() serpent.OptionSet {
|
||||
Name: "AI Bridge",
|
||||
YAML: "aibridge",
|
||||
}
|
||||
deploymentGroupRetention = serpent.Group{
|
||||
Name: "Retention",
|
||||
Description: "Configure data retention policies for various database tables. Retention policies automatically purge old data to reduce database size and improve performance. Setting a retention duration to 0 disables automatic purging for that data type.",
|
||||
YAML: "retention",
|
||||
}
|
||||
)
|
||||
|
||||
httpAddress := serpent.Option{
|
||||
@@ -3363,6 +3386,40 @@ Write out the current server config as YAML to stdout.`,
|
||||
YAML: "retention",
|
||||
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
|
||||
},
|
||||
// Retention settings
|
||||
{
|
||||
Name: "Audit Logs Retention",
|
||||
Description: "How long audit log entries are retained. Set to 0 to disable (keep indefinitely). We advise keeping audit logs for at least a year, and in accordance with your compliance requirements.",
|
||||
Flag: "audit-logs-retention",
|
||||
Env: "CODER_AUDIT_LOGS_RETENTION",
|
||||
Value: &c.Retention.AuditLogs,
|
||||
Default: "0",
|
||||
Group: &deploymentGroupRetention,
|
||||
YAML: "audit_logs",
|
||||
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
|
||||
},
|
||||
{
|
||||
Name: "Connection Logs Retention",
|
||||
Description: "How long connection log entries are retained. Set to 0 to disable (keep indefinitely).",
|
||||
Flag: "connection-logs-retention",
|
||||
Env: "CODER_CONNECTION_LOGS_RETENTION",
|
||||
Value: &c.Retention.ConnectionLogs,
|
||||
Default: "0",
|
||||
Group: &deploymentGroupRetention,
|
||||
YAML: "connection_logs",
|
||||
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
|
||||
},
|
||||
{
|
||||
Name: "API Keys Retention",
|
||||
Description: "How long expired API keys are retained before being deleted. Keeping expired keys allows the backend to return a more helpful error when a user tries to use an expired key. Set to 0 to disable automatic deletion of expired keys.",
|
||||
Flag: "api-keys-retention",
|
||||
Env: "CODER_API_KEYS_RETENTION",
|
||||
Value: &c.Retention.APIKeys,
|
||||
Default: "7d",
|
||||
Group: &deploymentGroupRetention,
|
||||
YAML: "api_keys",
|
||||
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
|
||||
},
|
||||
{
|
||||
Name: "Enable Authorization Recordings",
|
||||
Description: "All api requests will have a header including all authorization calls made during the request. " +
|
||||
|
||||
@@ -703,3 +703,65 @@ func TestNotificationsCanBeDisabled(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetentionConfigParsing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
environment []serpent.EnvVar
|
||||
expectedAuditLogs time.Duration
|
||||
expectedConnectionLogs time.Duration
|
||||
expectedAPIKeys time.Duration
|
||||
}{
|
||||
{
|
||||
name: "Defaults",
|
||||
environment: []serpent.EnvVar{},
|
||||
expectedAuditLogs: 0,
|
||||
expectedConnectionLogs: 0,
|
||||
expectedAPIKeys: 7 * 24 * time.Hour, // 7 days default
|
||||
},
|
||||
{
|
||||
name: "IndividualRetentionSet",
|
||||
environment: []serpent.EnvVar{
|
||||
{Name: "CODER_AUDIT_LOGS_RETENTION", Value: "30d"},
|
||||
{Name: "CODER_CONNECTION_LOGS_RETENTION", Value: "60d"},
|
||||
{Name: "CODER_API_KEYS_RETENTION", Value: "14d"},
|
||||
},
|
||||
expectedAuditLogs: 30 * 24 * time.Hour,
|
||||
expectedConnectionLogs: 60 * 24 * time.Hour,
|
||||
expectedAPIKeys: 14 * 24 * time.Hour,
|
||||
},
|
||||
{
|
||||
name: "AllRetentionSet",
|
||||
environment: []serpent.EnvVar{
|
||||
{Name: "CODER_AUDIT_LOGS_RETENTION", Value: "365d"},
|
||||
{Name: "CODER_CONNECTION_LOGS_RETENTION", Value: "30d"},
|
||||
{Name: "CODER_API_KEYS_RETENTION", Value: "0"},
|
||||
},
|
||||
expectedAuditLogs: 365 * 24 * time.Hour,
|
||||
expectedConnectionLogs: 30 * 24 * time.Hour,
|
||||
expectedAPIKeys: 0, // Explicitly disabled
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dv := codersdk.DeploymentValues{}
|
||||
opts := dv.Options()
|
||||
|
||||
err := opts.SetDefaults()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = opts.ParseEnv(tt.environment)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.expectedAuditLogs, dv.Retention.AuditLogs.Value(), "audit logs retention mismatch")
|
||||
assert.Equal(t, tt.expectedConnectionLogs, dv.Retention.ConnectionLogs.Value(), "connection logs retention mismatch")
|
||||
assert.Equal(t, tt.expectedAPIKeys, dv.Retention.APIKeys.Value(), "api keys retention mismatch")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+5
@@ -463,6 +463,11 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
|
||||
"disable_all": true
|
||||
},
|
||||
"redirect_to_access_url": true,
|
||||
"retention": {
|
||||
"api_keys": 0,
|
||||
"audit_logs": 0,
|
||||
"connection_logs": 0
|
||||
},
|
||||
"scim_api_key": "string",
|
||||
"session_lifetime": {
|
||||
"default_duration": 0,
|
||||
|
||||
Generated
+29
@@ -3147,6 +3147,11 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
"disable_all": true
|
||||
},
|
||||
"redirect_to_access_url": true,
|
||||
"retention": {
|
||||
"api_keys": 0,
|
||||
"audit_logs": 0,
|
||||
"connection_logs": 0
|
||||
},
|
||||
"scim_api_key": "string",
|
||||
"session_lifetime": {
|
||||
"default_duration": 0,
|
||||
@@ -3663,6 +3668,11 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
"disable_all": true
|
||||
},
|
||||
"redirect_to_access_url": true,
|
||||
"retention": {
|
||||
"api_keys": 0,
|
||||
"audit_logs": 0,
|
||||
"connection_logs": 0
|
||||
},
|
||||
"scim_api_key": "string",
|
||||
"session_lifetime": {
|
||||
"default_duration": 0,
|
||||
@@ -3808,6 +3818,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
| `proxy_trusted_origins` | array of string | false | | |
|
||||
| `rate_limit` | [codersdk.RateLimitConfig](#codersdkratelimitconfig) | false | | |
|
||||
| `redirect_to_access_url` | boolean | false | | |
|
||||
| `retention` | [codersdk.RetentionConfig](#codersdkretentionconfig) | false | | |
|
||||
| `scim_api_key` | string | false | | |
|
||||
| `session_lifetime` | [codersdk.SessionLifetime](#codersdksessionlifetime) | false | | |
|
||||
| `ssh_keygen_algorithm` | string | false | | |
|
||||
@@ -7506,6 +7517,24 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
||||
| `message` | string | false | | Message is an actionable message that depicts actions the request took. These messages should be fully formed sentences with proper punctuation. Examples: - "A user has been created." - "Failed to create a user." |
|
||||
| `validations` | array of [codersdk.ValidationError](#codersdkvalidationerror) | false | | Validations are form field-specific friendly error messages. They will be shown on a form field in the UI. These can also be used to add additional context if there is a set of errors in the primary 'Message'. |
|
||||
|
||||
## codersdk.RetentionConfig
|
||||
|
||||
```json
|
||||
{
|
||||
"api_keys": 0,
|
||||
"audit_logs": 0,
|
||||
"connection_logs": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|-------------------|---------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `api_keys` | integer | false | | Api keys controls how long expired API keys are retained before being deleted. Keys are only deleted if they have been expired for at least this duration. Defaults to 7 days to preserve existing behavior. |
|
||||
| `audit_logs` | integer | false | | Audit logs controls how long audit log entries are retained. Set to 0 to disable (keep indefinitely). |
|
||||
| `connection_logs` | integer | false | | Connection logs controls how long connection log entries are retained. Set to 0 to disable (keep indefinitely). |
|
||||
|
||||
## codersdk.Role
|
||||
|
||||
```json
|
||||
|
||||
Generated
+33
@@ -1770,3 +1770,36 @@ Whether to inject Coder's MCP tools into intercepted AI Bridge requests (require
|
||||
| Default | <code>60d</code> |
|
||||
|
||||
Length of time to retain data such as interceptions and all related records (token, prompt, tool use).
|
||||
|
||||
### --audit-logs-retention
|
||||
|
||||
| | |
|
||||
|-------------|------------------------------------------|
|
||||
| Type | <code>duration</code> |
|
||||
| Environment | <code>$CODER_AUDIT_LOGS_RETENTION</code> |
|
||||
| YAML | <code>retention.audit_logs</code> |
|
||||
| Default | <code>0</code> |
|
||||
|
||||
How long audit log entries are retained. Set to 0 to disable (keep indefinitely). We advise keeping audit logs for at least a year, and in accordance with your compliance requirements.
|
||||
|
||||
### --connection-logs-retention
|
||||
|
||||
| | |
|
||||
|-------------|-----------------------------------------------|
|
||||
| Type | <code>duration</code> |
|
||||
| Environment | <code>$CODER_CONNECTION_LOGS_RETENTION</code> |
|
||||
| YAML | <code>retention.connection_logs</code> |
|
||||
| Default | <code>0</code> |
|
||||
|
||||
How long connection log entries are retained. Set to 0 to disable (keep indefinitely).
|
||||
|
||||
### --api-keys-retention
|
||||
|
||||
| | |
|
||||
|-------------|----------------------------------------|
|
||||
| Type | <code>duration</code> |
|
||||
| Environment | <code>$CODER_API_KEYS_RETENTION</code> |
|
||||
| YAML | <code>retention.api_keys</code> |
|
||||
| Default | <code>7d</code> |
|
||||
|
||||
How long expired API keys are retained before being deleted. Keeping expired keys allows the backend to return a more helpful error when a user tries to use an expired key. Set to 0 to disable automatic deletion of expired keys.
|
||||
|
||||
@@ -697,6 +697,27 @@ updating, and deleting workspace resources.
|
||||
Number of provisioner daemons to create on start. If builds are stuck
|
||||
in queued state for a long time, consider increasing this.
|
||||
|
||||
RETENTION OPTIONS:
|
||||
Configure data retention policies for various database tables. Retention
|
||||
policies automatically purge old data to reduce database size and improve
|
||||
performance. Setting a retention duration to 0 disables automatic purging for
|
||||
that data type.
|
||||
|
||||
--api-keys-retention duration, $CODER_API_KEYS_RETENTION (default: 7d)
|
||||
How long expired API keys are retained before being deleted. Keeping
|
||||
expired keys allows the backend to return a more helpful error when a
|
||||
user tries to use an expired key. Set to 0 to disable automatic
|
||||
deletion of expired keys.
|
||||
|
||||
--audit-logs-retention duration, $CODER_AUDIT_LOGS_RETENTION (default: 0)
|
||||
How long audit log entries are retained. Set to 0 to disable (keep
|
||||
indefinitely). We advise keeping audit logs for at least a year, and
|
||||
in accordance with your compliance requirements.
|
||||
|
||||
--connection-logs-retention duration, $CODER_CONNECTION_LOGS_RETENTION (default: 0)
|
||||
How long connection log entries are retained. Set to 0 to disable
|
||||
(keep indefinitely).
|
||||
|
||||
TELEMETRY OPTIONS:
|
||||
Telemetry is critical to our ability to improve Coder. We strip all personal
|
||||
information before sending data to our servers. Please only disable telemetry
|
||||
|
||||
Generated
+27
@@ -1778,6 +1778,7 @@ export interface DeploymentValues {
|
||||
readonly web_terminal_renderer?: string;
|
||||
readonly allow_workspace_renames?: boolean;
|
||||
readonly healthcheck?: HealthcheckConfig;
|
||||
readonly retention?: RetentionConfig;
|
||||
readonly cli_upgrade_message?: string;
|
||||
readonly terms_of_service_url?: string;
|
||||
readonly notifications?: NotificationsConfig;
|
||||
@@ -4156,6 +4157,32 @@ export interface Response {
|
||||
readonly validations?: readonly ValidationError[];
|
||||
}
|
||||
|
||||
// From codersdk/deployment.go
|
||||
/**
|
||||
* RetentionConfig contains configuration for data retention policies.
|
||||
* These settings control how long various types of data are retained in the database
|
||||
* before being automatically purged. Setting a value to 0 disables retention for that
|
||||
* data type (data is kept indefinitely).
|
||||
*/
|
||||
export interface RetentionConfig {
|
||||
/**
|
||||
* AuditLogs controls how long audit log entries are retained.
|
||||
* Set to 0 to disable (keep indefinitely).
|
||||
*/
|
||||
readonly audit_logs: number;
|
||||
/**
|
||||
* ConnectionLogs controls how long connection log entries are retained.
|
||||
* Set to 0 to disable (keep indefinitely).
|
||||
*/
|
||||
readonly connection_logs: number;
|
||||
/**
|
||||
* APIKeys controls how long expired API keys are retained before being deleted.
|
||||
* Keys are only deleted if they have been expired for at least this duration.
|
||||
* Defaults to 7 days to preserve existing behavior.
|
||||
*/
|
||||
readonly api_keys: number;
|
||||
}
|
||||
|
||||
// From codersdk/roles.go
|
||||
/**
|
||||
* Role is a longer form of SlimRole that includes permissions details.
|
||||
|
||||
Reference in New Issue
Block a user