fix(skillpack): address review — symlink read, git arg-injection, dup-subscribe, nil panics
executus CI / test (pull_request) Successful in 3m30s
executus CI / test (pull_request) Successful in 3m30s
Real issues from the PR review: - security: readTree now skips symlinks (a pack with SKILL.md -> /etc/passwd or scripts/x -> ../../.ssh/id_rsa could read host files); covers file and dir symlinks, incl. within a git subpath - security: GitSource rejects url/ref beginning with '-' (git arg injection) and clones with '--' separator; --filter=blob:none (blobless partial clone) instead of full-history clone - correctness: Subscribe no longer swallows a non-ErrNotFound store error from GetByName (would create a duplicate subscription); handles *GitSource as well as GitSource in the URL/subpath extraction - correctness: pinTo no longer renames a subscription, so Apply can't silently collide two subscriptions when an upstream pack changes its name - validation: isKebab rejects leading/trailing/consecutive hyphens; BOM- prefixed SKILL.md now parses (matches the doc comment) - robustness: Catalog/Activate/renderPackBody/Stage guard nil/malformed packs - test cleanup: Syncer.Store field renamed Cache (collided with the Store interface); test NewID returns distinct ids - tests: symlink-skip, BOM, strict-kebab, nil-pack-safety Deferred (advisory perf, documented): PackCache stores raw trees so activation re-parses; CheckAll is serial. Both fine at expected scale. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+18
-2
@@ -88,17 +88,33 @@ func (g GitSource) run(ctx context.Context, dir string, args ...string) ([]byte,
|
||||
}
|
||||
|
||||
func (g GitSource) Fetch(ctx context.Context, ref string) (Tree, string, error) {
|
||||
// Argument-injection guard: a URL or ref beginning with "-" would be parsed
|
||||
// by git as an option (e.g. --upload-pack=…), not a value. Reject it rather
|
||||
// than rely solely on the "--" separator, which checkout does not honor for
|
||||
// a rev. Hosts should also allow-list sources, but this is defense-in-depth
|
||||
// for a library.
|
||||
if strings.HasPrefix(g.URL, "-") {
|
||||
return nil, "", fmt.Errorf("skillpack: git url must not start with '-': %q", g.URL)
|
||||
}
|
||||
if strings.HasPrefix(ref, "-") {
|
||||
return nil, "", fmt.Errorf("skillpack: git ref must not start with '-': %q", ref)
|
||||
}
|
||||
|
||||
tmp, err := os.MkdirTemp("", "skillpack-git-*")
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if _, err := g.run(ctx, "", "clone", "--quiet", g.URL, tmp); err != nil {
|
||||
// --filter=blob:none: a blobless partial clone gets the ref graph cheaply
|
||||
// and fetches only the blobs the checkout needs — much less than the full
|
||||
// history, while still supporting an arbitrary commit-ish ref. "--" ends
|
||||
// option parsing before the URL.
|
||||
if _, err := g.run(ctx, "", "clone", "--quiet", "--filter=blob:none", "--", g.URL, tmp); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if ref != "" {
|
||||
if _, err := g.run(ctx, tmp, "checkout", "--quiet", ref); err != nil {
|
||||
if _, err := g.run(ctx, tmp, "checkout", "--quiet", "--detach", ref); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user