Repository navigation
feat: multi-cluster shared repository support — cluster identity, foreign-aware discovery, collision-free maintenance leases - #251
Merged
Conversation
Several kopia-snapshot matchers resolved "which snapshot is mine" by source path only, ignoring the recorded username/hostname. A path like /pvc/data repeats across namespaces, and — in a shared repository — across clusters, so a path-only match can silently select ANOTHER identity's snapshot: in the delete self-heal (mover main.rs, after a recorded-id delete no-ops on a stale id) this means deleting someone else's snapshot; in quick/deep verify and restore-heal it means verifying or restoring the wrong source's data; in the controller's in-process (filesystem-repo) success resolution it means stamping the wrong snapshot id onto a Snapshot's status. Fix: thread an optional (username, hostname) identity filter through every matcher, applied in addition to path whenever the caller has one. Absent identity (older anchors/work specs) falls back to today's path-only behavior exactly — no CRD fields, no behavior change when identities are distinct per source. - SnapshotAnchor (mover work-spec wire type) gains optional username/hostname, serde-defaulted for back-compat; every producer (Snapshot delete/pin anchor, Restore source anchor) now populates them from the already-resolved identity in scope. - match_current_manifest (mover resolve.rs) and resolve_latest_snapshot (mover main.rs, quick/deep verify + restore-heal) both require identity when given; share one pure predicate (matches_source). - resolve_succeeded_snapshot's inline path-only match (controller snapshot/ mod.rs) is extracted into a unit-tested pure predicate (matches_snapshot_identity) and now requires identity too. Fixes the stale "the source path IS authoritative" comment, which is false once two sources share a path. Regression tests added at every layer: same path + different hostname ⇒ no match (the core regression guard), same path + same identity ⇒ match, legacy anchor/no-identity ⇒ path-only behavior preserved, ambiguity handling unchanged, plus SnapshotAnchor serde back-compat/round-trip coverage.
…FS is the sole deleter kopia's `snapshot create` unconditionally applies the source's own retention policy after every create (policy.ApplyRetentionPolicy, even under --override-source), and with no policy set kopia's own defaults apply (keep-latest 10, hourly 48, daily 7, weekly 4, monthly 24, annual 3). Any SnapshotPolicy.spec.retention window wider than those defaults had kopia silently deleting manifests that Succeeded Snapshot CRs still reference, surfacing only at restore. Kopiur's design is that CR-driven GFS is the SOLE deleter; this restores that invariant via two mechanisms: 1. The mover now pins all six kopia --keep-* fields to KOPIA_KEEP_MAX (i32::MAX) at the identity scope before every snapshot create, regardless of whether a SnapshotPolicy configures anything (kopiur_kopia::PolicyArgs grew the six fields; not exposed on any CRD/workspec surface, matching the existing kopia-side-retention-forbidden rule). 2. Every KopiaClient now carries --no-auto-maintenance globally: kopia opportunistically runs maintenance as a side effect of snapshot create/delete/expire (and even a bare policy set) when the connected identity is the maintenance owner; only the Maintenance CR's explicit `maintenance run` may trigger it. Verified against the pinned kopia 0.23.1 binary: twelve snapshot creates under one identity with no override left only 10 manifests (kopia's own keep-latest); with the identity-scope pin applied first, all 12 survived. That is now a permanent integration regression guard.
…hostname classification Multi-cluster shared-repository support (M1, api-crate only): N clusters backing up same-named namespaces into one shared ClusterRepository currently collide on kopia identity (hostname defaults to bare `<namespace>`), so one cluster's GFS retention prune can delete another cluster's snapshots. Adds `ClusterRepository.spec.identityDefaults.cluster` (an RFC 1123 label, no dots — the first `.` in a hostname is now the namespace/cluster delimiter). Hostname resolution precedence becomes: explicit `spec.identity.hostname` override > `hostnameExpr` > `<namespace>.<cluster>` (cluster set) > `namespace` (unchanged bare default). `cluster` is also always declared in the identity CEL environment (`""` when unset), so `hostnameExpr`/ `usernameExpr` can reference it directly, e.g. `namespace + '.' + cluster`; the admission-time trial context declares a non-empty placeholder so such an expression validates regardless of whether this particular repository sets `cluster`. `classify_hostname`/`HostClass` give the read path (retention, discovered Snapshot placement — later milestones) a total, pure way to tell whether a stored hostname is this cluster's own, another cluster's, or predates cluster identity (Bare) by splitting on the FIRST `.`. `validate_cluster_name` enforces the RFC 1123 shape at admission (webhook) and defensively (controller), wired into `validate_cluster_repository`. Additive and back-compat: no schema default (context-dependent), absent field behaves exactly as before. Placement, catalog, and webhook wiring beyond shape validation are out of scope here and land in later milestones. Includes regenerated deploy/crds, deploy/helm CRDs, and docs/field-reference.md (cargo xtask gen-all).
…y consumers Identity is re-resolved from the LIVE repository on every reconcile/backup (controller/snapshot_policy.rs, io/repo.rs) — nothing about a ClusterRepository's identityDefaults is pinned the way a policy's own spec.identity is. So editing identityDefaults on a live ClusterRepository silently re-identifies every consumer SnapshotPolicy on its next backup, with no per-policy edit to acknowledge it: new snapshots fork to a new kopia lineage while the old history orphans (GFS retention never prunes across the split). The existing fork guard (identity_fork.rs) only fires on a SnapshotPolicy's own UPDATE; nothing guarded the repository side of the same hole. This also doubles as the migration gate for setting `cluster` on a fleet with history (M1). - kopiur-api: new pure `detect_repository_identity_change` (mirrors detect_identity_fork) plus `ValidationError::RepositoryIdentityWouldFork`, rendered via `describe_identity_change_consumers` (count + up to 5 names + "and N more") so the deny message and the ack warning name policies identically. - kopiur-webhook: new identity_repo_edit module is the thin IO layer — cluster-wide SnapshotPolicy LIST (mirrors identity_collision.rs), keeping consumers that reference the edited repository, have snapshot history, and don't pin both username+hostname (fully pinned policies never consult defaults). Wired into handle_cluster_repository, which is now async and client-taking like the other handlers; the same kopiur.home-operations.com/allow-identity-change annotation from the per-policy guard acknowledges the change and surfaces an admission WARNING naming what was re-identified. - Fail-open posture matches identity_fork/identity_collision: no client, or the consumer LIST failing (403 under a namespaced Role install, apiserver blip), degrades to allow with a tracing::warn! — a repository apply must never wedge on a best-effort admission check. - Residual gap, by design: a delete + re-apply is a CREATE with no oldObject to diff, so it bypasses this guard exactly like the per-policy fork guard's CREATE gap. - The namespaced Repository handler is made async/client-taking for signature parity, but RepositorySpec has no identityDefaults field yet (that's M5) — left a // M5: wiring note plus an #[ignore]d placeholder test that fails loudly if accidentally un-ignored. - RBAC: no change. The webhook shares the operator ServiceAccount/ClusterRole, which already grants list/get/watch on snapshotpolicies cluster-wide; gen-check confirms no drift.
Adds the typed policy for what catalog discovery does with snapshots
classified as another cluster's (classify_hostname's ForeignCluster case),
plus status visibility. API crate + regenerated deploy/ only — the
controller consumes these in a later milestone.
- ForeignSnapshots enum (common/cache.rs): Ignore (default; skip, count
only) or Fallback (materialize into catalog.fallbackNamespace,
ClusterRepository only). Bare PascalCase wire strings, mirroring
TakeoverPolicy. No schemars default: the effective default is coupled to
identityDefaults.cluster, so it's context-dependent per the conventions
doc, and must stay `—` in the field reference.
- CatalogBounds.foreignSnapshots + effective_foreign_snapshots() resolver,
styled after effective_refresh_interval (absent catalog/field -> Ignore).
- CatalogStatus.foreignSnapshotCount: how many snapshots the last catalog
scan classified as foreign, never materialized under Ignore.
- Validators, shared by the webhook and the controller via api::validate:
(a) foreignSnapshots requires a cluster identity (identityDefaults.cluster)
— foreign-vs-own-cluster classification is undecidable without one.
Kind-neutral message: it fires unconditionally on a namespaced
Repository (no identityDefaults field yet, M5) without claiming the
field doesn't exist.
(b) Fallback requires catalog.fallbackNamespace to be set.
(c) Fallback is ClusterRepository-only, mirroring the existing
fallbackNamespace-requires-cluster-scope rule.
(d) A ClusterRepository with both identityDefaults.cluster and
catalog.fallbackNamespace set must choose foreignSnapshots explicitly
— adopting a cluster identity must never silently switch off an
already-configured fallback collector (Ignore expires its rows under
catalog.retain; Fallback keeps collecting). Two new ValidationError
variants (ForeignSnapshotsRequiresCluster,
ForeignSnapshotsChoiceRequired) carry (a)/(d); (b)/(c) reuse
InvalidFieldValue inside validate_catalog_bounds, alongside the
existing fallbackNamespace check it mirrors.
Regenerated deploy/crds, deploy/helm/kopiur/crds, docs/field-reference.md,
and the xtask CRD insta snapshot via `mise run gen`; `mise run gen-check`
is clean.
…n classification, foreign ignore/fallback, counting M4 of multi-cluster shared-repo support: the catalog scan now consumes M1's HostClass/classify_hostname and M3's catalog.foreignSnapshots instead of just threading them through unused. Architecture: one identity-aware placement pass runs over the FULL kopia listing BEFORE plan_catalog, replacing the old per-entry-in-plan.create IO+ placement loop. Split like the rest of this module: decide_cluster_placement/ decide_namespace_placement + plan_placements are pure (unit-tested with a stubbed ns_allowed map, no kube client); scan() does the thin IO (cached Namespace GET + tenancy check per distinct candidate namespace) and feeds plan_placements' foreign_ignored_ids into plan_catalog in the exact same eligible-filter spot as produced_ids — so a ForeignIgnored entry never consumes a retain.perIdentity slot, and any pre-existing discovered row for one expires via the ordinary absence mechanics once it's no longer eligible. Bare-hostname placement needs a namespace lookup only the controller can do, which is why this pass has to run in the controller rather than being fully front-loaded into the mover. The one genuine ambiguity classify_hostname leaves the caller (a Bare classification means EITHER no cluster identity at all, OR cluster identity on but this hostname has no dot) is resolved with an explicit cluster_mode bool parameter on decide_cluster_placement, keeping every row of the decision table a literal, exhaustive match arm instead of duplicating placement logic at the call site. Decision-table tests prove the cluster-off rows are byte-identical to the deleted placement_namespace (migrated into catalog.rs). Mover prefilter + cap interaction: BootstrapRepositoryOp gets catalog_foreign_prefilter_cluster, armed by the controller only when cluster mode is on AND the effective policy is Ignore (never under Fallback, which needs the entries back). The mover's new apply_foreign_prefilter/ prepare_catalog_entries drop ForeignCluster-classified entries BEFORE MAX_RETURNED_SNAPSHOTS is applied, so a busy foreign peer can no longer crowd this cluster's own snapshots out of the capped listing; bare-hostname foreign entries still count against the cap (they need the controller's namespace lookup). BootstrapResult.foreign_suffix_dropped reports the count; the controller adds it to its own foreign tally without double-counting, since a mover-dropped entry never reaches the controller's listing at all. Also: kopiur_repo_foreign_snapshots gauge + status.catalog.foreignSnapshotCount (both repository kinds), a bounded top-5 foreign-suffix breakdown at info log only (never status — cardinality is foreign-writer-controlled), and the DiscoveredSnapshotUnplaced warning now also names the shared-repo fix (identityDefaults.cluster + foreignSnapshots: Ignore). No crates/api changes (gen-check confirms) — this task only makes the controller/mover consume what M1/M3 already added.
…parity Per-namespace Repository CRs pointing at one shared bucket have the same cross-cluster identity-collision hazard as ClusterRepository (default hostname == namespace). Gives RepositorySpec the same identityDefaults surface ClusterRepository has had since M1, and activates every arm M1-M4 gated behind `// M5:` stubs: the repo-edit identity-change guard's namespaced arm, the catalog.foreignSnapshots x identityDefaults.cluster coupling (rule (a) now accepts Ignore+cluster on a namespaced Repository; Fallback still rejected via rule (c)), and the catalog placement pass's namespaced cluster-aware scan (own/bare place, foreign ignored+counted). IdentityDefaults moved from cluster_repository.rs into common/ (the crate's existing home for types shared by both repository kinds), reusing rather than duplicating the type; the public kopiur_api::IdentityDefaults path is unchanged. The webhook's identity_collision/identity_fork/identity_repo_edit guards now resolve a namespaced Repository's identityDefaults via a namespaced GET (previously silently None), and handle_repository runs the same fleet-wide identity-change guard handle_cluster_repository does, scoped to the repository's own namespace (works under namespaced Role installs). The Repository/ClusterRepository -> SnapshotPolicy referent watch needed for prompt re-pinning already existed (controllers.rs) - verified, not modified. mise run gen/gen-check clean; CRD schema shape matches ClusterRepository's identityDefaults byte-for-byte (no schema default, same properties).
…(cross-namespace refs) The `Repository` identityDefaults-edit guard scoped its consumer `SnapshotPolicy` LIST to the Repository's own namespace, silently missing consumers that reference it cross-namespace via a `RepositoryRef.namespace` (a documented, supported pattern the controller already honors in `repo_lookup`/`resolve_repository_ref`). A policy in another namespace could never be found by that scoped LIST, so an identityDefaults edit could silently re-identify its snapshot history with no deny and no warning. Widen the consumer LIST to cluster-wide, exactly mirroring `handle_cluster_repository`'s call and the pre-existing `check_identity_collision` posture (`Api::all` unconditionally). Since both call sites now always list cluster-wide, drop the now-dead `list_namespace` scoping parameter from `check_repository_identity_change`/ `affected_consumers` rather than leave an unused footgun. The existing `repo_key`-based consumer-match predicate already compares against the ref's effective namespace (falling back to the owner's namespace only when `ref.namespace` is unset), so no change was needed there. Also correct doc comments that justified the old narrow scoping with an RBAC argument that didn't hold, and update/add tests: rename the LIST-scope test to assert cluster-wide for both repository kinds, and add a test proving a cross-namespace consumer is caught and named in the deny message.
…alias migration + ReadOnly owner-stamp gating
Two clusters pointing a same-named ClusterRepository at one shared kopia
repository derive the SAME maintenance lease (managed_lease was name-only
for that kind), so both run concurrent full maintenance (content GC) on
the same data. kopia has no cross-host maintenance lock (its .mlock flock
is local-only) — the operator's owner lease is the only mutual exclusion,
so it must be collision-free. managed_lease now takes the repository's
identityDefaults.cluster and inserts it as a second path segment
(kopiur/{cluster}/... , exhaustive 4-arm match), giving each cluster a
distinct lease.
Naively per-cluster owners would PING-PONG: the bootstrap mover restamps
the stable owner on ANY mismatch on every connect-to-existing, so two
clusters would each see the other's owner as "stale" and re-claim it on
every bootstrap. Fixed by a restamp policy on the bootstrap work spec:
AnyStale (default, byte-compatible pre-existing behavior) vs
OwnFormatsOnly (used iff cluster is set), which only ever overwrites an
empty owner or one of its OWN recognized prior formats
(maintenance_owner_aliases) — never a foreign or unrecognized owner
(those need a one-time takeoverPolicy: Force; auto-clobber is exactly
what is unsafe on a shared repo). The same policy is applied by the
controller's in-process bare-path-filesystem restamp, which would
otherwise ping-pong against the repo's own managed Maintenance.
Migration rides Ownership.ownerAliases (new CRD field): the managed
Maintenance projected for a cluster-qualified repo carries its
pre-cluster lease as an alias, and the mover's lease decision
(lease_held_by_other) treats an alias-derived owner as SELF — the run
claims and re-stamps, upgrading the recorded owner with no manual Force.
A mode: ReadOnly consumer repository's bootstrap used to stamp/restamp
its own maintenance owner onto the shared repo, CLOBBERING the primary's
(a read-only consumer deciding who runs GC). Bootstrap work specs of
ReadOnly repos now carry maintenance_owner: None (as do repos with
maintenance disabled or covered by a foreign Maintenance) and connect
with --readonly (BootstrapRepositoryOp.read_only), making the probe
structurally unable to mutate the repository. Restore/delete movers are
unchanged (restore-heal legitimately writes pins).
The kopia owner identity derivation is now injective for
cluster-qualified leases: a 4-segment lease hostname is the segments
dot-joined, each sanitized individually with no per-segment cap, so
kopiur/east-prod/db/x and kopiur/east/prod-db/x no longer collide (the
old collapse-to-'-' + 63-char truncation made both collisions possible).
Legacy 3-segment and hand-authored leases keep byte-identical output.
…in derivation for kopiur-prefixed leases Two Important fixes from the M6 (ea96631) review: 1. Regression: the in-process (bare-path filesystem) create-then-connect path hardcoded `created: false` into `maintenance_restamp_target` even right after its own successful create — unlike the mover, which stamps the maintenance owner unconditionally on create (crates/mover/src/main.rs). Consequence: a freshly-created Repository with `identityDefaults.cluster` set recorded the controller pod's ephemeral kopia identity as maintenance owner, and `RestampPolicy::OwnFormatsOnly` (required once `cluster` is set) then refused to ever restamp it (not empty, not a recognized alias) — the managed Maintenance's `takeoverPolicy: Never` yielded forever. Pre-M6 healed this unconditionally on every reconcile, so this was a regression. Fixed by threading a real `created` flag through the in-process connect/ create block in crates/controller/src/repository.rs, and adding `io::in_process_create_owner_target` (crates/controller/src/io/maintenance.rs) which stamps the desired owner unconditionally on `created`, mirroring the mover exactly, and otherwise defers to the existing self-heal path. 2. Hardening: `kopia_lease_identity`'s 4-segment dot-join arm matched ANY 4-segment lease, including a hand-authored `Ownership.owner` like `a/b/c/d` that merely happens to split into 4 segments. That silently changed its derivation from the legacy `a-b-c-d` to `a.b.c.d` across the M6 upgrade, and with `takeoverPolicy: Never` maintenance would then yield forever. Gated the dot-join arm on the first segment being exactly `"kopiur"` (managed_lease's reserved prefix) so a hand-authored owner's derivation can never change across an upgrade merely by segment count. Tests: a create-vs-connect owner-stamp matrix (crates/controller/src/io/tests.rs), and a non-kopiur-prefixed 4-segment byte-identical-to-pre-M6 test plus updated doc comment (crates/api/src/maintenance.rs). Full gate green: cargo test -p kopiur-api -p kopiur-controller -p kopiur-mover, fmt-check, test, clippy, complexity-check, gen-check.
…eign handling, lease migration, identity matching
…d repository guide + identity-resolution doc fixes Ships the user-facing story for the multi-cluster shared-repository feature and pays down the doc inaccuracies it uncovered: - docs/repositories.md: document identityDefaults.cluster (RFC1123 <=32, dot-free, the <ns>.<cluster> default hostname, the CEL cluster variable, and the identity-change warning), and correct the ClusterRepository-exclusive framing of identityDefaults (Repository has had it since M5). - docs/backups.md, crates/api/src/identity.rs, crates/controller/src/ snapshot_policy.rs, crates/webhook/src/identity_repo_edit.rs, CLAUDE.md: fix the false "identity resolved once at admission, never re-rendered" claim - identity re-resolves from the live spec + live repository identityDefaults on every reconcile; per-policy edits are gated by the fork guard, repository identityDefaults edits by the repository-wide guard. - docs/maintenance.md: the lease format table (legacy vs. cluster-qualified, including the dotted kopia hostname), ownerAliases, the one-owner-cluster posture, and RestampPolicy self-heal rules. - docs/scenarios/migrate-across-clusters.md: distinguish a one-time app move from the new active-active shared-repo shape. - NEW docs/scenarios/shared-repository-multi-cluster.md (+ nav + index row): why (3 collision surfaces), greenfield setup (both shapes), the ordered live-migration steps, edge notes, and a verification checklist. - docs/troubleshooting.md: LeaseHeldByOther on a shared repo - expected vs. stale. - deploy/examples: new scenario manifest (two ClusterRepository views of one bucket) + a commented cluster: line on 02-cluster-repository.yaml. - Doc-debt: narrow the ForeignSnapshots foreign-counting wording in common/cache.rs (regenerated deploy/crds + docs/field-reference.md), mention `cluster` on IdentityInputs.defaults, mention the identity filter on the mover's resolve_pinned_info, and soften an overclaiming test comment in webhook/handlers.rs. mise run fmt-check/test/clippy/complexity-check, gen/gen-check, and docs (mkdocs --strict) all green.
kubectl kopiur status's REPOSITORIES table gains CLUSTER (spec.identityDefaults. cluster) and FOREIGN (status.catalog.foreignSnapshotCount) columns, for both Repository and ClusterRepository rows, so a shared repository's multi-cluster state is visible on the same one-screen overview without a separate kubectl get.
… story — merged GFS timeline, not a frozen split The identity-change warnings (docs/backups.md, docs/repositories.md, IdentityWouldFork/RepositoryIdentityWouldFork in crates/api/src/error.rs, and the identity_repo_edit module doc) claimed GFS "treats the old lineage as a separate source and never prunes it." That's backwards: GFS pools ALL of a policy's Snapshot CRs regardless of identity (backups_to_delete/select_kept key on end_time/pinned only), so old- and new-lineage snapshots compete in one merged timeline and the old lineage keeps aging out normally. The real consequence is that restore/verify/fromPolicy resolve the new identity, so old history is reachable only via Restore.source.identity. Reworded to match, and updated the one test asserting the old error-message substring.
…aims identity_fork.rs module doc and the allow-identity-change annotation doc in consts.rs carried the same disproven framing the previous commit removed from error.rs: GFS pools a policy's Snapshot CRs identity-blind into one merged timeline; old-lineage CRs keep pruning (and their finalizers delete the old kopia snapshots under deletionPolicy: Delete). The real consequences of an identity change are restore/verify/fromPolicy rebinding to the new identity and lineage interleaving in one GFS timeline — not an orphaned, never-pruned old set. Also softened the residual 'orphan' lead-ins in backups.md.
…ch implemented counting
Greptile SummaryThis PR adds multi-cluster support for shared Kopia repositories. The main changes are:
|
| Filename | Overview |
|---|---|
| crates/api/src/identity.rs | Adds cluster-aware identity resolution and hostname classification. |
| crates/api/src/validate/repository.rs | Extends repository validation for cluster identity and foreign snapshot policy combinations. |
| crates/controller/src/catalog.rs | Implements own/foreign catalog placement, filtering, and counting. |
| crates/controller/src/io/maintenance.rs | Adds cluster-qualified maintenance owner planning, aliases, and read-only suppression. |
| crates/mover/src/main.rs | Pins Kopia retention during snapshot creation and honors read-only bootstrap behavior. |
| crates/mover/src/bootstrap.rs | Adds foreign-suffix prefiltering before the catalog materialization cap. |
| crates/mover/src/resolve.rs | Adds identity-aware manifest matching to avoid same-path cross-identity collisions. |
| crates/webhook/src/identity_repo_edit.rs | Adds the repository identityDefaults edit guard and acknowledgement flow. |
| crates/webhook/src/handlers.rs | Wires identity default edit checks and warnings into repository admission handlers. |
| crates/controller/src/repository.rs | Propagates cluster, foreign snapshot, read-only, and maintenance settings into bootstrap. |
| crates/controller/src/cluster_repository.rs | Adds cluster repository bootstrap and catalog support for shared repositories. |
| crates/api/src/maintenance.rs | Adds injective cluster-qualified maintenance lease identity derivation. |
Reviews (1): Last reviewed commit: "docs(controller): correct PlacementPass:..." | Re-trigger Greptile
doonga
pushed a commit
to greyrock-labs/home-ops
that referenced
this pull request
Jul 15, 2026
….7.3 ➔ 0.7.4) (#74) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/home-operations/charts/kopiur](https://github.com/home-operations/kopiur) | patch | `0.7.3` → `0.7.4` | --- ### Release Notes <details> <summary>home-operations/kopiur (ghcr.io/home-operations/charts/kopiur)</summary> ### [`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 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:eyJjcmVhdGVkSW5WZXIiOiI0My4yNjAuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI2MC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19--> Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/74
eleboucher
pushed a commit
to eleboucher/homelab
that referenced
this pull request
Jul 16, 2026
….7.3 ➔ 0.7.4) (#1607) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/home-operations/charts/kopiur](https://github.com/home-operations/kopiur) | patch | `0.7.3` → `0.7.4` | --- ### Release Notes <details> <summary>home-operations/kopiur (ghcr.io/home-operations/charts/kopiur)</summary> ### [`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**: 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:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19--> Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/1607
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.
Multi-cluster shared kopia repository support: a first-class cluster identity, own/foreign-aware discovery, collision-free maintenance leases — plus two standalone data-safety fixes this work uncovered.
Why
Sharing one kopia repository across clusters (the volsync-style "back up on cluster A, restore on cluster B" workflow) currently fights the operator on three fronts:
hostname == namespace: other clusters' snapshots warnDiscoveredSnapshotUnplacedor pile intofallbackNamespace.username@hostname:path; kopia dedups identical manifests, so one cluster's GFS prune can delete a manifest the other cluster's Snapshot CR still references.What ships
One knob:
identityDefaults.cluster(both repo kinds; RFC1123 label ≤32, dot-free). Setting it flips, coherently:<namespace>.<cluster>(CEL gets aclustervariable; explicit overrides still win). Namespaces can't contain., so the scheme is placement-invertible.Bare/OwnCluster/ForeignCluster), with a typedcatalog.foreignSnapshots: Ignore | Fallbackpolicy. Foreign snapshots are counted (status.catalog.foreignSnapshotCount+kopiur_repo_foreign_snapshotsgauge), never silently invisible — and never warned about when they're expected. The mover pre-filters foreign suffixes before its listing cap so a busy peer can't crowd your own snapshots out.kopiur/{cluster}/…, dot-joined kopia identity reserved to thekopiurprefix), withownerAliasesso the legacy owner upgrades automatically on the first claim, andRestampPolicy: OwnFormatsOnlyso a cluster never clobbers a foreign owner. Exactly one cluster runs maintenance; others yield visibly.mode: ReadOnlyis now a safe consumer posture: bootstrap no longer stamps (or clobbers) the maintenance owner and connects with kopia's--readonly.identityDefaultsedits are guarded at admission: identity re-resolves live on every run (the "pinned at admission" story in the docs was wrong), so an unguarded edit silently re-identified every consumer. Edits now require theallow-identity-changeannotation when consumers have history, and list the affected policies as an admission warning.Cross-cluster restore needed nothing new —
Restore.spec.source.identity/fromPolicyalready restore without a Snapshot CR; the new scenario page ties it together.Standalone data-safety fixes (worth calling out — they affect every deployment, not just multi-cluster)
kopia snapshot createunconditionally applies the source's retention policy — and with none set, kopia's defaults (keep-latest 10 / hourly 48 / daily 7 / weekly 4 / monthly 24 / annual 3) delete manifests that Succeeded Snapshot CRs still reference, for any GFS window wider than those defaults. The mover now pins effectively-infinite kopia-side retention at the identity scope (CR-driven GFS is the sole deleter, as designed) and passes--no-auto-maintenance. Verified against the pinned kopia binary: 12 creates → 10 surviving manifests without the fix, 12 with it./pvc/<name>collides across namespaces (and clusters). All matchers now filter by identity, with a same-path/different-hostname regression test at unit and e2e tiers.Migration
docs/scenarios/shared-repository-multi-cluster.mddocuments the full live-migration story — the order is load-bearing (upgrade all clusters first; disable non-owner maintenance and removetakeoverPolicy: Forcebefore any identity flip; the residual pre-migration dedup window and itsdeletionPolicy: Orphanmitigation). Settingclusteris unset-by-default and byte-for-byte back-compatible: every cluster-off code path is covered by fixture tests proving plans identical to before.Verification
mise run test/clippy/complexity-check/gen-check), with each milestone independently re-verified.crates/e2e/tests/multi_cluster.rs): own-suffix placement, foreign ignore+count with zero unplaced warnings, legacy bare placement, lease yield + anti-restamp, legacy-owner alias upgrade, Fallback flip + restore-by-identity of foreign data, and the same-path/different-identity survival regression — plus the webhook acknowledgment flow. Green on fresh kind clusters (7/7 twice: the implementation run and an independent full-suite run).main-baseline worktree run, so pre-existing/environmental, not from this branch. CI is the arbiter for those suites.Related
RestoreSourceexhaustive-match refactor,restampPolicyserialization skip, milestone-marker comment sweep).