mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-09-30 05:02:06 +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>
55 lines
1.5 KiB
Go
55 lines
1.5 KiB
Go
package database
|
|
|
|
import (
|
|
"database/sql"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ConversationLastActivity 返回会话最近活动时间;ok=false 表示会话已不存在。
|
|
// 供存储清理判断目录是否为孤儿、以及会话是否仍在活跃使用。
|
|
func (db *DB) ConversationLastActivity(id string) (time.Time, bool, error) {
|
|
id = strings.TrimSpace(id)
|
|
if id == "" {
|
|
return time.Time{}, false, nil
|
|
}
|
|
var createdAt, updatedAt string
|
|
err := db.QueryRow(
|
|
"SELECT created_at, updated_at FROM conversations WHERE id = ? LIMIT 1", id,
|
|
).Scan(&createdAt, &updatedAt)
|
|
if err == sql.ErrNoRows {
|
|
return time.Time{}, false, nil
|
|
}
|
|
if err != nil {
|
|
return time.Time{}, false, err
|
|
}
|
|
created, updated := parseDBTime(createdAt), parseDBTime(updatedAt)
|
|
if created.After(updated) {
|
|
return created, true, nil
|
|
}
|
|
return updated, true, nil
|
|
}
|
|
|
|
// ProjectLastActivity 返回项目最近活动时间;ok=false 表示项目已不存在。
|
|
func (db *DB) ProjectLastActivity(id string) (time.Time, bool, error) {
|
|
id = strings.TrimSpace(id)
|
|
if id == "" {
|
|
return time.Time{}, false, nil
|
|
}
|
|
var createdAt, updatedAt string
|
|
err := db.QueryRow(
|
|
"SELECT created_at, updated_at FROM projects WHERE id = ? LIMIT 1", id,
|
|
).Scan(&createdAt, &updatedAt)
|
|
if err == sql.ErrNoRows {
|
|
return time.Time{}, false, nil
|
|
}
|
|
if err != nil {
|
|
return time.Time{}, false, err
|
|
}
|
|
created, updated := parseDBTime(createdAt), parseDBTime(updatedAt)
|
|
if created.After(updated) {
|
|
return created, true, nil
|
|
}
|
|
return updated, true, nil
|
|
}
|