[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 "net/http/httputil" 15 "net/url" 16 "os" 17 "runtime/debug" 18 "strings" 19 "time" ··· 217 "display audit log") 218 auditRead := flag.String("audit-read", "", 219 "extract contents of audit record `id` to files '<id>-*'") 220 auditServer := flag.String("audit-server", "", 221 "listen for notifications on `endpoint` and spawn a process for each audit event") 222 runMigration := flag.String("run-migration", "", ··· 237 *unfreezeDomain != "", 238 *auditLog, 239 *auditRead != "", 240 *auditServer != "", 241 *runMigration != "", 242 *traceGarbage, ··· 248 if cliOperations > 1 { 249 logc.Fatalln(ctx, "-list-blobs, -list-manifests, -get-blob, -get-manifest, -get-archive, "+ 250 "-update-site, -freeze-domain, -unfreeze-domain, -audit-log, -audit-read, "+ 251 - "-audit-server, -run-migration, and -trace-garbage are mutually exclusive") 252 } 253 254 if *configTomlPath != "" && *noConfig { ··· 480 } 481 482 if err = ExtractAuditRecord(ctx, id, record, "."); err != nil { 483 logc.Fatalln(ctx, err) 484 } 485
··· 14 "net/http/httputil" 15 "net/url" 16 "os" 17 + "path" 18 "runtime/debug" 19 "strings" 20 "time" ··· 218 "display audit log") 219 auditRead := flag.String("audit-read", "", 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`") 223 auditServer := flag.String("audit-server", "", 224 "listen for notifications on `endpoint` and spawn a process for each audit event") 225 runMigration := flag.String("run-migration", "", ··· 240 *unfreezeDomain != "", 241 *auditLog, 242 *auditRead != "", 243 + *auditRollback != "", 244 *auditServer != "", 245 *runMigration != "", 246 *traceGarbage, ··· 252 if cliOperations > 1 { 253 logc.Fatalln(ctx, "-list-blobs, -list-manifests, -get-blob, -get-manifest, -get-archive, "+ 254 "-update-site, -freeze-domain, -unfreeze-domain, -audit-log, -audit-read, "+ 255 + "-audit-rollback, -audit-server, -run-migration, and -trace-garbage are "+ 256 + "mutually exclusive") 257 } 258 259 if *configTomlPath != "" && *noConfig { ··· 485 } 486 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 { 516 logc.Fatalln(ctx, err) 517 } 518