Skip to content

Support multi-client and all-clients skill installation#4732

Open
samuv wants to merge 16 commits intomainfrom
skills-install-multi-client
Open

Support multi-client and all-clients skill installation#4732
samuv wants to merge 16 commits intomainfrom
skills-install-multi-client

Conversation

@samuv
Copy link
Copy Markdown
Contributor

@samuv samuv commented Apr 10, 2026

Summary

Extends the skill install API and CLI to install a skill to multiple clients in a single operation, with atomicity (all-or-nothing) and rollback on failure.

API / CLI changes

  • client (single string) is replaced by clients (array of strings) — breaking change
  • Omitting clients or passing ["all"] installs to every available skill-supporting client (previously defaulted to the first client only)
  • Mixing "all" with explicit client names returns HTTP 400
  • Invalid or non-skill-supporting client names return HTTP 400

Storage

  • InstalledSkill.Clients is populated and merged correctly across fresh installs, same-digest partial installs, and digest upgrades

Internals

  • resolveAndValidateClients handles the empty / "all" / explicit-list cases via a single switch
  • Path containment validation on every resolved directory
  • Atomic rollback removes written directories and reverts the DB record on any failure

Large PR Justification

  • The feature touches every layer of the stack atomically: API types, service logic, CLI flag, HTTP client, storage model, and generated OpenAPI docs. Splitting across PRs would leave the API in a broken or inconsistent state between merges.
  • The regenerated OpenAPI files (docs/server/docs.go, swagger.json, swagger.yaml) cannot be separated from the source change that drives them — they must land in the same commit to keep the spec in sync with the implementation.
  • Test additions are tightly coupled to the new rollback and multi-client paths and cannot be merged independently without the implementation.

@github-actions github-actions bot added the size/L Large PR: 600-999 lines changed label Apr 10, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 10, 2026

Codecov Report

❌ Patch coverage is 75.10730% with 58 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@25b5c78). Learn more about missing BASE report.
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/skills/skillsvc/skillsvc.go 74.78% 42 Missing and 16 partials ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4732   +/-   ##
=======================================
  Coverage        ?   68.79%           
=======================================
  Files           ?      516           
  Lines           ?    54390           
  Branches        ?        0           
=======================================
  Hits            ?    37415           
  Misses          ?    14115           
  Partials        ?     2860           

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

@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Apr 10, 2026
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Apr 10, 2026
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Apr 10, 2026
}
for _, ct := range toWrite {
dir := filepath.Clean(clientDirs[ct])
if _, statErr := os.Stat(dir); statErr == nil && !opts.Force { // lgtm[go/path-injection]
) (*skills.InstallResult, error) {
for _, ct := range clientTypes {
dir := filepath.Clean(clientDirs[ct])
if _, statErr := os.Stat(dir); statErr == nil && !opts.Force { // lgtm[go/path-injection]
var written []string
for _, ct := range toWrite {
dir := filepath.Clean(clientDirs[ct])
if _, statErr := os.Stat(dir); statErr == nil && !opts.Force { // lgtm[go/path-injection]
) (*skills.InstallResult, error) {
for _, ct := range clientTypes {
dir := filepath.Clean(clientDirs[ct])
if _, statErr := os.Stat(dir); statErr == nil && !opts.Force { // lgtm[go/path-injection]
@JAORMX
Copy link
Copy Markdown
Collaborator

JAORMX commented Apr 10, 2026

Shall we add support for all if it's not there already? And make it the default

@samuv
Copy link
Copy Markdown
Contributor Author

samuv commented Apr 10, 2026

Shall we add support for all if it's not there already? And make it the default

yeah, why not!

@samuv samuv changed the title Skills install multi client Support multi-client and all-clients skill installation Apr 10, 2026
@github-actions github-actions bot removed the size/L Large PR: 600-999 lines changed label Apr 10, 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 Apr 10, 2026
@github-actions
Copy link
Copy Markdown
Contributor

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

@github-actions github-actions bot dismissed their stale review April 10, 2026 15:58

Large PR justification has been provided. Thank you!

@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 Apr 10, 2026
@samuv samuv force-pushed the skills-install-multi-client branch from 6da5bc0 to 9ea4a88 Compare April 10, 2026 15:59
samuv added 16 commits April 10, 2026 18:00
Add InstallOptions.Clients, resolve and validate client paths, multi-dir
extract/write with rollback, and legacy empty-Clients digest no-op.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Breaking: install body field client is replaced by clients []string.
Signed-off-by: Samuele Verzi <samu@stacklok.com>
Mirror API install body; include group on install request DTO.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Comma-separated values map to InstallOptions.Clients.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Update OpenAPI install schema and CLI/skill user references.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Extract git and OCI install paths into smaller helpers, add
missingClients and removeSkillDirs, and fix import order in tests.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Signed-off-by: Samuele Verzi <samu@stacklok.com>
Signed-off-by: Samuele Verzi <samu@stacklok.com>
Cover legacy no-op with explicit client, upgrade extracting to all
existing clients, and multi-client rollback and error paths.
Apply filepath.Clean at path resolution time and validate against
traversal segments before any filesystem operation.
Apply filepath.Clean at every point where a path is retrieved from the
clientDirs/allDirs map before a filesystem operation (os.Stat, Extract,
WriteFiles, Remove). CodeQL's taint tracker loses the sanitization done
at storage time once the value flows through a map; cleaning at retrieval
makes the guard visible to the analyzer at each individual sink.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Made-with: Cursor
The four os.Stat(dir) pre-checks in applyGitInstallExisting,
applyGitInstallFresh, installExtractionSameDigestNewClients, and
installExtractionFresh are flagged by CodeQL's go/path-injection query
because 'dir' originates (transitively) from user-supplied client names.
The paths are safe: client names are validated against the known
skill-supporting client list, skill names pass validateLocalPath, and
PathResolver.GetSkillPath constructs paths from fixed base directories
which are then confirmed absolute and traversal-free by validateResolvedDir.

Add the same // lgtm[go/path-injection] suppression used in
pkg/skills/gitresolver/writer.go for the identical taint flow.

Signed-off-by: Samuele Verzi <samu@stacklok.com>
Made-with: Cursor
@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 Apr 10, 2026
@samuv samuv force-pushed the skills-install-multi-client branch from 9ea4a88 to 67250d4 Compare April 10, 2026 16:00
@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 Apr 10, 2026
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