Repository navigation
feat: mass-deletion protection (cascade guard, per-repo breaker, batched deletes) - #265
Merged
Merged
Conversation
…letionProtection, pruned-by) Lays down M0 of the mass-deletion-protection feature: the api-crate types, consts, and validator only (later milestones wire controller behavior). - ScheduleDeletePolicy (common): Retain/Delete cascade policy for a SnapshotSchedule's produced Snapshots on schedule deletion. - SnapshotScheduleSpec.deletion (ScheduleDeletionSpec.onScheduleDelete, default Retain) + effective_on_schedule_delete resolver. - SnapshotSpec.onScheduleDelete (no schema default; stamped by the schedule, consulted by the finalizer when external + owner gone). - PrunedBy (Retention/FailedHistory) + annotation_value/parse, so the finalizer can distinguish operator prunes from external deletions. - DeletionProtectionSpec.threshold (default 10, 0 disables) on both Repository and ClusterRepository: the mass-deletion circuit breaker. - consts: PRUNED_BY_ANNOTATION, ALLOW_MASS_DELETION_ANNOTATION, DEFAULT_MASS_DELETION_THRESHOLD + effective_mass_deletion_threshold, MASS_DELETION_HELD_CONDITION. - validate_backup_on_schedule_delete: origin: discovered may never set onScheduleDelete (their owner is a repository, not a schedule); wired into the existing validate_backup aggregate the webhook already calls, so no webhook changes were needed. Regenerated deploy/crds, Helm CRDs, and docs/field-reference.md; updated the snapshot/repository CRD insta snapshots.
Adds the mover-side batch snapshot-delete operation for mass-deletion protection (M1): one Job deletes many manifest ids over a single kopia connect, instead of one Job per Snapshot CR. Nothing emits this operation yet, so it is an upgrade-safe no-op until a later milestone wires the controller dispatcher. - Extract delete_one (shared by the legacy single SnapshotDelete arm and the new batch loop) so the stale-id self-heal logic lives in one place. - Data-loss fix (adversarial review): gate the self-heal on the anchor's start_time being present. Without it, the path(+identity)-only fallback in match_current_manifest can uniquely match a NEWER, unrelated snapshot at the same source path/identity and delete the wrong data. - Batch semantics are attempt-all-then-fail: every member is tried independently since kopia's delete is idempotent, so a retry of the whole batch converges instead of wedging on the first failure. - Add StatusReporter::log_only, hand-selected for SnapshotDeleteBatch (whose targetRef names the Job itself, with no RBAC to PATCH it) so a status PATCH is never even attempted for this op.
…r, batch) M2 of mass-deletion protection: rewrites plan_deletion around a single DeletionFacts input, absorbing namespace_delete_plan into an exhaustive decision table (skip-cleanup > namespace cascade > schedule cascade guard > operator prune > external breaker gate), and adds a new pure batch.rs module (pending-member filtering, fire/throttle/requeue decisions, deterministic Job naming) for the upcoming mass-delete batching. handle_deletion's call site is rewired to the new signature with owner/breaker facts that are provably behavior-preserving (M4/M5 wire the real owner GET and breaker count). Everything stays pure and clock-injected; every match over the new enums is exhaustive.
… surface, metrics) Adds the infrastructure M4/M5 will consume to enforce mass-deletion protection, with no reconcile-behavior change beyond an additive backfill: - KOPIUR_MAX_CONCURRENT_DELETE_JOBS config knob (+ full Helm surface). - Context gains OnceLock-backed snapshot/schedule reflector stores + synced flags, mirroring the maintenance_store precedent. - ResolvedRepository gains deletion_protection + mass_deletion_ack fields. - New consts: batch-delete op/label/annotation, DeletionHeld condition, and the mass-deletion event reasons. - New metrics: kopiur_snapshot_deletions, kopiur_snapshots_cascade_retained, kopiur_snapshot_delete_batch_jobs/_members counters, plus kopiur_snapshot_deletions_pending_external/_held store-backed gauges. - Snapshot's startup backfill now also stamps status.resolved.repository for pre-#255 CRs, so the mass-deletion breaker's per-repo count isn't blind to the legacy fleet.
Maintainer amendment: batching already drains one Job per repository per accumulation window, not one per Snapshot, so a small default concurrency cap risked head-of-line-blocking every other repository's deletions behind one slow/failing one. KOPIUR_MAX_CONCURRENT_DELETE_JOBS now defaults to 0 (uncapped), matching the repo's threshold-0-disables idiom; the resolved Context/ControllerConfig field is Option<NonZeroUsize> so "no cap" can't be mistaken for "cap of zero" at any call site. throttle_verdict adapted: None always Proceeds, Some(n) behaves as before. Helm surface (values.yaml, schema minimum 0, deployment test, regenerated README) updated to match.
… Snapshot finalizer M4a makes the mass-deletion-protection semantics real. Thin IO over the M2 pure decision layer: gather live facts, feed the tested functions, execute the two new plan variants, and surface the observability. - Stamp produced Snapshots with the schedule's effective onScheduleDelete, and propagate a schedule edit to existing drifted children (children_needing_cascade_stamp); skip firing into a terminating slot twin. - Prune discriminator (io/prune.rs): stamp pruned-by before deleting so an operator prune bypasses the breaker/cascade guard; GFS hardening reclassifies an in-flight prune wave straddling the upgrade (partition_retention_prune). - Real deletion facts (gather_deletion_facts): live owner GET via the schedule store/get_opt, and the store-gated per-repo breaker (pending_members + unacked_breaker_count), fail-safe to requeue when the snapshot store is unset/unsynced, conservative on missing refs, ignore+warn on an unparseable ack (InvalidMassDeletionAck). - Execute the new plans: RetainSnapshotOnScheduleDelete (retain + cascade counter + event) and HoldSnapshotDeletion (keep finalizer, DeletionHeld=True via live_conditions_source, transition-only event, 5m requeue, ack command + escape hatch in the message); clear DeletionHeld when a held deletion proceeds. Single inc_snapshot_deletion point per terminal outcome. - Ack-drain watch: Snapshot controller watches Repository/ClusterRepository -> deleting snapshots resolving to that repo. Lazy non-blocking MassDeletionHeld condition on both repo kinds (mirrors IndexBlobHealth). handle_deletion stays under the complexity ratchet (facts-gathering extracted).
…_until_ready getter The M4a mass-deletion breaker gates destructive deletion on `snapshot_synced` / `schedule_synced`, which were flipped by a spawned `store.wait_until_ready()` on the very `Controller::store()` the applier already awaits internally (`delay_tasks_until(store.wait_until_ready())`). kube-rs's `DelayedInit` multiplexes a single-waker `oneshot` behind a `Mutex`, so the two concurrent getters race: the loser's waker is overwritten and it hangs forever. When our getter lost, the flag never flipped and EVERY external `deletionPolicy: Delete` deletion deferred (`StoresNotSynced`) indefinitely — breaking normal snapshot deletion, not only the breaker. Fix: publish the store handle only (`publish_store`, no second getter — which also removes the latent risk of starving the applier's own getter), and flip each `*_synced` from that kind's reconcile. A dispatched reconcile is itself proof the reflector completed its initial LIST (the applier's readiness gate) — a reliable signal with no `DelayedInit` contention. Unit test on the idempotent flip helper. Exposed by crates/e2e mass_deletion.rs (breaker held forever) and lifecycle.rs backup_restore_delete_lifecycle (normal delete never drained).
New crates/e2e/tests/mass_deletion.rs proves the M4a mass-deletion protection
end-to-end against a live operator in kind:
- schedule_cascade_delete_leaves_kopia_intact_and_recatalogs — THE incident's
regression guard: deleting a SnapshotSchedule (default onScheduleDelete:
Retain) drains the produced Snapshot CRs with ZERO delete Jobs and an
UNCHANGED kopia count, fires one SnapshotRetainedOnScheduleDelete Warning per
CR, and the catalog rediscovers them as forced-Retain discovered rows.
- mass_deletion_breaker_holds_and_ack_drains — a wave >= threshold is HELD
(DeletionHeld/MassDeletionBreaker, repo MassDeletionHeld, kopia untouched);
the allow-mass-deletion ack (exact RFC3339 value parsed from the surfaced
message) drains it and really deletes the kopia snapshots; a sub-threshold
single delete is never held.
- retention_prune_not_held_by_breaker — operator GFS prunes bypass the breaker
even at an aggressive threshold (1).
Plus a webhook admission case in webhook.rs (origin: discovered + onScheduleDelete
rejected; a manual Snapshot with the field accepted). Assertions are OUTCOMES
(CRs drained, kopia counts, conditions/events), never delete-Job names, so they
survive the M5 batch dispatcher. Adds massdel-{cascade,breaker,prune} to
REPO_SUBPATHS and the node-seed loop (kept in lockstep).
…CR delete Jobs
Replace the legacy per-CR `{name}-delete` Job with a per-repository BATCH
delete dispatcher (mass-deletion protection M5a). One mover Job
(`SnapshotDeleteBatch`, M1) deletes MANY members' kopia manifests over a
single connect, gated by the M2 pure decision layer, CREATEd (never
SSA-applied), reaped explicitly, and optionally throttled.
Dispatcher (`drive_batch_deletion`): honor a legacy `{name}-delete` Job via an
upgrade shim (both old placements); resolve placement via `batch_job_placement`
(repo-home ns / operator ns, else orphan); gate on the snapshot store being
synced (pruned deletions are NOT breaker-gated, so the dispatcher repeats the
fail-safe); LIST the repo's batch Jobs ONCE, reap the drained/aged terminal
ones (single whole-Job metric point), classify THIS CR against that same list,
and — if not yet enrolled — fire a fresh wave (no-overlap: fireable = pending
minus in-flight UIDs from the SAME list; deterministic name + 409 dedup).
The finalizer is released ONLY on a SUCCEEDED batch covering the CR's UID (or
the legacy shim's succeeded Job); the no-snapshot-id release survives.
New pure classifiers in snapshot/batch.rs (TDD): `member_disposition`,
`in_flight_uids`, `reap_targets` (+ `BatchJobView`/`BatchJobState`). Batch Job
construction reuses the retired path's semantics N-at-a-time: pin-first repo
resolution, projection HARDCODED OFF, moverDefaults inheritance, RBAC minting;
NO ttlSecondsAfterFinished, sorted-UID members annotation, ownerRef only for a
namespaced Repository.
Also:
- sweep.rs: leak backstop for terminal batch Jobs whose members all drained
(logged, not metered — the dispatcher owns the counter); pure eligibility fn.
- batch.rs M2 leftovers: UID tiebreak in `oldest_first_truncated`,
`batch_job_name` non-empty debug_assert + doc.
- context.rs: one-shot "informer cache synced" log on the first flip (swap).
- Retire `delete_snapshot_via_job`, `delete_projection_enabled`,
`pinned_mover_identity`, `CredsPrefix::snapshot_delete` (now dead); the mover
keeps decoding the old op for wire compat. Ratchet complexity budget 30 -> 29.
…rios Add M5b e2e scenarios 5-8 to crates/e2e/tests/mass_deletion.rs proving the per-repository batch delete dispatcher end-to-end (they LIST batch Jobs by the op label + managed-by and read the delete-members UID annotation), plus the M4b scenario-2 settle hardening: - single_snapshot_delete_still_releases: batch-of-1 unification (exactly one SnapshotDeleteBatch Job whose delete-members is exactly the CR UID; CR drains; kopia -1). - concurrent_batches_do_not_overlap: two disjoint delete waves -> two disjoint, separate batch Jobs (uncapped default allows concurrency); all drain, kopia -5. - throttle_caps_concurrent_batch_jobs: KOPIUR_MAX_CONCURRENT_DELETE_JOBS=1 patched onto the controller Deployment (+ rollout wait) -> at most one live batch Job at any instant; both waves drain; env restored to uncapped on every exit. - batch_delete_retries_after_repo_outage: repo dir flipped read-only (root chmod pod) so the batch mover fails EACCES -> Job fails, is reaped, refires (>=2 Job generations by UID) with no finalizer release; restore writability -> all drain + real kopia deletion. - Scenario 2 hardening: settle on all three deletionTimestamps before asserting the breaker hold, so a loaded box can't evaluate the breaker before the wave registers. - Lockstep: 4 new subpaths (massdel-single/nooverlap/throttle/outage) added to both crates/e2e/src/consts.rs REPO_SUBPATHS and the crates/e2e/mise.toml node-seed list. fix(controller): the batch no-overlap exclusion set must exclude members covered by a LIVE *or SUCCEEDED* job, not only LIVE (surfaced by the concurrent-batches e2e). A member whose kopia snapshot a succeeded batch already deleted is still "pending" to pending_members until its finalizer is released, so an uncapped second wave fired before it drained re-enrolled it: the second batch became set_a U set_b instead of set_b, and at scale (oldest-first MAX_BATCH_MEMBERS truncation) every new wave keeps re-selecting already-deleted members, serializing a mass deletion. Rename in_flight_uids -> covered_uids filtering Live|Succeeded (FAILED members stay fireable for a genuine retry, mirroring member_disposition's precedence); a succeeded job is never reaped until its members drain, so an excluded member is never stranded. +2 unit tests.
…es) + ADR-0006 Documents the M0-M5b mass-deletion-protection feature for all three audiences: - docs/backups.md: what happens when a SnapshotSchedule is deleted (the cascade guard, default Retain, rediscovery, opting into cascade, propagation-on-edit), batched delete execution (quiet window, batch-of-1 latency), and the post-fire skip-snapshot-cleanup caveat. - docs/repositories.md: extended the onNamespaceDelete cascade table to all three deletion axes (single Snapshot / namespace / schedule), plus a new `deletionProtection` section covering the breaker, the exact ack flow, 0-disables, prune bypass, and the namespace-teardown corner. - deploy/examples/34-schedule-deletion-protection.yaml: a schedule opting into the cascade + a repository with a raised breaker threshold. - docs/dev/design-rationale.md: the design reasoning behind the 2-variant ScheduleDeletePolicy, the pruned-by discriminator, the valued (not presence-only) timestamp ack, batched create-not-apply execution, and the uncapped-by-default concurrency throttle. - docs/adr/0006-mass-deletion-protection.md: the ADR recording the incident, the decisions, and upgrade notes. - CLAUDE.md: one-line-each mention of the cascade guard, breaker, and batched deletes in the Deletion row of the locked technical decisions table. No .rs files touched. Verified every field/annotation/metric name against crates/api, crates/controller/src/consts.rs, and the actual reconcile code before writing prose (see the M6 report for corrections made against the task brief). mise run test / fmt-check / gen-check / docs all green.
- The Helm value for the delete-Job concurrency cap is top-level maxConcurrentDeleteJobs (deploy/helm/kopiur/values.yaml:124) — this chart has no `controller:` nesting. Fixed the wrong `controller.maxConcurrentDeleteJobs` path in docs/backups.md, docs/adr/0006-mass-deletion-protection.md, and the uncommitted release-notes scratch file. - docs/repositories.md overstated what the InvalidMassDeletionAck Warning event reports: publish_invalid_ack_event names the annotation key, not the malformed value the user set. Reworded to "flagging the annotation as unparseable RFC3339".
…NT set
The mass-deletion pending COUNT is deliberately maximally INCLUSIVE (over-count
trips the breaker earlier — the fail-safe direction for a count), but fire_batch
reused that same set as the FIRE set. A breaker-exempt trigger (an operator
prune — never held by design — or an acked older wave) could therefore enroll
members the count only over-includes and delete their kopia data with no ack.
Introduce a pure, maximally-EXCLUSIVE fire-eligibility layer
(fire_eligible/FireEligibility), run before the no-overlap exclusion, whose
fail-safe direction is under-fire + requeue:
- CRITICAL-1: while the breaker is tripping (unacked >= threshold over the FULL
pending set), exclude HELD external peers (external && deletion_timestamp > ack).
- IMPORTANT-2: exclude onNamespaceDelete:Orphan peers whose namespace is
terminating (resolved once per distinct member namespace; a namespace that
can't be read is treated as terminating — under-fire).
- IMPORTANT-3a: exclude schedule-owned EXTERNAL peers while the schedule store is
unsynced (its owner lookup defaults to Alive, disabling the cascade guard);
3b: flip schedule_synced at startup via a bounded authoritative LIST when the
cluster has zero SnapshotSchedules (a reconcile never runs to flip it there).
- IMPORTANT-4: exclude unpinned PEERS (the count matches them to every repo key,
but their manifest ids must not ride an unrelated repo's batch). The triggering
self CR is always fireable — the finalizer path already authorized it.
Also in this wave:
- MINOR-7: emit kopiur_snapshot_delete_batch_members{outcome="failed"} once, at
the single FAILED-Job reap point (its members never drain their own finalizer).
- MINOR-8: drop the dead MASS_DELETION_HELD_REASON const (condition-only surface).
- MINOR-9: reshape member_disposition/covered_uids to exhaustive match over
BatchJobState so a new state fails closed (no behavior change).
- MINOR-10: mark the legacy {name}-delete adoption shim + delete_job_placement
TODO(one-release).
Every filter is TDD-guarded by the review's counterexamples (the tests fail
against the pre-fix pass-through set).
…ICAL-1) Scenario 9 (held_wave_not_swept_by_concurrent_prune) — the final-review flagship counterexample. On ONE repository (threshold 2): an aggressive keepLatest:1 scheduled policy prunes continuously (breaker-EXEMPT batches firing on the repo), while 3 manual externals are bulk-deleted into a HELD wave. keepLatest:1 never keeps >=3 scheduled snapshots at once, so the counterexample window observes >=2 DISTINCT prune drains OVER TIME while the schedule stays live (as scenario 3 collects >=3 distinct produced names), asserting on every poll that the 3 held manuals stay terminating with DeletionHeld=True and never drain. Then the schedule is suspended + converged (still asserting held) and the allow-mass-deletion ack drains the manuals — kopia count drops by exactly 3. A manual draining before the ack is the regression (a prune's oldest-first batch sweeping a held external). Adds the isolated `massdel-heldprune` repo subpath in lockstep to REPO_SUBPATHS (crates/e2e/src/consts.rs) and the node-seed enumeration (crates/e2e/mise.toml).
…ch reality - ADR-0006 / design-rationale: record the load-bearing polarity the original design left implicit — the breaker's pending COUNT is inclusive (over-count is fail-safe), while the set a reconcile FIRES is exclusive (under-fire is fail-safe), and the fire path drops held/ns-orphan/unsynced-schedule-owned/ unpinned members that still count toward the breaker. - backups.md (MINOR-6): rewrite the stale "what Delete needs" bit — the batch delete runs at the repository's home namespace against the canonical Secret with projection off, so there is no per-run <snapshot>-delete-creds-N copy. - observability.md (MINOR-7): document the per-member batch metric semantics — `deleted` per member on drain, `failed` once per member at the FAILED reap.
The M2 feature commit (1d636ba) rewrote the node entries in .mise/mise.lock (linux-x64 prebuilt tarball -> generic source tarball + install="source", plus source-install variants) — the known mise install/uninstall lock-rewrite gotcha, staged by a hook. Restore .mise/mise.lock to main (94f9a15); the toolchain re-resolves and the hermetic gate still passes.
Greptile SummaryThis PR adds mass-deletion protection for Snapshot cleanup paths. The main changes are:
|
| Filename | Overview |
|---|---|
| crates/controller/src/snapshot/mod.rs | Wires live deletion facts into the finalizer and dispatches repository-scoped batch delete Jobs. |
| crates/controller/src/snapshot/batch.rs | Adds batch membership, breaker counting, fire eligibility, throttling, and batch Job lifecycle helpers. |
| crates/controller/src/snapshot/plan.rs | Centralizes deletion decisions for cascade retention, namespace deletion, prune bypass, and breaker holds. |
| crates/controller/src/snapshot_schedule.rs | Stamps and propagates schedule deletion policy onto produced Snapshots. |
| crates/controller/src/io/prune.rs | Adds stamp-then-delete helpers for retention and failed-history prunes. |
| crates/mover/src/main.rs | Runs batch snapshot deletes and reports batch Jobs through log-only status handling. |
| crates/mover/src/workspec/mod.rs | Adds the batch snapshot-delete work-spec payload. |
| crates/e2e/tests/mass_deletion.rs | Adds e2e coverage for cascade retention, breaker hold/ack, batching, throttling, and prune interaction. |
Reviews (1): Last reviewed commit: "chore(mise): revert unintended node lock..." | Re-trigger Greptile
1 task
doonga
pushed a commit
to greyrock-labs/home-ops
that referenced
this pull request
Jul 21, 2026
…0.7.5 ➔ 0.8.0) (#107) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/home-operations/charts/kopiur](https://github.com/home-operations/kopiur) | minor | `0.7.5` → `0.8.0` | --- >⚠️ **Warning** > > Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/11) for more information. --- ### Release Notes <details> <summary>home-operations/kopiur (ghcr.io/home-operations/charts/kopiur)</summary> ### [`v0.8.0`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#080-2026-07-19) [Compare Source](home-operations/kopiur@0.7.5...0.8.0) ##### ⚠ BREAKING CHANGES - SnapshotPolicy deletion cascade + auto-adoption of discovered snapshots ([#​272](home-operations/kopiur#272)) ##### Features - **deps:** update rust crate tokio (1.52.4 → 1.53.0) ([#​264](home-operations/kopiur#264)) ([6cab0c6](home-operations/kopiur@6cab0c6)) - mass-deletion protection (cascade guard, per-repo breaker, batched deletes) ([#​265](home-operations/kopiur#265)) ([038ea6d](home-operations/kopiur@038ea6d)) - SnapshotPolicy deletion cascade + auto-adoption of discovered snapshots ([#​272](home-operations/kopiur#272)) ([9da8c26](home-operations/kopiur@9da8c26)) ##### Bug Fixes - **deps:** update rust crate anyhow (1.0.103 → 1.0.104) ([#​269](home-operations/kopiur#269)) ([4d81496](home-operations/kopiur@4d81496)) - **deps:** update rust crate clap (4.6.1 → 4.6.2) ([#​257](home-operations/kopiur#257)) ([c238df1](home-operations/kopiur@c238df1)) - **deps:** update rust crate futures (0.3.32 → 0.3.33) ([#​268](home-operations/kopiur#268)) ([926b52d](home-operations/kopiur@926b52d)) - **deps:** update rust crate serde (1.0.228 → 1.0.229) ([#​270](home-operations/kopiur#270)) ([5fbd713](home-operations/kopiur@5fbd713)) - **deps:** update rust crate thiserror (2.0.18 → 2.0.19) ([#​271](home-operations/kopiur#271)) ([d83730f](home-operations/kopiur@d83730f)) - **deps:** update rust crate tokio (1.52.3 → 1.52.4) ([#​261](home-operations/kopiur#261)) ([accf6ae](home-operations/kopiur@accf6ae)) - writable backup source ([#​254](home-operations/kopiur#254)), stuck deletion finalizer ([#​255](home-operations/kopiur#255)), kopia epoch parameters ([#​258](home-operations/kopiur#258)) ([#​263](home-operations/kopiur#263)) ([94f9a15](home-operations/kopiur@94f9a15)) ##### Miscellaneous Chores - **krew:** kopiur 0.7.5 manifest ([16d7390](home-operations/kopiur@16d7390)) - **mise:** Update tool aqua:astral-sh/uv (0.11.28 → 0.11.29) ([#​256](home-operations/kopiur#256)) ([f822335](home-operations/kopiur@f822335)) - **mise:** Update tool cosign (3.1.1 → 3.1.2) ([#​267](home-operations/kopiur#267)) ([649ba2e](home-operations/kopiur@649ba2e)) </details> --- ### Configuration 📅 **Schedule**: (in timezone America/New_York) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNjAuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19--> Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/107
eleboucher
pushed a commit
to eleboucher/homelab
that referenced
this pull request
Jul 23, 2026
…0.7.4 ➔ 0.8.0) (#1627) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/home-operations/charts/kopiur](https://github.com/home-operations/kopiur) | minor | `0.7.4` → `0.8.0` | --- ### Release Notes <details> <summary>home-operations/kopiur (ghcr.io/home-operations/charts/kopiur)</summary> ### [`v0.8.0`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#080-2026-07-19) [Compare Source](home-operations/kopiur@0.7.5...0.8.0) ##### ⚠ BREAKING CHANGES - SnapshotPolicy deletion cascade + auto-adoption of discovered snapshots ([#​272](home-operations/kopiur#272)) ##### Features - **deps:** update rust crate tokio (1.52.4 → 1.53.0) ([#​264](home-operations/kopiur#264)) ([6cab0c6](home-operations/kopiur@6cab0c6)) - mass-deletion protection (cascade guard, per-repo breaker, batched deletes) ([#​265](home-operations/kopiur#265)) ([038ea6d](home-operations/kopiur@038ea6d)) - SnapshotPolicy deletion cascade + auto-adoption of discovered snapshots ([#​272](home-operations/kopiur#272)) ([9da8c26](home-operations/kopiur@9da8c26)) ##### Bug Fixes - **deps:** update rust crate anyhow (1.0.103 → 1.0.104) ([#​269](home-operations/kopiur#269)) ([4d81496](home-operations/kopiur@4d81496)) - **deps:** update rust crate clap (4.6.1 → 4.6.2) ([#​257](home-operations/kopiur#257)) ([c238df1](home-operations/kopiur@c238df1)) - **deps:** update rust crate futures (0.3.32 → 0.3.33) ([#​268](home-operations/kopiur#268)) ([926b52d](home-operations/kopiur@926b52d)) - **deps:** update rust crate serde (1.0.228 → 1.0.229) ([#​270](home-operations/kopiur#270)) ([5fbd713](home-operations/kopiur@5fbd713)) - **deps:** update rust crate thiserror (2.0.18 → 2.0.19) ([#​271](home-operations/kopiur#271)) ([d83730f](home-operations/kopiur@d83730f)) - **deps:** update rust crate tokio (1.52.3 → 1.52.4) ([#​261](home-operations/kopiur#261)) ([accf6ae](home-operations/kopiur@accf6ae)) - writable backup source ([#​254](home-operations/kopiur#254)), stuck deletion finalizer ([#​255](home-operations/kopiur#255)), kopia epoch parameters ([#​258](home-operations/kopiur#258)) ([#​263](home-operations/kopiur#263)) ([94f9a15](home-operations/kopiur@94f9a15)) ##### Miscellaneous Chores - **krew:** kopiur 0.7.5 manifest ([16d7390](home-operations/kopiur@16d7390)) - **mise:** Update tool aqua:astral-sh/uv (0.11.28 → 0.11.29) ([#​256](home-operations/kopiur#256)) ([f822335](home-operations/kopiur@f822335)) - **mise:** Update tool cosign (3.1.1 → 3.1.2) ([#​267](home-operations/kopiur#267)) ([649ba2e](home-operations/kopiur@649ba2e)) ### [`v0.7.5`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#075-2026-07-16) [Compare Source](home-operations/kopiur@0.7.4...0.7.5) ##### Bug Fixes - **readme:** update readme admonition ([987957c](home-operations/kopiur@987957c)) - **secctx:** SecurityContextCompatible is verified, not asserted; inherit merges with explicit ([#​259](home-operations/kopiur#259)) ([cbfd97d](home-operations/kopiur@cbfd97d)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19--> Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/1627
hbjydev
pushed a commit
to hbjydev/phoebe
that referenced
this pull request
Aug 27, 2026
…0.7.3 → 0.10.4) (#273) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/home-operations/charts/kopiur](https://github.com/home-operations/kopiur) | minor | `0.7.3` → `0.10.4` | --- >⚠️ **Warning** > > Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/141) for more information. --- ### Release Notes <details> <summary>home-operations/kopiur (ghcr.io/home-operations/charts/kopiur)</summary> ### [`v0.10.4`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#0104-2026-08-24) [Compare Source](home-operations/kopiur@0.10.3...0.10.4) ##### Bug Fixes - **chart:** give flowSchema its doc comment and timings a clean schema entry ([#​397](home-operations/kopiur#397)) ([7c8dd3f](home-operations/kopiur@7c8dd3f)) - **mover:** read status.resolved via the /status subresource ([#​408](home-operations/kopiur#408)) ([06fc2f9](home-operations/kopiur@06fc2f9)) ##### Miscellaneous Chores - **github-action:** update action docker/github-builder (v1.16.0 → v1.17.0) ([#​407](home-operations/kopiur#407)) ([b6d7d04](home-operations/kopiur@b6d7d04)) - **mise:** update mise tools ([#​400](home-operations/kopiur#400)) ([b1a83f8](home-operations/kopiur@b1a83f8)) - **mise:** update tool kubectl (1.36.3 → 1.36.4) ([#​405](home-operations/kopiur#405)) ([274e3d6](home-operations/kopiur@274e3d6)) - **mise:** update tool lefthook (2.1.10 → 2.1.11) ([#​406](home-operations/kopiur#406)) ([2ba700d](home-operations/kopiur@2ba700d)) - **mise:** update tool rust (1.97.1 → 1.98.0) ([#​403](home-operations/kopiur#403)) ([c655005](home-operations/kopiur@c655005)) - **mise:** update tool yq (4.53.3 → 4.53.4) ([#​402](home-operations/kopiur#402)) ([d1ed8a7](home-operations/kopiur@d1ed8a7)) - **mise:** update tool yq (4.53.4 → 4.53.6) ([#​404](home-operations/kopiur#404)) ([dd5878c](home-operations/kopiur@dd5878c)) ### [`v0.10.3`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#0103-2026-08-18) [Compare Source](home-operations/kopiur@0.10.2...0.10.3) ##### Features - **repository:** seed a fresh repository from its replica — DR for replicated repositories ([#​380](home-operations/kopiur#380)) ([#​396](home-operations/kopiur#396)) ([74665dc](home-operations/kopiur@74665dc)) ##### Bug Fixes - **rust:** update crate cel (0.14.2 → 0.14.3) ([#​387](home-operations/kopiur#387)) ([bf9aa0c](home-operations/kopiur@bf9aa0c)) - **rust:** update crate http-body-util (0.1.4 → 0.1.5) ([#​381](home-operations/kopiur#381)) ([6354e17](home-operations/kopiur@6354e17)) ##### Miscellaneous Chores - **github-action:** update action jdx/mise-action (v4.2.4 → v4.2.5) ([#​388](home-operations/kopiur#388)) ([1040c9e](home-operations/kopiur@1040c9e)) - **mise:** update tool aqua:astral-sh/uv (0.12.3 → 0.12.4) ([#​390](home-operations/kopiur#390)) ([bf3916c](home-operations/kopiur@bf3916c)) - **mise:** update tool aqua:astral-sh/uv (0.12.4 → 0.12.5) ([#​395](home-operations/kopiur#395)) ([b919878](home-operations/kopiur@b919878)) - **mise:** update tool helm (4.2.3 → 4.2.4) ([#​389](home-operations/kopiur#389)) ([5b134fa](home-operations/kopiur@5b134fa)) - **mise:** Update tool oxfmt (0.62.0 → 0.63.0) ([#​386](home-operations/kopiur#386)) ([65db237](home-operations/kopiur@65db237)) ### [`v0.10.2`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#0102-2026-08-13) [Compare Source](home-operations/kopiur@0.10.1...0.10.2) ##### Performance Improvements - **controller:** store-backed reads, LIST dedup, bounded PVC retries, client-side request metrics ([#​382](home-operations/kopiur#382)) ([#​383](home-operations/kopiur#383)) ([2b07022](home-operations/kopiur@2b07022)) ### [`v0.10.1`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#0101-2026-08-11) [Compare Source](home-operations/kopiur@0.10.0...0.10.1) ##### Bug Fixes - **mise:** something about mise warnings ([#​373](home-operations/kopiur#373)) ([fde8073](home-operations/kopiur@fde8073)) - **rust:** update crate cel (0.14.1 → 0.14.2) ([#​379](home-operations/kopiur#379)) ([4a60221](home-operations/kopiur@4a60221)) - **rust:** update crate futures (0.3.33 → 0.3.34) ([#​378](home-operations/kopiur#378)) ([ff657b8](home-operations/kopiur@ff657b8)) - **rust:** update crate rcgen (0.14.8 → 0.14.9) ([#​377](home-operations/kopiur#377)) ([e3b3b3f](home-operations/kopiur@e3b3b3f)) ##### Miscellaneous Chores - **mise:** Update tool aqua:astral-sh/uv (0.12.2 → 0.12.3) ([#​375](home-operations/kopiur#375)) ([952af6d](home-operations/kopiur@952af6d)) ### [`v0.10.0`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#0100-2026-08-09) [Compare Source](home-operations/kopiur@0.9.5...0.10.0) ##### ⚠ BREAKING CHANGES - **rust:** Update crate base64 (0.22.1 → 0.23.1) ([#​366](home-operations/kopiur#366)) ##### Features - **rust:** Update crate base64 (0.22.1 → 0.23.1) ([#​366](home-operations/kopiur#366)) ([2c6e3e7](home-operations/kopiur@2c6e3e7)) - SnapshotReplication (logical snapshot-level replication) + SnapshotPolicy multi-repository fan-out ([#​370](home-operations/kopiur#370)) ([4e06e42](home-operations/kopiur@4e06e42)) ##### Continuous Integration - **github-action:** Update action Swatinem/rust-cache (v2.9.1 → v2.9.2) ([#​372](home-operations/kopiur#372)) ([e4ce173](home-operations/kopiur@e4ce173)) ##### Miscellaneous Chores - **mise:** Update mise tools ([#​367](home-operations/kopiur#367)) ([d6f82f4](home-operations/kopiur@d6f82f4)) - **mise:** Update tool cosign (3.1.2 → 3.1.3) ([#​371](home-operations/kopiur#371)) ([558b9f4](home-operations/kopiur@558b9f4)) ### [`v0.9.5`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#095-2026-08-08) [Compare Source](home-operations/kopiur@0.9.4...0.9.5) ##### Bug Fixes - deliver s3 tls.caBundleRef to every kopia invocation ([#​365](home-operations/kopiur#365)) ([cda0237](home-operations/kopiur@cda0237)) - doctor misses structurally-blocked work ([#​359](home-operations/kopiur#359)) + phase/gate exhaustiveness ratchet ([#​363](home-operations/kopiur#363)) ([b844974](home-operations/kopiur@b844974)) - **rust:** update crate thiserror (2.0.19 → 2.0.20) ([#​360](home-operations/kopiur#360)) ([4aa646d](home-operations/kopiur@4aa646d)) ##### Continuous Integration - **github-action:** Update action docker/github-builder (v1.15.0 → v1.16.0) ([#​362](home-operations/kopiur#362)) ([db32818](home-operations/kopiur@db32818)) ### [`v0.9.4`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#094-2026-08-08) [Compare Source](home-operations/kopiur@0.9.3...0.9.4) ##### Features - **docs:** Update README.md ([#​358](home-operations/kopiur#358)) ([05d2506](home-operations/kopiur@05d2506)) ##### Bug Fixes - implement pvcSelector/groupBy ([#​346](home-operations/kopiur#346)) and model deduped backups as Unchanged ([#​351](home-operations/kopiur#351)) ([#​354](home-operations/kopiur#354)) ([a2b9ae6](home-operations/kopiur@a2b9ae6)) - **rust:** update crate clap (4.6.5 → 4.6.6) ([#​357](home-operations/kopiur#357)) ([e9ca396](home-operations/kopiur@e9ca396)) ##### Miscellaneous Chores - **mise:** Update tool node (24.18.1 → v24.19.0) ([#​353](home-operations/kopiur#353)) ([2f28c6d](home-operations/kopiur@2f28c6d)) - **mise:** Update tool oxfmt (0.61.0 → 0.62.0) ([#​356](home-operations/kopiur#356)) ([e95df6b](home-operations/kopiur@e95df6b)) ### [`v0.9.3`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#093-2026-08-05) [Compare Source](home-operations/kopiur@0.9.2...0.9.3) ##### Features - repository-level circuit breaker — stop fanning out doomed Jobs when the backend is unreachable ([#​350](home-operations/kopiur#350)) ([5d787b9](home-operations/kopiur@5d787b9)) ##### Bug Fixes - **rust:** update crate base64 (0.23.0 → 0.23.1) ([#​349](home-operations/kopiur#349)) ([11e7aa8](home-operations/kopiur@11e7aa8)) ##### Continuous Integration - **github-action:** Update action jdx/mise-action (v4.2.3 → v4.2.4) ([#​347](home-operations/kopiur#347)) ([1c9cf3b](home-operations/kopiur@1c9cf3b)) ##### Miscellaneous Chores - **renovate:** keep 0.x minors out of automerge ([#​352](home-operations/kopiur#352)) ([95d672a](home-operations/kopiur@95d672a)) ### [`v0.9.2`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#092-2026-08-02) [Compare Source](home-operations/kopiur@0.9.1...0.9.2) ##### Features - **repository:** object-lock blob retention ([#​332](home-operations/kopiur#332)); fix blank volumeSnapshotClassName ([#​344](home-operations/kopiur#344)) ([dab8fdd](home-operations/kopiur@dab8fdd)) ##### Bug Fixes - **ci:** fail the merge gate on cancelled jobs, and cut e2e artifact time ([#​330](home-operations/kopiur#330)) ([1847a8a](home-operations/kopiur@1847a8a)) - **rust:** update crate time (0.3.54 → 0.3.55) ([#​337](home-operations/kopiur#337)) ([ee1b951](home-operations/kopiur@ee1b951)) ##### Continuous Integration - **github-action:** Update action docker/github-builder (v1.14.0 → v1.15.0) ([#​327](home-operations/kopiur#327)) ([f5514fc](home-operations/kopiur@f5514fc)) - **github-action:** Update action docker/login-action (v4.5.1 → v4.5.2) ([#​331](home-operations/kopiur#331)) ([d90efdf](home-operations/kopiur@d90efdf)) - **github-action:** Update action docker/login-action (v4.5.2 → v4.6.0) ([#​339](home-operations/kopiur#339)) ([b783bcc](home-operations/kopiur@b783bcc)) - **github-action:** Update action home-operations/.github/actions/workflow-lint (v1.0.2 → v1.0.3) ([#​343](home-operations/kopiur#343)) ([4af16d5](home-operations/kopiur@4af16d5)) - update shared actions and use self-repository syntax ([#​341](home-operations/kopiur#341)) ([559e23f](home-operations/kopiur@559e23f)) ##### Miscellaneous Chores - **deps:** lock file maintenance (pep621) ([#​334](home-operations/kopiur#334)) ([e19ae0e](home-operations/kopiur@e19ae0e)) - **mise:** Lock file maintenance tool (mise) ([#​335](home-operations/kopiur#335)) ([666afb5](home-operations/kopiur@666afb5)) - **mise:** prune lockfile to used platforms ([#​342](home-operations/kopiur#342)) ([741d6a4](home-operations/kopiur@741d6a4)) - **mise:** Update tool aqua:astral-sh/uv (0.12.0 → 0.12.1) ([#​333](home-operations/kopiur#333)) ([3ed2766](home-operations/kopiur@3ed2766)) - **mise:** Update tool promtool (3.13.1 → 3.13.2) ([#​329](home-operations/kopiur#329)) ([ac1752e](home-operations/kopiur@ac1752e)) - **mise:** Update tool zizmor (1.28.0 → 1.29.0) ([#​340](home-operations/kopiur#340)) ([410dc26](home-operations/kopiur@410dc26)) - **release-please:** standardize the release pull request title pattern ([#​338](home-operations/kopiur#338)) ([21013a3](home-operations/kopiur@21013a3)) - **rust:** lock file maintenance crate (cargo) ([#​336](home-operations/kopiur#336)) ([8606177](home-operations/kopiur@8606177)) ### [`v0.9.1`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#091-2026-07-29) [Compare Source](home-operations/kopiur@0.9.0...0.9.1) ##### Features - **rust:** update crate http (1.4.2 → 1.5.0) ([#​323](home-operations/kopiur#323)) ([cf0b149](home-operations/kopiur@cf0b149)) ##### Bug Fixes - **controller:** survive a slow API server instead of abdicating on the first one ([#​319](home-operations/kopiur#319)) ([#​324](home-operations/kopiur#324)) ([df7e90c](home-operations/kopiur@df7e90c)) - **rust:** update crate rustls (0.23.42 → 0.23.43) ([#​326](home-operations/kopiur#326)) ([2f5123e](home-operations/kopiur@2f5123e)) ##### Tests - **e2e:** retry flaky tests with cargo-nextest ([#​322](home-operations/kopiur#322)) ([558ac85](home-operations/kopiur@558ac85)) ##### Miscellaneous Chores - **mise:** Update tool aqua:astral-sh/uv (0.11.33 → 0.12.0) ([#​320](home-operations/kopiur#320)) ([66ec350](home-operations/kopiur@66ec350)) - **mise:** Update tool node (24.18.0 → v24.18.1) ([#​325](home-operations/kopiur#325)) ([1c833a4](home-operations/kopiur@1c833a4)) ### [`v0.9.0`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#090-2026-07-28) [Compare Source](home-operations/kopiur@0.8.1...0.9.0) ##### ⚠ BREAKING CHANGES - **rust:** Update crate serial\_test (3.5.0 → 4.0.1) ([#​307](home-operations/kopiur#307)) - **secctx:** identity-aware mover merge, recorded snapshot identity, restore inherit-from-snapshot ([#​304](home-operations/kopiur#304)) ##### Features - **rust:** Update crate serial\_test (3.5.0 → 4.0.1) ([#​307](home-operations/kopiur#307)) ([4392e4a](home-operations/kopiur@4392e4a)) - **secctx:** identity-aware mover merge, recorded snapshot identity, restore inherit-from-snapshot ([#​304](home-operations/kopiur#304)) ([0632a29](home-operations/kopiur@0632a29)) ##### Bug Fixes - **rust:** update crate cel (0.14.0 → 0.14.1) ([#​317](home-operations/kopiur#317)) ([00cf539](home-operations/kopiur@00cf539)) - **rust:** update crate schemars (1.2.1 → 1.2.2) ([#​313](home-operations/kopiur#313)) ([b6e6268](home-operations/kopiur@b6e6268)) ##### Build System - **mise:** add actionlint and refresh the lockfile ([#​309](home-operations/kopiur#309)) ([e74c9b3](home-operations/kopiur@e74c9b3)) ##### Continuous Integration - adopt the shared workflow-lint and docs-build actions ([#​310](home-operations/kopiur#310)) ([7d4b329](home-operations/kopiur@7d4b329)) - gate pull requests on Build Success and share the docs build ([#​306](home-operations/kopiur#306)) ([1b693aa](home-operations/kopiur@1b693aa)) - **github-action:** Update action docker/login-action (v4.5.0 → v4.5.1) ([#​312](home-operations/kopiur#312)) ([29d00b1](home-operations/kopiur@29d00b1)) - **github-action:** Update action jdx/mise-action (v4.2.1 → v4.2.2) ([#​311](home-operations/kopiur#311)) ([65bbca4](home-operations/kopiur@65bbca4)) - **github-action:** Update action jdx/mise-action (v4.2.2 → v4.2.3) ([#​315](home-operations/kopiur#315)) ([5f517d4](home-operations/kopiur@5f517d4)) - skip release-please PRs in checks and drop nightly e2e ([#​305](home-operations/kopiur#305)) ([ee6d4f5](home-operations/kopiur@ee6d4f5)) ##### Miscellaneous Chores - **krew:** kopiur 0.8.1 manifest ([84df757](home-operations/kopiur@84df757)) - **mise:** Update tool aqua:astral-sh/uv (0.11.32 → 0.11.33) ([#​318](home-operations/kopiur#318)) ([f63bc3a](home-operations/kopiur@f63bc3a)) - **mise:** Update tool oxfmt (0.60.0 → 0.61.0) ([#​314](home-operations/kopiur#314)) ([bdbf6c6](home-operations/kopiur@bdbf6c6)) - **renovate:** drop the stale automerge overrides ([#​308](home-operations/kopiur#308)) ([c13a3d5](home-operations/kopiur@c13a3d5)) - standardize release-please changelog sections ([#​316](home-operations/kopiur#316)) ([273d0f8](home-operations/kopiur@273d0f8)) ### [`v0.8.1`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#081-2026-07-24) [Compare Source](home-operations/kopiur@0.8.0...0.8.1) ##### Features - **deps:** update rust crate base64 (0.22.1 → 0.23.0) ([#​293](home-operations/kopiur#293)) ([5ab14d5](home-operations/kopiur@5ab14d5)) - **deps:** update rust crate kube (4.0.0 → 4.2.0) ([#​288](home-operations/kopiur#288)) ([b067458](home-operations/kopiur@b067458)) - httpRequest hook headers ([#​290](home-operations/kopiur#290)) + recovery-aware alerts ([#​280](home-operations/kopiur#280)) ([#​296](home-operations/kopiur#296)) ([f388a14](home-operations/kopiur@f388a14)) - **renovate:** automerge if it passes CI ([66f243f](home-operations/kopiur@66f243f)) ##### Bug Fixes - **controller:** survive an API-server outage without exhausting file descriptors ([#​287](home-operations/kopiur#287)) ([ce184b6](home-operations/kopiur@ce184b6)) - **deps:** update rust crate clap (4.6.2 → 4.6.3) ([#​277](home-operations/kopiur#277)) ([e3d4113](home-operations/kopiur@e3d4113)) - **deps:** update rust crate libc (0.2.186 → 0.2.189) ([#​283](home-operations/kopiur#283)) ([2b2e636](home-operations/kopiur@2b2e636)) - **deps:** update rust crate serde\_json (1.0.150 → 1.0.151) ([#​275](home-operations/kopiur#275)) ([1410f42](home-operations/kopiur@1410f42)) - **deps:** update rust crate time (0.3.53 → 0.3.54) ([#​276](home-operations/kopiur#276)) ([ff250ff](home-operations/kopiur@ff250ff)) - **deps:** update rust crate tokio (1.53.0 → 1.53.1) ([#​281](home-operations/kopiur#281)) ([82082e9](home-operations/kopiur@82082e9)) - **helm:** stamp Chart.yaml version on release + document image sub-fields ([#​289](home-operations/kopiur#289)) ([041549a](home-operations/kopiur@041549a)) - **probe:** stamp the health probe at launch so it stops recycling its Job ([#​273](home-operations/kopiur#273)) ([#​278](home-operations/kopiur#278)) ([7fa3657](home-operations/kopiur@7fa3657)) - **release:** use the generic updater for Chart.yaml + stamp README badges ([#​292](home-operations/kopiur#292)) ([f4a3141](home-operations/kopiur@f4a3141)) - retention-aware adoption stops the adopt/prune/rediscover livelock ([#​299](home-operations/kopiur#299)) ([4093f12](home-operations/kopiur@4093f12)) ##### Styles - indent markdown at 2 to match embedded yaml ([#​279](home-operations/kopiur#279)) ([06885e0](home-operations/kopiur@06885e0)) ##### Miscellaneous Chores - **github-release:** Update release helm-unittest/helm-unittest (v1.1.1 → v1.1.2) ([#​301](home-operations/kopiur#301)) ([e62272d](home-operations/kopiur@e62272d)) - **krew:** kopiur 0.8.0 manifest ([2be416f](home-operations/kopiur@2be416f)) - **mise:** Update tool aqua:astral-sh/uv (0.11.29 → 0.11.30) ([#​282](home-operations/kopiur#282)) ([e12f96c](home-operations/kopiur@e12f96c)) - **mise:** Update tool aqua:astral-sh/uv (0.11.30 → 0.11.31) ([#​286](home-operations/kopiur#286)) ([a3f31e6](home-operations/kopiur@a3f31e6)) - **mise:** Update tool aqua:astral-sh/uv (0.11.31 → 0.11.32) ([#​298](home-operations/kopiur#298)) ([9d8c171](home-operations/kopiur@9d8c171)) - **mise:** Update tool kubectl (1.36.2 → 1.36.3) ([#​291](home-operations/kopiur#291)) ([ef290f8](home-operations/kopiur@ef290f8)) - **mise:** Update tool oxfmt (0.59.0 → 0.60.0) ([#​284](home-operations/kopiur#284)) ([ad8a18a](home-operations/kopiur@ad8a18a)) - **mise:** Update tool rust (1.96.1 → 1.97.1) ([#​222](home-operations/kopiur#222)) ([fbeb2fa](home-operations/kopiur@fbeb2fa)) - **mise:** Update tool zizmor (1.27.0 → 1.28.0) ([#​285](home-operations/kopiur#285)) ([9ef35ce](home-operations/kopiur@9ef35ce)) ### [`v0.8.0`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#080-2026-07-19) [Compare Source](home-operations/kopiur@0.7.5...0.8.0) ##### ⚠ BREAKING CHANGES - SnapshotPolicy deletion cascade + auto-adoption of discovered snapshots ([#​272](home-operations/kopiur#272)) ##### Features - **deps:** update rust crate tokio (1.52.4 → 1.53.0) ([#​264](home-operations/kopiur#264)) ([6cab0c6](home-operations/kopiur@6cab0c6)) - mass-deletion protection (cascade guard, per-repo breaker, batched deletes) ([#​265](home-operations/kopiur#265)) ([038ea6d](home-operations/kopiur@038ea6d)) - SnapshotPolicy deletion cascade + auto-adoption of discovered snapshots ([#​272](home-operations/kopiur#272)) ([9da8c26](home-operations/kopiur@9da8c26)) ##### Bug Fixes - **deps:** update rust crate anyhow (1.0.103 → 1.0.104) ([#​269](home-operations/kopiur#269)) ([4d81496](home-operations/kopiur@4d81496)) - **deps:** update rust crate clap (4.6.1 → 4.6.2) ([#​257](home-operations/kopiur#257)) ([c238df1](home-operations/kopiur@c238df1)) - **deps:** update rust crate futures (0.3.32 → 0.3.33) ([#​268](home-operations/kopiur#268)) ([926b52d](home-operations/kopiur@926b52d)) - **deps:** update rust crate serde (1.0.228 → 1.0.229) ([#​270](home-operations/kopiur#270)) ([5fbd713](home-operations/kopiur@5fbd713)) - **deps:** update rust crate thiserror (2.0.18 → 2.0.19) ([#​271](home-operations/kopiur#271)) ([d83730f](home-operations/kopiur@d83730f)) - **deps:** update rust crate tokio (1.52.3 → 1.52.4) ([#​261](home-operations/kopiur#261)) ([accf6ae](home-operations/kopiur@accf6ae)) - writable backup source ([#​254](home-operations/kopiur#254)), stuck deletion finalizer ([#​255](home-operations/kopiur#255)), kopia epoch parameters ([#​258](home-operations/kopiur#258)) ([#​263](home-operations/kopiur#263)) ([94f9a15](home-operations/kopiur@94f9a15)) ##### Miscellaneous Chores - **krew:** kopiur 0.7.5 manifest ([16d7390](home-operations/kopiur@16d7390)) - **mise:** Update tool aqua:astral-sh/uv (0.11.28 → 0.11.29) ([#​256](home-operations/kopiur#256)) ([f822335](home-operations/kopiur@f822335)) - **mise:** Update tool cosign (3.1.1 → 3.1.2) ([#​267](home-operations/kopiur#267)) ([649ba2e](home-operations/kopiur@649ba2e)) ### [`v0.7.5`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#075-2026-07-16) [Compare Source](home-operations/kopiur@0.7.4...0.7.5) ##### Bug Fixes - **readme:** update readme admonition ([987957c](home-operations/kopiur@987957c)) - **secctx:** SecurityContextCompatible is verified, not asserted; inherit merges with explicit ([#​259](home-operations/kopiur#259)) ([cbfd97d](home-operations/kopiur@cbfd97d)) ### [`v0.7.4`](https://github.com/home-operations/kopiur/blob/HEAD/CHANGELOG.md#074-2026-07-15) [Compare Source](home-operations/kopiur@0.7.3...0.7.4) ##### Features - bound Snapshot CR reconcile cost at scale ([#​249](home-operations/kopiur#249)) ([#​253](home-operations/kopiur#253)) ([3697aa9](home-operations/kopiur@3697aa9)) - **docs:** clean up admonitions in docs ([71c5d85](home-operations/kopiur@71c5d85)) - multi-cluster shared repository support — cluster identity, foreign-aware discovery, collision-free maintenance leases ([#​251](home-operations/kopiur#251)) ([a4593d8](home-operations/kopiur@a4593d8)) ##### Bug Fixes - batch of six open-issue fixes ([#​248](home-operations/kopiur#248) [#​238](home-operations/kopiur#238) [#​245](home-operations/kopiur#245) [#​196](home-operations/kopiur#196) [#​237](home-operations/kopiur#237) [#​250](home-operations/kopiur#250)) ([#​252](home-operations/kopiur#252)) ([045a5a5](home-operations/kopiur@045a5a5)) - **deps:** update rust crate http-body-util (0.1.3 → 0.1.4) ([#​244](home-operations/kopiur#244)) ([4878006](home-operations/kopiur@4878006)) - **deps:** update rust crate rustls (0.23.41 → 0.23.42) ([#​243](home-operations/kopiur#243)) ([13b1dc4](home-operations/kopiur@13b1dc4)) ##### Miscellaneous Chores - **krew:** kopiur 0.7.3 manifest ([d521675](home-operations/kopiur@d521675)) - **mise:** Update tool aqua:EmbarkStudios/cargo-deny (0.19.9 → 0.20.2) ([#​226](home-operations/kopiur#226)) ([9c109b4](home-operations/kopiur@9c109b4)) - **mise:** Update tool oxfmt (0.58.0 → 0.59.0) ([#​246](home-operations/kopiur#246)) ([41625e9](home-operations/kopiur@41625e9)) - **mise:** Update tool zizmor (1.26.1 → 1.27.0) ([#​247](home-operations/kopiur#247)) ([fe10a6a](home-operations/kopiur@fe10a6a)) </details> --- ### Configuration 📅 **Schedule**: (in timezone Europe/London) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNjAuMiIsInVwZGF0ZWRJblZlciI6IjQ0LjQ2LjUiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbInJlbm92YXRlL2NvbnRhaW5lciIsInR5cGUvbWlub3IiXX0=--> Reviewed-on: https://forgejo.hayden.moe/hayden/phoebe/pulls/273
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A user's kro tooling briefly deleted and recreated their SnapshotSchedules. Every scheduled
Snapshot carries an ownerReference to its schedule, so Kubernetes GC cascade-deleted roughly 600
to 700 Snapshot CRs in one burst. Each CR defaulted to
deletionPolicy: Delete, and each finalizerspawned its own mover Job running
kopia snapshot deletewith no concurrency bound anywhere. Theresult was hundreds of pods actively destroying backup history, stopped only because the user
noticed in time. Deleting all of your backups while making the cluster suffer should not be the
default behavior of a backup operator.
There were three uncapped delete surfaces: external cascades (this incident, but also GitOps prunes
and bulk kubectl deletes), the GFS retention prune, and the failed-history prune. Only the
namespace-deletion axis had a guard (
onNamespaceDelete, default Orphan).What
One discriminator plus three guards, all decided in pure, exhaustively matched functions
(ADR-0006 has the full rationale):
pruned-bydiscriminator. The operator's own prune paths now stampkopiur.home-operations.com/pruned-by: retention|failed-historybefore deleting, so the finalizer cantell Kopiur's lifecycle from an external deletion. Unrecognized values are treated as external
(fail-safe).
Schedule-deletion cascade guard. New
SnapshotSchedule.spec.deletion.onScheduleDelete(default
Retain), stamped onto every produced Snapshot and propagated on edit. When a Snapshotis deleted externally and its owning schedule is gone, terminating, or was replaced (UID
mismatch), an effective
Deletedowngrades to a retain: the finalizer releases with zero repocontact, a Warning event is emitted, and the catalog rediscovers the kopia snapshots as
origin: discovered(forced Retain) within the catalog interval. The pre-upgrade fleet isprotected retroactively because an absent stamp resolves to Retain. Deliberate cascade remains
available by setting
onScheduleDelete: Delete.Per-repository mass-deletion breaker. New
deletionProtection.thresholdon both repositorykinds (default 10,
0disables). When pending external destructive deletions reach thethreshold, they hold: no delete work happens, the Snapshot gets a
DeletionHeldcondition whosemessage contains the exact ack command and the value to copy, and the repository mirrors a
MassDeletionHeldcondition. Release is a timestamp-valued annotation(
kopiur.home-operations.com/allow-mass-deletion) that only frees deletions requested at or before theacked instant, so a stale ack committed to Git is inert against any later wave. Operator prunes
bypass the breaker by design; retention keeps working during a held wave.
Batched, optionally capped execution. Deletions now aggregate per repository into one mover
Job (up to 200 manifest ids over a single repo connect, ~10s accumulation window) instead of one
Job per Snapshot. A lone delete is a batch of one. The old per-CR delete Job is retired (an
adoption shim honors in-flight legacy Jobs across the upgrade, removal tracked for next
release). A global concurrency cap exists as an opt-in backstop
(
maxConcurrentDeleteJobs, default uncapped) since batching already collapses the incidentscenario to about three pods; a small default cap would only add head-of-line blocking.
The counting and firing filters deliberately diverge: breaker counting over-includes (trips
earlier, fail-safe), batch firing under-includes (held, namespace-terminating-orphan-destined,
unpinned-peer, and unsynced-schedule-owned members are excluded and simply retry). An excluded
member requeues; it is never silently dropped.
Bugs found and fixed along the way
The e2e tiers caught three real bugs during development, each now guarded by a regression test:
wait_until_ready()on the controller's own store races the applier's getter(kube-rs
DelayedInitholds a single waker); the synced flag never flipped and every externaldeletion deferred forever. Fixed by flipping the flag from reconcile, which kube-runtime already
gates behind the store's init swap.
batch could be re-enrolled before their finalizers released, serializing mass drains at scale.
retention prune sweep held members' data into its batch without an ack. The flagship e2e scenario
(held wave survives a concurrent prune untouched) now pins the fix.
Testing
guard (schedule delete leaves kopia intact, zero delete Jobs, rediscovery), breaker hold/ack
drain with real kopia-side count assertions, concurrent-wave disjointness, throttle cap,
repo-outage retry convergence, and held-wave-vs-prune. Full suite green (known local-only NFS
failures excepted, unchanged from main).
ending in
kopia snapshot deleteand every finalizer release that skips deletion.Upgrade notes
repository pin for pre-Snapshot deletion remains stuck when its credential-projecting SnapshotPolicy was deleted first #255 CRs so per-repo breaker counting sees them.
concurrent external CR deletions should raise it or set
0.{name}-deleteJob names (dashboards, alerts) should switch to thesnapdel-*batch Jobs and the newkopiur_snapshot_deletions*metrics.stamp; a very large wave may need one ack.
Closes the incident class discussed in Discord; supersedes nothing.