Skip to content

Commit 8500ffa

Browse files
authored
add configurable init container image (PR 1007 from kagent) (#92)
fixes #91 (code from https://github.com/kagent-dev/kagent/pull/1007/files) Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
1 parent a74515d commit 8500ffa

4 files changed

Lines changed: 106 additions & 7 deletions

File tree

api/v1alpha1/mcpserver_types.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,25 @@ type MCPServerDeployment struct {
231231
// This allows for custom volume configurations beyond just secrets and configmaps.
232232
// +optional
233233
Volumes []corev1.Volume `json:"volumes,omitempty"`
234+
235+
// InitContainer defines the configuration for the init container that copies
236+
// the transport adapter binary. This is used for stdio transport type.
237+
// +optional
238+
InitContainer *InitContainerConfig `json:"initContainer,omitempty"`
239+
}
240+
241+
// InitContainerConfig defines the configuration for the init container.
242+
type InitContainerConfig struct {
243+
// Image defines the full image reference for the init container.
244+
// If specified, this overrides the default transport adapter image.
245+
// Example: "myregistry.com/agentgateway/agentgateway:0.9.0-musl"
246+
// +optional
247+
Image string `json:"image,omitempty"`
248+
249+
// ImagePullPolicy defines the pull policy for the init container image.
250+
// +optional
251+
// +kubebuilder:validation:Enum=Always;Never;IfNotPresent
252+
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
234253
}
235254

236255
// +kubebuilder:object:root=true

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/kagent.dev_mcpservers.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,26 @@ spec:
9292
description: Image defines the container image to to deploy the
9393
MCP server.
9494
type: string
95+
initContainer:
96+
description: |-
97+
InitContainer defines the configuration for the init container that copies
98+
the transport adapter binary. This is used for stdio transport type.
99+
properties:
100+
image:
101+
description: |-
102+
Image defines the full image reference for the init container.
103+
If specified, this overrides the default transport adapter image.
104+
Example: "myregistry.com/agentgateway/agentgateway:0.9.0-musl"
105+
type: string
106+
imagePullPolicy:
107+
description: ImagePullPolicy defines the pull policy for the
108+
init container image.
109+
enum:
110+
- Always
111+
- Never
112+
- IfNotPresent
113+
type: string
114+
type: object
95115
port:
96116
default: 3000
97117
description: Port defines the port on which the MCP server will

pkg/controller/transportadapter/transportadapter_translator.go

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/hex"
77
"fmt"
88
"os"
9+
"regexp"
910
"sort"
1011

1112
"go.uber.org/multierr"
@@ -23,9 +24,14 @@ import (
2324
)
2425

2526
const (
26-
defaultTransportAdapterContainerImage = "ghcr.io/agentgateway/agentgateway:0.9.0-musl"
27+
transportAdapterRepository = "ghcr.io/agentgateway/agentgateway"
28+
defaultTransportAdapterVersion = "0.9.0"
2729
)
2830

31+
// versionRegex validates that version strings contain only allowed characters
32+
// (alphanumeric, dots, hyphens) to prevent potential image injection attacks
33+
var versionRegex = regexp.MustCompile(`^[a-zA-Z0-9.\-]+$`)
34+
2935
// Translator is the interface for translating MCPServer objects to TransportAdapter objects.
3036
type Translator interface {
3137
TranslateTransportAdapterOutputs(
@@ -103,10 +109,19 @@ func (t *transportAdapterTranslator) translateTransportAdapterDeployment(
103109
// Create volume mounts from the MCPServer spec
104110
volumeMounts := t.createVolumeMounts(server.Spec.Deployment)
105111

106-
transportAdapterContainerImage := defaultTransportAdapterContainerImage
107-
transportAdapterVersion := os.Getenv("TRANSPORT_ADAPTER_VERSION")
108-
if transportAdapterVersion != "" {
109-
transportAdapterContainerImage = fmt.Sprintf("ghcr.io/agentgateway/agentgateway:%s-musl", transportAdapterVersion)
112+
// Determine the init container image and pull policy to use
113+
// Start with the default transport adapter image
114+
transportAdapterContainerImage := getTransportAdapterImage()
115+
116+
initContainerPullPolicy := corev1.PullIfNotPresent
117+
118+
// Override with custom image if specified in the MCPServer spec
119+
if server.Spec.Deployment.InitContainer != nil && server.Spec.Deployment.InitContainer.Image != "" {
120+
transportAdapterContainerImage = server.Spec.Deployment.InitContainer.Image
121+
initContainerPullPolicy = server.Spec.Deployment.InitContainer.ImagePullPolicy
122+
if initContainerPullPolicy == "" {
123+
initContainerPullPolicy = corev1.PullIfNotPresent
124+
}
110125
}
111126

112127
var template corev1.PodSpec
@@ -118,7 +133,7 @@ func (t *transportAdapterTranslator) translateTransportAdapterDeployment(
118133
InitContainers: []corev1.Container{{
119134
Name: "copy-binary",
120135
Image: transportAdapterContainerImage,
121-
ImagePullPolicy: corev1.PullIfNotPresent,
136+
ImagePullPolicy: initContainerPullPolicy,
122137
Command: []string{},
123138
Args: []string{
124139
"--copy-self",
@@ -544,3 +559,28 @@ func (t *transportAdapterTranslator) runPlugins(
544559

545560
return objects, errs
546561
}
562+
563+
// validateVersion validates that a version string contains only allowed characters
564+
// to prevent potential image injection attacks
565+
func validateVersion(version string) error {
566+
if !versionRegex.MatchString(version) {
567+
return fmt.Errorf("invalid version format: %s (only alphanumeric characters, dots, and hyphens are allowed)", version)
568+
}
569+
return nil
570+
}
571+
572+
// getTransportAdapterImage returns the transport adapter container image,
573+
// using the environment variable if provided and valid, otherwise using the default
574+
func getTransportAdapterImage() string {
575+
transportAdapterVersion := os.Getenv("TRANSPORT_ADAPTER_VERSION")
576+
if transportAdapterVersion == "" {
577+
return fmt.Sprintf("%s:%s-musl", transportAdapterRepository, defaultTransportAdapterVersion)
578+
}
579+
580+
if err := validateVersion(transportAdapterVersion); err != nil {
581+
klog.Warningf("Invalid TRANSPORT_ADAPTER_VERSION: %v, fallback to %s", err, defaultTransportAdapterVersion)
582+
return fmt.Sprintf("%s:%s-musl", transportAdapterRepository, defaultTransportAdapterVersion)
583+
}
584+
585+
return fmt.Sprintf("%s:%s-musl", transportAdapterRepository, transportAdapterVersion)
586+
}

0 commit comments

Comments
 (0)