1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-04 15:04:43 +00:00

feat: allow audit log retention to be controlled by env variable (#1158)

This commit is contained in:
Jenic Rycr
2025-12-23 07:50:00 -05:00
committed by GitHub
parent 08e4ffeb60
commit e358c433f0
4 changed files with 58 additions and 14 deletions

View File

@@ -68,6 +68,7 @@ type EnvConfigSchema struct {
TracingEnabled bool `env:"TRACING_ENABLED"` TracingEnabled bool `env:"TRACING_ENABLED"`
LogJSON bool `env:"LOG_JSON"` LogJSON bool `env:"LOG_JSON"`
TrustProxy bool `env:"TRUST_PROXY"` TrustProxy bool `env:"TRUST_PROXY"`
AuditLogRetentionDays int `env:"AUDIT_LOG_RETENTION_DAYS"`
AnalyticsDisabled bool `env:"ANALYTICS_DISABLED"` AnalyticsDisabled bool `env:"ANALYTICS_DISABLED"`
AllowDowngrade bool `env:"ALLOW_DOWNGRADE"` AllowDowngrade bool `env:"ALLOW_DOWNGRADE"`
InternalAppURL string `env:"INTERNAL_APP_URL"` InternalAppURL string `env:"INTERNAL_APP_URL"`
@@ -85,16 +86,17 @@ func init() {
func defaultConfig() EnvConfigSchema { func defaultConfig() EnvConfigSchema {
return EnvConfigSchema{ return EnvConfigSchema{
AppEnv: AppEnvProduction, AppEnv: AppEnvProduction,
LogLevel: "info", LogLevel: "info",
DbProvider: "sqlite", DbProvider: "sqlite",
FileBackend: "filesystem", FileBackend: "filesystem",
KeysPath: "data/keys", KeysPath: "data/keys",
AppURL: AppUrl, AuditLogRetentionDays: 90,
Port: "1411", AppURL: AppUrl,
Host: "0.0.0.0", Port: "1411",
GeoLiteDBPath: "data/GeoLite2-City.mmdb", Host: "0.0.0.0",
GeoLiteDBUrl: MaxMindGeoLiteCityUrl, GeoLiteDBPath: "data/GeoLite2-City.mmdb",
GeoLiteDBUrl: MaxMindGeoLiteCityUrl,
} }
} }
@@ -214,6 +216,10 @@ func validateEnvConfig(config *EnvConfigSchema) error {
} }
if config.AuditLogRetentionDays <= 0 {
return errors.New("AUDIT_LOG_RETENTION_DAYS must be greater than 0")
}
return nil return nil
} }

View File

@@ -187,6 +187,41 @@ func TestParseEnvConfig(t *testing.T) {
assert.False(t, EnvConfig.AnalyticsDisabled) assert.False(t, EnvConfig.AnalyticsDisabled)
}) })
t.Run("should default audit log retention days to 90", func(t *testing.T) {
EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
t.Setenv("DB_CONNECTION_STRING", "file:test.db")
t.Setenv("APP_URL", "http://localhost:3000")
err := parseEnvConfig()
require.NoError(t, err)
assert.Equal(t, 90, EnvConfig.AuditLogRetentionDays)
})
t.Run("should parse audit log retention days override", func(t *testing.T) {
EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
t.Setenv("DB_CONNECTION_STRING", "file:test.db")
t.Setenv("APP_URL", "http://localhost:3000")
t.Setenv("AUDIT_LOG_RETENTION_DAYS", "365")
err := parseEnvConfig()
require.NoError(t, err)
assert.Equal(t, 365, EnvConfig.AuditLogRetentionDays)
})
t.Run("should fail when AUDIT_LOG_RETENTION_DAYS is non-positive", func(t *testing.T) {
EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
t.Setenv("DB_CONNECTION_STRING", "file:test.db")
t.Setenv("APP_URL", "http://localhost:3000")
t.Setenv("AUDIT_LOG_RETENTION_DAYS", "0")
err := parseEnvConfig()
require.Error(t, err)
assert.ErrorContains(t, err, "AUDIT_LOG_RETENTION_DAYS must be greater than 0")
})
t.Run("should parse string environment variables correctly", func(t *testing.T) { t.Run("should parse string environment variables correctly", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "postgres") t.Setenv("DB_PROVIDER", "postgres")

View File

@@ -10,6 +10,7 @@ import (
"github.com/go-co-op/gocron/v2" "github.com/go-co-op/gocron/v2"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/pocket-id/pocket-id/backend/internal/common"
"github.com/pocket-id/pocket-id/backend/internal/model" "github.com/pocket-id/pocket-id/backend/internal/model"
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types" datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
) )
@@ -119,11 +120,13 @@ func (j *DbCleanupJobs) clearReauthenticationTokens(ctx context.Context) error {
return nil return nil
} }
// ClearAuditLogs deletes audit logs older than 90 days // ClearAuditLogs deletes audit logs older than the configured retention window
func (j *DbCleanupJobs) clearAuditLogs(ctx context.Context) error { func (j *DbCleanupJobs) clearAuditLogs(ctx context.Context) error {
cutoff := time.Now().AddDate(0, 0, -common.EnvConfig.AuditLogRetentionDays)
st := j.db. st := j.db.
WithContext(ctx). WithContext(ctx).
Delete(&model.AuditLog{}, "created_at < ?", datatype.DateTime(time.Now().AddDate(0, 0, -90))) Delete(&model.AuditLog{}, "created_at < ?", datatype.DateTime(cutoff))
if st.Error != nil { if st.Error != nil {
return fmt.Errorf("failed to delete old audit logs: %w", st.Error) return fmt.Errorf("failed to delete old audit logs: %w", st.Error)
} }

View File

@@ -95,7 +95,7 @@
"settings": "Settings", "settings": "Settings",
"update_pocket_id": "Update Pocket ID", "update_pocket_id": "Update Pocket ID",
"powered_by": "Powered by", "powered_by": "Powered by",
"see_your_account_activities_from_the_last_3_months": "See your account activities from the last 3 months.", "see_your_recent_account_activities": "See your account activities within the configured retention period.",
"time": "Time", "time": "Time",
"event": "Event", "event": "Event",
"approximate_location": "Approximate Location", "approximate_location": "Approximate Location",
@@ -328,7 +328,7 @@
"all_clients": "All Clients", "all_clients": "All Clients",
"all_locations": "All Locations", "all_locations": "All Locations",
"global_audit_log": "Global Audit Log", "global_audit_log": "Global Audit Log",
"see_all_account_activities_from_the_last_3_months": "See all user activity for the last 3 months.", "see_all_recent_account_activities": "View the account activities of all users during the set retention period.",
"token_sign_in": "Token Sign In", "token_sign_in": "Token Sign In",
"client_authorization": "Client Authorization", "client_authorization": "Client Authorization",
"new_client_authorization": "New Client Authorization", "new_client_authorization": "New Client Authorization",