mirror of
https://github.com/go-task/task.git
synced 2026-06-11 09:51:50 +00:00
feat: add --trusted-hosts CLI and remote.trusted-hosts config for remote tasks (#2491)
Co-authored-by: Valentin Maerten <maerten.valentin@gmail.com>
This commit is contained in:
@@ -3,6 +3,7 @@ package ast
|
||||
import (
|
||||
"cmp"
|
||||
"maps"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
@@ -17,10 +18,11 @@ type TaskRC struct {
|
||||
}
|
||||
|
||||
type Remote struct {
|
||||
Insecure *bool `yaml:"insecure"`
|
||||
Offline *bool `yaml:"offline"`
|
||||
Timeout *time.Duration `yaml:"timeout"`
|
||||
CacheExpiry *time.Duration `yaml:"cache-expiry"`
|
||||
Insecure *bool `yaml:"insecure"`
|
||||
Offline *bool `yaml:"offline"`
|
||||
Timeout *time.Duration `yaml:"timeout"`
|
||||
CacheExpiry *time.Duration `yaml:"cache-expiry"`
|
||||
TrustedHosts []string `yaml:"trusted-hosts"`
|
||||
}
|
||||
|
||||
// Merge combines the current TaskRC with another TaskRC, prioritizing non-nil fields from the other TaskRC.
|
||||
@@ -43,6 +45,12 @@ func (t *TaskRC) Merge(other *TaskRC) {
|
||||
t.Remote.Timeout = cmp.Or(other.Remote.Timeout, t.Remote.Timeout)
|
||||
t.Remote.CacheExpiry = cmp.Or(other.Remote.CacheExpiry, t.Remote.CacheExpiry)
|
||||
|
||||
if len(other.Remote.TrustedHosts) > 0 {
|
||||
merged := slices.Concat(other.Remote.TrustedHosts, t.Remote.TrustedHosts)
|
||||
slices.Sort(merged)
|
||||
t.Remote.TrustedHosts = slices.Compact(merged)
|
||||
}
|
||||
|
||||
t.Verbose = cmp.Or(other.Verbose, t.Verbose)
|
||||
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -135,3 +136,174 @@ func TestGetConfig_All(t *testing.T) { //nolint:paralleltest // cannot run in pa
|
||||
},
|
||||
}, cfg)
|
||||
}
|
||||
|
||||
func TestGetConfig_RemoteTrustedHosts(t *testing.T) { //nolint:paralleltest // cannot run in parallel
|
||||
_, _, localDir := setupDirs(t)
|
||||
|
||||
// Test with single host
|
||||
configYAML := `
|
||||
remote:
|
||||
trusted-hosts:
|
||||
- github.com
|
||||
`
|
||||
writeFile(t, localDir, ".taskrc.yml", configYAML)
|
||||
|
||||
cfg, err := GetConfig(localDir)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cfg)
|
||||
assert.Equal(t, []string{"github.com"}, cfg.Remote.TrustedHosts)
|
||||
|
||||
// Test with multiple hosts
|
||||
configYAML = `
|
||||
remote:
|
||||
trusted-hosts:
|
||||
- github.com
|
||||
- gitlab.com
|
||||
- example.com:8080
|
||||
`
|
||||
writeFile(t, localDir, ".taskrc.yml", configYAML)
|
||||
|
||||
cfg, err = GetConfig(localDir)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cfg)
|
||||
assert.Equal(t, []string{"github.com", "gitlab.com", "example.com:8080"}, cfg.Remote.TrustedHosts)
|
||||
}
|
||||
|
||||
func TestGetConfig_RemoteTrustedHostsMerge(t *testing.T) { //nolint:paralleltest // cannot run in parallel
|
||||
t.Run("file-based merge precedence", func(t *testing.T) { //nolint:paralleltest // parent test cannot run in parallel
|
||||
xdgConfigDir, homeDir, localDir := setupDirs(t)
|
||||
|
||||
// XDG config has github.com and gitlab.com
|
||||
xdgConfig := `
|
||||
remote:
|
||||
trusted-hosts:
|
||||
- github.com
|
||||
- gitlab.com
|
||||
timeout: "30s"
|
||||
`
|
||||
writeFile(t, xdgConfigDir, "taskrc.yml", xdgConfig)
|
||||
|
||||
// Home config has example.com (should be combined with XDG)
|
||||
homeConfig := `
|
||||
remote:
|
||||
trusted-hosts:
|
||||
- example.com
|
||||
`
|
||||
writeFile(t, homeDir, ".taskrc.yml", homeConfig)
|
||||
|
||||
cfg, err := GetConfig(localDir)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cfg)
|
||||
// Home config entries come first, then XDG
|
||||
assert.Equal(t, []string{"example.com", "github.com", "gitlab.com"}, cfg.Remote.TrustedHosts)
|
||||
|
||||
// Test with local config too
|
||||
localConfig := `
|
||||
remote:
|
||||
trusted-hosts:
|
||||
- local.dev
|
||||
`
|
||||
writeFile(t, localDir, ".taskrc.yml", localConfig)
|
||||
|
||||
cfg, err = GetConfig(localDir)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cfg)
|
||||
// Local config entries come first
|
||||
assert.Equal(t, []string{"example.com", "github.com", "gitlab.com", "local.dev"}, cfg.Remote.TrustedHosts)
|
||||
})
|
||||
|
||||
t.Run("merge edge cases", func(t *testing.T) { //nolint:paralleltest // parent test cannot run in parallel
|
||||
tests := []struct {
|
||||
name string
|
||||
base *ast.TaskRC
|
||||
other *ast.TaskRC
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "merge hosts into empty",
|
||||
base: &ast.TaskRC{},
|
||||
other: &ast.TaskRC{
|
||||
Remote: ast.Remote{
|
||||
TrustedHosts: []string{"github.com"},
|
||||
},
|
||||
},
|
||||
expected: []string{"github.com"},
|
||||
},
|
||||
{
|
||||
name: "merge combines lists",
|
||||
base: &ast.TaskRC{
|
||||
Remote: ast.Remote{
|
||||
TrustedHosts: []string{"base.com"},
|
||||
},
|
||||
},
|
||||
other: &ast.TaskRC{
|
||||
Remote: ast.Remote{
|
||||
TrustedHosts: []string{"other.com"},
|
||||
},
|
||||
},
|
||||
expected: []string{"base.com", "other.com"},
|
||||
},
|
||||
{
|
||||
name: "merge empty list does not override",
|
||||
base: &ast.TaskRC{
|
||||
Remote: ast.Remote{
|
||||
TrustedHosts: []string{"base.com"},
|
||||
},
|
||||
},
|
||||
other: &ast.TaskRC{
|
||||
Remote: ast.Remote{
|
||||
TrustedHosts: []string{},
|
||||
},
|
||||
},
|
||||
expected: []string{"base.com"},
|
||||
},
|
||||
{
|
||||
name: "merge nil does not override",
|
||||
base: &ast.TaskRC{
|
||||
Remote: ast.Remote{
|
||||
TrustedHosts: []string{"base.com"},
|
||||
},
|
||||
},
|
||||
other: &ast.TaskRC{
|
||||
Remote: ast.Remote{
|
||||
TrustedHosts: nil,
|
||||
},
|
||||
},
|
||||
expected: []string{"base.com"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) { //nolint:paralleltest // parent test cannot run in parallel
|
||||
tt.base.Merge(tt.other)
|
||||
assert.Equal(t, tt.expected, tt.base.Remote.TrustedHosts)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("all remote fields merge", func(t *testing.T) { //nolint:paralleltest // parent test cannot run in parallel
|
||||
insecureTrue := true
|
||||
offlineTrue := true
|
||||
timeout := 30 * time.Second
|
||||
cacheExpiry := 1 * time.Hour
|
||||
|
||||
base := &ast.TaskRC{}
|
||||
other := &ast.TaskRC{
|
||||
Remote: ast.Remote{
|
||||
Insecure: &insecureTrue,
|
||||
Offline: &offlineTrue,
|
||||
Timeout: &timeout,
|
||||
CacheExpiry: &cacheExpiry,
|
||||
TrustedHosts: []string{"github.com", "gitlab.com"},
|
||||
},
|
||||
}
|
||||
|
||||
base.Merge(other)
|
||||
|
||||
assert.Equal(t, &insecureTrue, base.Remote.Insecure)
|
||||
assert.Equal(t, &offlineTrue, base.Remote.Offline)
|
||||
assert.Equal(t, &timeout, base.Remote.Timeout)
|
||||
assert.Equal(t, &cacheExpiry, base.Remote.CacheExpiry)
|
||||
assert.Equal(t, []string{"github.com", "gitlab.com"}, base.Remote.TrustedHosts)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user