fix(admin): always send dry_run on storage-GC requests - #176
Conversation
`run_storage_gc` built its body with `dry_run.then_some(true)`. The
generated SDK field is `Option<bool>` carrying
`#[serde(skip_serializing_if = "Option::is_none")]`, so on a live run
(no `--dry-run`) the `None` dropped the key entirely and the CLI posted
`{}` to `POST /api/v1/admin/storage-gc`.
That relied on the server defaulting the field. artifact-keeper#3619
removes that default: `dry_run` becomes required and unknown fields are
rejected, so `{}` is refused with 422 and no GC runs. `ak admin
storage-gc run --dry-run` was always fine — it sent `{"dry_run": true}`.
Send the value unconditionally instead, via a small `storage_gc_body`
helper so the body is testable without a client. A live run now posts
`{"dry_run": false}`, which is what the 1.8.x backend already means by
an empty body, so this is safe to merge before #3619 and required
after it.
The added test asserts both bodies; restoring `then_some(true)` fails
it with `left: Object {}`.
33eaf47 to
a639c7b
Compare
|
The red
Reproduced on unmodified This PR touches only |
|



Closes #175
Companion to artifact-keeper/artifact-keeper#3619 — that PR should not merge before this one is ready.
What
ak admin storage-gc runbuilt its request body withdry_run.then_some(true):The generated field is
Option<bool>carrying#[serde(default, skip_serializing_if = "::std::option::Option::is_none")](sdk/src/generated_sdk.rs), so on a live run (no--dry-run) theNonedrops the key and the CLI posts{}toPOST /api/v1/admin/storage-gc. The--dry-runpath always sent{"dry_run": true}and is unaffected.That has worked so far only because the backend defaulted the missing field to
false. #3619 removes that:dry_runbecomes required and the request gainsdeny_unknown_fields, so an empty body is refused with 422 (missing field `dry_run`) and no GC runs. Against a backend carrying #3619,ak admin storage-gc runwithout--dry-runstops working entirely.The fix
Send the value unconditionally, through a small
storage_gc_body(dry_run)helper so the body can be asserted without standing up a client:{"dry_run": false}is exactly what today's backend already infers from{}, so this is safe to merge before #3619 and required after it. No SDK regeneration is involved — the type is unchanged; only what we put in it changes. (When the spec is next regenerated,dry_runbecomes required and the field will lose itsOption, at which point this line becomesdry_run,— another reason to have the call site sending a real value already.)Scope
run_storage_gcis the CLI's only constructor ofStorageGcRequest, and #3619 touches onlybackend/src/api/handlers/storage_gc.rs, so no other call site is affected. The repo-scopedPOST /api/v1/repositories/{key}/storage-gchandler that #3619 also hardens is not wired into the CLI (absent from the generated SDK), so nothing to fix there.I checked the other 14
then_some(true)body fields insrc/commands/(backup restore, cleanup, user create/update, promotion, approval, format-handler toggles). They have the same "omit when false" shape, but none of their request types are validated by #3619, so they are out of scope here — they stay correct as long as the backend keeps defaulting those fields.Testing
New unit test
storage_gc_body_always_sends_dry_runasserts both bodies serialize with the key present:Revert-proofed: restoring
dry_run.then_some(true)fails it withleft: Object {}/right: Object {"dry_run": false}— i.e. the test reproduces the empty body the backend would 422 on.cargo nextest run --workspace— 2025 passed, 0 failed (2024 before, +1 new)cargo clippy --workspace -- -D warningscleancargo fmt --checkcleanCHANGELOG updated under
Unreleased / Fixed.