b32755b35f
- scripts/backup_layout.sh:定义 $KB_BACKUP_ROOT/{target-kb-snapshots,rds-logical,es-snapshots,logs}
与 /etc/knowledge-governance/backup.env,任意主机跑同一份(测试云主机 → 未来生产云主机)
- scripts/es_kb_export.py:只读 scroll 导出目标库 ES 文档(gzip JSONL,_id/_source,可按 _id 重建)
- scripts/target_kb_snapshot.sh:留档改为 PG 行 + ES 文档两层;PULL_ES 默认 0(692 MB / 家用上行 19m40s,
留在目标主机,清单记 location=cloud:<host>:<path>);挂载源与落点统一走 KB_BACKUP_ROOT
- scripts/logical-backup.sh:自管整库逻辑备份(pg_dump -Fd -j4 -Z6,按天轮转)
- internal/releasesnapshot:门禁要求 PG 与 ES 两层齐备(ES 计数 >0);云侧留档核声明与哈希、
声明本地却缺失则 fail-closed;新增 3 条用例(共 10)
- cmd/guardcheck:用真实产物复核门禁判断
- docs:PRODUCTION_BACKUP_RECOVERY.md 重写(契约/RDS 控制台/恢复路径/边界);P6 同步留档语义
32 lines
825 B
Go
32 lines
825 B
Go
// 用真实产物验证发布前门禁:Guard 必须放行覆盖该库的完整留档(PG + ES)。
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"knowledge-governance/internal/releasesnapshot"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) < 3 {
|
|
fmt.Println("用法: guardcheck <快照根目录> <知识库ID> [...]")
|
|
os.Exit(2)
|
|
}
|
|
root, ids := os.Args[1], os.Args[2:]
|
|
guard := releasesnapshot.Guard{Root: root, MaxAge: 24 * time.Hour, Now: time.Now, VerifyLocalFiles: true}
|
|
for _, id := range ids {
|
|
err := guard.Check(id)
|
|
switch {
|
|
case err == nil:
|
|
fmt.Printf("PASS %s → 门禁放行(PG 行 + ES 文档 + 哈希校验通过)\n", id)
|
|
case errors.Is(err, releasesnapshot.ErrNoFreshSnapshot):
|
|
fmt.Printf("BLOCK %s → %v\n", id, err)
|
|
default:
|
|
fmt.Printf("ERROR %s → %v\n", id, err)
|
|
}
|
|
}
|
|
}
|