mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-09-30 13:09:40 +02:00
Runtime artifacts (agent workspaces, tool-output spill, C2 payloads, chat uploads, workflow checkpoints, diagnostic logs) previously accumulated without bound: most were only removed when a conversation or project was deleted, and tmp/c2 plus workflow checkpoints were never removed at all. Add a storage cleaner with named per-category tasks (Gitea-style), a settings page tab, and a background sweep that is off by default so upgrading never deletes existing data. Safety properties, since mis-deleting live task data costs far more than the disk saved: - dry-run is the default; a real cleanup requires dry_run=false together with confirm=true at the API layer, not just a frontend dialog - sessions active within active_grace_hours are always skipped, and a failed activity lookup skips conservatively (fail closed) - directories whose conversation/project no longer exists are reclaimed as orphans after orphan_grace_days - scanners never follow symlinks and every candidate path is confined to its category root; deletion renames to a .tmp-for-deletion marker first so a crash leaves recoverable residue instead of a half-deleted dir - storage:* permissions are admin-only; without the grantSystemRolePermissions skip the default branch would have given operators an irreversible file-deletion right Also fix two confirmed leaks: DeleteConversation left chat_uploads files on disk (their rows already vanished via ON DELETE CASCADE), and workflow checkpoints had no deletion path at all. Co-authored-by: Parallels <parallels@kali-linux-2025-2.localdomain>
This commit is contained in:
1 parent
e9b6e0d86e
commit
470eb5ead1
28 files changed
+3356
-1
No files matched your search
@@ -37,6 +37,7 @@ type Config struct {
|
||||
Auth AuthConfig `yaml:"auth"`
|
||||
Audit AuditConfig `yaml:"audit,omitempty" json:"audit,omitempty"`
|
||||
Monitor MonitorConfig `yaml:"monitor,omitempty" json:"monitor,omitempty"`
|
||||
Storage StorageConfig `yaml:"storage,omitempty" json:"storage,omitempty"`
|
||||
ExternalMCP ExternalMCPConfig `yaml:"external_mcp,omitempty"`
|
||||
Knowledge KnowledgeConfig `yaml:"knowledge,omitempty"`
|
||||
C2 C2Config `yaml:"c2,omitempty" json:"c2,omitempty"` // 内置 C2 总开关;未配置时默认启用
|
||||
@@ -1370,6 +1371,132 @@ func (m MonitorConfig) RetentionDaysEffective() int {
|
||||
return *m.RetentionDays
|
||||
}
|
||||
|
||||
// 运行空间垃圾清理的类别键。顺序即前端展示顺序,勿依赖 map 迭代顺序。
|
||||
const (
|
||||
StorageCategoryWorkspace = "workspace"
|
||||
StorageCategoryReduction = "reduction"
|
||||
StorageCategoryConversationArtifact = "conversation_artifacts"
|
||||
StorageCategoryPlantask = "plantask"
|
||||
StorageCategoryC2Artifacts = "c2_artifacts"
|
||||
StorageCategoryChatUploads = "chat_uploads"
|
||||
StorageCategoryWorkflowCheckpoints = "workflow_checkpoints"
|
||||
StorageCategoryDiagnosticLogs = "diagnostic_logs"
|
||||
)
|
||||
|
||||
// StorageCategoryOrder 列出全部可清理类别,供 UI 与报表稳定排序。
|
||||
var StorageCategoryOrder = []string{
|
||||
StorageCategoryWorkspace,
|
||||
StorageCategoryReduction,
|
||||
StorageCategoryConversationArtifact,
|
||||
StorageCategoryPlantask,
|
||||
StorageCategoryC2Artifacts,
|
||||
StorageCategoryChatUploads,
|
||||
StorageCategoryWorkflowCheckpoints,
|
||||
StorageCategoryDiagnosticLogs,
|
||||
}
|
||||
|
||||
// StorageCategoryDefaults 各类别默认保留天数。取较短值的是纯派生产物
|
||||
// (reduction/checkpoint),取较长值的是可能仍需人工回看的上传件。
|
||||
var StorageCategoryDefaults = map[string]int{
|
||||
StorageCategoryWorkspace: 30,
|
||||
StorageCategoryReduction: 7,
|
||||
StorageCategoryConversationArtifact: 30,
|
||||
StorageCategoryPlantask: 30,
|
||||
StorageCategoryC2Artifacts: 30,
|
||||
StorageCategoryChatUploads: 90,
|
||||
StorageCategoryWorkflowCheckpoints: 7,
|
||||
StorageCategoryDiagnosticLogs: 14,
|
||||
}
|
||||
|
||||
// StorageCategoryConfig 单个清理类别的策略覆盖。
|
||||
type StorageCategoryConfig struct {
|
||||
// Enabled 省略时默认 true;显式 false 表示该类别既不自动清理也不出现在手动清理范围内。
|
||||
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
|
||||
// RetentionDays 省略时使用 StorageCategoryDefaults;0 表示不按保留期清理(孤儿目录仍会回收)。
|
||||
RetentionDays *int `yaml:"retention_days,omitempty" json:"retention_days,omitempty"`
|
||||
}
|
||||
|
||||
// StorageConfig 运行空间垃圾清理策略。
|
||||
// 自动清理默认关闭:与 Argo ttlStrategy / K8s ttlSecondsAfterFinished 的 unset 语义一致,
|
||||
// 升级后不会在管理员不知情的情况下删除既有数据。
|
||||
type StorageConfig struct {
|
||||
// AutoClean 省略或 false 关闭后台自动清理;显式 true 才启用。
|
||||
AutoClean *bool `yaml:"auto_clean,omitempty" json:"auto_clean,omitempty"`
|
||||
// IntervalMinutes 后台清理轮询间隔;省略默认 60,最小 5。
|
||||
IntervalMinutes *int `yaml:"interval_minutes,omitempty" json:"interval_minutes,omitempty"`
|
||||
// OrphanGraceDays 会话/项目已删除但目录残留时的最小保留天数;省略默认 1。
|
||||
OrphanGraceDays *int `yaml:"orphan_grace_days,omitempty" json:"orphan_grace_days,omitempty"`
|
||||
// ActiveGraceHours 最近有活动的会话一律跳过清理;省略默认 24。
|
||||
ActiveGraceHours *int `yaml:"active_grace_hours,omitempty" json:"active_grace_hours,omitempty"`
|
||||
// Categories 按类别覆盖策略;未列出的类别使用内置默认值。
|
||||
Categories map[string]StorageCategoryConfig `yaml:"categories,omitempty" json:"categories,omitempty"`
|
||||
}
|
||||
|
||||
// AutoCleanEffective returns true only when storage.auto_clean is explicitly true.
|
||||
func (s StorageConfig) AutoCleanEffective() bool {
|
||||
return s.AutoClean != nil && *s.AutoClean
|
||||
}
|
||||
|
||||
// IntervalMinutesEffective returns the background sweep interval; defaults to 60, floor 5.
|
||||
func (s StorageConfig) IntervalMinutesEffective() int {
|
||||
if s.IntervalMinutes == nil {
|
||||
return 60
|
||||
}
|
||||
if *s.IntervalMinutes < 5 {
|
||||
return 5
|
||||
}
|
||||
return *s.IntervalMinutes
|
||||
}
|
||||
|
||||
// OrphanGraceDaysEffective returns the minimum age before an orphaned session dir is reclaimed; defaults to 1.
|
||||
func (s StorageConfig) OrphanGraceDaysEffective() int {
|
||||
if s.OrphanGraceDays == nil {
|
||||
return 1
|
||||
}
|
||||
if *s.OrphanGraceDays < 0 {
|
||||
return 0
|
||||
}
|
||||
return *s.OrphanGraceDays
|
||||
}
|
||||
|
||||
// ActiveGraceHoursEffective returns the recent-activity protection window; defaults to 24, floor 1.
|
||||
func (s StorageConfig) ActiveGraceHoursEffective() int {
|
||||
if s.ActiveGraceHours == nil {
|
||||
return 24
|
||||
}
|
||||
if *s.ActiveGraceHours < 1 {
|
||||
return 1
|
||||
}
|
||||
return *s.ActiveGraceHours
|
||||
}
|
||||
|
||||
// CategoryEnabled reports whether a category participates in cleanup; unknown keys default to false.
|
||||
func (s StorageConfig) CategoryEnabled(key string) bool {
|
||||
if _, known := StorageCategoryDefaults[key]; !known {
|
||||
return false
|
||||
}
|
||||
if c, ok := s.Categories[key]; ok && c.Enabled != nil {
|
||||
return *c.Enabled
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// CategoryRetentionDays returns the effective retention for a category; unknown keys yield 0 (keep forever).
|
||||
func (s StorageConfig) CategoryRetentionDays(key string) int {
|
||||
def, known := StorageCategoryDefaults[key]
|
||||
if !known {
|
||||
return 0
|
||||
}
|
||||
c, ok := s.Categories[key]
|
||||
if !ok || c.RetentionDays == nil {
|
||||
return def
|
||||
}
|
||||
if *c.RetentionDays < 0 {
|
||||
return 0
|
||||
}
|
||||
return *c.RetentionDays
|
||||
}
|
||||
|
||||
// AuditConfig platform operation audit log settings (not chat/tool execution bodies).
|
||||
type AuditConfig struct {
|
||||
// Enabled nil or true enables persistence; explicit false disables.
|
||||
|
||||
Reference in new issue
Block a user