Skip to content
Open
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ GIT_COMMIT := $(shell git rev-parse --short HEAD)

export KPT_FN_WASM_RUNTIME ?= nodejs

LDFLAGS := -ldflags "-X github.com/kptdev/kpt/run.version=${GIT_COMMIT}
# For local development builds: inject dev version with commit hash
# Goreleaser releases set version via ldflags from git tags (handled in release workflow)
LDFLAGS := -ldflags "-X github.com/kptdev/kpt/run.version=v0.0.0-dev+${GIT_COMMIT}
ifeq ($(OS),Windows_NT)
# Do nothing
else
Expand Down
30 changes: 13 additions & 17 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ require (
github.com/google/go-cmp v0.7.0
github.com/google/go-containerregistry v0.20.6
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/kptdev/krm-functions-catalog/functions/go/apply-setters v0.2.2
github.com/kptdev/krm-functions-sdk/go/fn v1.0.2
github.com/kptdev/krm-functions-catalog/functions/go/apply-setters v0.2.4
github.com/kptdev/krm-functions-sdk/go/fn v1.0.0
github.com/otiai10/copy v1.14.1
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f
github.com/pkg/errors v0.9.1
Expand All @@ -25,19 +25,19 @@ require (
golang.org/x/text v0.31.0
gopkg.in/yaml.v2 v2.4.0
gotest.tools v2.2.0+incompatible
k8s.io/api v0.34.1
k8s.io/apiextensions-apiserver v0.34.1
k8s.io/apimachinery v0.34.1
k8s.io/cli-runtime v0.34.1
k8s.io/client-go v0.34.1
k8s.io/component-base v0.34.1
k8s.io/api v0.35.0
k8s.io/apiextensions-apiserver v0.35.0
k8s.io/apimachinery v0.35.0
k8s.io/cli-runtime v0.35.0
k8s.io/client-go v0.35.0
k8s.io/component-base v0.35.0
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
k8s.io/kubectl v0.34.1
k8s.io/kubectl v0.35.0
sigs.k8s.io/cli-utils v0.37.2
sigs.k8s.io/controller-runtime v0.22.4
sigs.k8s.io/kustomize/api v0.20.1
sigs.k8s.io/kustomize/kyaml v0.20.1
sigs.k8s.io/kustomize/api v0.21.0
sigs.k8s.io/kustomize/kyaml v0.21.0
sigs.k8s.io/yaml v1.6.0
)

Expand Down Expand Up @@ -75,11 +75,9 @@ require (
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
github.com/go-openapi/swag/typeutils v0.25.1 // indirect
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jonboulle/clockwork v0.5.0 // indirect
Expand All @@ -88,14 +86,12 @@ require (
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/onsi/gomega v1.37.0 // indirect
github.com/onsi/gomega v1.38.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/otiai10/mint v1.6.3 // indirect
Expand Down Expand Up @@ -126,7 +122,7 @@ require (
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/component-helpers v0.34.1 // indirect
k8s.io/component-helpers v0.35.0 // indirect
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
Expand Down
103 changes: 32 additions & 71 deletions go.sum

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion internal/builtins/pkg_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ func TestPkgContextGenerator(t *testing.T) {

exp, err := os.ReadFile(filepath.Join("testdata", test.dir, "out.yaml"))
assert.NoError(t, err)
// Normalize line endings to LF for cross-platform comparison
expNormalized := bytes.ReplaceAll(exp, []byte("\r\n"), []byte("\n"))

err = pkgCtxGenerator.Run(bytes.NewReader(in), out)
if err != test.expErr {
t.Errorf("exp: %v got: %v", test.expErr, err)
}
if diff := cmp.Diff(string(exp), out.String()); diff != "" {
if diff := cmp.Diff(string(expNormalized), out.String()); diff != "" {
t.Errorf("pkg context mistmach (-want +got):\n%s", diff)
}
})
Expand Down
2 changes: 2 additions & 0 deletions internal/kptops/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import (
)

var functions map[string]framework.ResourceListProcessorFunc = map[string]framework.ResourceListProcessorFunc{
// v0.2.0 kept for backward compatibility with existing Kptfiles
"ghcr.io/kptdev/krm-functions-catalog/apply-setters:v0.2.0": applySetters,
"ghcr.io/kptdev/krm-functions-catalog/apply-setters:v0.2.4": applySetters,
"ghcr.io/kptdev/krm-functions-catalog/set-labels:v0.1.5": setLabels,
"ghcr.io/kptdev/krm-functions-catalog/set-namespace:v0.4.1": setNamespace,
}
Expand Down
16 changes: 11 additions & 5 deletions internal/util/render/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@ import (
"sigs.k8s.io/kustomize/kyaml/kio"
)

const rootString = "/root"
const subPkgString = "/root/subpkg"
// absPath returns a forward-slash absolute path for use with filesys.MakeFsInMemory(),
// which only understands Unix-style paths regardless of host OS.
func absPath(suffix string) string {
return "/" + strings.ReplaceAll(suffix, string(filepath.Separator), "/")
}

var rootString = "/root"
var subPkgString = "/root/subpkg"

func TestPathRelToRoot(t *testing.T) {
tests := []struct {
Expand Down Expand Up @@ -257,11 +263,11 @@ func setupRendererTest(t *testing.T, renderBfs bool) (*Renderer, *bytes.Buffer,
assert.NoError(t, err)

childPkgPath := "/root/subpkg/child"
err = mockFileSystem.Mkdir(subPkgPath)
err = mockFileSystem.Mkdir(childPkgPath)
assert.NoError(t, err)

siblingPkgPath := "/root/sibling"
err = mockFileSystem.Mkdir(subPkgPath)
err = mockFileSystem.Mkdir(siblingPkgPath)
assert.NoError(t, err)

err = mockFileSystem.WriteFile(filepath.Join(rootPkgPath, "Kptfile"), fmt.Appendf(nil, `
Expand Down Expand Up @@ -388,7 +394,7 @@ metadata:

t.Run("Error in LocalResources", func(t *testing.T) {
// Simulate an error in LocalResources by creating a package with no Kptfile
invalidPkgPath := "/invalid"
invalidPkgPath := absPath("invalid")
err := mockFileSystem.Mkdir(invalidPkgPath)
assert.NoError(t, err)

Expand Down
9 changes: 6 additions & 3 deletions pkg/api/kptfile/v1/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package v1

import (
"fmt"
"path"
"path/filepath"
"regexp"
"slices"
Expand Down Expand Up @@ -157,11 +158,13 @@ func validateFnConfigPathSyntax(p string) error {
if strings.TrimSpace(p) == "" {
return fmt.Errorf("path must not be empty")
}
p = filepath.Clean(p)
if filepath.IsAbs(p) {
// Use path.IsAbs (forward-slash based) since Kptfile paths are always
// slash-separated regardless of the host OS.
if path.IsAbs(p) {
return fmt.Errorf("path must be relative")
}
if strings.Contains(p, "..") {
cleaned := filepath.Clean(p)
if strings.Contains(cleaned, "..") {
// fn config must not live outside the package directory
// Allowing outside path opens up an attack vector that allows
// reading any YAML file on package consumer's machine.
Expand Down
1 change: 0 additions & 1 deletion pkg/test/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ func (r *Runner) runFnEval() error {
return fmt.Errorf("failed to prepare package: %w", err)
}


err = r.runSetupScript(pkgPath)
if err != nil {
return err
Expand Down
31 changes: 31 additions & 0 deletions run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"os"
"os/exec"
"runtime/debug"
"strconv"
"strings"

Expand All @@ -36,6 +37,8 @@ var pgr []string

func GetMain(ctx context.Context) *cobra.Command {
os.Setenv(commandutil.EnableAlphaCommmandsEnvName, "true")
// Initialize version info from build settings at startup.
initVersion()
cmd := &cobra.Command{
Use: "kpt",
Short: overview.CliShort,
Expand Down Expand Up @@ -155,6 +158,34 @@ func newHelp(e []string, c *cobra.Command) func(command *cobra.Command, strings

var version = "unknown"

// initVersion enriches the version string with runtime build information.
// It reads VCS revision from Go's build info when available (i.e., when
// built with module mode). This provides the commit hash for development builds.
//
// For release builds, goreleaser injects the proper version tag (e.g., v1.0.0-beta.62)
// via ldflags. In that case, version will already be set to a proper semver string
// and this function will not override it.
func initVersion() {
// If version is already set to a proper release version (starts with 'v'),
// don't override it. Goreleaser sets the version at build time for releases.
if strings.HasPrefix(version, "v") && !strings.Contains(version, "-dev+") {
return
}

if info, ok := debug.ReadBuildInfo(); ok {
for _, setting := range info.Settings {
if setting.Key == "vcs.revision" {
shortCommit := setting.Value
if len(shortCommit) >= 12 {
shortCommit = shortCommit[:12]
}
version = "v0.0.0-dev+" + shortCommit
return
}
}
}
}

var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of kpt",
Expand Down
Loading