Skip to content

skills-init: full-clone SHA pinning always fails (checkout treats commit SHA as pathspec, not revision) #2608

Description

@haakotsm

Summary

skills-init's full-clone-then-checkout path (CloneGit in go/core/internal/skillsinit/git.go) always fails when Full: true is used with a commit SHA ref, because the checkout command passes the SHA as a pathspec rather than a revision:

if err := runGitIn(ref.Dest, "checkout", "--", ref.Ref); err != nil {

The -- separator before ref.Ref forces git to interpret ref.Ref as a pathspec, not a commit-ish. Since no file in the repo is literally named after the 40-char SHA, this always fails with:

error: pathspec '<sha>' did not match any file(s) known to git

Reproduction

git init repo && cd repo
echo x > f && git add f && git commit -m init
SHA=$(git rev-parse HEAD)

git checkout -- "$SHA"
# error: pathspec '<sha>' did not match any file(s) known to git

git checkout "$SHA"
# Note: switching to '<sha>'.  ... (works correctly)

Confirmed against the released v0.9.12 tag (same code present on main as of this report) — the bug affects every deployment using a gitRefs[].full: true entry pinned to a commit SHA, which is exactly the pattern the skills-init docs recommend for supply-chain-safe SHA pinning (full clone + immutable SHA, as opposed to the depth-1 --branch path which only accepts mutable branch/tag names).

Impact

Any Agent CRD that references a skill via a SHA-pinned full: true git ref will have its skills-init init container crash-loop forever with Init:Error, because the container restarts and re-runs from a directory that was already (partially) cloned on the previous attempt, compounding with a second bug: retries against an already-cloned dest fail with destination path ... already exists and is not an empty directory before ever reaching the checkout step. Users relying on SHA pinning for supply-chain integrity have no working code path today.

Suggested fix

Drop the -- separator (or place it after the ref) in the checkout call:

if err := runGitIn(ref.Dest, "checkout", ref.Ref, "--"); err != nil {

ref.Ref is already validated upstream as a 40/64-char hex string when Full is true, so there's no argument-injection risk from treating it as a revision instead of a pathspec.

Environment

  • kagent skills-init image: v0.9.12
  • Discovered while live-verifying a kagent Agent CRD using a SHA-pinned skill in a lab cluster.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions