[mirror] Scalable static site server for Git forges (like GitHub Pages)

Implement `-audit-rollback`.

This feature is useful if you need to restore data after an accidental
overwrite or compromise.

+34 -1
+34 -1
src/main.go
··· 14 14 "net/http/httputil" 15 15 "net/url" 16 16 "os" 17 + "path" 17 18 "runtime/debug" 18 19 "strings" 19 20 "time" ··· 217 218 "display audit log") 218 219 auditRead := flag.String("audit-read", "", 219 220 "extract contents of audit record `id` to files '<id>-*'") 221 + auditRollback := flag.String("audit-rollback", "", 222 + "restore site from contents of audit record `id`") 220 223 auditServer := flag.String("audit-server", "", 221 224 "listen for notifications on `endpoint` and spawn a process for each audit event") 222 225 runMigration := flag.String("run-migration", "", ··· 237 240 *unfreezeDomain != "", 238 241 *auditLog, 239 242 *auditRead != "", 243 + *auditRollback != "", 240 244 *auditServer != "", 241 245 *runMigration != "", 242 246 *traceGarbage, ··· 248 252 if cliOperations > 1 { 249 253 logc.Fatalln(ctx, "-list-blobs, -list-manifests, -get-blob, -get-manifest, -get-archive, "+ 250 254 "-update-site, -freeze-domain, -unfreeze-domain, -audit-log, -audit-read, "+ 251 - "-audit-server, -run-migration, and -trace-garbage are mutually exclusive") 255 + "-audit-rollback, -audit-server, -run-migration, and -trace-garbage are "+ 256 + "mutually exclusive") 252 257 } 253 258 254 259 if *configTomlPath != "" && *noConfig { ··· 480 485 } 481 486 482 487 if err = ExtractAuditRecord(ctx, id, record, "."); err != nil { 488 + logc.Fatalln(ctx, err) 489 + } 490 + 491 + case *auditRollback != "": 492 + ctx = WithPrincipal(ctx) 493 + GetPrincipal(ctx).CliAdmin = proto.Bool(true) 494 + 495 + id, err := ParseAuditID(*auditRollback) 496 + if err != nil { 497 + logc.Fatalln(ctx, err) 498 + } 499 + 500 + record, err := backend.QueryAuditLog(ctx, id) 501 + if err != nil { 502 + logc.Fatalln(ctx, err) 503 + } 504 + 505 + if record.GetManifest() == nil || record.GetDomain() == "" || record.GetProject() == "" { 506 + logc.Fatalln(ctx, "no manifest in audit record") 507 + } 508 + 509 + webRoot := path.Join(record.GetDomain(), record.GetProject()) 510 + err = backend.StageManifest(ctx, record.GetManifest()) 511 + if err != nil { 512 + logc.Fatalln(ctx, err) 513 + } 514 + err = backend.CommitManifest(ctx, webRoot, record.GetManifest(), ModifyManifestOptions{}) 515 + if err != nil { 483 516 logc.Fatalln(ctx, err) 484 517 } 485 518