Add agent_plan_content to backup utilities
What does this MR do and why?
Last part of Figure out agent_plan_content backups (#600081) — closes #600081. See discussion at gitlab-org/build/CNG!2946 (comment 3390367925).
See prior work at:
- Create WorkItem::AgentPlan and its table, with ... (!232335 - merged)
- Add agent_plan_content object storage configura... (omnibus-gitlab!9382 - merged)
- Add agent_plan_content object storage configura... (gitlab-org/charts/gitlab!5029 - merged)
- Add agent_plan_content config and MinIO bucket (gitlab-development-kit!5970 - merged)
- Add agent_plan_content to backup-utility (gitlab-org/build/CNG!2946 - merged)
- https://ops.gitlab.net/gitlab-com/gl-infra/terraform-modules/google/storage-buckets/-/merge_requests/140
How to set up and validate locally
We'll validate this on the GDK by creating an agent plan, backing it up using the newly-empowered utilities, deleting the backing file, confirming it's no longer reachable by the Rails app, and then restoring it and confirming it's back!
I'm going to assume you have object storage disabled (the default; gdk config set object_store.enabled false). If you have it enabled, and don't want to disable it, that's OK! Just use the MinIO console (http://gdk.test:9002/, default login minio / gdk-minio) to locate and delete the file in steps 4, 6, and 10.
You'll need an EE license for this.
- Enable the
agent_planfeature at http://gdk.test:3000/rails/features. - Navigate to a work item. You should see the "Workplan" experimental widget:

- Click the "edit" pencil icon and fill out anything in the workplan:

- Locate the file on disk now! Here's how I found mine:
$ grep -r Schneeeeeeef shared/agent_plan_content shared/agent_plan_content/29/db/29db0c6782dbd5000559ef4d9e953e300e2b479eed26d887ef3f92b921c06a67/work_item_agent_plans/684/684.json:{"content":"Schneeeeeeef","content_html":"\u003cp data-sourcepos=\"1:1-1:12\" dir=\"auto\"\u003eSchneeeeeeef\u003c/p\u003e"} - Create a backup:
There's going to be a fair bit of output, maybe a lot depending on how much is in your GDK. Mine took about 30 seconds. In the output, spot this:
$ bundle exec rake gitlab:backup:create 2026-05-28 03:38:58 UTC -- Dumping database ... 2026-05-28 03:38:58 UTC -- Dumping PostgreSQL database gitlabhq_development ... 2026-05-28 03:39:01 UTC -- [DONE] 2026-05-28 03:39:01 UTC -- Dumping PostgreSQL database gitlabhq_development_ci ... 2026-05-28 03:39:03 UTC -- [DONE] 2026-05-28 03:39:03 UTC -- Dumping PostgreSQL database gitlabhq_development_sec ... [... continued ...]We can further confirm that it's part of the resulting tarball. The prefix (!) of the final output file is in the second last line of output:[...] 2026-05-28 03:39:12 UTC -- Dumping agent plan content ... 2026-05-28 03:39:13 UTC -- Dumping agent plan content ... done [...][...] 2026-05-28 03:39:13 UTC -- Backup 1779939538_2026_05_28_19.1.0-pre is done. 2026-05-28 03:39:13 UTC -- Deleting backup and restore PID file at [/Users/kivikakk/g/gdk/gitlab/tmp/backup_restore.pid] ... done $ tar tvf tmp/backups/1779939538_2026_05_28_19.1.0-pre_gitlab_backup.tar | grep agent_plan_content -rw------- 0 kivikakk staff 27391 28 May 13:39 agent_plan_content.tar.gz - Delete the file we located in step 4!
$ rm shared/agent_plan_content/29/db/29db0c6782dbd5000559ef4d9e953e300e2b479eed26d887ef3f92b921c06a67/work_item_agent_plans/684/684.json - Refresh the work item. The workplan should be
✨ gone✨ :

- Restore from the backup we created! To minimise mayhem, restore only the
agent_plan_contentdata, by skipping everything else. NoteBACKUPtakes only the timestamp prefix, not the full filename:$ BACKUP=1779939538_2026_05_28_19.1.0-pre SKIP=db,repositories,uploads,builds,artifacts,lfs,terraform_state,registry,packages,ci_secure_files,external_diffs,pages bundle exec rake gitlab:backup:restore 2026-05-28 03:44:09 UTC -- Unpacking backup ... 2026-05-28 03:44:09 UTC -- Unpacking backup ... done 2026-05-28 03:44:09 UTC -- Restoring agent plan content ... 2026-05-28 03:44:09 UTC -- Restoring agent plan content ... done This task will now rebuild the authorized_keys file. You will lose any data stored in the authorized_keys file. Do you want to continue (yes/no)? no Quitting... 2026-05-28 03:44:14 UTC -- Deleting tar staging files ... 2026-05-28 03:44:14 UTC -- Cleaning up /Users/kivikakk/g/gdk/gitlab/tmp/backups/backup_information.yml 2026-05-28 03:44:15 UTC -- Cleaning up /Users/kivikakk/g/gdk/gitlab/tmp/backups/db [... more cleanup output follows ...] - Refresh the workplan!!!

- You can also confirm the exact file is back where it should be and is at it ought:
$ ls shared/agent_plan_content/29/db/29db0c6782dbd5000559ef4d9e953e300e2b479eed26d887ef3f92b921c06a67/work_item_agent_plans/684/684.json
shared/agent_plan_content/29/db/29db0c6782dbd5000559ef4d9e953e300e2b479eed26d887ef3f92b921c06a67/work_item_agent_plans/684/684.json
$ cat shared/agent_plan_content/29/db/29db0c6782dbd5000559ef4d9e953e300e2b479eed26d887ef3f92b921c06a67/work_item_agent_plans/684/684.json
{"content":"Schneeeeeeef","content_html":"\u003cp data-sourcepos=\"1:1-1:12\" dir=\"auto\"\u003eSchneeeeeeef\u003c/p\u003e"}MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.



