Skip to content

Add plugin key rotation workflows - #6663

Merged
samuv merged 3 commits into
mainfrom
samuv/plugins-key-reanchor
Sep 18, 2026
Merged

samuv merged 3 commits into
mainfrom
samuv/plugins-key-reanchor

Conversation

@samuv

@samuv samuv commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Plugin projects have the same key-rotation and adoption gap as skills. This mirrors the lock-driven re-anchor contract so both user-facing surfaces apply the same trust rules.
  • Add --public-key support to plugin upgrade and sync adoption, require --allow-signer-change for replacement anchors, and retain the recorded key whenever it still verifies.
  • Share project transaction locking between skills and plugins while preserving per-plugin locking for user-scoped operations.
  • Update the CLI, API, SDK, architecture documentation, and regression coverage for plugin key rotation.

Fixes #6640

Type of change

  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Dependency update
  • Documentation
  • Other (describe):

Test plan

  • Unit tests (task test)
  • E2E tests (task test-e2e)
  • Linting (task lint-fix)
  • Manual testing (describe below)

task gen, task docs, and task build pass. Changed-package unit tests pass. The full task test run reaches five unrelated pkg/api failures because no container runtime is available. The focused plugin key-trust E2E suite compiles and reaches setup, where it stops for the same missing runtime.

Changes

Area Change
Plugin CLI and API Accept and validate replacement public keys for upgrade and sync adoption.
Plugin service Re-anchor only after successful verification and update trust state transactionally.
Project transactions Move shared project locking into pkg/projecttxn for skills and plugins.
Generated reference Regenerate CLI, OpenAPI, and Go SDK outputs.
Tests and architecture Cover rotation, adoption, rollback, concurrency, and documented trust semantics.

Does this introduce a user-facing change?

Yes. thv ai-plugin upgrade --allow-signer-change --public-key <PUBLIC_KEY_PATH> can re-anchor a key-pinned OCI plugin, and thv ai-plugin sync --adopt --public-key <PUBLIC_KEY_PATH> can adopt an installed key-signed plugin.

Implementation plan

Approved implementation plan
  1. Mirror the approved skill key-rotation contract for plugin upgrade and sync adoption.
  2. Keep lock-first policy selection, try the recorded key first, and consider the replacement only after a conclusive mismatch.
  3. Reuse strict OCI snapshots for explicit replacement-key re-anchors and preserve ordinary upgrade compatibility.
  4. Extract project transaction locking for shared skill and plugin use while retaining user-scope plugin locks.
  5. Add unit and E2E coverage, then regenerate CLI and API documentation.

Special notes for reviewers

This is the second PR in the stack and is based on #6662. The approved PR-size exception keeps plugin parity, shared transaction extraction, tests, and generated outputs in one reviewable change.

@samuv
samuv added this pull request to stack #6664 September 15, 2026 13:17
@github-actions github-actions Bot added the size/XL Extra large PR: 1000+ lines changed label Sep 15, 2026
@samuv samuv mentioned this pull request Sep 15, 2026
10 tasks
@codecov

codecov Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.50000% with 84 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@97b81d8). Learn more about missing BASE report.

Files with missing lines Patch % Lines
pkg/plugins/pluginsvc/upgrade.go 74.73% 71 Missing ⚠️
pkg/projecttxn/transaction.go 82.85% 6 Missing ⚠️
pkg/plugins/pluginsvc/sync.go 94.11% 3 Missing ⚠️
pkg/plugins/pluginsvc/verify.go 92.00% 2 Missing ⚠️
pkg/plugins/pluginsvc/install_extraction.go 88.88% 1 Missing ⚠️
pkg/skills/lockfile/lockfile.go 87.50% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6663   +/-   ##
=======================================
  Coverage        ?   79.20%           
=======================================
  Files           ?      792           
  Lines           ?    79873           
  Branches        ?        0           
=======================================
  Hits            ?    63263           
  Misses          ?    16605           
  Partials        ?        5           

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

@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from 3592c58 to 32904c3 Compare September 15, 2026 14:06
@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 Sep 15, 2026
@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from 32904c3 to f155300 Compare September 16, 2026 08: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 Sep 16, 2026
JAORMX
JAORMX previously requested changes Sep 16, 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.

Reviewed the plugin-only stack against #6662: initially 32904c3 vs 560a05b, then verified the exact trees at f155300 vs d655077. The rebase changes only go.mod/go.sum relative to the initially reviewed plugin head; all implementation blobs are identical.

Spec: the plugin flow follows #6640's old-key-first, lock-first, explicit replacement and offline-adoption contract. No separate spec mismatch found.
Standards: the new projecttxn package exposes implementation-oriented Lock/LockPath helpers; reducing that API or documenting its canonical-root precondition would be worthwhile, but current production callers normalize roots, so this is nonblocking.
Domain: one newly added metadata-refresh rollback path can leave SQLite metadata inconsistent with the lock after cancellation (inline). Shared project transaction locking and the bounded trust-only rollback otherwise follow the intended design.

I excluded inherited SDK issues and concerns outside the documented contract, including crash-atomic journaling and treating offline adoption as authentication of already-materialized filesystem bytes. The keyless fallback for an unrecorded legacy entry is also consistent with the per-entry policy, not a replacement-key bypass.

Nonblocking: document public_key's base64-encoded DER SPKI representation and allowed option combinations in the API fields so generated SDK/OpenAPI docs explain the wire contract.

Core #297 has now been re-reviewed and approved at e5c9df0. The local cancellation issue on skills #6662 still needs its separate fix. All 46 checks passed on the originally reviewed plugin head; the new head's CI was still running at the last check. No local tests or linters were run.

Comment thread pkg/plugins/pluginsvc/install_extraction.go
@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from f155300 to ab54e7c Compare September 16, 2026 09:40
@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 Sep 16, 2026
@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from ab54e7c to dbe24af Compare September 16, 2026 16:17
@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 Sep 16, 2026
@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from dbe24af to bd94161 Compare September 16, 2026 16:38
@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 Sep 16, 2026
@samuv
samuv requested review from blkt and jerm-dro as code owners September 17, 2026 16:14
@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from bd94161 to 35c9f1a Compare September 17, 2026 16:14
@samuv samuv self-assigned this Sep 17, 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 Sep 17, 2026
@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from 35c9f1a to b4bd3ee Compare September 18, 2026 12:34
@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 Sep 18, 2026
@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from b4bd3ee to 1ce95bb Compare September 18, 2026 12:58
@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 Sep 18, 2026
jhrozek
jhrozek previously approved these changes Sep 18, 2026
@samuv
samuv dismissed JAORMX’s stale review September 18, 2026 13:12

going with the approval from jakub

Base automatically changed from samuv/skills-key-reanchor to main September 18, 2026 13:22
Signed-off-by: Samuele Verzi <samu@stacklok.com>
Signed-off-by: Samuele Verzi <samu@stacklok.com>
Signed-off-by: Samuele Verzi <samu@stacklok.com>
@samuv
samuv force-pushed the samuv/plugins-key-reanchor branch from 1ce95bb to d49231c Compare September 18, 2026 13:22
@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 Sep 18, 2026
@samuv
samuv merged commit 6eb9398 into main Sep 18, 2026
47 checks passed
@samuv
samuv deleted the samuv/plugins-key-reanchor branch September 18, 2026 13:44
@github-actions github-actions Bot mentioned this pull request Sep 18, 2026
2 tasks
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.

Key-pinned entries need a lock-driven re-anchor path (skills and plugins)

3 participants