Prefer slices package and slices.Concat where possible

This commit is contained in:
Joshua Casey
2024-05-21 09:31:16 -05:00
parent bdd79a9984
commit fe911a7b7a
26 changed files with 97 additions and 85 deletions
+6 -6
View File
@@ -12,6 +12,7 @@ import (
"io"
"net/http"
"os"
"slices"
"strconv"
"strings"
"time"
@@ -23,7 +24,6 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth" // Adds handlers for various dynamic auth plugins in client-go
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/utils/strings/slices"
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
conciergeconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
@@ -303,7 +303,7 @@ func newExecConfig(deps kubeconfigDeps, flags getKubeconfigParams) (*clientcmdap
if flags.staticToken != "" && flags.staticTokenEnvName != "" {
return nil, fmt.Errorf("only one of --static-token and --static-token-env can be specified")
}
execConfig.Args = append([]string{"login", "static"}, execConfig.Args...)
execConfig.Args = slices.Concat([]string{"login", "static"}, execConfig.Args)
if flags.staticToken != "" {
execConfig.Args = append(execConfig.Args, "--token="+flags.staticToken)
}
@@ -314,7 +314,7 @@ func newExecConfig(deps kubeconfigDeps, flags getKubeconfigParams) (*clientcmdap
}
// Otherwise continue to parse the OIDC-related flags and output a config that runs `pinniped login oidc`.
execConfig.Args = append([]string{"login", "oidc"}, execConfig.Args...)
execConfig.Args = slices.Concat([]string{"login", "oidc"}, execConfig.Args)
if flags.oidc.issuer == "" {
return nil, fmt.Errorf("could not autodiscover --oidc-issuer and none was provided")
}
@@ -783,12 +783,12 @@ func pinnipedSupervisorDiscovery(ctx context.Context, flags *getKubeconfigParams
return err
}
if !supervisorSupportsBothUsernameAndGroupsScopes {
flags.oidc.scopes = slices.Filter(nil, flags.oidc.scopes, func(scope string) bool {
flags.oidc.scopes = slices.DeleteFunc(flags.oidc.scopes, func(scope string) bool {
if scope == oidcapi.ScopeUsername || scope == oidcapi.ScopeGroups {
log.Info("removed scope from --oidc-scopes list because it is not supported by this Supervisor", "scope", scope)
return false // Remove username and groups scopes if there were present in the flags.
return true // Remove username and groups scopes if there were present in the flags.
}
return true // Keep any other scopes in the flag list.
return false // Keep any other scopes in the flag list.
})
}
+2 -1
View File
@@ -10,6 +10,7 @@ import (
"net/http"
"os"
"path/filepath"
"slices"
"testing"
"time"
@@ -3252,7 +3253,7 @@ func TestGetKubeconfig(t *testing.T) {
fake = conciergefake.NewSimpleClientset(tt.conciergeObjects(string(testServerCA), testServer.URL)...)
}
if len(tt.conciergeReactions) > 0 {
fake.ReactionChain = append(tt.conciergeReactions, fake.ReactionChain...)
fake.ReactionChain = slices.Concat(tt.conciergeReactions, fake.ReactionChain)
}
return fake, nil
},
@@ -11,6 +11,7 @@ import (
"encoding/json"
"errors"
"fmt"
"slices"
"strings"
"time"
@@ -609,7 +610,7 @@ func getContainerArgByName(pod *corev1.Pod, name, fallbackValue string) string {
flagset.ParseErrorsWhitelist = pflag.ParseErrorsWhitelist{UnknownFlags: true}
var val string
flagset.StringVar(&val, name, "", "")
_ = flagset.Parse(append(container.Command, container.Args...))
_ = flagset.Parse(slices.Concat(container.Command, container.Args))
if val != "" {
return val
}
@@ -7,6 +7,7 @@ import (
"bytes"
"context"
"fmt"
"slices"
"testing"
"time"
@@ -1081,8 +1082,7 @@ func TestAgentController(t *testing.T) {
actualErrors := deduplicate(errorMessages)
assert.Subsetf(t, actualErrors, tt.wantDistinctErrors, "required error(s) were not found in the actual errors")
allAllowedErrors := append([]string{}, tt.wantDistinctErrors...)
allAllowedErrors = append(allAllowedErrors, tt.alsoAllowUndesiredDistinctErrors...)
allAllowedErrors := slices.Concat(tt.wantDistinctErrors, tt.alsoAllowUndesiredDistinctErrors)
assert.Subsetf(t, allAllowedErrors, actualErrors, "actual errors contained additional error(s) which is not expected by the test")
assert.Equal(t, tt.wantDistinctLogs, deduplicate(testutil.SplitByNewline(buf.String())), "unexpected logs")
@@ -16,6 +16,7 @@ package mocks
import (
context "context"
reflect "reflect"
"slices"
gomock "go.uber.org/mock/gomock"
)
@@ -59,6 +60,6 @@ func (m *MockPodCommandExecutor) Exec(arg0 context.Context, arg1, arg2, arg3 str
// Exec indicates an expected call of Exec.
func (mr *MockPodCommandExecutorMockRecorder) Exec(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...)
varargs := slices.Concat([]any{arg0, arg1, arg2, arg3}, arg4)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockPodCommandExecutor)(nil).Exec), varargs...)
}
@@ -7,12 +7,12 @@ package downstreamsession
import (
"context"
"fmt"
"slices"
"time"
"github.com/ory/fosite"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/token/jwt"
"k8s.io/utils/strings/slices"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/constable"
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"net/http"
"slices"
"time"
"github.com/ory/fosite"
@@ -16,7 +17,6 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/warning"
"k8s.io/utils/strings/slices"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
@@ -17,6 +17,7 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"slices"
"strings"
"testing"
"time"
@@ -39,7 +40,6 @@ import (
"k8s.io/client-go/kubernetes/fake"
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/utils/ptr"
"k8s.io/utils/strings/slices"
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
+2 -1
View File
@@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"runtime"
"slices"
"strings"
"sync"
"testing"
@@ -1184,7 +1185,7 @@ func makeClient(t *testing.T, restConfig *rest.Config, f func(*rest.Config), opt
f(restConfig)
client, err := New(append([]Option{WithConfig(restConfig)}, opts...)...)
client, err := New(slices.Concat([]Option{WithConfig(restConfig)}, opts)...)
require.NoError(t, err)
return client
+7 -6
View File
@@ -28,6 +28,7 @@ package plog
import (
"os"
"slices"
"github.com/go-logr/logr"
)
@@ -87,7 +88,7 @@ func (p pLogger) warningDepth(msg string, depth int, keysAndValues ...any) {
// Thus we use info at log level zero as a proxy
// klog's info logs have an I prefix and its warning logs have a W prefix
// Since we lose the W prefix by using InfoS, just add a key to make these easier to find
keysAndValues = append([]any{"warning", true}, keysAndValues...)
keysAndValues = slices.Concat([]any{"warning", true}, keysAndValues)
p.logr().V(klogLevelWarning).WithCallDepth(depth+1).Info(msg, keysAndValues...)
}
}
@@ -97,7 +98,7 @@ func (p pLogger) Warning(msg string, keysAndValues ...any) {
}
func (p pLogger) WarningErr(msg string, err error, keysAndValues ...any) {
p.warningDepth(msg, p.depth+1, append([]any{errorKey, err}, keysAndValues...)...)
p.warningDepth(msg, p.depth+1, slices.Concat([]any{errorKey, err}, keysAndValues)...)
}
func (p pLogger) infoDepth(msg string, depth int, keysAndValues ...any) {
@@ -111,7 +112,7 @@ func (p pLogger) Info(msg string, keysAndValues ...any) {
}
func (p pLogger) InfoErr(msg string, err error, keysAndValues ...any) {
p.infoDepth(msg, p.depth+1, append([]any{errorKey, err}, keysAndValues...)...)
p.infoDepth(msg, p.depth+1, slices.Concat([]any{errorKey, err}, keysAndValues)...)
}
func (p pLogger) debugDepth(msg string, depth int, keysAndValues ...any) {
@@ -125,7 +126,7 @@ func (p pLogger) Debug(msg string, keysAndValues ...any) {
}
func (p pLogger) DebugErr(msg string, err error, keysAndValues ...any) {
p.debugDepth(msg, p.depth+1, append([]any{errorKey, err}, keysAndValues...)...)
p.debugDepth(msg, p.depth+1, slices.Concat([]any{errorKey, err}, keysAndValues)...)
}
func (p pLogger) traceDepth(msg string, depth int, keysAndValues ...any) {
@@ -139,7 +140,7 @@ func (p pLogger) Trace(msg string, keysAndValues ...any) {
}
func (p pLogger) TraceErr(msg string, err error, keysAndValues ...any) {
p.traceDepth(msg, p.depth+1, append([]any{errorKey, err}, keysAndValues...)...)
p.traceDepth(msg, p.depth+1, slices.Concat([]any{errorKey, err}, keysAndValues)...)
}
func (p pLogger) All(msg string, keysAndValues ...any) {
@@ -181,7 +182,7 @@ func (p pLogger) withDepth(d int) Logger {
func (p pLogger) withLogrMod(mod func(logr.Logger) logr.Logger) Logger {
out := p // make a copy and carefully avoid mutating the mods slice
mods := make([]func(logr.Logger) logr.Logger, 0, len(out.mods)+1)
mods = append(mods, out.mods...)
mods = slices.Concat(mods, out.mods)
mods = append(mods, mod)
out.mods = mods
return out
+4 -3
View File
@@ -1,4 +1,4 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package plog
@@ -9,6 +9,7 @@ import (
"fmt"
"io"
"os"
"slices"
"strings"
"time"
@@ -85,7 +86,7 @@ func newLogr(ctx context.Context, encoding string, klogLevel klog.Level) (logr.L
if overrides.f != nil {
f = overrides.f
}
opts = append(opts, overrides.opts...)
opts = slices.Concat(opts, overrides.opts)
}
// when using the trace or all log levels, an error log will contain the full stack.
@@ -96,7 +97,7 @@ func newLogr(ctx context.Context, encoding string, klogLevel klog.Level) (logr.L
}
func newZapr(level zap.AtomicLevel, addStack zapcore.LevelEnabler, encoding, path string, f func(config *zap.Config), opts ...zap.Option) (logr.Logger, func(), error) {
opts = append([]zap.Option{zap.AddStacktrace(addStack)}, opts...)
opts = slices.Concat([]zap.Option{zap.AddStacktrace(addStack)}, opts)
config := zap.Config{
Level: level,
@@ -9,6 +9,7 @@ import (
"encoding/hex"
"fmt"
"io"
"slices"
"strings"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -172,7 +173,7 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
}
t.Step("bcrypt.GenerateFromPassword")
hashes = append([]string{string(hash)}, hashes...)
hashes = slices.Concat([]string{string(hash)}, hashes)
}
// If requested, remove all client secrets except for the most recent one.
@@ -267,7 +268,7 @@ func (r *REST) validateRequest(
if !strings.HasPrefix(name, "client.oauth.pinniped.dev-") {
errs = append(errs, `must start with 'client.oauth.pinniped.dev-'`)
}
return append(errs, path.IsValidPathSegmentName(name)...)
return slices.Concat(errs, path.IsValidPathSegmentName(name))
},
field.NewPath("metadata"),
); len(errs) > 0 {
@@ -7,6 +7,7 @@ import (
"context"
"net/url"
"regexp"
"slices"
"strings"
"testing"
"time"
@@ -17,7 +18,6 @@ import (
"k8s.io/client-go/kubernetes/fake"
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
kubetesting "k8s.io/client-go/testing"
"k8s.io/utils/strings/slices"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/fositestorage/authorizationcode"
@@ -5,6 +5,7 @@ package testidplister
import (
"fmt"
"slices"
"testing"
"github.com/stretchr/testify/require"
@@ -135,17 +136,17 @@ type UpstreamIDPListerBuilder struct {
}
func (b *UpstreamIDPListerBuilder) WithOIDC(upstreamOIDCIdentityProviders ...*oidctestutil.TestUpstreamOIDCIdentityProvider) *UpstreamIDPListerBuilder {
b.upstreamOIDCIdentityProviders = append(b.upstreamOIDCIdentityProviders, upstreamOIDCIdentityProviders...)
b.upstreamOIDCIdentityProviders = slices.Concat(b.upstreamOIDCIdentityProviders, upstreamOIDCIdentityProviders)
return b
}
func (b *UpstreamIDPListerBuilder) WithLDAP(upstreamLDAPIdentityProviders ...*oidctestutil.TestUpstreamLDAPIdentityProvider) *UpstreamIDPListerBuilder {
b.upstreamLDAPIdentityProviders = append(b.upstreamLDAPIdentityProviders, upstreamLDAPIdentityProviders...)
b.upstreamLDAPIdentityProviders = slices.Concat(b.upstreamLDAPIdentityProviders, upstreamLDAPIdentityProviders)
return b
}
func (b *UpstreamIDPListerBuilder) WithActiveDirectory(upstreamActiveDirectoryIdentityProviders ...*oidctestutil.TestUpstreamLDAPIdentityProvider) *UpstreamIDPListerBuilder {
b.upstreamActiveDirectoryIdentityProviders = append(b.upstreamActiveDirectoryIdentityProviders, upstreamActiveDirectoryIdentityProviders...)
b.upstreamActiveDirectoryIdentityProviders = slices.Concat(b.upstreamActiveDirectoryIdentityProviders, upstreamActiveDirectoryIdentityProviders)
return b
}
+2 -1
View File
@@ -9,6 +9,7 @@ import (
"fmt"
"log"
"runtime"
"slices"
"sort"
"github.com/go-logr/logr"
@@ -154,7 +155,7 @@ func (l logger) WithName(name string) logr.LogSink {
// saved.
func (l logger) WithValues(kvList ...any) logr.LogSink {
lgr := l.clone()
lgr.values = append(lgr.values, kvList...)
lgr.values = slices.Concat(lgr.values, kvList)
return lgr
}
+2 -1
View File
@@ -5,6 +5,7 @@ package testutil
import (
"fmt"
"slices"
"sync"
"testing"
@@ -33,7 +34,7 @@ func (log *TranscriptLogger) Transcript() []TranscriptLogMessage {
log.lock.Lock()
defer log.lock.Unlock()
result := make([]TranscriptLogMessage, 0, len(log.transcript))
result = append(result, log.transcript...)
result = slices.Concat(result, log.transcript)
return result
}
+3 -2
View File
@@ -1,4 +1,4 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package filesession implements the file format for session caches.
@@ -9,6 +9,7 @@ import (
"fmt"
"os"
"reflect"
"slices"
"sort"
"time"
@@ -153,5 +154,5 @@ func (c *sessionCache) lookup(key oidcclient.SessionCacheKey) *sessionEntry {
// insert a cache entry.
func (c *sessionCache) insert(entries ...sessionEntry) {
c.Sessions = append(c.Sessions, entries...)
c.Sessions = slices.Concat(c.Sessions, entries)
}
+1 -1
View File
@@ -480,7 +480,7 @@ func (h *handlerState) baseLogin() (*oidctypes.Token, error) {
return nil, err
}
h.loginFlow = loginFlow
authorizeOptions = append(authorizeOptions, pinnipedSupervisorOptions...)
authorizeOptions = slices.Concat(authorizeOptions, pinnipedSupervisorOptions)
// Preserve the legacy behavior where browser-based auth is preferred
authFunc := h.webBrowserBasedAuth
+3 -2
View File
@@ -14,6 +14,7 @@ import (
"os/exec"
"path/filepath"
"regexp"
"slices"
"strings"
"testing"
"time"
@@ -142,7 +143,7 @@ func assertWhoami(ctx context.Context, t *testing.T, useProxy bool, pinnipedExe,
apiGroupSuffix,
)
if useProxy {
cmd.Env = append(os.Environ(), testlib.IntegrationEnv(t).ProxyEnv()...)
cmd.Env = slices.Concat(os.Environ(), testlib.IntegrationEnv(t).ProxyEnv())
}
cmd.Stdout = &stdout
cmd.Stderr = &stderr
@@ -427,6 +428,6 @@ func oidcLoginCommand(ctx context.Context, t *testing.T, pinnipedExe string, ses
}
// If there is a custom proxy, set it using standard environment variables.
cmd.Env = append(os.Environ(), env.ProxyEnv()...)
cmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
return cmd
}
@@ -22,6 +22,7 @@ import (
"os"
"os/exec"
"path/filepath"
"slices"
"sort"
"strings"
"sync"
@@ -594,7 +595,7 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
require.NoError(t, err)
expectedGroups := make([]string, 0, len(env.TestUser.ExpectedGroups)+1) // make sure we do not mutate env.TestUser.ExpectedGroups
expectedGroups = append(expectedGroups, env.TestUser.ExpectedGroups...)
expectedGroups = slices.Concat(expectedGroups, env.TestUser.ExpectedGroups)
expectedGroups = append(expectedGroups, "system:authenticated")
expectedOriginalUserInfo := authenticationv1.UserInfo{
Username: env.TestUser.ExpectedUsername,
@@ -880,7 +881,7 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
Create(ctx, &identityv1alpha1.WhoAmIRequest{}, metav1.CreateOptions{})
require.NoError(t, err, testlib.Sdump(err))
expectedGroups := make([]string, 0, len(env.TestUser.ExpectedGroups)+1) // make sure we do not mutate env.TestUser.ExpectedGroups
expectedGroups = append(expectedGroups, env.TestUser.ExpectedGroups...)
expectedGroups = slices.Concat(expectedGroups, env.TestUser.ExpectedGroups)
expectedGroups = append(expectedGroups, "system:authenticated")
require.Equal(t,
expectedWhoAmIRequestResponse(
@@ -2116,7 +2117,7 @@ func performImpersonatorDiscovery(ctx context.Context, t *testing.T, env *testli
require.NoError(t, err)
expectedGroups := make([]string, 0, len(env.TestUser.ExpectedGroups)+1) // make sure we do not mutate env.TestUser.ExpectedGroups
expectedGroups = append(expectedGroups, env.TestUser.ExpectedGroups...)
expectedGroups = slices.Concat(expectedGroups, env.TestUser.ExpectedGroups)
expectedGroups = append(expectedGroups, "system:authenticated")
// probe each pod directly for readiness since the concierge status is a lie - it just means a single pod is ready
@@ -2339,7 +2340,7 @@ func getImpersonationKubeconfig(t *testing.T, env *testlib.TestEnv, impersonatio
var envVarsWithProxy []string
if !env.HasCapability(testlib.HasExternalLoadBalancerProvider) {
// Only if you don't have a load balancer, use the squid proxy when it's available.
envVarsWithProxy = append(os.Environ(), env.ProxyEnv()...)
envVarsWithProxy = slices.Concat(os.Environ(), env.ProxyEnv())
}
// Get the kubeconfig.
@@ -2380,7 +2381,7 @@ func getImpersonationKubeconfig(t *testing.T, env *testlib.TestEnv, impersonatio
func kubectlCommand(timeout context.Context, t *testing.T, kubeconfigPath string, envVarsWithProxy []string, args ...string) (*exec.Cmd, *syncBuffer, *syncBuffer) {
t.Helper()
allArgs := append([]string{"--kubeconfig", kubeconfigPath}, args...)
allArgs := slices.Concat([]string{"--kubeconfig", kubeconfigPath}, args)
kubectlCmd := exec.CommandContext(timeout, "kubectl", allArgs...)
var stdout, stderr syncBuffer
kubectlCmd.Stdout = &stdout
+28 -28
View File
@@ -184,7 +184,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser login via the plugin.
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath, "-v", "6")
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
// Run the kubectl command, wait for the Pinniped CLI to print the authorization URL, and open it in the browser.
kubectlOutputChan := startKubectlAndOpenAuthorizationURLInBrowser(testCtx, t, kubectlCmd, browser)
@@ -270,7 +270,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser login via the plugin.
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath, "-v", "6")
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
// Run the kubectl command, wait for the Pinniped CLI to print the authorization URL, and open it in the browser.
kubectlOutputChan := startKubectlAndOpenAuthorizationURLInBrowser(testCtx, t, kubectlCmd, browser)
@@ -360,7 +360,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser login via the plugin.
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -484,7 +484,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser login via the plugin.
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
var kubectlStdoutPipe io.ReadCloser
if runtime.GOOS != "darwin" {
// For some unknown reason this breaks the pty library on some MacOS machines.
@@ -616,7 +616,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser-less CLI prompt login via the plugin.
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -699,7 +699,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// would be stuck waiting for input on the second username prompt. "kubectl get --raw /healthz" doesn't need
// to do API discovery, so we know it will only call the credential exec plugin once.
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "--raw", "/healthz", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -749,7 +749,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger an LDAP-style login CLI prompt via the plugin.
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -808,7 +808,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger an LDAP-style login CLI prompt via the plugin.
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -889,7 +889,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should run an LDAP-style login without interactive prompts for username and password.
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -942,7 +942,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger an LDAP-style login CLI prompt via the plugin.
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -1019,7 +1019,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should run an LDAP-style login without interactive prompts for username and password.
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -1076,7 +1076,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser login via the plugin.
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath, "-v", "6")
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
// Run the kubectl command, wait for the Pinniped CLI to print the authorization URL, and open it in the browser.
kubectlOutputChan := startKubectlAndOpenAuthorizationURLInBrowser(testCtx, t, kubectlCmd, browser)
@@ -1131,7 +1131,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser login via the plugin.
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath, "-v", "6")
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
// Run the kubectl command, wait for the Pinniped CLI to print the authorization URL, and open it in the browser.
kubectlOutputChan := startKubectlAndOpenAuthorizationURLInBrowser(testCtx, t, kubectlCmd, browser)
@@ -1192,7 +1192,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser login via the plugin.
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath, "-v", "6")
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
// Run the kubectl command, wait for the Pinniped CLI to print the authorization URL, and open it in the browser.
kubectlOutputChan := startKubectlAndOpenAuthorizationURLInBrowser(testCtx, t, kubectlCmd, browser)
@@ -1404,7 +1404,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
t.Log("starting LDAP auth via kubectl")
start := time.Now()
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", ldapKubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err := pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -1431,7 +1431,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a browser login via the plugin for the OIDC IDP.
t.Log("starting OIDC auth via kubectl")
kubectlCmd = exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", oidcKubeconfigPath, "-v", "6")
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
// Run the kubectl command, wait for the Pinniped CLI to print the authorization URL, and open it in the browser.
kubectlOutputChan := startKubectlAndOpenAuthorizationURLInBrowser(testCtx, t, kubectlCmd, browser)
@@ -1517,7 +1517,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger an LDAP-style login CLI prompt via the plugin for the LDAP IDP.
t.Log("starting second LDAP auth via kubectl")
kubectlCmd = exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", ldapKubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
ptyFile, err = pty.Start(kubectlCmd)
require.NoError(t, err)
@@ -1561,8 +1561,8 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
createdLDAPProvider := setupClusterForEndToEndLDAPTest(t, expectedDownstreamLDAPUsername, env)
// Having one IDP should put the FederationDomain into a ready state.
testlib.WaitForFederationDomainStatusPhase(testCtx, t, federationDomain.Name, configv1alpha1.FederationDomainPhaseReady)
testlib.WaitForJWTAuthenticatorStatusPhase(testCtx, t, authenticator.Name, authv1alpha.JWTAuthenticatorPhaseReady)
testlib.WaitForFederationDomainStatusPhase(testCtx, t, federationDomain.Name, supervisorconfigv1alpha1.FederationDomainPhaseReady)
testlib.WaitForJWTAuthenticatorStatusPhase(testCtx, t, authenticator.Name, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
// Create a ClusterRoleBinding to give our test user from the upstream read-only access to the cluster.
testlib.CreateTestClusterRoleBinding(t,
@@ -1596,8 +1596,8 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
}, idpv1alpha1.PhaseReady)
// Having a second IDP should put the FederationDomain back into an error state until we tell it which one to use.
testlib.WaitForFederationDomainStatusPhase(testCtx, t, federationDomain.Name, configv1alpha1.FederationDomainPhaseError)
testlib.WaitForJWTAuthenticatorStatusPhase(testCtx, t, authenticator.Name, authv1alpha.JWTAuthenticatorPhaseReady)
testlib.WaitForFederationDomainStatusPhase(testCtx, t, federationDomain.Name, supervisorconfigv1alpha1.FederationDomainPhaseError)
testlib.WaitForJWTAuthenticatorStatusPhase(testCtx, t, authenticator.Name, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
// Update the FederationDomain to use the two IDPs.
federationDomainsClient := testlib.NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(env.SupervisorNamespace)
@@ -1611,7 +1611,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
ldapIDPDisplayName := "My LDAP IDP 💾"
oidcIDPDisplayName := "My OIDC IDP 🚀"
gotFederationDomain.Spec.IdentityProviders = []configv1alpha1.FederationDomainIdentityProvider{
gotFederationDomain.Spec.IdentityProviders = []supervisorconfigv1alpha1.FederationDomainIdentityProvider{
{
DisplayName: ldapIDPDisplayName,
ObjectRef: corev1.TypedLocalObjectReference{
@@ -1633,8 +1633,8 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
require.NoError(t, err)
// The FederationDomain should be valid after the above update.
testlib.WaitForFederationDomainStatusPhase(testCtx, t, federationDomain.Name, configv1alpha1.FederationDomainPhaseReady)
testlib.WaitForJWTAuthenticatorStatusPhase(testCtx, t, authenticator.Name, authv1alpha.JWTAuthenticatorPhaseReady)
testlib.WaitForFederationDomainStatusPhase(testCtx, t, federationDomain.Name, supervisorconfigv1alpha1.FederationDomainPhaseReady)
testlib.WaitForJWTAuthenticatorStatusPhase(testCtx, t, authenticator.Name, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
// Use a specific session cache for this test.
sessionCachePath := tempDir + "/test-sessions.yaml"
@@ -1979,7 +1979,7 @@ func requireUserCanUseKubectlWithoutAuthenticatingAgain(
) {
// Run kubectl, which should work without any prompting for authentication.
kubectlCmd := exec.CommandContext(ctx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
startTime := time.Now()
kubectlOutput2, err := kubectlCmd.CombinedOutput()
require.NoError(t, err)
@@ -2017,7 +2017,7 @@ func requireUserCanUseKubectlWithoutAuthenticatingAgain(
require.ElementsMatch(t, expectedGroupsAsEmptyInterfaces, idTokenClaims["groups"])
}
expectedGroupsPlusAuthenticated := append([]string{}, expectedGroups...)
expectedGroupsPlusAuthenticated := expectedGroups
expectedGroupsPlusAuthenticated = append(expectedGroupsPlusAuthenticated, "system:authenticated")
// Confirm we are the right user according to Kube by calling the WhoAmIRequest API.
@@ -2029,7 +2029,7 @@ func requireUserCanUseKubectlWithoutAuthenticatingAgain(
// While it is true that the user cannot list CRDs, that fact seems unrelated to making a create call to the
// aggregated API endpoint, so this is a strange error, but it can be easily reproduced.
kubectlCmd3 := exec.CommandContext(ctx, "kubectl", "create", "-f", "-", "-o", "yaml", "--kubeconfig", kubeconfigPath, "--validate=false")
kubectlCmd3.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd3.Env = slices.Concat(os.Environ(), env.ProxyEnv())
kubectlCmd3.Stdin = strings.NewReader(here.Docf(`
apiVersion: identity.concierge.%s/v1alpha1
kind: WhoAmIRequest
@@ -2091,7 +2091,7 @@ func requireGCAnnotationsOnSessionStorage(ctx context.Context, t *testing.T, sup
func runPinnipedGetKubeconfig(t *testing.T, env *testlib.TestEnv, pinnipedExe string, tempDir string, pinnipedCLICommand []string) string {
// Run "pinniped get kubeconfig" to get a kubeconfig YAML.
envVarsWithProxy := append(os.Environ(), env.ProxyEnv()...)
envVarsWithProxy := slices.Concat(os.Environ(), env.ProxyEnv())
kubeconfigYAML, stderr := runPinnipedCLI(t, envVarsWithProxy, pinnipedExe, pinnipedCLICommand...)
t.Logf("stderr output from 'pinniped get kubeconfig':\n%s\n\n", stderr)
t.Logf("test kubeconfig:\n%s\n\n", kubeconfigYAML)
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2023-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration
@@ -7,6 +7,7 @@ import (
"bytes"
"context"
"io"
"slices"
"strings"
"testing"
"time"
@@ -14,7 +15,6 @@ import (
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/strings/slices"
"go.pinniped.dev/test/testlib"
)
@@ -13,6 +13,7 @@ import (
"net"
"net/http"
"net/url"
"slices"
"strings"
"testing"
"time"
@@ -23,7 +24,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/util/retry"
"k8s.io/utils/strings/slices"
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
+2 -2
View File
@@ -16,6 +16,7 @@ import (
"net/http/httptest"
"net/url"
"regexp"
"slices"
"strings"
"testing"
"time"
@@ -27,7 +28,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
"k8s.io/utils/strings/slices"
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
@@ -802,7 +802,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
requestAuthorizationUsingCLIPasswordFlow(t,
downstreamAuthorizeURL,
env.SupervisorUpstreamLDAP.TestUserMailAttributeValue, // username to present to server during login
"incorrect", // password to present to server during login
"incorrect", // password to present to server during login
httpClient,
true,
)
@@ -10,6 +10,7 @@ import (
"encoding/json"
"fmt"
"os/exec"
"slices"
"testing"
"time"
@@ -1020,10 +1021,7 @@ func retainOnlyMostRecentSecret(list []string) []string {
}
func prependSecret(list []string, newItem string) []string {
newList := make([]string, 0, len(list)+1)
newList = append(newList, newItem)
newList = append(newList, list...)
return newList
return slices.Concat([]string{newItem}, list)
}
func TestOIDCClientSecretRequestUnauthenticated_Parallel(t *testing.T) {
+7 -6
View File
@@ -13,6 +13,7 @@ import (
"path/filepath"
"regexp"
"runtime"
"slices"
"sort"
"strings"
"testing"
@@ -129,7 +130,7 @@ func TestSupervisorWarnings_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a cli-based login.
start := time.Now()
kubectlCmd := exec.CommandContext(ctx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
var kubectlStdoutPipe io.ReadCloser
if runtime.GOOS != "darwin" {
// For some unknown reason this breaks the pty library on some MacOS machines.
@@ -219,7 +220,7 @@ func TestSupervisorWarnings_Browser(t *testing.T) {
// Run kubectl, which should work without any prompting for authentication.
kubectlCmd2 := exec.CommandContext(ctx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd2.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd2.Env = slices.Concat(os.Environ(), env.ProxyEnv())
startTime2 := time.Now()
var kubectlStdoutPipe2 io.ReadCloser
if runtime.GOOS != "darwin" {
@@ -277,7 +278,7 @@ func TestSupervisorWarnings_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a cli-based login.
start := time.Now()
kubectlCmd := exec.CommandContext(ctx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
var kubectlStdoutPipe io.ReadCloser
if runtime.GOOS != "darwin" {
// For some unknown reason this breaks the pty library on some MacOS machines.
@@ -348,7 +349,7 @@ func TestSupervisorWarnings_Browser(t *testing.T) {
// Run kubectl, which should work without any prompting for authentication.
kubectlCmd2 := exec.CommandContext(ctx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd2.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd2.Env = slices.Concat(os.Environ(), env.ProxyEnv())
startTime2 := time.Now()
var kubectlStdoutPipe2 io.ReadCloser
if runtime.GOOS != "darwin" {
@@ -442,7 +443,7 @@ func TestSupervisorWarnings_Browser(t *testing.T) {
// Run "kubectl get namespaces" which should trigger a cli-based login.
start := time.Now()
kubectlCmd := exec.CommandContext(ctx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd.Env = slices.Concat(os.Environ(), env.ProxyEnv())
var kubectlStdoutPipe io.ReadCloser
if runtime.GOOS != "darwin" {
// For some unknown reason this breaks the pty library on some MacOS machines.
@@ -555,7 +556,7 @@ func TestSupervisorWarnings_Browser(t *testing.T) {
// Run kubectl, which should work without any prompting for authentication.
kubectlCmd2 := exec.CommandContext(ctx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath)
kubectlCmd2.Env = append(os.Environ(), env.ProxyEnv()...)
kubectlCmd2.Env = slices.Concat(os.Environ(), env.ProxyEnv())
startTime2 := time.Now()
var kubectlStdoutPipe2 io.ReadCloser
if runtime.GOOS != "darwin" {