From 132d093021041762c3d4390b6fa0b8b06e311a69 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 11 Dec 2025 03:11:42 +0000 Subject: [PATCH] Implement `-audit-rollback`. This feature is useful if you need to restore data after an accidental overwrite or compromise. --- src/main.go | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/main.go b/src/main.go index 3692623..aef5932 100644 --- a/src/main.go +++ b/src/main.go @@ -14,6 +14,7 @@ import ( "net/http/httputil" "net/url" "os" + "path" "runtime/debug" "strings" "time" @@ -217,6 +218,8 @@ func Main() { "display audit log") auditRead := flag.String("audit-read", "", "extract contents of audit record `id` to files '-*'") + auditRollback := flag.String("audit-rollback", "", + "restore site from contents of audit record `id`") auditServer := flag.String("audit-server", "", "listen for notifications on `endpoint` and spawn a process for each audit event") runMigration := flag.String("run-migration", "", @@ -237,6 +240,7 @@ func Main() { *unfreezeDomain != "", *auditLog, *auditRead != "", + *auditRollback != "", *auditServer != "", *runMigration != "", *traceGarbage, @@ -248,7 +252,8 @@ func Main() { if cliOperations > 1 { logc.Fatalln(ctx, "-list-blobs, -list-manifests, -get-blob, -get-manifest, -get-archive, "+ "-update-site, -freeze-domain, -unfreeze-domain, -audit-log, -audit-read, "+ - "-audit-server, -run-migration, and -trace-garbage are mutually exclusive") + "-audit-rollback, -audit-server, -run-migration, and -trace-garbage are "+ + "mutually exclusive") } if *configTomlPath != "" && *noConfig { @@ -483,6 +488,34 @@ func Main() { logc.Fatalln(ctx, err) } + case *auditRollback != "": + ctx = WithPrincipal(ctx) + GetPrincipal(ctx).CliAdmin = proto.Bool(true) + + id, err := ParseAuditID(*auditRollback) + if err != nil { + logc.Fatalln(ctx, err) + } + + record, err := backend.QueryAuditLog(ctx, id) + if err != nil { + logc.Fatalln(ctx, err) + } + + if record.GetManifest() == nil || record.GetDomain() == "" || record.GetProject() == "" { + logc.Fatalln(ctx, "no manifest in audit record") + } + + webRoot := path.Join(record.GetDomain(), record.GetProject()) + err = backend.StageManifest(ctx, record.GetManifest()) + if err != nil { + logc.Fatalln(ctx, err) + } + err = backend.CommitManifest(ctx, webRoot, record.GetManifest(), ModifyManifestOptions{}) + if err != nil { + logc.Fatalln(ctx, err) + } + case *auditServer != "": if flag.NArg() < 1 { logc.Fatalln(ctx, "handler path not provided")