Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions cli/testdata/coder_server_--help.golden
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 19 additions & 0 deletions cli/testdata/server-config.yaml.golden
Original file line number Diff line number Diff line change
Expand Up @@ -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
20 changes: 20 additions & 0 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions codersdk/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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"`
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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. " +
Expand Down
62 changes: 62 additions & 0 deletions codersdk/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
})
}
}
5 changes: 5 additions & 0 deletions docs/reference/api/general.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions docs/reference/api/schemas.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions docs/reference/cli/server.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading