Skip to content

Add plugin lock-file sync - #6316

Merged
samuv merged 9 commits into
mainfrom
plugins-lock/04-sync
Aug 19, 2026
Merged

Add plugin lock-file sync#6316
samuv merged 9 commits into
mainfrom
plugins-lock/04-sync

Conversation

@samuv

@samuv samuv commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Why: A lock file that is only written on install cannot restore a fresh clone or detect on-disk tampering. Sync is the restore half of RFC THV-0080 for plugins:.
  • What:
    • thv ai-plugin sync and POST /plugins/sync restore project plugins from toolhive.lock.yaml (--check / --adopt / --prune, confirmation gate, exit codes 0/2/3/4).
    • Missing or drifted entries are reinstalled at their pinned digest via buildPinnedReference — never re-resolved from source. SyncRestore bypasses the same-digest no-op so on-disk drift is repaired.
    • --check hashes every client's canonical plugin directory (contentDigest), not marketplace.json.
    • --adopt records unmanaged project-scope installs without requiring --allow-unsigned (plugin Sigstore is Stack 2).
    • Gated by TOOLHIVE_PLUGINS_LOCK_ENABLED (403 when off). Upgrade is a 501 stub until the next stack PR.

Part of #6300. Stack 4/5 — schema → lock-service → install-hooks → sync → upgrade.

Type of change

  • New feature

Test plan

  • Unit tests (./pkg/plugins/pluginsvc sync/pin tests and ./pkg/api/v1 sync endpoint tests, with the Taskfile race/ldflags flags)
  • Linting (task lint-fix)

Does this introduce a user-facing change?

No by default — the feature is inert unless TOOLHIVE_PLUGINS_LOCK_ENABLED=true. With the gate on, thv ai-plugin sync restores project plugins from toolhive.lock.yaml.

Special notes for reviewers

  • pin.go is copied from skillsvc rather than extracted — agreed: reuse, don't extract.
  • Adopt does not require --allow-unsigned. Until Stack 2, lock validation allows an entry with neither provenance nor unsigned. Requiring the flag here would make every plugin adopt fail.
  • Upgrade on *service is a 501 stub so PluginLockService type-asserts for /sync. The next PR replaces it.
  • Confirmation and exit codes reuse cmd/thv/app/skill_confirm.go and exitcode.go.

@github-actions github-actions Bot added the size/XL Extra large PR: 1000+ lines changed label Aug 13, 2026
@samuv samuv self-assigned this Aug 13, 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 Aug 13, 2026
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.75000% with 117 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.11%. Comparing base (0b8acf2) to head (a649e0a).

Files with missing lines Patch % Lines
pkg/plugins/pluginsvc/sync.go 62.73% 65 Missing and 33 partials ⚠️
pkg/plugins/client/client.go 0.00% 11 Missing ⚠️
pkg/plugins/pluginsvc/pin.go 88.23% 3 Missing and 3 partials ⚠️
pkg/plugins/pluginsvc/install_oci.go 66.66% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6316      +/-   ##
==========================================
+ Coverage   73.04%   73.11%   +0.07%     
==========================================
  Files         745      747       +2     
  Lines       79208    79584     +376     
==========================================
+ Hits        57857    58189     +332     
+ Misses      17300    17282      -18     
- Partials     4051     4113      +62     

☔ View full report in Codecov by Harness.
📢 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 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Panel review found one state-consistency bug plus missing CLI E2E coverage and a thin-wrapper boundary violation. Please address the inline findings before merge.

Comment thread pkg/plugins/pluginsvc/sync.go
Comment thread cmd/thv/app/ai_plugin_sync.go
Comment thread cmd/thv/app/ai_plugin_sync.go
@samuv
samuv force-pushed the plugins-lock/04-sync branch from eb93233 to 735241d Compare August 14, 2026 08:16
@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 Aug 14, 2026
@samuv
samuv force-pushed the plugins-lock/04-sync branch from 735241d to 68fb269 Compare August 14, 2026 08:46
@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 Aug 14, 2026
@samuv
samuv force-pushed the plugins-lock/04-sync branch from 68fb269 to b820980 Compare August 14, 2026 08:57
@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 Aug 14, 2026

@JAORMX JAORMX left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The adoption rollback and CLI E2E findings were addressed. The follow-up panel found a concurrency hole in adoption compensation and incomplete Claude Code registration health checks.

Comment thread pkg/plugins/pluginsvc/sync.go Outdated
Comment thread pkg/plugins/adapters/claudecode.go
@samuv
samuv force-pushed the plugins-lock/04-sync branch from b820980 to 2ebd4a8 Compare August 14, 2026 12:52
@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 Aug 14, 2026

@JAORMX JAORMX left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two merge-blocking sync correctness issues remain in the current head.

Comment thread pkg/plugins/pluginsvc/sync.go Outdated
Comment thread pkg/plugins/pluginsvc/sync.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 Aug 19, 2026
@samuv
samuv requested a review from tgrunnagle as a code owner August 19, 2026 13:42
@samuv
samuv force-pushed the plugins-lock/04-sync branch from a7bc74d to c572121 Compare August 19, 2026 13:42
@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 Aug 19, 2026
Base automatically changed from plugins-lock/03-install-hooks to main August 19, 2026 15:20
JAORMX
JAORMX previously approved these changes Aug 19, 2026
@samuv
samuv force-pushed the plugins-lock/04-sync branch from c572121 to 880e12e Compare August 19, 2026 15:20
@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 Aug 19, 2026
samuv added 9 commits August 19, 2026 17:45
Restore project plugins from the lock file via thv ai-plugin sync
and POST /plugins/sync, gated by TOOLHIVE_PLUGINS_LOCK_ENABLED.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
A failed DB update after writing the lock entry left the plugin
untracked; remove the entry so the next sync can retry. Cover
thv ai-plugin sync exit codes the same way skills lock does.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Sync must not report a plugin current when a requested client is
missing or marketplace registration is gone, and must refuse to
adopt a local tag that cannot be restored later.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Adoption must hold the per-plugin lock and put back the
pre-existing entry if marking Managed fails.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
A stale lock/DB snapshot can resurrect uninstalls; default
sync must also expand to newly detected clients.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Default sync targets installed plugin clients, validates pinned
canonical names before mutate, and drops context lock reentrancy.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Sync already calls adoptLocked under the held mutex; remove the
dead public wrapper and quiet installFromOCI gocyclo.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
A lone --clients all now matches the documented detected-client
default instead of failing validation on every sync.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Signed-off-by: Samuele Verzi <samu@stacklok.com>
@samuv
samuv force-pushed the plugins-lock/04-sync branch from 880e12e to a649e0a Compare August 19, 2026 15:46
@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 Aug 19, 2026
@samuv
samuv merged commit 95002a5 into main Aug 19, 2026
49 checks passed
@samuv
samuv deleted the plugins-lock/04-sync branch August 19, 2026 17:40
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.

3 participants