Skip to content

Add git reference support for skill install#4046

Closed
JAORMX wants to merge 4 commits intorefactor/move-git-packagefrom
feat/skill-install-git-refs-v2
Closed

Add git reference support for skill install#4046
JAORMX wants to merge 4 commits intorefactor/move-git-packagefrom
feat/skill-install-git-refs-v2

Conversation

@JAORMX
Copy link
Collaborator

@JAORMX JAORMX commented Mar 9, 2026

Summary

  • Plain skill names (thv skill install my-skill) created "pending" records that never resolved — a dead-end UX problem. This replaces the pending path with an actionable 404 error.
  • Users can now install skills directly from git repos: thv skill install git://github.com/org/repo#path/to/skill
  • New pkg/skills/gitresolver/ package handles URL parsing, clone resolution, host-scoped auth, and secure file writing.

Relates to #4015

Type of change

  • New feature

Test plan

  • Unit tests (task test)
  • E2E tests (task test-e2e)
  • Linting (task lint-fix)

Changes

File Change
pkg/skills/gitresolver/reference.go Newgit:// URL parsing with SSRF prevention (private IP/localhost rejection, absolute path/backslash rejection)
pkg/skills/gitresolver/resolver.go NewResolver interface: clones repo, extracts skill files, enforces 2-min clone timeout
pkg/skills/gitresolver/auth.go New — host-scoped auth resolution (GITHUB_TOKEN only sent to github.com, etc.)
pkg/skills/gitresolver/writer.go New — writes files to disk with symlink checks, containment validation, permission cap (0644)
pkg/skills/skillsvc/git_install.go NewinstallFromGit, resolveGitReference, upsertGitSkill methods with supply chain defense
pkg/skills/skillsvc/skillsvc.go Git check added before OCI in Install(), dead-end installPending replaced with actionable 404
pkg/skills/skillsvc/skillsvc_test.go Updated tests for new behavior (pending → 404, group tests use extraction path)
pkg/api/server.go Wired WithGitResolver in service construction
cmd/thv/app/skill_install.go Updated Long description with git reference examples
test/e2e/api_skills_test.go Updated E2E tests for new plain-name 404 behavior

Does this introduce a user-facing change?

Yes. thv skill install now accepts git references:

thv skill install git://github.com/org/repo#skills/my-skill
thv skill install git://github.com/org/repo@v1.0#skills/my-skill

Plain skill names that can't be resolved locally now return an actionable error instead of creating a dead-end "pending" record.

Special notes for reviewers

Security review completed

  • Credential exfiltration prevented: Tokens are host-scoped per-clone — GITHUB_TOKEN only sent to github.com, GITLAB_TOKEN only to gitlab.com. GIT_TOKEN is opt-in fallback.
  • Clone timeout: 2-minute context.WithTimeout prevents slowloris-style hangs.
  • Path validation hardened: validateSkillPath rejects absolute paths and backslashes in addition to .. traversal.
  • SSRF: Static host validation rejects localhost/private IPs.
  • Supply chain: Skill name in SKILL.md must match the name implied by the git reference.
  • Resource limits: LimitedFs caps clones at 10k files / 100MB.

Known limitations for follow-up

  • DNS rebinding not mitigated (needs custom http.Transport with DialContext hook)
  • No host allowlist (denylist only)
  • collectFiles reads only top-level files in the skill directory (flat structure)
  • No Resolver mock generated yet — installFromGit unit tests should be added with a mock

This is PR 2 of 2 — split from #4042. Depends on the git package move in the base branch.

Generated with Claude Code

@github-actions github-actions bot added the size/XS Extra small PR: < 100 lines changed label Mar 9, 2026
@JAORMX JAORMX force-pushed the refactor/move-git-package branch 2 times, most recently from 13536fb to efa601e Compare March 9, 2026 10:36
@JAORMX JAORMX requested a review from jerm-dro as a code owner March 9, 2026 10:36
JAORMX and others added 4 commits March 9, 2026 12:44
Users can now install skills directly from git repositories using:
  thv skill install git://github.com/org/repo#path/to/skill

This eliminates the "pending forever" problem where plain skill names
created dead-end records. Unresolved plain names now return an
actionable 404 error suggesting valid installation methods.

New package pkg/skills/gitresolver/ provides:
- Reference parsing with SSRF prevention (private IP/localhost rejection)
- Path traversal validation (reject .., absolute paths, backslashes)
- Host-scoped auth (GITHUB_TOKEN only sent to github.com, etc.)
- Clone timeout (2 minutes) to prevent slowloris attacks
- Supply chain defense (SKILL.md name must match git reference)
- File writer with symlink checks and permission sanitization (0644 cap)

Security reviewed: credential exfiltration prevented by scoping tokens
to their respective hosts. DNS rebinding mitigation deferred as
follow-up (requires custom DialContext).

Relates to #4015

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add filepath.Clean at function entry so CodeQL can trace the sanitized
path through all downstream os calls. Add #nosec annotations for gosec
consistency with the existing installer.go patterns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The targetDir parameter in WriteFiles is produced by
PathResolver.GetSkillPath which builds paths from known base
directories — not directly from user input. Add codeql[go/path-injection]
inline suppression comments to document this.

This is the same false-positive pattern as the existing alerts in
pkg/skills/installer.go and pkg/skills/skillsvc/skillsvc.go on main.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The git reference support PR replaced dead-end "pending" records
with an actionable 404 for unresolvable plain skill names. The E2E
tests were still installing plain names without building first.

Each affected test now calls buildTestSkill() before installSkill()
to place the artifact in the local OCI store, matching the real
build-then-install workflow. A new test explicitly covers the 404
path for unresolvable names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@JAORMX JAORMX force-pushed the feat/skill-install-git-refs-v2 branch from 6202e00 to bd0f454 Compare March 9, 2026 10:45
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XS Extra small PR: < 100 lines changed labels Mar 9, 2026
Copy link
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.

@JAORMX JAORMX closed this Mar 9, 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.

1 participant