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
28 changes: 20 additions & 8 deletions pkg/plugins/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,40 @@ func getPluginDir() (string, error) {
dir := os.Getenv(pluginDirEnv)
// if TKN_PLUGINS_DIR is set, follow it
if dir != "" {
if !filepath.IsAbs(dir) {
return "", fmt.Errorf("plugin dir %q is not an absolute path", dir)
}
return dir, nil
}
// Respect XDG_CONFIG_HOME if set
if xdgHome := os.Getenv("XDG_CONFIG_HOME"); xdgHome != "" {
if !filepath.IsAbs(xdgHome) {
return "", fmt.Errorf("XDG_CONFIG_HOME %q is not an absolute path", xdgHome)
}
return filepath.Join(xdgHome, "tkn", "plugins"), nil
}
// Fallback to default pluginDir (~/.config/tkn/plugins)
return homedir.Expand(pluginDir)
dir, err := homedir.Expand(pluginDir)
if err != nil {
return "", err
}
if !filepath.IsAbs(dir) {
return "", fmt.Errorf("plugin dir %q is not an absolute path", dir)
}
return dir, nil
}

// Find a binary in plugin homedir directory or user paths.
func FindPlugin(pluginame string) (string, error) {
cmd := tknPrefix + pluginame
dir, _ := getPluginDir()
path := filepath.Join(dir, cmd)
_, err := os.Stat(path)
if err == nil {
// Found in dir
return path, nil
if dir, err := getPluginDir(); err == nil {
path := filepath.Join(dir, cmd)
Comment thread
divyansh42 marked this conversation as resolved.
if _, err := os.Stat(path); err == nil {
return path, nil
}
}

path, err = exec.LookPath(cmd)
path, err := exec.LookPath(cmd)
if err == nil {
return path, nil
}
Expand Down
36 changes: 36 additions & 0 deletions pkg/plugins/plugins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,42 @@ func TestGetAllTknPluginFromPathPlugindir(t *testing.T) {
assert.Equal(t, paths[0], "fromplugindir")
}

func TestGetPluginDirRelativeTKNPluginsDir(t *testing.T) {
t.Setenv(pluginDirEnv, "relative/path")
_, err := getPluginDir()
assert.ErrorContains(t, err, "not an absolute path")
}

func TestGetPluginDirRelativeXDGConfigHome(t *testing.T) {
t.Setenv(pluginDirEnv, "")
t.Setenv("XDG_CONFIG_HOME", "relative/xdg")
_, err := getPluginDir()
assert.ErrorContains(t, err, "not an absolute path")
}

func TestFindPluginDoesNotFallBackToCwd(t *testing.T) {
nd := fs.NewDir(t, "TestFindPluginCwd")
defer nd.Remove()
err := os.WriteFile(nd.Join("tkn-evil"), []byte("evil"), 0o700)
assert.NilError(t, err)

// Change into the directory that contains the malicious binary.
orig, err := os.Getwd()
assert.NilError(t, err)
defer os.Chdir(orig) //nolint:errcheck
assert.NilError(t, os.Chdir(nd.Path()))

// Use "." as TKN_PLUGINS_DIR: the old code would resolve filepath.Join(".", "tkn-evil")
// against cwd and find the binary; the fixed code rejects "." as non-absolute.
// Keep nd off PATH so LookPath cannot find the binary either.
t.Setenv(pluginDirEnv, ".")
t.Setenv("PATH", "")

// The binary is only reachable via cwd — FindPlugin must not find it.
_, err = FindPlugin("evil")
assert.ErrorContains(t, err, "cannot find plugin")
}

// as well tested differently in root_test.go
func TestGetAllTknPluginFromPaths(t *testing.T) {
nd := fs.NewDir(t, "TestGetAllTknPluginFromPaths1")
Expand Down