Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ build-golang-adk-full: buildx-create
.PHONY: build-skills-init
build-skills-init: ## Build and push the skills-init image
build-skills-init: buildx-create
$(DOCKER_BUILDER) $(DOCKER_BUILD_ARGS) -t $(SKILLS_INIT_IMG) -f docker/skills-init/Dockerfile docker/skills-init
$(DOCKER_BUILDER) $(DOCKER_BUILD_ARGS) -t $(SKILLS_INIT_IMG) -f docker/skills-init/Dockerfile ./go
$(DOCKER_PUSH) $(SKILLS_INIT_IMG)

.PHONY: push
Expand Down
49 changes: 33 additions & 16 deletions docker/skills-init/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
### Stage 0: build krane
FROM golang:1.26-alpine AS krane-builder

ENV KRANE_VERSION=v0.21.2
WORKDIR /build

RUN apk add --no-cache git && \
git clone --depth 1 --branch $KRANE_VERSION \
https://github.com/google/go-containerregistry.git

WORKDIR /build/go-containerregistry/cmd/krane

RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /build/krane .

### Stage 0: build the skills-init Go binary
ARG BASE_IMAGE_REGISTRY=cgr.dev
ARG BUILDPLATFORM
FROM --platform=$BUILDPLATFORM $BASE_IMAGE_REGISTRY/chainguard/go:latest AS builder
ARG TARGETARCH
ARG TARGETOS

WORKDIR /workspace

COPY go.mod go.sum ./
RUN --mount=type=cache,target=/root/go/pkg/mod,rw \
--mount=type=cache,target=/root/.cache/go-build,rw \
go mod download

COPY api/ api/
COPY core/ core/
COPY adk/ adk/

ARG LDFLAGS
RUN --mount=type=cache,target=/root/go/pkg/mod,rw \
--mount=type=cache,target=/root/.cache/go-build,rw \
CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \
go build -a -trimpath -ldflags "$LDFLAGS" -o /skills-init ./core/cmd/skills-init

### Stage 1: runtime
FROM alpine:3.23

ARG PYTHON_UID=1001
ARG PYTHON_GID=1001

RUN apk upgrade --no-cache && apk add --no-cache git jq
COPY --from=krane-builder /build/krane /usr/local/bin/krane
# git is invoked by skills-init via exec.Command with an argv vector — never
# through a shell — so the only attack surface here is git itself. OCI fetch
# uses the in-process go-containerregistry library, so krane and jq are gone.
RUN apk upgrade --no-cache && apk add --no-cache git openssh-client ca-certificates

COPY --from=builder /skills-init /usr/local/bin/skills-init

# Run as the same UID/GID as the main agent container (python user) so that
# files written to the shared /skills volume are readable by the main container.
Expand All @@ -28,3 +43,5 @@ RUN addgroup -g ${PYTHON_GID} pythongroup && \
adduser -u ${PYTHON_UID} -G pythongroup -s /bin/sh -D python

USER ${PYTHON_UID}:${PYTHON_GID}

ENTRYPOINT ["/usr/local/bin/skills-init"]
34 changes: 34 additions & 0 deletions go/core/cmd/skills-init/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Command skills-init is the init container binary that fetches an Agent's
// skills from git repositories and OCI images before the main agent container
// starts.
//
// It reads its configuration from a ConfigMap-mounted JSON file (see the
// skillsinit package for the wire format) and performs all subprocess
// invocations with argv vectors — no user input is ever interpolated into a
// shell, which is the original design defect that motivated this rewrite.
package main

import (
"log"
"os"

"github.com/kagent-dev/kagent/go/core/internal/skillsinit"
)

func main() {
log.SetFlags(log.LstdFlags | log.Lmicroseconds)

cfg, err := skillsinit.LoadConfig()
if err != nil {
log.Fatalf("skills-init: %v", err)
}

home, _ := os.UserHomeDir()
if home == "" {
home = "/root"
}
Comment on lines +26 to +29
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this give us? Is it better to run with relative paths from where the binary is in the container? I just don't like how it can be dependent on the $HOME env var.


if err := skillsinit.Run(cfg, home); err != nil {
log.Fatalf("skills-init: %v", err)
}
}
Loading
Loading