Skip to content

Add workload upgrade detection package#5407

Merged
JAORMX merged 3 commits into
mainfrom
upgrade-1-detection
Jun 2, 2026
Merged

Add workload upgrade detection package#5407
JAORMX merged 3 commits into
mainfrom
upgrade-1-detection

Conversation

@JAORMX
Copy link
Copy Markdown
Collaborator

@JAORMX JAORMX commented Jun 1, 2026

Summary

CLI and API users have no way to discover when a registry-sourced MCP server has a newer version available. Today only ToolHive Studio detects image-tag drift, and it does so in its frontend — so CLI users are blind to updates and every new client would have to reimplement the same logic. This is the first slice of RFC THV-0068 (Workload Upgrade), moving detection into the backend where all clients can consume it. Local experience only (Kubernetes is out of scope for this RFC).

  • Add a new pkg/workloads/upgrade package with a Checker that compares a running workload's image tag against its current registry entry.
  • Tag comparison is semver-aware (via golang.org/x/mod/semver) with a string-equality fallback; it degrades safely to unknown for :latest, digest references, repository changes (host-normalized), and non-registry-sourced workloads, so only a strictly-newer tag on the same repository yields upgrade-available.
  • Reports environment-variable drift (new/removed registry-declared vars) and configuration drift (permission profile, transport, network isolation), with secret env-var defaults cleared from results.

Type of change

  • New feature

Test plan

  • Unit tests (task test) — table-driven coverage of tag comparison (incl. double-digit-minor and prerelease ordering), env/config drift, and status gating; registry provider mocked.
  • Linting (task lint-fix)

Changes

File Change
pkg/workloads/upgrade/doc.go Package doc, cycle guard, no-rollback note
pkg/workloads/upgrade/types.go CheckResult, EnvVarDrift, ConfigDrift, UpgradeStatus, ApplyOptions
pkg/workloads/upgrade/version.go Semver-aware tag comparison helper
pkg/workloads/upgrade/checker.go Checker + Check/CheckAll
pkg/workloads/upgrade/*_test.go Unit tests incl. a drift-guard for the env-var boundary type

Does this introduce a user-facing change?

No — this PR adds an internal package only. The thv upgrade commands and REST endpoints that consume it land in later PRs of this stack.

Large PR Justification

This PR is ~1,158 lines, but 627 of those are unit tests (*_test.go) and only 531 are source across one cohesive new package (doc.go + types.go + version.go + checker.go).

  • The source cannot be split smaller without leaving code uncompilable or untested. The Checker depends on its result types (types.go) and the tag-comparison helper (version.go); separating them yields a package that does not build. This is one self-contained unit, the smallest reviewable slice of the feature.
  • Tests must ship with the code, not separately. Splitting the 627 lines of table-driven tests into a follow-up PR would merge untested detection logic — exactly what review is meant to prevent.
  • The feature as a whole was deliberately split into 6 stacked PRs (this is fix(typo): corrects readme #1) to keep each phase focused; this phase is the irreducible detection core.

Special notes for reviewers

This is PR 1 of 6 in a stack implementing RFC THV-0068 (split to stay within the repo's PR-size limit). Each PR is one logical phase; later PRs are based on this branch:

  1. Detection package ← this PR
  2. Check REST API (GET .../upgrade-check)
  3. CLI thv upgrade check + thv list --check-upgrades
  4. upgrade.Applier
  5. Apply CLI + API (thv upgrade apply, POST .../upgrade)
  6. e2e + lifecycle docs

🤖 Generated with Claude Code

@github-actions github-actions Bot added the size/XL Extra large PR: 1000+ lines changed label Jun 1, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Large PR Detected

This PR exceeds 1000 lines of changes and requires justification before it can be reviewed.

How to unblock this PR:

Add a section to your PR description with the following format:

## Large PR Justification

[Explain why this PR must be large, such as:]
- Generated code that cannot be split
- Large refactoring that must be atomic
- Multiple related changes that would break if separated
- Migration or data transformation

Alternative:

Consider splitting this PR into smaller, focused changes (< 1000 lines each) for easier review and reduced risk.

See our Contributing Guidelines for more details.


This review will be automatically dismissed once you add the justification section.

CLI and API users have no way to discover when a newer version of a
registry-sourced MCP server is available; only Studio implements drift
detection, in its frontend. Introduce a backend package that all clients
can consume.

Add pkg/workloads/upgrade with a Checker that compares a running
workload's image tag against its registry entry (semver-aware, with a
string fallback) and reports environment-variable and configuration
(transport / permission-profile / network-isolation) drift. Comparison
degrades safely to "unknown" for :latest, digest refs, repository
changes, and non-registry-sourced workloads, so only a strictly-newer
tag on the same repository yields "upgrade-available".

This is the read-only detection core (RFC THV-0068, phase A); the apply
path, API endpoints, and CLI follow in later changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JAORMX JAORMX force-pushed the upgrade-1-detection branch from b1361f7 to 3350917 Compare June 1, 2026 09:31
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jun 1, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Codecov Report

❌ Patch coverage is 91.89189% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.83%. Comparing base (05ca226) to head (d9f4c8d).

Files with missing lines Patch % Lines
pkg/workloads/upgrade/checker.go 90.19% 8 Missing and 2 partials ⚠️
pkg/workloads/upgrade/version.go 95.23% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5407      +/-   ##
==========================================
+ Coverage   68.77%   68.83%   +0.06%     
==========================================
  Files         629      632       +3     
  Lines       63937    64085     +148     
==========================================
+ Hits        43970    44111     +141     
- Misses      16713    16718       +5     
- Partials     3254     3256       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@JAORMX JAORMX marked this pull request as ready for review June 1, 2026 10:21
@JAORMX JAORMX requested review from amirejaz and lujunsan as code owners June 1, 2026 10:21
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jun 1, 2026
@github-actions github-actions Bot dismissed their stale review June 1, 2026 10:25

Large PR justification has been provided. Thank you!

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

✅ Large PR justification has been provided. The size review has been dismissed and this PR can now proceed with normal review.

Copy link
Copy Markdown
Contributor

@jhrozek jhrozek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detection logic looks solid and the tests are thorough. A few comments from a focused review of the comparison/drift logic — one correctness item on semver normalization, plus two defensive/semantic notes. Nothing blocking.

Comment thread pkg/workloads/upgrade/version.go Outdated
Comment thread pkg/workloads/upgrade/checker.go Outdated
Comment thread pkg/workloads/upgrade/checker.go
Comment thread pkg/workloads/upgrade/checker.go Outdated
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jun 1, 2026
- Lowercase an uppercase "V" tag prefix so semver comparison works;
  "V1.2.0" vs "V1.3.0" no longer falls through to undecidable and
  hides a real upgrade.
- Drop the raw provider error from CheckResult.Reason (it is serialized
  into the API response and can leak internal addressing); log it at
  DEBUG and return a fixed string. Same for the CheckAll path.
- Add a defensive default to the comparison switch so an unexpected
  value yields StatusUnknown rather than the least-safe StatusUpToDate.
- Stop reporting network-isolation drift: the registry has no
  network-isolation field, so it fired for every isolated workload
  regardless of the candidate version. Remove the ConfigDrift field
  and the now-unused BoolChange type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JAORMX JAORMX force-pushed the upgrade-1-detection branch from 0431342 to 6cb9506 Compare June 1, 2026 13:27
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jun 1, 2026
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jun 2, 2026
@JAORMX JAORMX merged commit db82aef into main Jun 2, 2026
45 checks passed
@JAORMX JAORMX deleted the upgrade-1-detection branch June 2, 2026 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Extra large PR: 1000+ lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants