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:
@@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user