Skip to content

Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.21#2528

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/ghcr.io-cenodude-crosswatch-0.x
Open

Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.21#2528
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/ghcr.io-cenodude-crosswatch-0.x

Conversation

@renovate
Copy link
Copy Markdown
Contributor

@renovate renovate Bot commented Feb 7, 2026

This PR contains the following updates:

Package Update Change
ghcr.io/cenodude/crosswatch minor 0.8.20.9.21

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


Configuration

📅 Schedule: (in timezone America/Los_Angeles)

  • 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.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@ansg191 ansg191 force-pushed the main branch 2 times, most recently from 72654d8 to d12f2db Compare February 7, 2026 00:36
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch 2 times, most recently from 8c59881 to 2fab7bb Compare February 7, 2026 00:38
@ansg191 ansg191 force-pushed the main branch 2 times, most recently from 7fbd471 to 59d9811 Compare February 7, 2026 00:47
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch 2 times, most recently from bb80100 to 3c9eab1 Compare February 7, 2026 00:49
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from 3c9eab1 to 4d32777 Compare February 7, 2026 00:53
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from 4d32777 to 15c6b72 Compare February 7, 2026 00:55
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from 15c6b72 to c9f87e4 Compare February 7, 2026 01:07
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from c9f87e4 to 7a8c056 Compare February 7, 2026 01:15
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.0 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.1 Feb 8, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from 7a8c056 to 6b21eff Compare February 8, 2026 00:41
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.1 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.2 Feb 8, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch 2 times, most recently from 4071a69 to a1f19ca Compare February 10, 2026 16:50
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.2 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.3 Feb 10, 2026
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.3 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.4 Feb 12, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch 2 times, most recently from 4de054c to eebc6b5 Compare February 12, 2026 13:46
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.4 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.5 Feb 14, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from eebc6b5 to 9a07d1e Compare February 14, 2026 20:27
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.5 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.6 Feb 18, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch 2 times, most recently from c317ca2 to 5444516 Compare February 20, 2026 13:10
@ansg191 ansg191 force-pushed the main branch 5 times, most recently from fe65844 to 82fc28b Compare March 8, 2026 00:46
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.12 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.13 Mar 12, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from 18a3ae0 to de5b3e5 Compare March 12, 2026 01:04
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.13 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.14 Mar 18, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from de5b3e5 to c24b317 Compare March 18, 2026 21:53
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.14 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.15 Mar 21, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from c24b317 to 3dc3b4d Compare March 21, 2026 01:52
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from 3dc3b4d to 535f16e Compare March 30, 2026 14:10
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.15 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.16 Mar 30, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from 535f16e to 7b281ab Compare March 30, 2026 16:58
@ansg191 ansg191 force-pushed the main branch 2 times, most recently from 207d061 to 85771a5 Compare April 1, 2026 21:31
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.16 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.17 Apr 2, 2026
@renovate renovate Bot force-pushed the renovate/ghcr.io-cenodude-crosswatch-0.x branch from 7b281ab to 01c1a16 Compare April 2, 2026 21:02
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.17 chore(deps): update ghcr.io/cenodude/crosswatch docker tag to v0.9.17 Apr 6, 2026
@renovate renovate Bot changed the title chore(deps): update ghcr.io/cenodude/crosswatch docker tag to v0.9.17 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.17 Apr 6, 2026
@renovate renovate Bot changed the title Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.17 chore(deps): update ghcr.io/cenodude/crosswatch docker tag to v0.9.17 Apr 6, 2026
@anshulg-hermes
Copy link
Copy Markdown
Contributor

anshulg-hermes Bot commented Apr 8, 2026

Hermes deep-dive review

Re-triaged on HEAD 3635e78 — branch was rebased since the prior review (single squashed commit on top of 6180cf2); image tag still 0.9.18. No upstream releases newer than v0.9.18 at the time of this pass. Prior RED-MANUAL classification still stands; runbook unchanged. No "OK to merge" / runbook-complete approval from ansg191 found in the PR comments.

What I re-checked

  • PR diff on HEAD 3635e78 — still the single image tag line in rpi5/crosswatch/statefulset.yaml: 0.8.2@sha256:a1d08c…0.9.18@sha256:00a9dd….
  • Manifest unchanged: explicit app port 8787, persistent /config via PVC, both internal (crosswatch.internal) and public (crosswatch.anshulg.direct) ingress.
  • rpi5/crosswatch/ directory contents — plain manifests, no Kustomize/Helm rewrites in play.
  • All PR checks green.

Cluster-specific impact

Kubernetes manifests remain compatible — no port/env/probe/storage change is required by the upgrade.

Operational risk still sits entirely in the persisted /config state that survives the rollout. Because /config is persisted, the upstream migration and cleanup steps from v0.9.11 / v0.9.14 / v0.9.15–0.9.17 are directly relevant on this cluster, and this PR does not encode them in Git.

Safety conclusion

RED-MANUAL (unchanged).

Rationale:

  • Large pre-1.0 minor jump (0.8.2 → 0.9.18, ~16 intermediate point releases) with multiple documented manual migration steps.
  • Required actions are app-level/operator steps, not something this PR can safely automate.
  • Persisted /config state makes the upstream migration notes applicable here.

Manual runbook (unchanged)

  1. Inventory the live CrossWatch setup (providers, media servers, watcher config, captures).
  2. Merge/deploy only in a maintenance window.
  3. Verify login immediately after rollout under the mandatory auth model (v0.9.14+).
  4. Run Migrate if prompted (v0.9.11 TMDb-first migration).
  5. Run upstream-recommended maintenance: at minimum Clear state and provider cache; escalate to Clean everything if matching/state looks wrong or Plex/MDBList is involved.
  6. Migrate/verify any legacy watcher setup under watcher routes (v0.9.14+).
  7. Re-enable/validate pairs gradually, one at a time.
  8. Recreate captures if needed and spot-check pair matching under stricter ID matching (v0.9.17+ default).

Action

Do not auto-merge. Leaving this PR unqueued for manual merge by Anshul after the runbook.

@anshulg-hermes anshulg-hermes Bot requested a review from ansg191 April 8, 2026 16:07
@renovate renovate Bot changed the title chore(deps): update ghcr.io/cenodude/crosswatch docker tag to v0.9.17 Update ghcr.io/cenodude/crosswatch Docker tag to v0.9.17 Apr 8, 2026
@ansg191 ansg191 force-pushed the main branch 3 times, most recently from 20eb24b to 749c517 Compare April 9, 2026 05:42
@anshulg-hermes
Copy link
Copy Markdown
Contributor

Hermes deep-dive review

Re-triaged on HEAD 5a68367 — Renovate retargeted the PR from 0.9.180.9.19 since the prior pass (pitfall #25: target moved → fresh re-run, not the rebase-only shortcut). Prior classification carries: large pre-1.0 jump with persisted-state migration requirements is still RED-MANUAL.

Supply-chain audit

  • Verdict: CLEAN
  • Diff scope: single image tag line in rpi5/crosswatch/statefulset.yaml (0.8.20.9.19, sha256 digest pin updated).
  • Provenance: cenodude/crosswatch 0.9.19 release published 2026-05-10 by the project (release body explicitly versioned as v0.9.19). Publisher consistent with prior 0.9.x line.
  • cosign tree: no supply-chain artifacts (consistent with prior crosswatch tags; project does not sigstore-sign).
  • OSV: no advisories.
  • Typosquat: image path matches canonical github.com/cenodude/crosswatch.

Delta vs prior review (0.9.18 → 0.9.19)

The v0.9.19 release is a small cleanup release on top of v0.9.18:

  • Improved: Material Symbols icons now loaded locally (privacy / restricted-network compatibility) instead of from Google Fonts.
  • Fixed: exporter no longer renders a duplicate provider dropdown.

Neither changes the data-on-PVC migration path. The 0.9.11 TMDb migration prompt, the v0.9.14 mandatory auth, the v0.9.15-0.9.17 cleanup steps, and the v0.9.17 stricter ID-matching default all still apply identically to a 0.8.2 → 0.9.19 jump.

Classification

RED-MANUAL (unchanged) — large pre-1.0 minor jump (0.8.2 → 0.9.19, ~17 intermediate point releases) with documented manual migration / cleanup steps required against persisted /config state. The 0.9.18 → 0.9.19 delta doesn't add any new manual step but it doesn't shorten the existing runbook either.

Manual runbook (unchanged from prior pass)

  1. Inventory the live CrossWatch setup (providers, media servers, watcher config, captures).
  2. Merge/deploy only in a maintenance window.
  3. Verify login immediately after rollout under the mandatory auth model (v0.9.14+).
  4. Run Migrate if prompted (v0.9.11 TMDb-first migration).
  5. Run upstream-recommended maintenance: at minimum Clear state and provider cache; escalate to Clean everything if matching/state looks wrong or Plex/MDBList is involved.
  6. Migrate/verify any legacy watcher setup under watcher routes (v0.9.14+).
  7. Re-enable/validate pairs gradually, one at a time.
  8. Recreate captures if needed and spot-check pair matching under stricter ID matching (v0.9.17+ default).

Action

Do not auto-merge. Anshul to merge manually after the runbook.

@anshulg-dep-review
Copy link
Copy Markdown
Contributor

anshulg-dep-review Bot commented May 28, 2026

Triage: YELLOW -- possible breakage, reviewer requested

This is a major pre-release version bump (0.8.2 → 0.9.21) spanning 19 intermediate releases with multiple documented breaking changes and required in-app migration steps. The image itself is trusted and the 0.9.21 delta over prior reviewed 0.9.20 is a security-fix release, but the upgrade cannot proceed unattended — the operator must execute a runbook of 6–8 manual steps after rollout (TMDb state migration, cache wipe, webhook URL updates, authentication verification, and others) to avoid sync pair corruption and data loss.

Package Old New Breaking Changelog Provenance
ghcr.io/cenodude/crosswatch 0.8.2 0.9.21 breaking major refactor, multiple migrations trusted

Required actions

  1. Back up the /config PVC before merging. Once v0.9.13+ runs, config.json is encrypted and incompatible with v0.8.2. This is the only recovery path if rollback is needed. (See breaking report, finding M-7.)

  2. Schedule a maintenance window. This upgrade must not be merged and left to auto-rollout unattended. The operator must be present to execute the post-rollout runbook.

  3. After rollout: verify login immediately under the mandatory auth model introduced in v0.9.14. If no credentials are pre-configured, the UI will be locked out. (See breaking report, finding M-1.)

  4. After rollout: click Migrate if prompted by the upgrade modal (v0.9.11 TMDb-first state migration — wipes state and cache). (See breaking report, finding M-2.)

  5. After rollout: run Settings → Maintenance → Clear state and provider cache (minimum); escalate to "Clean everything" if Plex or MDBList pairs are configured. (See breaking report, finding M-3.)

  6. After rollout: verify Watcher Routes are configured — the legacy watcher bridge was removed in v0.9.14. (See breaking report, finding M-4.)

  7. After rollout: update Plex/Jellyfin/Emby webhook URLs — v0.9.12 added unique URL tokens; old bare webhook paths no longer work. (See breaking report, finding M-6.)

  8. After rollout: review each sync pair's Strict ID Matching setting — v0.9.17 changed the default for new pairs. (See breaking report, finding M-5.)

Update summary

ghcr.io/cenodude/crosswatch 0.8.2 → 0.9.21

  • Major pre-release bump spanning 19 intermediate versions (0.9.0 through 0.9.21) with cumulative breaking changes across authentication, state format, webhook URLs, and provider versioning.
  • TMDb-first ID priority replaces IMDb-first; requires clicking Migrate in the upgrade modal to wipe and rebuild state.
  • Authentication now mandatory (v0.9.14); unauthenticated access is no longer supported.
  • Webhook URLs require unique tokens (v0.9.12); all existing webhook integrations must be reconfigured with new paths.
  • Config encryption introduced (v0.9.13); downgrade to pre-v0.9.13 versions is impossible after the first Settings save.
  • Provider cache versioning changed (v0.9.16); requires running Maintenance → Clear state and provider cache or Clean everything.
  • Security fixes in v0.9.21 — authentication endpoint hardening, unauthenticated session metadata leak closed, maintenance endpoint bypass fixed. Being on 0.9.21 rather than 0.9.20 is strictly safer.

Provenance

All updates from the expected publisher (ghcr.io/cenodude) with consistent namespace, corresponding git tags and GitHub releases on the source repository, and attestation manifests present on both versions. No signature, source, or metadata drift indicating compromise. The Python base image was updated from 3.11.14 to 3.11.15 (patch-level bump, documented in release notes). Verdict: trusted.

Sub-agent reports — ghcr.io/cenodude/crosswatch

Breaking-change impact

I now have all the information needed. The PR has moved from 0.9.20 to 0.9.21 (Renovate retargeted again). The prior deep-dive reviews covered 0.8.2 → 0.9.18 and 0.8.2 → 0.9.20. I need to assess 0.8.2 → 0.9.21, which means the prior analysis still applies for all the 0.9.0–0.9.20 findings, plus I need to assess what 0.9.21 adds.

Key new information from v0.9.21:

  1. Security fixes — authentication endpoint hardening (no new breaking changes, these are fixes)
  2. MDBList Device Code authentication — new default auth method for MDBList; API key mode still available for existing setups (no breaking change for existing configs)
  3. Recent Activity — new UI feature (additive)
  4. No new migration steps — no new data migration, no config schema changes, no PVC format changes

The digest in the PR (sha256:3cfafbee01f412d00ca1198ab9c55229a0e2a41ebafb3a08df809a56420a86fc) matches the GHCR page for 0.9.21. The GHCR page shows 256 downloads for 0.9.21 (just published ~3 hours ago at time of page fetch), consistent with a fresh release.

Architecture: The GHCR page doesn't explicitly list architectures in the web UI text, but the pattern across all 0.9.x tags has been consistently linux/amd64 + linux/arm64. The 0.9.21 release notes contain no mention of architecture changes.

Now I have everything needed to produce the full report.


Impact verdict: ghcr.io/cenodude/crosswatch 0.8.2 → 0.9.21 (PR #2528)

Verdict

merge_with_actions

This is a leaf-app image bump with no Kubernetes infrastructure changes required — no port, probe, selector, PVC path, env var, or API version changes are needed in the manifests. However, the upgrade spans 19 intermediate pre-1.0 releases (0.8.2 → 0.9.21) with multiple documented in-app migration steps that must be performed manually via the CrossWatch UI after the pod rolls over. The 0.9.21 delta over the prior reviewed 0.9.20 is a security-fix release with no new migration requirements; it is strictly safer to be on 0.9.21 than 0.9.20. The full runbook from the prior reviews remains unchanged and must be executed. Merging without the runbook leaves the application in a degraded or partially-migrated state, with risk of sync pair data corruption and an irreversible config format change on the PVC.


Blast radius

  • Scope: leaf_app
  • Direct usage: 1 manifest — rpi5/crosswatch/statefulset.yaml
  • Transitive dependents: 0 apps — CrossWatch is a media-sync utility; no other service in the repo connects to it as a database, API, or dependency.
  • User-facing exposure:
    • Public hostnames affected: crosswatch.anshulg.direct (Let's Encrypt cert via letsencrypt-prod ClusterIssuer, Traefik IngressRoute)
    • Internal (oauth-gated) hostnames affected: crosswatch.internal (Traefik IngressRoute, internal CA cert via rpi5-ca ClusterIssuer) — no oauth2-proxy annotation; access is controlled by CrossWatch's own mandatory auth (v0.9.14+)
    • Cron / scheduled jobs affected: none
  • Failure mode if upgrade goes wrong: soft_down — the pod will start (no liveness/readiness probe is configured, so Kubernetes will consider it ready immediately after container start). The application may refuse logins, show stale/incorrect sync state, or silently mis-sync pairs until in-app migration steps are completed. Hard-down is possible if the encrypted config written by v0.9.13+ cannot be parsed by the new version without a migration step, but this is unlikely given the release history.
  • Recovery: rollback_after_data_write — rolling back the image tag is trivial, but v0.9.13+ writes an encrypted config.json and v0.9.11+ rewrites state to TMDb-first format. If the new version has already run and written these formats, the old image (0.8.2) cannot read them. Rollback after any sync run requires restoring /config from backup.

Required actions before merge

  • Back up the /config PVC before merging — once v0.9.13+ runs, config.json is encrypted and incompatible with v0.8.2. This is the only recovery path if rollback is needed. See finding M-7.
  • Schedule a maintenance window — this upgrade should not be merged and left to auto-rollout unattended. See findings M-1 through M-6.
  • After rollout: verify login immediately under the mandatory auth model introduced in v0.9.14. If no credentials are pre-configured, the UI will be locked out. See finding M-1.
  • After rollout: click Migrate if prompted (v0.9.11 TMDb-first state migration — wipes state and cache). See finding M-2.
  • After rollout: run Settings → Maintenance → Clear state and provider cache (minimum); escalate to "Clean everything" if Plex or MDBList pairs are configured. See finding M-3.
  • After rollout: verify Watcher Routes are configured — the legacy watcher bridge was removed in v0.9.14. See finding M-4.
  • After rollout: update Plex/Jellyfin/Emby webhook URLs — v0.9.12 added unique URL tokens; old bare webhook paths no longer work. See finding M-6.
  • After rollout: review each sync pair's Strict ID Matching setting — v0.9.17 changed the default for new pairs. See finding M-5.

Findings

M-1: Mandatory authentication introduced (v0.9.14)

  • Severity: action_required
  • Category: config_schema
  • What changed: Authentication became mandatory in v0.9.14. The old optional-auth model is removed; every session must log in. A new login screen and Plex SSO option were added.
  • Why it affects this deployment: rpi5/crosswatch/statefulset.yaml sets only TZ=America/Los_Angeles — no AUTH_* env vars, no credentials mounted via Secret or ConfigMap. If the running instance was using CrossWatch without authentication enabled (the pre-v0.9.14 default), the first boot of v0.9.14+ will enforce auth. The operator must verify that credentials are set in the persisted /config/config.json on the PVC before or immediately after rollout, or the UI will be locked out.
  • Affected dependents: crosswatch only
  • Required action: After rollout, immediately navigate to the CrossWatch UI. If prompted for login and no credentials are set, follow the first-run setup. Confirm login works before leaving the maintenance window.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

M-2: TMDb-first state migration required (v0.9.11)

  • Severity: action_required
  • Category: data_migration
  • What changed: v0.9.11 changed internal ID priority from IMDb-first to TMDb-first across all sync pairs. The upgrade modal presents a Migrate button that wipes current state and cache and temporarily stops the scheduler. Skipping migration causes duplicate entries to be pushed to external trackers.
  • Why it affects this deployment: The deployment mounts a persistent /config PVC (rpi5/crosswatch/statefulset.yaml, volumeClaimTemplates[0], mountPath: /config). The existing state on that PVC was written by v0.8.2 under IMDb-first logic. The new version will detect the mismatch and prompt for migration. If the migration prompt is dismissed or missed, sync pairs will produce incorrect results (false adds/removes to Trakt, SIMKL, MDBList, etc.).
  • Affected dependents: crosswatch only; downstream effect is on external tracker accounts (Trakt, SIMKL, MDBList, etc.) that CrossWatch syncs to
  • Required action: When the upgrade modal appears after rollout, click Migrate. After migration, re-enable pairs one at a time and let state rebuild. Recreate any Captures that existed before the upgrade.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

M-3: Provider cache and state cleanup required after multiple refactors (v0.9.16, v0.9.17)

  • Severity: action_required
  • Category: data_migration
  • What changed: v0.9.16 refactored all providers to x.x versioning (from x.x.x) and made significant sync behavior changes. v0.9.17 changed strict ID matching to be the default for new Plex/Jellyfin/Emby pairs. Both releases explicitly recommend running Maintenance → Clear state and provider cache (or "Clean everything") after upgrade.
  • Why it affects this deployment: The /config PVC contains provider caches written by v0.8.2 using the old versioning scheme and old ID-matching logic. Running the new version against stale caches will produce incorrect sync results (false positives, wrong counts, duplicate entries).
  • Affected dependents: crosswatch only; downstream effect on external tracker accounts
  • Required action: After the TMDb migration (M-2), run Settings → Maintenance → Clear state and provider cache. If Plex or MDBList pairs are configured, escalate to Clean everything per the v0.9.17 release note.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

M-4: Legacy watcher bridge removed (v0.9.14)

  • Severity: action_required
  • Category: config_schema
  • What changed: v0.9.14 removed the old legacy watcher bridge (pre-v0.9 watcher setup). Any watcher configuration created before v0.9.0's Watcher Routes model will no longer function.
  • Why it affects this deployment: If the CrossWatch instance was configured with the legacy watcher (pre-v0.9.0 style), that configuration will stop working entirely after upgrade. The v0.9.0 release notes state that legacy watcher configs auto-migrate to routes mode with the Default profile applied, but v0.9.14 is the hard cutoff where the bridge is gone.
  • Affected dependents: crosswatch only; downstream effect is on real-time scrobbling to Trakt/SIMKL/MDBList
  • Required action: After rollout, verify that Watcher Routes are configured and active. If the legacy watcher was in use, reconfigure under the Routes model.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

M-5: Strict ID matching now default for new Plex/Jellyfin/Emby pairs (v0.9.17)

  • Severity: monitor
  • Category: config_schema
  • What changed: v0.9.17 changed the default for newly configured pairs to use Strict ID Matching (IDs only, no title fallback). Existing pairs are not automatically changed but may produce different results if title fallback was relied upon.
  • Why it affects this deployment: Existing pairs configured under v0.8.2 used the old default (title fallback allowed). The release notes explicitly state: "for existing pairs you need to change it in your pair - providers - Plex/Emby/Jellyfin and enable Strict ID Matching." If not updated, matching behavior will differ from the new default and may produce false positives.
  • Affected dependents: crosswatch only
  • Required action: After upgrade, review each sync pair's Plex/Emby/Jellyfin settings and decide whether to enable Strict ID Matching. The release note recommends enabling it to reduce false positives.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

M-6: Webhook URLs now require a unique token (v0.9.12)

  • Severity: action_required
  • Category: networking
  • What changed: v0.9.12 added a unique URL token to all webhook endpoints. Old bare webhook paths (/webhook/plextrakt, /webhook/jellyfintrakt, /webhook/embytrakt, /webhook/plexwatcher) no longer work. New paths require ?uniqueID suffix.
  • Why it affects this deployment: If Plex, Jellyfin, or Emby are configured to send webhooks to CrossWatch (a common use case for real-time scrobbling), those webhook URLs configured in the media server must be updated to include the new unique token generated by CrossWatch. The token is generated by CrossWatch itself and visible in the UI after upgrade.
  • Affected dependents: crosswatch only; downstream effect is on real-time scrobbling
  • Required action: After upgrade, navigate to CrossWatch Settings → Scrobbler → Webhooks, copy the new webhook URLs (which include the unique token), and update the corresponding webhook configuration in Plex/Jellyfin/Emby.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

M-7: Config file encryption introduced (v0.9.13) — one-way format change

  • Severity: action_required
  • Category: data_migration
  • What changed: v0.9.13 introduced encrypted storage of sensitive values in config.json using a local master key file. The release note explicitly states: "after your upgrade to v0.9.13 you can't downgrade. This version now includes encrypted config file, and is not compatible with older versions."
  • Why it affects this deployment: Once v0.9.13+ runs and saves settings, the config.json on the /config PVC (rpi5/crosswatch/statefulset.yaml, volumeClaimTemplates[0], mountPath: /config) is written in the encrypted format. Rolling back to v0.8.2 after this point will result in CrossWatch being unable to read its own config. This makes rollback effectively irreversible without restoring the PVC from backup. Severity is elevated from monitor to action_required because the backup must be taken before merge, not after.
  • Affected dependents: crosswatch only
  • Required action: Take a backup of the /config PVC contents before merging this PR. This is the only recovery path if rollback is needed after the new version writes its encrypted config.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

S-1: Security fixes in v0.9.21 — authentication endpoint hardening (new in this PR vs. prior reviews)

  • Severity: informational
  • Category: other
  • What changed: v0.9.21 fixed /api/app-auth/status leaking session metadata (IP addresses, User-Agent strings, session IDs, timestamps) to unauthenticated clients. Also hardened POST /api/maintenance/reset-all-default against an unauthenticated setup-lock bypass, and removed filesystem details (config path, file size, modification time) from unauthenticated /api/config/meta responses.
  • Why it affects this deployment: These are security fixes, not breaking changes. The deployment exposes CrossWatch publicly at crosswatch.anshulg.direct — the unauthenticated session metadata leak and the maintenance endpoint bypass were real security issues on this public-facing instance. Being on 0.9.21 rather than 0.9.20 is strictly better from a security standpoint. No manifest changes required.
  • Affected dependents: crosswatch only
  • Required action: No action required — informational. This finding is a positive reason to prefer 0.9.21 over 0.9.20.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

I-1: No liveness/readiness probe configured — upgrade failure is silent

  • Severity: informational
  • Category: networking
  • What changed: v0.9.15 added /api/health and /healthz health check endpoints. The current StatefulSet has no liveness or readiness probe configured.
  • Why it affects this deployment: The absence of probes means Kubernetes cannot detect if CrossWatch fails to start correctly after the upgrade. The rolling update will complete as soon as the container starts (not as soon as the app is healthy). This is a pre-existing gap, not introduced by this PR.
  • Affected dependents: crosswatch only
  • Required action: No action required for this PR. Consider adding a readiness probe pointing to /api/health or /healthz in a follow-up PR.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

I-2: Watchlist auto-remove behavior changed (v0.9.18)

  • Severity: informational
  • Category: config_schema
  • What changed: Watchlist auto-remove now only targets providers that are part of enabled watchlist pairs, instead of scanning all configured providers.
  • Why it affects this deployment: Only relevant if watchlist auto-remove is configured. Subsumed by M-3 (cache/state cleanup). No manifest change required.
  • Affected dependents: crosswatch only
  • Required action: No additional action beyond M-3.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

I-3: One-way sync default delete behavior changed (v0.9.5)

  • Severity: informational
  • Category: config_schema
  • What changed: The default delete behavior for one-way syncs changed from mirror mode (always follows source, destructive) to only propagating items actually deleted on the source. Users who want the old mirror behavior must set sync.one_way_remove_mode = "mirror" in config.json.
  • Why it affects this deployment: Only relevant if one-way sync pairs with delete behavior are configured. No manifest change required; config change is in the PVC-persisted config.json if needed.
  • Affected dependents: crosswatch only
  • Required action: No action required unless one-way mirror sync was in use. If so, add sync.one_way_remove_mode = "mirror" to config.json.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

I-4: Trakt watched_at minute-precision change (v0.9.6)

  • Severity: informational
  • Category: config_schema
  • What changed: The Trakt adapter now rounds watched_at timestamps to minute precision. Existing history entries with sub-minute precision may be treated as duplicates or mismatches.
  • Why it affects this deployment: Subsumed by M-3 (the general cache/state cleanup). If the cleanup in M-3 is performed, this is automatically addressed.
  • Affected dependents: crosswatch only
  • Required action: No additional action beyond M-3.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

I-5: Plex shared-server support requires Plex auth recreation (v0.9.8)

  • Severity: informational
  • Category: config_schema
  • What changed: v0.9.8 added shared Plex server support, requiring major changes to Plex authentication and sync adapters. Recommended action: delete and re-add Plex authentication configs.
  • Why it affects this deployment: Only relevant if Plex is configured. The recommendation to recreate Plex auth is superseded by the broader M-3 cleanup. If "Clean everything" is run, Plex auth will need to be reconfigured anyway.
  • Affected dependents: crosswatch only
  • Required action: No additional action beyond M-3.
  • Source: upstream release notes
  • Confidence: documented
  • Render-limited: no

Deployment fingerprint (summary)

Surface Value
Image ghcr.io/cenodude/crosswatch:0.8.2@sha256:a1d08c…0.9.21@sha256:3cfafb…
Namespace crosswatch
Kind StatefulSet (1 replica)
Container port 8787/TCP named http
Service port 80 → http (8787), ClusterIP
Env vars TZ=America/Los_Angeles only — no AUTH_, no DB_, no API key env vars
Mounted ConfigMaps/Secrets None
Volume mounts /config from PVC config (ReadWriteOnce, 1Gi)
Security context None set (runs as whatever user the image specifies)
Resource limits/requests None set
Liveness probe None
Readiness probe None
Startup probe None
Internal ingress crosswatch.internal via Traefik IngressRoute, TLS from rpi5-ca ClusterIssuer
Public ingress crosswatch.anshulg.direct via Traefik IngressRoute, TLS from letsencrypt-prod ClusterIssuer
ArgoCD Application rpi5/apps/templates/crosswatch.yaml, plain manifest sync (no Helm/Kustomize)
StatefulSet selector app: crosswatch — unchanged, no immutable selector conflict
Transitive dependents None found (no other service in repo references crosswatch by Service name, DNS, or env var)

Cluster fit

  • Architectures required by cluster: amd64, arm64 (rpi5 nodes)
  • Architectures supported by new version: Pattern across all 0.9.x tags has been consistently linux/amd64 + linux/arm64; v0.9.21 release notes contain no mention of architecture changes. GHCR web UI does not expose per-architecture sub-manifests in the page text, so direct confirmation for 0.9.21 specifically was not possible. The digest sha256:3cfafbee01f412d00ca1198ab9c55229a0e2a41ebafb3a08df809a56420a86fc in the PR matches the GHCR package page for 0.9.21. No architecture regression detected; low confidence without manifest inspection.
  • Kubernetes API versions used in manifest sources: apps/v1 (StatefulSet), v1 (Service, Namespace), cert-manager.io/v1 (Certificate), traefik.io/v1alpha1 (IngressRoute), argoproj.io/v1alpha1 (Application) — all stable, no deprecated APIs.
  • Minimum K8s version stated by dep: Not stated (CrossWatch is a plain container image, not a Helm chart with K8s version requirements).
  • Peer dependency check: No Helm chart, no CRDs shipped by CrossWatch. cert-manager (for Certificate resources) and Traefik (for IngressRoute) are already installed in the cluster and are not affected by this image bump. No new peer dependencies introduced in v0.9.21.
  • StatefulSet selector: app: crosswatch — unchanged between old and new image. No immutable selector conflict.
  • PSA: No privileged capabilities, no hostPath mounts, no root requirement visible in the manifest. No securityContext is set, so the image's default USER applies. No PSA violation expected.

Gaps

  1. Image USER not verified for 0.9.21. The StatefulSet sets no securityContext.runAsUser or fsGroup. If the new image changed its USER directive (e.g., from root to a non-root UID), existing files on the /config PVC owned by the old UID would become inaccessible. This cannot be confirmed without docker inspect or image layer inspection tooling. No USER change was mentioned in any release note across the 0.8.x → 0.9.x range; risk is assessed as low but unverified.

  2. Architecture confirmation for 0.9.21 specifically. The GHCR package page shows the correct digest for 0.9.21 but does not expose per-architecture sub-manifests in the web UI text. The pattern is consistent across all prior 0.9.x tags (amd64 + arm64 confirmed for 0.9.18 and earlier in prior reviews). Direct manifest inspection (docker manifest inspect ghcr.io/cenodude/crosswatch:0.9.21) was not possible with available tooling.

  3. Live CrossWatch configuration unknown. The actual providers, pairs, watcher routes, and captures configured in the running instance are stored in the /config PVC and are not visible from the Git repository. The severity of findings M-1 through M-6 depends on which features are actively configured. For example, M-6 (webhook URL change) is only relevant if webhooks are in use.

  4. No formal upgrade guide exists. CrossWatch is a pre-1.0 project with no UPGRADING.md or dedicated migration guide. All migration instructions are embedded in individual release notes. The runbook above was assembled by reading all 19 intermediate release notes; there may be edge cases not captured in the release notes.

  5. PVC backup state unknown. Finding M-7 requires backing up the /config PVC before merge. Whether a current backup exists (e.g., via resticprofile or another backup mechanism in the cluster) is not verifiable from the manifests alone.

  6. MDBList Device Code authentication (v0.9.21) — existing API key configs unaffected. The release notes state "API key mode remains available for existing and legacy setups," so this is not a breaking change. However, if MDBList is configured, the operator should be aware that the preferred auth method has changed and may want to migrate to Device Code auth at their discretion.

Upstream changelog

I have all the data needed. The range is v0.8.2v0.9.21, and I have complete release notes for every version in between. Let me now compile the structured output.


ghcr.io/cenodude/crosswatch 0.8.2 → 0.9.21

Summary

  • Artifact type: Container image (GHCR)
  • Input format: SemVer image tags
  • Resolved references: ghcr.io/cenodude/crosswatch:0.8.2ghcr.io/cenodude/crosswatch:0.9.21; source repo github.com/cenodude/CrossWatch (Python application); tags map directly to GitHub release tags v0.8.2v0.9.21
  • Versions in range: v0.9.0 (experimental), v0.9.1, v0.9.2, v0.9.3, v0.9.4, v0.9.5, v0.9.6, v0.9.7, v0.9.8, v0.9.9, v0.9.10, v0.9.11, v0.9.12, v0.9.13, v0.9.14, v0.9.15, v0.9.16, v0.9.17, v0.9.18, v0.9.19, v0.9.20, v0.9.21
  • Source repo: https://github.com/cenodude/CrossWatch
  • Primary sources used: GitHub Releases page — comprehensive release notes for every version
  • Versioning scheme: ZeroVer / custom pre-1.0 (0.x.y); no major-version boundary in this range; maintainer explicitly states v1.0.0 stable release is approaching
  • Major version boundary crossed: No (all within 0.9.x)
  • Confidence: high — maintainer-authored release notes cover every version in the range with explicit migration instructions where applicable

Breaking Changes

TMDb-first ID priority replaces IMDb-first (state/cache wipe required)

  • What changed: CrossWatch now resolves provider IDs in the order TMDb → IMDb → TVDb → (other) instead of the previous IMDb-first approach; all existing sync state and provider caches are incompatible with this change.
  • Affects: All sync pairs; state.json; all provider caches in .cw_state; Captures (must be recreated)
  • Migration: When upgrading, click Migrate in the upgrade warning modal — this wipes current state and cache and temporarily stops the scheduler. After migration: re-enable pairs one at a time and let state rebuild. Recreate any Captures. Do not run tracker-to-media-server pairs immediately after migration. Run Maintenance → Clear state and provider cache (or Clean everything) if Migrate is not triggered.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.11

Authentication is now mandatory; unauthenticated access removed

  • What changed: Authentication is no longer optional — every client must authenticate to access the CrossWatch UI and API; the previous "no auth" mode is gone.
  • Affects: All HTTP clients, automation scripts, reverse proxy setups, and any tooling that accessed CrossWatch endpoints without credentials
  • Migration: Set up authentication credentials via the login screen before upgrading. After upgrade, perform a hard browser refresh (Ctrl+Shift+R or Ctrl+F5). Plex SSO is available as an alternative login method.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.14

Webhook URLs now require a unique token; all existing webhook URLs are broken

  • What changed: Webhook endpoints are now protected by a unique URL token generated by CrossWatch; the old bare webhook paths no longer work.
  • Affects: Webhook integrations — /webhook/plextrakt, /webhook/jellyfintrakt, /webhook/embytrakt, /webhook/plexwatcher — all must be updated with the new ?uniqueID query parameter
  • Migration: After upgrading, copy the new webhook URL from CrossWatch settings and paste it into each media server's webhook configuration. Also recommended: run Maintenance → Clear Everything to clear existing cache.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.12

config.json now uses encrypted secrets; downgrade to pre-v0.9.13 is impossible

  • What changed: Sensitive values (API keys, tokens) in config.json are now stored encrypted using a local master key file; the encrypted format is not compatible with older versions.
  • Affects: config.json file; any tooling that reads/writes config.json directly; downgrade path is blocked
  • Migration: No action required on upgrade (encryption is applied automatically on next Settings save). Downgrade to versions before v0.9.13 is explicitly unsupported — the encrypted config cannot be read by older versions.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.13

Legacy watcher bridge removed; legacy watcher configs (<0.9) no longer work

  • What changed: The old watcher bridge (pre-v0.9 legacy watcher setup) has been completely removed; only the new Watcher Routes model is supported.
  • Affects: Any installation still using the pre-v0.9 watcher configuration
  • Migration: Migrate to Watcher Routes. Legacy configs were supposed to auto-migrate to routes mode in v0.9.0, but the bridge removal in v0.9.14 means any remaining legacy setup will stop working entirely.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.14

Strict ID matching is now the default for Plex, Jellyfin, and Emby pairs

  • What changed: Newly configured pairs for Plex, Emby, and Jellyfin now default to Strict ID matching (GUIDs only, no title/year fallback); existing pairs retain their previous setting but may need manual update if experiencing issues.
  • Affects: Sync pair configuration for Plex/Emby/Jellyfin; existing pairs are not automatically changed but the behavior change may cause previously-syncing items to become "unresolved"
  • Migration: For existing pairs with issues: go to Pair → Providers → Plex/Emby/Jellyfin and enable Strict ID Matching manually. If using Plex and/or MDBList: run Maintenance → Clear state and provider cache (or Clean everything).
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.17

Provider versioning scheme changed from x.x.x to x.x

  • What changed: All provider/tracker/media server modules now use x.x versioning starting from 1.0 instead of x.x.x; provider caches must be cleared after upgrade.
  • Affects: Internal provider cache files in .cw_state; any tooling that inspects provider version strings
  • Migration: Run Maintenance → Clear state and provider cache (or Clean everything) after upgrading.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.16

Trakt watched_at now rounded to minute precision; existing Trakt History pairs may produce duplicate entries

  • What changed: The Trakt adapter now rounds watched_at timestamps to minute precision, matching Trakt's own upcoming API change; existing state built with sub-minute timestamps is incompatible.
  • Affects: All sync pairs involving Trakt History
  • Migration: Either recreate the Trakt History pair, or run Maintenance → Clean everything. See: https://wiki.crosswatch.app/crosswatch/faq
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.6

POST /api/maintenance/reset-all-default no longer accessible without authentication

  • What changed: The maintenance reset endpoint can no longer be reached via an unauthenticated setup-lock bypass; it now requires a valid authenticated session.
  • Affects: Any automation or scripts that called this endpoint without authentication
  • Migration: Authenticate before calling maintenance endpoints.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.21

/api/app-auth/status no longer leaks session metadata to unauthenticated clients

  • What changed: The auth status endpoint now returns a restricted response to unauthenticated clients; session IP addresses, User-Agent strings, internal session IDs, and timestamps are no longer exposed.
  • Affects: Any unauthenticated client or monitoring script that previously parsed session metadata from this endpoint
  • Migration: Authenticate before querying session metadata.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.21

/api/config/meta no longer includes filesystem details for unauthenticated requests

  • What changed: Unauthenticated responses from /api/config/meta no longer include config path, file size, or modification time.
  • Affects: Any unauthenticated client or monitoring script that read filesystem metadata from this endpoint
  • Migration: Authenticate before querying config metadata.
  • Source: upstream release notes
  • Confidence: documented
  • Introduced in: v0.9.21

Other Notable Changes

  • v0.9.0: New Profile/Instance system — multiple profiles per provider (e.g., Plex "Default" and "Kids"); new Watcher Routes model replaces legacy single-watcher setup.
  • v0.9.2: Split "Synchronize" button — click ▾ to run a single enabled pair directly.
  • v0.9.3: Maintenance "Reset all to default" action added — wipes state/caches/reports/TLS, backs up config.json with timestamp.
  • v0.9.5: One-way sync safe deletes fixed — deletes now only propagate items actually deleted on source (not mirror-mode by default); sync.one_way_remove_mode = "mirror" in config.json restores old behavior.
  • v0.9.6: Plex history capture is now incremental (watermark-based) instead of full re-scan; persistent GUID index added for strict matching.
  • v0.9.7: Scheduler guardrails — switching to Advanced mode automatically disables Standard (and vice versa) to prevent conflicting schedules.
  • v0.9.8/v0.9.9: Shared Plex server support (servers you don't own); Plex auth configs should be recreated (delete and re-add).
  • v0.9.10: MDBList adapter updated to v4.1.0; SIMKL adapter updated to v4.1.0; Trakt adapter updated to v4.4.0 — all with improved API compatibility.
  • v0.9.12: Progress (experimental) — sync resume position between Plex, Emby, and Jellyfin; configurable per pair.
  • v0.9.12: Trusted reverse proxies setting added in Settings → Security for improved cookie security and rate limiting accuracy.
  • v0.9.13: UI refresh — cleaner, more modern interface across main, analyzer, exporter, syncbar, watchlist, captures, editor, settings.
  • v0.9.14: Plex SSO — CrossWatch can use a linked Plex account for sign-in; Advanced Scheduling now supports event triggers (watcher/webhook activity).
  • v0.9.15: New health check endpoints /api/health and /healthz for Docker healthcheck. Plex history and ratings indexing now uses parallel workers (~34% speed improvement).
  • v0.9.15: Per-route watcher options (route-specific auto-remove, custom Plex ratings webhooks); global defaults and per-route control for Watcher settings.
  • v0.9.16: "Ignore dropped shows" support for MDBList, Trakt, and SIMKL; CW Tracker progress sync support.
  • v0.9.18: Quick Add feature — manually send watched history, watchlist entries, and ratings to configured providers; Plex watcher route filter to ignore Live TV & DVR.
  • v0.9.19: Material Symbols icons now loaded locally (privacy improvement, no Google Fonts dependency).
  • v0.9.20: PublicMetaDB provider support (experimental, one-way recommended); hybrid scrobbling (Webhooks + Watcher simultaneously); Server UUID allowlist and blacklist filtering for Plex Webhooks and Watcher; Yamtrack exports now use native CSV format.
  • v0.9.21: Recent Activity dashboard widget; MDBList Device Code authentication (new default); MDBList API key mode still available for legacy setups.
  • v0.9.14: Username masking in watcher/sink and webhook logs — only first two letters of username are shown.

Deprecations Introduced

  • Legacy webhook setup — deprecated as of v0.6.3 (before this range), but the legacy watcher bridge was fully removed in v0.9.14. No further support or fixes for webhook-based setups. Migration: use Watcher Routes.
  • MDBList API key authentication — superseded by Device Code authentication as the new default in v0.9.21; API key mode remains available for existing/legacy setups but is no longer the recommended path.

Gaps and Caveats

  • Pre-1.0 project: This is a ZeroVer project (0.x.y) where the maintainer explicitly states every release can introduce breaking changes. The maintainer's own words: "you can just wait a few versions before it's stable again." The v1.0.0 stable release is described as approaching but not yet released.
  • v0.9.0 was marked experimental: The initial v0.9.0 release was explicitly labeled experimental due to the Profile/Instance system multiplying possible setups. Users upgrading from v0.8.2 directly to v0.9.21 skip the stabilization period that occurred across v0.9.1–v0.9.5.
  • Cumulative cache/state wipes: Multiple releases in this range (v0.9.11, v0.9.12, v0.9.16, v0.9.17) each independently require clearing state and provider cache. A fresh upgrade from v0.8.2 should plan for a full Maintenance → Clean everything operation.
  • No CHANGELOG.md found at standard paths; all change information sourced exclusively from GitHub Releases page.
  • No formal migration guide document (no UPGRADING.md or MIGRATING.md); migration instructions are embedded inline in individual release notes.
  • Plex auth recreation recommended for v0.9.8: Users with Plex configured should delete and re-add their Plex authentication configs after upgrading past v0.9.8 (shared server support required major auth changes).
  • v0.9.5 one-way sync behavior change: The default delete behavior for one-way syncs changed from mirror-mode to safe-delete. Users who intentionally relied on mirror behavior must set sync.one_way_remove_mode = "mirror" in config.json to restore it.

Provenance

Perfect! I now have all the information needed to produce a comprehensive provenance verdict. Let me compile the findings:

Provenance verdict: ghcr.io/cenodude/crosswatch 0.8.2 → 0.9.21

Verdict

trusted

Both versions have corresponding git tags and releases on the source repository, publisher namespace is consistent, attestation manifests are present on both versions, and no external compromise signals detected. The image description changed between versions (expected for a major feature release), and the Python base image was updated (3.11.14 → 3.11.15), both consistent with documented release notes.

Resolved references

  • Artifact type: OCI container image (GHCR)
  • Old: ghcr.io/cenodude/crosswatch:0.8.2 → digest sha256:a1d08cfefb74689d9ed0c200edd080a8a82ee044d2d63bceae6a0e263445dbf6
  • New: ghcr.io/cenodude/crosswatch:0.9.21 → digest sha256:3cfafbee01f412d00ca1198ab9c55229a0e2a41ebafb3a08df809a56420a86fc
  • Declared source repo: github.com/cenodude/CrossWatch (verified)
  • Publisher namespace: ghcr.io/cenodude (old) → ghcr.io/cenodude (new) — same

Indicators

Severity Category Finding Evidence
info source_correspondence v0.8.2 git tag exists on source repo git tag v0.8.2 → commit 86d7be44d7a25b7f3c80cbcbf2c8b93f40b6e15b
info source_correspondence v0.9.21 git tag exists on source repo git tag v0.9.21 → commit e3d624eb6a86516f911e40cf062cd645a6c44e33
info publisher_continuity Publisher namespace unchanged Both versions published to ghcr.io/cenodude
info publisher_continuity Single maintainer (cenodude) across all releases Consistent author across commit history
info build_provenance Attestation manifests present on both versions OCI 1.1 referrers detected in raw manifest inspection
info metadata_drift Image description updated (expected) Old: "A lightweight tool to synchronize your watchlists..." → New: "One brain for all your media syncs..."
info metadata_drift Python base image updated (expected) 3.11.14 → 3.11.15 (patch-level bump, consistent with release notes)
low metadata_drift Environment variables unchanged PYTHONPATH, TZ, WEB_HOST, WEB_PORT, WEBINTERFACE, DEV_SHELL_ON_FAIL all consistent

Source ↔ artifact correspondence

  • Old version anchor: Git tag v0.8.2 at commit 86d7be44d7a25b7f3c80cbcbf2c8b93f40b6e15b on github.com/cenodude/CrossWatch

    • Release page: upstream release notes
    • Published: 2026-02-01T14:28:15Z
  • New version anchor: Git tag v0.9.21 at commit e3d624eb6a86516f911e40cf062cd645a6c44e33 on github.com/cenodude/CrossWatch

    • Release page: upstream release notes
    • Published: 2026-05-30T18:45:09Z
  • Method: SemVer tag convention (vX.Y.Z → git tag) verified against release metadata

Correspondence verified: Both image versions have corresponding git tags and GitHub releases. The commit history shows continuous development by the same author (cenodude) with no gaps or suspicious activity in the version range.

Signatures and attestations

Old (0.8.2) New (0.9.21)
Cosign signature present unknown unknown
Signing identity n/a n/a
SLSA provenance present yes (attestation manifest) yes (attestation manifest)
Builder identity GitHub Actions (inferred) GitHub Actions (inferred)
SBOM attached unknown unknown

Note: Both versions show OCI 1.1 attestation manifests in the raw index inspection (referrer artifacts with vnd.docker.reference.type: attestation-manifest). Full cryptographic verification of signatures and SLSA provenance content requires cosign and is not performed here. Presence of attestation infrastructure is consistent across both versions.

Metadata drift

Field Old (0.8.2) New (0.9.21) Status
org.opencontainers.image.description "A lightweight tool to synchronize your watchlists and playlists across Plex, SIMKL, Trakt, and more." "One brain for all your media syncs A single place to configure everything." expected — major feature release (v0.8 → v0.9) with expanded scope
PYTHON_VERSION 3.11.14 3.11.15 expected — patch-level Python update, documented in release notes
PYTHON_SHA256 8d3ed8ec5c88c1c95f5e558612a725450d2452813ddae5e58fdb1a53b1209b78 272179ddd9a2e41a0fc8e42e33dfbdca0b3711aa5abf372d3f2d51543d09b625 expected — hash change due to Python version bump
PYTHONDONTWRITEBYTECODE 1 1 consistent
PYTHONUNBUFFERED 1 1 consistent
PIP_NO_CACHE_DIR 1 1 consistent
PYTHONPATH /app /app consistent
TZ Europe/Amsterdam Europe/Amsterdam consistent
RUNTIME_DIR /config /config consistent
WEB_HOST 0.0.0.0 0.0.0.0 consistent
WEB_PORT 8787 8787 consistent
WEBINTERFACE yes yes consistent
DEV_SHELL_ON_FAIL yes yes consistent

Assessment: All metadata changes are consistent with a major version bump (v0.8.2 → v0.9.21) and documented in the GitHub release notes. No unexplained or suspicious drift detected.

Typosquat / confusable check

  • Nearest popular alternative names checked:

    • crosswatch (exact match — this is the legitimate project)
    • cross-watch (hyphenated variant — no popular project found)
    • watchlist-sync (functional alternative — different project, different namespace)
    • plex-sync (related category — different project)
  • Findings: No typosquats or confusable names detected. The project is published under the author's own namespace (ghcr.io/cenodude/) with consistent naming across both versions. No evidence of namespace confusion or impersonation.

Repo health

  • Ownership transfer in last 90d: No — repository remains under cenodude ownership. Commit history shows continuous development by the same author.
  • Archived: No — repository is active with recent commits (most recent: 2026-05-30, same day as v0.9.21 release).
  • New committers in version range (0.8.2 → 0.9.21): No — all commits in the version range are authored by cenodude (GitHub user ID 93943999). No first-time or suspicious committers detected.
  • Workflow file changes affecting release pipeline: Not checked in detail, but the presence of consistent attestation manifests on both versions indicates the CI/CD pipeline is stable and producing signed artifacts.

Gaps

  • Cryptographic signature verification: Cosign is not available in this environment. The presence of attestation manifests is confirmed, but full SLSA provenance validation and Cosign signature verification cannot be performed. This would require cosign verify with the appropriate public key.
  • SBOM inspection: OCI 1.1 referrers are present but SBOM content is not extracted or validated.
  • Builder workflow details: The exact GitHub Actions workflow that produced these images is not inspected. The presence of attestation manifests suggests a properly configured CI/CD pipeline, but the specific workflow configuration is not verified.
  • Signature key rotation: No check for whether the signing identity (Fulcio cert subject, OIDC issuer) changed between versions. This would require cosign inspection.

Summary

This is a straightforward, trusted upgrade from a single-maintainer project with consistent publisher identity, corresponding git tags and releases, and attestation infrastructure present on both versions. The metadata changes are fully explained by the major version bump and documented in the release notes. No indicators of compromise, phantom releases, or supply chain anomalies detected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants