Unverified Commit 47890ca9 authored by Lemon-miaow's avatar Lemon-miaow
Browse files

feat(offsite): 世界归档与数据库备份加密同步到异地 S3,reaper 确认异地副本后才删除世界

parent fa8db4c7
Loading
Loading
Loading
Loading
+1 −0
Changes for AUDIT-2026-09-22.md: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -963,6 +963,7 @@ IPv6-only 接入(`ssh -6 -i ~/.ssh/id_ed25519 root@fdb2:2c26:f4e4:0:21c:42ff:f
30. ~~已装机系统服的新增 CR 字段(tracker #1)~~ ✅ **已修并真机闭环**(第四十六批 #78:`sudo felis converge`——零值才填、非零不覆写;剥字段→填回→幂等三连真机过)。
31. ~~troubleshooting `[INERT]` 图例~~ ✅ **已修**(第四十六批 #79,文档级)。
32. ~~稳定版发布与 release 安装/升级通道~~ ✅ **已实证**(第四十七批:tag `v0.1.0`(`b9c97ff`)+ release run `35950722509` 双资产、`/releases/latest` 解析到 v0.1.0;无 checkout 全量安装 2m17s / 零 fail / 零 warn、registry mirror 四镜像、reaper CronJob 对齐 `felis:v0.1.0`;`felis update` 双向报告〔rc1→v0.1.0 notify / v0.1.0 up to date〕)。
33. ~~世界归档与数据库备份只在本机~~ ✅ **已修并真机闭环**(2026-09-24:`felis offsite` + `felis-offsite.timer` 每小时把世界归档与 DB bundle 以 AES-256-GCM 分段加密推到 S3 兼容桶,`world_backups.offsite_at` 记账〔迁移 0024〕;配了 `[offsite]` 后 reaper 只在归档的异地副本确认后才删 PVC;watchdog 12 小时无成功同步即告警;安装器 `FELIS_OFFSITE_*` 生成密钥并在收尾横幅要求离机保存。真机(MinIO):首次同步 8 世界 1.2 GiB + 12 bundle、两条"记录在册但盘上已无"的历史归档如实列出;`fetch-db latest` sha256 与本机一致、错误密钥拒绝且不留半成品;`fetch-worlds` 取回被挪走的归档 sha256 一致;reaper 演练〔20 天空闲世界〕第一轮 `awaiting_offsite=1` 且 PVC 保留 → 同步后第二轮 `reaped=1`、PVC 删除、所有权释放;watchdog 把 status 改成 35 小时前 → `[warning] offsite`。演练装置已清理)。

## 剩余待演练队列(截至第四十三批)

cmd/felis/offsite.go

0 → 100644
+556 −0

File added.

Preview size limit exceeded, changes collapsed.

+96 −0

File added.

Preview size limit exceeded, changes collapsed.

+3 −2
Changes for cmd/felis/reaper.go: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -131,8 +131,8 @@ func cmdReaper(args []string, stdout, stderr io.Writer) int {
		fmt.Fprintf(stderr, "felis reaper: %v\n", err)
		return 1
	}
	fmt.Fprintf(stdout, "felis reaper: evaluated=%d reaped=%d warned=%d skipped=%d evicted=%d expired=%d\n",
		sum.Evaluated, sum.WorldsReaped, sum.Warned, sum.Skipped, sum.EvictedEarly, sum.BackupsExpired)
	fmt.Fprintf(stdout, "felis reaper: evaluated=%d reaped=%d awaiting_offsite=%d warned=%d skipped=%d evicted=%d expired=%d\n",
		sum.Evaluated, sum.WorldsReaped, sum.AwaitingOffsite, sum.Warned, sum.Skipped, sum.EvictedEarly, sum.BackupsExpired)
	return 0
}

@@ -198,6 +198,7 @@ func reaperConfig(cfg *config.Config) (reaper.Config, error) {
		}
		rc.MaxLocalBytes = b
	}
	rc.RequireOffsite = cfg.Offsite.Enabled()
	return rc, nil
}

+2 −0
Changes for cmd/felis/run.go: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ Usage:
Commands:
  migrate up        Apply embedded database migrations under an advisory lock (snapshots the database first)
  db                Back up, verify, list and restore the control-plane database (backup|restore|verify|list|check)
  offsite           Copy world archives and database bundles to an off-site bucket, and fetch them back (sync|status|list|fetch-db|fetch-worlds|keygen)
  operator          Run the MinecraftServer controller-manager
  api               Run the felis-api HTTP server
  nano              Run the Felis-nano hasJoined multiplexer (multi-Yggdrasil, no control plane)
@@ -47,6 +48,7 @@ Run "felis <command> -h" for command-specific flags.
var commands = map[string]func(args []string, stdout, stderr io.Writer) int{
	"migrate":          cmdMigrate,
	"db":               cmdDB,
	"offsite":          cmdOffsite,
	"operator":         cmdOperator,
	"api":              cmdAPI,
	"nano":             cmdNano,
Loading