From ec3e48bec4719e1350d3df2d561c3bceb5e86524 Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Tue, 1 Oct 2024 15:49:43 -0600 Subject: [PATCH 1/5] all: use package filepath for file paths (#47061) Some day Teleport will run on systems that don't use / as a path separator. --- api/client/credentials_test.go | 3 +-- build.assets/tooling/cmd/difftest/ast.go | 4 +-- build.assets/tooling/cmd/difftest/main.go | 3 +-- .../notarize-apple-binaries/gon_wrapper.go | 6 ++--- .../dynamoathenamigration/migration_test.go | 8 +++--- integration/utmp_integration_test.go | 12 ++++----- integrations/event-handler/cli_test.go | 26 +++++++++---------- integrations/event-handler/configure_cmd.go | 25 +++++++++--------- .../event-handler/fake_fluentd_test.go | 14 +++++----- integrations/event-handler/mtls_certs_test.go | 6 ++--- integrations/event-handler/state.go | 6 ++--- integrations/lib/tar/extract.go | 5 ++-- lib/backend/pgbk/common/gcp_test.go | 4 +-- lib/cgroup/cgroup_test.go | 12 ++++----- lib/client/db/dbcmd/dbcmd.go | 4 +-- lib/client/db/opensearch/profile.go | 6 ++--- lib/client/db/opensearch/profile_test.go | 4 +-- lib/client/tshconfig_test.go | 10 +++---- lib/config/configuration_test.go | 3 +-- lib/srv/server/installer/autodiscover.go | 6 ++--- lib/srv/server/installer/autodiscover_test.go | 18 ++++++------- lib/srv/sess.go | 10 +++---- lib/tbot/output_utils.go | 6 ++--- lib/tbot/tbot_test.go | 4 +-- lib/utils/packagemanager/apt.go | 6 ++--- tool/tbot/systemd_test.go | 8 +++--- .../sso/configure/flags/file_reader_test.go | 8 +++--- tool/tctl/sso/configure/saml_test.go | 6 ++--- tool/tsh/common/app_azure.go | 4 +-- tool/tsh/common/app_azure_test.go | 6 ++--- tool/tsh/common/app_gcp.go | 10 +++---- tool/tsh/common/kube_proxy.go | 4 +-- tool/tsh/common/kube_proxy_test.go | 4 +-- tool/tsh/common/kube_test.go | 5 ++-- tool/tsh/common/kubectl_test.go | 6 ++--- tool/tsh/common/proxy_test.go | 7 +++-- tool/tsh/common/recording_export_test.go | 6 ++--- tool/tsh/common/workload_identity.go | 8 +++--- tool/tsh/common/workload_identity_test.go | 8 +++--- 39 files changed, 147 insertions(+), 154 deletions(-) diff --git a/api/client/credentials_test.go b/api/client/credentials_test.go index a3ae2473cb8f6..ba82451b024d9 100644 --- a/api/client/credentials_test.go +++ b/api/client/credentials_test.go @@ -27,7 +27,6 @@ import ( "log" "math/big" "os" - "path" "path/filepath" "testing" "time" @@ -445,7 +444,7 @@ Private-MAC: 8951bbe929e0714a61df01bc8fbc5223e3688f174aee29339931984fb9224c7d`) func TestDynamicIdentityFileCreds(t *testing.T) { dir := t.TempDir() - identityPath := path.Join(dir, "identity") + identityPath := filepath.Join(dir, "identity") idFile := &identityfile.IdentityFile{ PrivateKey: keyPEM, diff --git a/build.assets/tooling/cmd/difftest/ast.go b/build.assets/tooling/cmd/difftest/ast.go index 812300805604d..dfae5b176c6b8 100644 --- a/build.assets/tooling/cmd/difftest/ast.go +++ b/build.assets/tooling/cmd/difftest/ast.go @@ -69,7 +69,7 @@ func findAllSuiteRunners(repoPath string, filename []string) (RunnersMap, error) // Find all affected directories for _, f := range filename { - dir := path.Join(repoPath, path.Dir(f)) + dir := filepath.Join(repoPath, path.Dir(f)) s[dir] = struct{}{} } @@ -77,7 +77,7 @@ func findAllSuiteRunners(repoPath string, filename []string) (RunnersMap, error) // Find all test files in affected directoriees for dir := range s { - matches, err := filepath.Glob(path.Join(dir, "*_test.go")) + matches, err := filepath.Glob(filepath.Join(dir, "*_test.go")) if err != nil { return nil, trace.Wrap(err) } diff --git a/build.assets/tooling/cmd/difftest/main.go b/build.assets/tooling/cmd/difftest/main.go index c83061dd9800b..6c0d4a5cc6998 100644 --- a/build.assets/tooling/cmd/difftest/main.go +++ b/build.assets/tooling/cmd/difftest/main.go @@ -22,7 +22,6 @@ import ( "fmt" "log" "os" - "path" "path/filepath" "slices" "strings" @@ -244,7 +243,7 @@ func inspect(repoPath string, ref string, changedFiles []string, fn func(string, } } - head, err := parseMethodMap(path.Join(repoPath, filename), nil, runners) + head, err := parseMethodMap(filepath.Join(repoPath, filename), nil, runners) if err != nil { return trace.Wrap(err) } diff --git a/build.assets/tooling/cmd/notarize-apple-binaries/gon_wrapper.go b/build.assets/tooling/cmd/notarize-apple-binaries/gon_wrapper.go index 9ce9d9b79c968..8cfe475976392 100644 --- a/build.assets/tooling/cmd/notarize-apple-binaries/gon_wrapper.go +++ b/build.assets/tooling/cmd/notarize-apple-binaries/gon_wrapper.go @@ -21,7 +21,7 @@ package main import ( "context" "os" - "path" + "path/filepath" "github.com/gravitational/trace" "github.com/hashicorp/go-hclog" @@ -65,7 +65,7 @@ func (gw *GonWrapper) SignAndNotarizeBinaries() error { if err != nil { return trace.Wrap(err, "failed to zip binaries for notarization") } - defer os.RemoveAll(path.Dir(zipPath)) + defer os.RemoveAll(filepath.Dir(zipPath)) err = gw.NotarizeBinaries(zipPath) if err != nil { @@ -99,7 +99,7 @@ func (gw *GonWrapper) ZipBinaries() (string, error) { return "", trace.Wrap(err, "failed to create temporary directory for binary zipping") } - outputPath := path.Join(tmpDir, zipFileName) + outputPath := filepath.Join(tmpDir, zipFileName) gw.logger.Debug("Using binary zip path %q", outputPath) err = zip.Zip(gw.ctx, &zip.Options{ diff --git a/examples/dynamoathenamigration/migration_test.go b/examples/dynamoathenamigration/migration_test.go index b4bf9538af087..1b682cca53e29 100644 --- a/examples/dynamoathenamigration/migration_test.go +++ b/examples/dynamoathenamigration/migration_test.go @@ -24,7 +24,7 @@ import ( "io" "math/rand" "os" - "path" + "path/filepath" "sort" "strings" "sync" @@ -62,7 +62,7 @@ func TestMigrateProcessDataObjects(t *testing.T) { Logger: utils.NewLoggerForTests(), NoOfEmitWorkers: 5, bufferSize: 10, - CheckpointPath: path.Join(t.TempDir(), "migration-tests.json"), + CheckpointPath: filepath.Join(t.TempDir(), "migration-tests.json"), }, } err := mt.ProcessDataObjects(ctx, &exportInfo{ @@ -133,7 +133,7 @@ func TestLargeEventsParse(t *testing.T) { Logger: utils.NewLoggerForTests(), NoOfEmitWorkers: 5, bufferSize: 10, - CheckpointPath: path.Join(t.TempDir(), "migration-tests.json"), + CheckpointPath: filepath.Join(t.TempDir(), "migration-tests.json"), }, } err := mt.ProcessDataObjects(ctx, &exportInfo{ @@ -223,7 +223,7 @@ func TestMigrationCheckpoint(t *testing.T) { Logger: utils.NewLoggerForTests(), NoOfEmitWorkers: noOfWorkers, bufferSize: noOfWorkers * 5, - CheckpointPath: path.Join(t.TempDir(), "migration-tests.json"), + CheckpointPath: filepath.Join(t.TempDir(), "migration-tests.json"), } t.Run("no migration checkpoint, emit every event", func(t *testing.T) { diff --git a/integration/utmp_integration_test.go b/integration/utmp_integration_test.go index 0b5d6e54ca14d..6d00c0c91dad2 100644 --- a/integration/utmp_integration_test.go +++ b/integration/utmp_integration_test.go @@ -22,7 +22,7 @@ import ( "context" "os" "os/user" - "path" + "path/filepath" "testing" "time" @@ -170,8 +170,8 @@ func TestRootUsernameLimit(t *testing.T) { } dir := t.TempDir() - utmpPath := path.Join(dir, "utmp") - wtmpPath := path.Join(dir, "wtmp") + utmpPath := filepath.Join(dir, "utmp") + wtmpPath := filepath.Join(dir, "wtmp") err := TouchFile(utmpPath) require.NoError(t, err) @@ -287,9 +287,9 @@ func newSrvCtx(ctx context.Context, t *testing.T) *SrvCtx { require.NoError(t, err) uaccDir := t.TempDir() - utmpPath := path.Join(uaccDir, "utmp") - wtmpPath := path.Join(uaccDir, "wtmp") - btmpPath := path.Join(uaccDir, "btmp") + utmpPath := filepath.Join(uaccDir, "utmp") + wtmpPath := filepath.Join(uaccDir, "wtmp") + btmpPath := filepath.Join(uaccDir, "btmp") require.NoError(t, TouchFile(utmpPath)) require.NoError(t, TouchFile(wtmpPath)) require.NoError(t, TouchFile(btmpPath)) diff --git a/integrations/event-handler/cli_test.go b/integrations/event-handler/cli_test.go index 7668688880a80..70eef6eea9c06 100644 --- a/integrations/event-handler/cli_test.go +++ b/integrations/event-handler/cli_test.go @@ -18,7 +18,7 @@ package main import ( "os" - "path" + "path/filepath" "testing" "time" @@ -47,13 +47,13 @@ func TestStartCmdConfig(t *testing.T) { FluentdConfig: FluentdConfig{ FluentdURL: "https://localhost:8888/test.log", FluentdSessionURL: "https://localhost:8888/session", - FluentdCert: path.Join(wd, "testdata", "fake-file"), - FluentdKey: path.Join(wd, "testdata", "fake-file"), - FluentdCA: path.Join(wd, "testdata", "fake-file"), + FluentdCert: filepath.Join(wd, "testdata", "fake-file"), + FluentdKey: filepath.Join(wd, "testdata", "fake-file"), + FluentdCA: filepath.Join(wd, "testdata", "fake-file"), }, TeleportConfig: TeleportConfig{ TeleportAddr: "localhost:3025", - TeleportIdentityFile: path.Join(wd, "testdata", "fake-file"), + TeleportIdentityFile: filepath.Join(wd, "testdata", "fake-file"), TeleportRefreshEnabled: true, TeleportRefreshInterval: 2 * time.Minute, }, @@ -85,13 +85,13 @@ func TestStartCmdConfig(t *testing.T) { FluentdConfig: FluentdConfig{ FluentdURL: "https://localhost:8888/test.log", FluentdSessionURL: "https://localhost:8888/session", - FluentdCert: path.Join(wd, "testdata", "fake-file"), - FluentdKey: path.Join(wd, "testdata", "fake-file"), - FluentdCA: path.Join(wd, "testdata", "fake-file"), + FluentdCert: filepath.Join(wd, "testdata", "fake-file"), + FluentdKey: filepath.Join(wd, "testdata", "fake-file"), + FluentdCA: filepath.Join(wd, "testdata", "fake-file"), }, TeleportConfig: TeleportConfig{ TeleportAddr: "localhost:3025", - TeleportIdentityFile: path.Join(wd, "testdata", "fake-file"), + TeleportIdentityFile: filepath.Join(wd, "testdata", "fake-file"), TeleportRefreshEnabled: true, TeleportRefreshInterval: 2 * time.Minute, }, @@ -123,13 +123,13 @@ func TestStartCmdConfig(t *testing.T) { FluentdConfig: FluentdConfig{ FluentdURL: "https://localhost:8888/test.log", FluentdSessionURL: "https://localhost:8888/session", - FluentdCert: path.Join(wd, "testdata", "fake-file"), - FluentdKey: path.Join(wd, "testdata", "fake-file"), - FluentdCA: path.Join(wd, "testdata", "fake-file"), + FluentdCert: filepath.Join(wd, "testdata", "fake-file"), + FluentdKey: filepath.Join(wd, "testdata", "fake-file"), + FluentdCA: filepath.Join(wd, "testdata", "fake-file"), }, TeleportConfig: TeleportConfig{ TeleportAddr: "localhost:3025", - TeleportIdentityFile: path.Join(wd, "testdata", "fake-file"), + TeleportIdentityFile: filepath.Join(wd, "testdata", "fake-file"), TeleportRefreshEnabled: true, TeleportRefreshInterval: 2 * time.Minute, }, diff --git a/integrations/event-handler/configure_cmd.go b/integrations/event-handler/configure_cmd.go index 1b2ade49c9647..bc76427cae046 100644 --- a/integrations/event-handler/configure_cmd.go +++ b/integrations/event-handler/configure_cmd.go @@ -25,7 +25,6 @@ import ( "io" "math/big" "os" - "path" "path/filepath" "strings" @@ -119,15 +118,15 @@ const ( func RunConfigureCmd(cfg *ConfigureCmdConfig) error { c := ConfigureCmd{ ConfigureCmdConfig: cfg, - caCertPath: path.Join(cfg.Out, cfg.CAName) + ".crt", - caKeyPath: path.Join(cfg.Out, cfg.CAName) + ".key", - serverCertPath: path.Join(cfg.Out, cfg.ServerName) + ".crt", - serverKeyPath: path.Join(cfg.Out, cfg.ServerName) + ".key", - clientCertPath: path.Join(cfg.Out, cfg.ClientName) + ".crt", - clientKeyPath: path.Join(cfg.Out, cfg.ClientName) + ".key", - roleDefPath: path.Join(cfg.Out, roleDefFileName), - fluentdConfPath: path.Join(cfg.Out, fluentdConfFileName), - confPath: path.Join(cfg.Out, confFileName), + caCertPath: filepath.Join(cfg.Out, cfg.CAName) + ".crt", + caKeyPath: filepath.Join(cfg.Out, cfg.CAName) + ".key", + serverCertPath: filepath.Join(cfg.Out, cfg.ServerName) + ".crt", + serverKeyPath: filepath.Join(cfg.Out, cfg.ServerName) + ".key", + clientCertPath: filepath.Join(cfg.Out, cfg.ClientName) + ".crt", + clientKeyPath: filepath.Join(cfg.Out, cfg.ClientName) + ".key", + roleDefPath: filepath.Join(cfg.Out, roleDefFileName), + fluentdConfPath: filepath.Join(cfg.Out, fluentdConfFileName), + confPath: filepath.Join(cfg.Out, confFileName), } g, err := GenerateMTLSCerts(cfg.DNSNames, cfg.IP, cfg.TTL, cfg.Length) @@ -347,9 +346,9 @@ func (c *ConfigureCmd) writeFluentdConf(pwd string) error { ServerKeyFileName string Pwd string }{ - path.Base(c.caCertPath), - path.Base(c.serverCertPath), - path.Base(c.serverKeyPath), + filepath.Base(c.caCertPath), + filepath.Base(c.serverCertPath), + filepath.Base(c.serverKeyPath), pwd, } diff --git a/integrations/event-handler/fake_fluentd_test.go b/integrations/event-handler/fake_fluentd_test.go index 070265398ee4d..2d9293b7925aa 100644 --- a/integrations/event-handler/fake_fluentd_test.go +++ b/integrations/event-handler/fake_fluentd_test.go @@ -25,7 +25,7 @@ import ( "net/http" "net/http/httptest" "os" - "path" + "path/filepath" "testing" "time" @@ -73,12 +73,12 @@ func (f *FakeFluentd) writeCerts() error { return trace.Wrap(err) } - f.caCertPath = path.Join(f.keyTmpDir, "ca.crt") - f.caKeyPath = path.Join(f.keyTmpDir, "ca.key") - f.serverCertPath = path.Join(f.keyTmpDir, "server.crt") - f.serverKeyPath = path.Join(f.keyTmpDir, "server.key") - f.clientCertPath = path.Join(f.keyTmpDir, "client.crt") - f.clientKeyPath = path.Join(f.keyTmpDir, "client.key") + f.caCertPath = filepath.Join(f.keyTmpDir, "ca.crt") + f.caKeyPath = filepath.Join(f.keyTmpDir, "ca.key") + f.serverCertPath = filepath.Join(f.keyTmpDir, "server.crt") + f.serverKeyPath = filepath.Join(f.keyTmpDir, "server.key") + f.clientCertPath = filepath.Join(f.keyTmpDir, "client.crt") + f.clientKeyPath = filepath.Join(f.keyTmpDir, "client.key") err = g.CACert.WriteFile(f.caCertPath, f.caKeyPath, "") if err != nil { diff --git a/integrations/event-handler/mtls_certs_test.go b/integrations/event-handler/mtls_certs_test.go index 68502768fa505..cfe725fd0c70f 100644 --- a/integrations/event-handler/mtls_certs_test.go +++ b/integrations/event-handler/mtls_certs_test.go @@ -21,7 +21,7 @@ import ( "encoding/pem" "io" "os" - "path" + "path/filepath" "testing" "time" @@ -60,9 +60,9 @@ func TestGenerateClientCertFile(t *testing.T) { require.Equal(t, "localhost", certs.serverCert.DNSNames[0]) // Write the cert to the tempdir - err = certs.ClientCert.WriteFile(path.Join(td, cp), path.Join(td, kp), ".") + err = certs.ClientCert.WriteFile(filepath.Join(td, cp), filepath.Join(td, kp), ".") require.NoError(t, err) - f, err := os.Open(path.Join(td, cp)) + f, err := os.Open(filepath.Join(td, cp)) require.NoError(t, err) b, err := io.ReadAll(f) require.NoError(t, err) diff --git a/integrations/event-handler/state.go b/integrations/event-handler/state.go index 0706f0ef8a561..9ea74f9905614 100644 --- a/integrations/event-handler/state.go +++ b/integrations/event-handler/state.go @@ -23,7 +23,7 @@ import ( "io/fs" "net" "os" - "path" + "path/filepath" "strings" "syscall" "time" @@ -110,10 +110,10 @@ func createStorageDir(c *StartCmdConfig) (string, error) { return "", trace.Wrap(err) } - dir = path.Join(dir, "dry_run", rs) + dir = filepath.Join(dir, "dry_run", rs) } - dir = path.Join(c.StorageDir, dir) + dir = filepath.Join(c.StorageDir, dir) _, err = os.Stat(dir) if os.IsNotExist(err) { diff --git a/integrations/lib/tar/extract.go b/integrations/lib/tar/extract.go index 2897207a94263..c71030c96cd69 100644 --- a/integrations/lib/tar/extract.go +++ b/integrations/lib/tar/extract.go @@ -24,7 +24,6 @@ import ( "errors" "io" "os" - "path" "path/filepath" "strings" @@ -116,10 +115,10 @@ func Extract(reader io.Reader, options ExtractOptions) error { if strip > len(parts)-1 { strip = len(parts) - 1 } - outFileName = path.Join(parts[strip:]...) + outFileName = filepath.Join(parts[strip:]...) } - outFilePath := path.Join(outDir, outFileName) + outFilePath := filepath.Join(outDir, outFileName) outFilePerm := os.FileMode(header.Mode).Perm() // fail if the outFilePath is outside outDir, see the "zip slip" vulnerability diff --git a/lib/backend/pgbk/common/gcp_test.go b/lib/backend/pgbk/common/gcp_test.go index c1d94991e4490..fb02ac20b498b 100644 --- a/lib/backend/pgbk/common/gcp_test.go +++ b/lib/backend/pgbk/common/gcp_test.go @@ -22,7 +22,7 @@ import ( "context" "log/slog" "os" - "path" + "path/filepath" "testing" "time" @@ -79,7 +79,7 @@ func Test_makeGCPCloudSQLAuthOptionsForServiceAccount(t *testing.T) { func mustSetGoogleApplicationCredentialsEnv(t *testing.T) { t.Helper() - file := path.Join(t.TempDir(), uuid.New().String()) + file := filepath.Join(t.TempDir(), uuid.New().String()) err := os.WriteFile(file, []byte(fakeServiceAccountCredentialsJSON), 0644) require.NoError(t, err) diff --git a/lib/cgroup/cgroup_test.go b/lib/cgroup/cgroup_test.go index 0ca776c1692f5..fdd341ff6f25a 100644 --- a/lib/cgroup/cgroup_test.go +++ b/lib/cgroup/cgroup_test.go @@ -23,7 +23,7 @@ package cgroup import ( "os" - "path" + "path/filepath" "testing" "github.com/google/uuid" @@ -62,7 +62,7 @@ func TestRootCreate(t *testing.T) { require.NoError(t, err) // Make sure that it exists. - cgroupPath := path.Join(service.teleportRoot, sessionID) + cgroupPath := filepath.Join(service.teleportRoot, sessionID) require.DirExists(t, cgroupPath) // Remove cgroup. @@ -112,7 +112,7 @@ func TestRootCreateCustomRootPath(t *testing.T) { err = service.Create(sessionID) require.NoError(t, err) - cgroupPath := path.Join(service.teleportRoot, sessionID) + cgroupPath := filepath.Join(service.teleportRoot, sessionID) require.DirExists(t, cgroupPath) require.Contains(t, cgroupPath, rootPath) @@ -159,7 +159,7 @@ func TestRootCleanup(t *testing.T) { require.NoError(t, err) // Make sure the cgroup no longer exists. - cgroupPath := path.Join(service.teleportRoot, sessionID) + cgroupPath := filepath.Join(service.teleportRoot, sessionID) require.NoDirExists(t, cgroupPath) } @@ -181,7 +181,7 @@ func TestRootSkipUnmount(t *testing.T) { require.NoError(t, err) sessionID := uuid.NewString() - sessionPath := path.Join(service.teleportRoot, sessionID) + sessionPath := filepath.Join(service.teleportRoot, sessionID) require.NoError(t, service.Create(sessionID)) require.DirExists(t, sessionPath) @@ -190,7 +190,7 @@ func TestRootSkipUnmount(t *testing.T) { require.NoError(t, service.Close(skipUnmount)) require.DirExists(t, service.teleportRoot) - require.NoDirExists(t, path.Join(service.teleportRoot, sessionID)) + require.NoDirExists(t, filepath.Join(service.teleportRoot, sessionID)) require.NoError(t, service.unmount()) diff --git a/lib/client/db/dbcmd/dbcmd.go b/lib/client/db/dbcmd/dbcmd.go index 4b6b2cefe4bf6..603a284ea7ec9 100644 --- a/lib/client/db/dbcmd/dbcmd.go +++ b/lib/client/db/dbcmd/dbcmd.go @@ -24,7 +24,7 @@ import ( "net/url" "os" "os/exec" - "path" + "path/filepath" "runtime" "strconv" "strings" @@ -697,7 +697,7 @@ func (c *CLICommandBuilder) getOpenSearchCLICommand() (*exec.Cmd, error) { c.profile.DatabaseKeyPathForCluster(c.tc.SiteName, c.db.ServiceName)) } - baseDir := path.Join(c.profile.Dir, c.profile.Cluster, c.db.ServiceName) + baseDir := filepath.Join(c.profile.Dir, c.profile.Cluster, c.db.ServiceName) tempCfg, err := opensearch.WriteConfig(baseDir, cfg) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/client/db/opensearch/profile.go b/lib/client/db/opensearch/profile.go index b32e406fa93f7..8c3968dd71c1c 100644 --- a/lib/client/db/opensearch/profile.go +++ b/lib/client/db/opensearch/profile.go @@ -22,7 +22,7 @@ import ( "fmt" "hash/fnv" "os" - "path" + "path/filepath" "github.com/ghodss/yaml" "github.com/gravitational/trace" @@ -104,14 +104,14 @@ func WriteConfig(baseDir string, cfg Config) (string, error) { hash := h.Sum32() // create config directory if it doesn't exist - configDir := path.Join(baseDir, "opensearch-cli") + configDir := filepath.Join(baseDir, "opensearch-cli") err = os.MkdirAll(configDir, 0700) if err != nil { return "", trace.Wrap(err) } // write config to file - fn := path.Join(configDir, fmt.Sprintf("%x.yml", hash)) + fn := filepath.Join(configDir, fmt.Sprintf("%x.yml", hash)) err = os.WriteFile(fn, bytes, 0600) if err != nil { return "", trace.Wrap(err) diff --git a/lib/client/db/opensearch/profile_test.go b/lib/client/db/opensearch/profile_test.go index 88c5bae6a899a..efc80d18b491a 100644 --- a/lib/client/db/opensearch/profile_test.go +++ b/lib/client/db/opensearch/profile_test.go @@ -20,7 +20,7 @@ package opensearch import ( "os" - "path" + "path/filepath" "testing" "github.com/stretchr/testify/require" @@ -67,7 +67,7 @@ func TestWriteConfig(t *testing.T) { tmp := t.TempDir() fn, err := WriteConfig(tmp, ConfigNoTLS("host.example.com", 8080)) require.NoError(t, err) - require.Equal(t, path.Join(tmp, "opensearch-cli", "150502df.yml"), fn) + require.Equal(t, filepath.Join(tmp, "opensearch-cli", "150502df.yml"), fn) bytes, err := os.ReadFile(fn) require.NoError(t, err) require.Equal(t, `profiles: diff --git a/lib/client/tshconfig_test.go b/lib/client/tshconfig_test.go index a9acbee98993b..99e3b3872570a 100644 --- a/lib/client/tshconfig_test.go +++ b/lib/client/tshconfig_test.go @@ -20,7 +20,7 @@ package client import ( "os" - "path" + "path/filepath" "testing" "github.com/google/uuid" @@ -55,7 +55,7 @@ func TestLoadAllConfigs(t *testing.T) { t.Parallel() writeConf := func(fn string, config TSHConfig) { - dir, _ := path.Split(fn) + dir, _ := filepath.Split(fn) err := os.MkdirAll(dir, 0777) require.NoError(t, err) out, err := yaml.Marshal(config) @@ -66,7 +66,7 @@ func TestLoadAllConfigs(t *testing.T) { tmp := t.TempDir() - globalPath := path.Join(tmp, "etc", "tsh_global.yaml") + globalPath := filepath.Join(tmp, "etc", "tsh_global.yaml") globalConf := TSHConfig{ ExtraHeaders: []ExtraProxyHeaders{{ Proxy: "global", @@ -74,8 +74,8 @@ func TestLoadAllConfigs(t *testing.T) { }}, } - homeDir := path.Join(tmp, "home", "myuser", ".tsh") - userPath := path.Join(homeDir, "config", "config.yaml") + homeDir := filepath.Join(tmp, "home", "myuser", ".tsh") + userPath := filepath.Join(homeDir, "config", "config.yaml") userConf := TSHConfig{ ExtraHeaders: []ExtraProxyHeaders{{ Proxy: "user", diff --git a/lib/config/configuration_test.go b/lib/config/configuration_test.go index 860133ac5fa48..52c1a46b91c66 100644 --- a/lib/config/configuration_test.go +++ b/lib/config/configuration_test.go @@ -25,7 +25,6 @@ import ( "fmt" "net" "os" - "path" "path/filepath" "strconv" "strings" @@ -2998,7 +2997,7 @@ func TestDatabaseCLIFlags(t *testing.T) { func TestTLSCert(t *testing.T) { tmpDir := t.TempDir() - tmpCA := path.Join(tmpDir, "ca.pem") + tmpCA := filepath.Join(tmpDir, "ca.pem") err := os.WriteFile(tmpCA, fixtures.LocalhostCert, 0o644) require.NoError(t, err) diff --git a/lib/srv/server/installer/autodiscover.go b/lib/srv/server/installer/autodiscover.go index 2597c2e05cf54..9d19b472f33b3 100644 --- a/lib/srv/server/installer/autodiscover.go +++ b/lib/srv/server/installer/autodiscover.go @@ -28,7 +28,7 @@ import ( "net/url" "os" "os/exec" - "path" + "path/filepath" "slices" "sort" "strings" @@ -538,8 +538,8 @@ func fetchNodeAutoDiscoverLabels(ctx context.Context, imdsClient imds.Client) (m } // buildAbsoluteFilePath creates the absolute file path -func (ani *AutoDiscoverNodeInstaller) buildAbsoluteFilePath(filepath string) string { - return path.Join(ani.fsRootPrefix, filepath) +func (ani *AutoDiscoverNodeInstaller) buildAbsoluteFilePath(path string) string { + return filepath.Join(ani.fsRootPrefix, path) } // linuxDistribution reads the current file system to detect the Linux Distro and Version of the current system. diff --git a/lib/srv/server/installer/autodiscover_test.go b/lib/srv/server/installer/autodiscover_test.go index 9a4e0e20475b9..4fd1c2316d1d6 100644 --- a/lib/srv/server/installer/autodiscover_test.go +++ b/lib/srv/server/installer/autodiscover_test.go @@ -24,7 +24,7 @@ import ( "net/http" "net/http/httptest" "os" - "path" + "path/filepath" "strings" "testing" @@ -71,20 +71,20 @@ func buildMockBins(t *testing.T) (map[string]*bintest.Mock, packagemanager.Binar } func setupDirsForTest(t *testing.T, testTempDir string, distroConfig map[string]string) { - require.NoError(t, os.MkdirAll(path.Join(testTempDir, "/etc"), fs.ModePerm)) - require.NoError(t, os.MkdirAll(path.Join(testTempDir, "/usr/local/bin"), fs.ModePerm)) - require.NoError(t, os.MkdirAll(path.Join(testTempDir, "/usr/share"), fs.ModePerm)) - require.NoError(t, os.MkdirAll(path.Join(testTempDir, "/var/lock"), fs.ModePerm)) + require.NoError(t, os.MkdirAll(filepath.Join(testTempDir, "etc"), fs.ModePerm)) + require.NoError(t, os.MkdirAll(filepath.Join(testTempDir, "usr/local/bin"), fs.ModePerm)) + require.NoError(t, os.MkdirAll(filepath.Join(testTempDir, "usr/share"), fs.ModePerm)) + require.NoError(t, os.MkdirAll(filepath.Join(testTempDir, "var/lock"), fs.ModePerm)) for fileName, contents := range distroConfig { isDir := strings.HasSuffix(fileName, "/") if isDir { require.Empty(t, contents, "expected no contents for directory %q", fileName) - require.NoError(t, os.MkdirAll(path.Join(testTempDir, fileName), fs.ModePerm)) + require.NoError(t, os.MkdirAll(filepath.Join(testTempDir, fileName), fs.ModePerm)) } else { - filePathWithoutParent := path.Base(fileName) - require.NoError(t, os.MkdirAll(path.Join(testTempDir, filePathWithoutParent), fs.ModePerm)) - require.NoError(t, os.WriteFile(path.Join(testTempDir, fileName), []byte(contents), fs.ModePerm)) + filePathWithoutParent := filepath.Base(fileName) + require.NoError(t, os.MkdirAll(filepath.Join(testTempDir, filePathWithoutParent), fs.ModePerm)) + require.NoError(t, os.WriteFile(filepath.Join(testTempDir, fileName), []byte(contents), fs.ModePerm)) } } } diff --git a/lib/srv/sess.go b/lib/srv/sess.go index beff153e5ac7b..7dd830f307063 100644 --- a/lib/srv/sess.go +++ b/lib/srv/sess.go @@ -28,7 +28,7 @@ import ( "log/slog" "os" "os/user" - "path" + "path/filepath" "slices" "sync" "sync/atomic" @@ -1757,8 +1757,8 @@ func (s *session) newFileTransferRequest(params *rsession.FileTransferRequestPar } func (s *session) expandFileTransferRequestPath(p string) (string, error) { - expanded := path.Clean(p) - dir := path.Dir(expanded) + expanded := filepath.Clean(p) + dir := filepath.Dir(expanded) var tildePrefixed bool var noBaseDir bool @@ -1785,11 +1785,11 @@ func (s *session) expandFileTransferRequestPath(p string) (string, error) { if tildePrefixed { // expand home dir to make an absolute path - expanded = path.Join(homeDir, expanded[2:]) + expanded = filepath.Join(homeDir, expanded[2:]) } else { // if no directories are specified SFTP will assume the file // to be in the user's home dir - expanded = path.Join(homeDir, expanded) + expanded = filepath.Join(homeDir, expanded) } } diff --git a/lib/tbot/output_utils.go b/lib/tbot/output_utils.go index ff3ee76845b41..bd94651b39246 100644 --- a/lib/tbot/output_utils.go +++ b/lib/tbot/output_utils.go @@ -24,7 +24,7 @@ import ( "io/fs" "log/slog" "os" - "path" + "path/filepath" "slices" "strings" "time" @@ -75,9 +75,9 @@ type BotConfigWriter struct { // WriteFile writes the file to the Destination. Only the basename of the path // is used. Specified permissions are ignored. func (b *BotConfigWriter) WriteFile(name string, data []byte, _ os.FileMode) error { - p := path.Base(name) + p := filepath.Base(name) if b.subpath != "" { - p = path.Join(b.subpath, p) + p = filepath.Join(b.subpath, p) } return trace.Wrap(b.dest.Write(b.ctx, p, data)) diff --git a/lib/tbot/tbot_test.go b/lib/tbot/tbot_test.go index 48abca8c58632..8b33a36c92261 100644 --- a/lib/tbot/tbot_test.go +++ b/lib/tbot/tbot_test.go @@ -971,8 +971,8 @@ func TestBotSSHMultiplexer(t *testing.T) { currentUser, err := user.Current() require.NoError(t, err) - // 104 length limit on UDS on MacOS forces us to use a custom tmpdir. - tmpDir := path.Join(os.TempDir(), t.Name()) + // 104 length limit on UDS on macOS forces us to use a custom tmpdir. + tmpDir := filepath.Join(os.TempDir(), t.Name()) require.NoError(t, os.RemoveAll(tmpDir)) require.NoError(t, os.Mkdir(tmpDir, 0777)) t.Cleanup(func() { diff --git a/lib/utils/packagemanager/apt.go b/lib/utils/packagemanager/apt.go index f20225231673c..8b3c7a100c64c 100644 --- a/lib/utils/packagemanager/apt.go +++ b/lib/utils/packagemanager/apt.go @@ -24,7 +24,7 @@ import ( "net/http" "os" "os/exec" - "path" + "path/filepath" "strings" "github.com/gravitational/trace" @@ -125,8 +125,8 @@ func (pm *APT) AddTeleportRepository(ctx context.Context, linuxInfo *linux.OSRel return trace.Wrap(err) } - aptTeleportSourceListFile := path.Join(pm.fsRootPrefix, aptTeleportSourceListFileRelative) - aptTeleportPublicKeyFile := path.Join(pm.fsRootPrefix, aptTeleportPublicKeyFileRelative) + aptTeleportSourceListFile := filepath.Join(pm.fsRootPrefix, aptTeleportSourceListFileRelative) + aptTeleportPublicKeyFile := filepath.Join(pm.fsRootPrefix, aptTeleportPublicKeyFileRelative) // Format for teleport repo entry should look like this: // deb [signed-by=/usr/share/keyrings/teleport-archive-keyring.asc] https://apt.releases.teleport.dev/${ID?} ${VERSION_CODENAME?} $RepoChannel" teleportRepoMetadata := fmt.Sprintf("deb [signed-by=%s] %s%s %s %s", aptTeleportPublicKeyFile, aptRepoEndpoint, linuxInfo.ID, linuxInfo.VersionCodename, repoChannel) diff --git a/tool/tbot/systemd_test.go b/tool/tbot/systemd_test.go index 8fd176467db8e..10705aeaa44df 100644 --- a/tool/tbot/systemd_test.go +++ b/tool/tbot/systemd_test.go @@ -24,7 +24,7 @@ import ( "context" "fmt" "os" - "path" + "path/filepath" "testing" "github.com/alecthomas/kingpin/v2" @@ -40,7 +40,7 @@ func TestInstallSystemdCmd(t *testing.T) { // Create pre-existing file to test --force preExistingDir := t.TempDir() - err := os.WriteFile(path.Join(preExistingDir, "tbot.service"), []byte("pre-existing"), 0644) + err := os.WriteFile(filepath.Join(preExistingDir, "tbot.service"), []byte("pre-existing"), 0644) require.NoError(t, err) tests := []struct { @@ -128,14 +128,14 @@ func TestInstallSystemdCmd(t *testing.T) { if tt.wantStdout { // Ensure that in dry run, no actual output is written! _, err = os.ReadFile( - path.Join(dirPath, fmt.Sprintf("%s.service", cmp.Or(tt.wantUnitName, "tbot"))), + filepath.Join(dirPath, fmt.Sprintf("%s.service", cmp.Or(tt.wantUnitName, "tbot"))), ) require.ErrorIs(t, err, os.ErrNotExist) data = stdout.Bytes() data = bytes.ReplaceAll(data, []byte(dirPath), []byte("/test/dir")) } else { data, err = os.ReadFile( - path.Join(dirPath, fmt.Sprintf("%s.service", cmp.Or(tt.wantUnitName, "tbot"))), + filepath.Join(dirPath, fmt.Sprintf("%s.service", cmp.Or(tt.wantUnitName, "tbot"))), ) require.NoError(t, err) } diff --git a/tool/tctl/sso/configure/flags/file_reader_test.go b/tool/tctl/sso/configure/flags/file_reader_test.go index ad5fb8ed3aab3..742f0352b49a3 100644 --- a/tool/tctl/sso/configure/flags/file_reader_test.go +++ b/tool/tctl/sso/configure/flags/file_reader_test.go @@ -19,7 +19,7 @@ package flags import ( "math/rand" "os" - "path" + "path/filepath" "strings" "testing" "time" @@ -34,13 +34,13 @@ func TestFileReader(t *testing.T) { tmp := t.TempDir() // running against non-existing file returns error, does not change the stored value - fn := path.Join(tmp, "does-not-exist.txt") + fn := filepath.Join(tmp, "does-not-exist.txt") err := reader.Set(fn) require.Error(t, err) require.Equal(t, "initial", out) // lots of ones... - fn = path.Join(tmp, "ones.txt") + fn = filepath.Join(tmp, "ones.txt") ones := strings.Repeat("1", 1024*1024) err = os.WriteFile(fn, []byte(ones), 0777) require.NoError(t, err) @@ -49,7 +49,7 @@ func TestFileReader(t *testing.T) { require.Equal(t, ones, out) // random string - fn = path.Join(tmp, "random.txt") + fn = filepath.Join(tmp, "random.txt") src := rand.NewSource(time.Now().UnixNano()) buf := make([]byte, 1024*1024) for ix := range buf { diff --git a/tool/tctl/sso/configure/saml_test.go b/tool/tctl/sso/configure/saml_test.go index 00d75b6002459..ec9e6be0ca9f3 100644 --- a/tool/tctl/sso/configure/saml_test.go +++ b/tool/tctl/sso/configure/saml_test.go @@ -19,7 +19,7 @@ package configure import ( "io" "os" - "path" + "path/filepath" "testing" "github.com/sirupsen/logrus" @@ -50,10 +50,10 @@ V115UGOwvjOOxmOFbYBn865SHgMndFtr dir := t.TempDir() - edBadFile := path.Join(dir, "entity_descriptor_bad.xml") + edBadFile := filepath.Join(dir, "entity_descriptor_bad.xml") require.NoError(t, os.WriteFile(edBadFile, []byte("foo bar baz"), 0777)) - edGoodFile := path.Join(dir, "entity_descriptor_good.xml") + edGoodFile := filepath.Join(dir, "entity_descriptor_good.xml") require.NoError(t, os.WriteFile(edGoodFile, []byte(edOk), 0777)) tests := []struct { diff --git a/tool/tsh/common/app_azure.go b/tool/tsh/common/app_azure.go index 1dbcaab69b938..5a8494aae5d3e 100644 --- a/tool/tsh/common/app_azure.go +++ b/tool/tsh/common/app_azure.go @@ -24,7 +24,7 @@ import ( "fmt" "os" "os/exec" - "path" + "path/filepath" "sort" "strings" @@ -155,7 +155,7 @@ func (a *azureApp) GetEnvVars() (map[string]string, error) { // 1. `tsh az login` in one console // 2. `az ...` in another console // without custom config dir the second invocation will hang, attempting to connect to (inaccessible without configuration) MSI. - "AZURE_CONFIG_DIR": path.Join(profile.FullProfilePath(a.cf.HomePath), "azure", a.appInfo.RouteToApp.ClusterName, a.appInfo.RouteToApp.Name), + "AZURE_CONFIG_DIR": filepath.Join(profile.FullProfilePath(a.cf.HomePath), "azure", a.appInfo.RouteToApp.ClusterName, a.appInfo.RouteToApp.Name), // setting MSI_ENDPOINT instructs Azure CLI to make managed identity calls on this address. // the requests will be handled by tsh proxy. "MSI_ENDPOINT": "https://" + types.TeleportAzureMSIEndpoint + "/" + a.msiSecret, diff --git a/tool/tsh/common/app_azure_test.go b/tool/tsh/common/app_azure_test.go index 840b8a62b2dbf..2a0db09e4490c 100644 --- a/tool/tsh/common/app_azure_test.go +++ b/tool/tsh/common/app_azure_test.go @@ -27,7 +27,7 @@ import ( "net/http" "net/url" "os/exec" - "path" + "path/filepath" "strings" "testing" @@ -161,9 +161,9 @@ func TestAzure(t *testing.T) { return "" } - require.Equal(t, path.Join(tmpHomePath, "azure/localhost/azure-api"), getEnvValue("AZURE_CONFIG_DIR")) + require.Equal(t, filepath.Join(tmpHomePath, "azure/localhost/azure-api"), getEnvValue("AZURE_CONFIG_DIR")) require.Equal(t, "https://azure-msi.teleport.dev/very-secret", getEnvValue("MSI_ENDPOINT")) - require.Equal(t, path.Join(tmpHomePath, "keys/127.0.0.1/alice@example.com-app/localhost/azure-api-localca.pem"), getEnvValue("REQUESTS_CA_BUNDLE")) + require.Equal(t, filepath.Join(tmpHomePath, "keys/127.0.0.1/alice@example.com-app/localhost/azure-api-localca.pem"), getEnvValue("REQUESTS_CA_BUNDLE")) require.True(t, strings.HasPrefix(getEnvValue("HTTPS_PROXY"), "http://127.0.0.1:")) // Validate MSI endpoint can be reached diff --git a/tool/tsh/common/app_gcp.go b/tool/tsh/common/app_gcp.go index faedb4608f725..237eb207446c5 100644 --- a/tool/tsh/common/app_gcp.go +++ b/tool/tsh/common/app_gcp.go @@ -24,7 +24,7 @@ import ( "hash/fnv" "os" "os/exec" - "path" + "path/filepath" "sort" "strings" @@ -162,7 +162,7 @@ func (a *gcpApp) Close() error { } func (a *gcpApp) getGcloudConfigPath() string { - return path.Join(profile.FullProfilePath(a.cf.HomePath), "gcp", a.appInfo.RouteToApp.ClusterName, a.appInfo.RouteToApp.Name, "gcloud") + return filepath.Join(profile.FullProfilePath(a.cf.HomePath), "gcp", a.appInfo.RouteToApp.ClusterName, a.appInfo.RouteToApp.Name, "gcloud") } // removeBotoConfig removes config files written by WriteBotoConfig. @@ -175,15 +175,15 @@ func (a *gcpApp) removeBotoConfig() []error { } func (a *gcpApp) getBotoConfigDir() string { - return path.Join(profile.FullProfilePath(a.cf.HomePath), "gcp", a.appInfo.RouteToApp.ClusterName, a.appInfo.RouteToApp.Name) + return filepath.Join(profile.FullProfilePath(a.cf.HomePath), "gcp", a.appInfo.RouteToApp.ClusterName, a.appInfo.RouteToApp.Name) } func (a *gcpApp) getBotoConfigPath() string { - return path.Join(a.getBotoConfigDir(), a.prefix+"_boto.cfg") + return filepath.Join(a.getBotoConfigDir(), a.prefix+"_boto.cfg") } func (a *gcpApp) getExternalAccountFilePath() string { - return path.Join(a.getBotoConfigDir(), a.prefix+"_external.json") + return filepath.Join(a.getBotoConfigDir(), a.prefix+"_external.json") } // getBotoConfig returns minimal boto configuration, referencing an external account file. diff --git a/tool/tsh/common/kube_proxy.go b/tool/tsh/common/kube_proxy.go index c6c7334ab54cc..fd2ff714e0608 100644 --- a/tool/tsh/common/kube_proxy.go +++ b/tool/tsh/common/kube_proxy.go @@ -27,7 +27,7 @@ import ( "net" "os" "os/exec" - "path" + "path/filepath" "text/template" "time" @@ -369,7 +369,7 @@ func makeKubeLocalProxy(cf *CLIConf, tc *client.TeleportClient, clusters kubecon kubeProxy.kubeConfigPath = os.Getenv(proxyKubeConfigEnvVar) if kubeProxy.kubeConfigPath == "" { _, port, _ := net.SplitHostPort(kubeProxy.forwardProxy.GetAddr()) - kubeProxy.kubeConfigPath = path.Join(profile.KubeConfigPath(fmt.Sprintf("localproxy-%v", port))) + kubeProxy.kubeConfigPath = filepath.Join(profile.KubeConfigPath(fmt.Sprintf("localproxy-%v", port))) } } diff --git a/tool/tsh/common/kube_proxy_test.go b/tool/tsh/common/kube_proxy_test.go index fe337c24c8a92..89e08105fc682 100644 --- a/tool/tsh/common/kube_proxy_test.go +++ b/tool/tsh/common/kube_proxy_test.go @@ -27,7 +27,7 @@ import ( "net/url" "os" "os/exec" - "path" + "path/filepath" "strings" "testing" @@ -50,7 +50,7 @@ import ( func (p *kubeTestPack) testProxyKube(t *testing.T) { // Set default kubeconfig to a non-exist file to avoid loading other things. - t.Setenv("KUBECONFIG", path.Join(os.Getenv(types.HomeEnvVar), uuid.NewString())) + t.Setenv("KUBECONFIG", filepath.Join(os.Getenv(types.HomeEnvVar), uuid.NewString())) // Test "tsh proxy kube root-cluster1". t.Run("with kube cluster arg", func(t *testing.T) { diff --git a/tool/tsh/common/kube_test.go b/tool/tsh/common/kube_test.go index 5cd3aefd1ffbd..6fb399aa5cc72 100644 --- a/tool/tsh/common/kube_test.go +++ b/tool/tsh/common/kube_test.go @@ -26,7 +26,6 @@ import ( "os" "os/exec" "os/user" - "path" "path/filepath" "reflect" "slices" @@ -76,7 +75,7 @@ func TestKubeLogin(t *testing.T) { testKubeLogin := func(t *testing.T, kubeCluster string, expectedAddr string) { // Set default kubeconfig to a non-exist file to avoid loading other things. - t.Setenv("KUBECONFIG", path.Join(os.Getenv(types.HomeEnvVar), uuid.NewString())) + t.Setenv("KUBECONFIG", filepath.Join(os.Getenv(types.HomeEnvVar), uuid.NewString())) // Test "tsh proxy kube root-cluster1". @@ -554,7 +553,7 @@ func TestKubeSelection(t *testing.T) { // clients work in the same profile dir. tshHome, _ := mustLogin(t, s) // Set kubeconfig to a non-exist file to avoid loading other things. - kubeConfigPath := path.Join(tshHome, "kube-config") + kubeConfigPath := filepath.Join(tshHome, "kube-config") var cmdRunner func(*exec.Cmd) error if len(test.wantProxied) > 0 { cmdRunner = func(cmd *exec.Cmd) error { diff --git a/tool/tsh/common/kubectl_test.go b/tool/tsh/common/kubectl_test.go index 21eab7e8d4465..d55e679dae3a1 100644 --- a/tool/tsh/common/kubectl_test.go +++ b/tool/tsh/common/kubectl_test.go @@ -19,7 +19,7 @@ package common import ( - "path" + "path/filepath" "testing" "github.com/google/uuid" @@ -113,7 +113,7 @@ func Test_maybeStartKubeLocalProxy(t *testing.T) { var localProxyCreated bool var loadedKubeClusters kubeconfig.LocalProxyClusters - wantLocalProxyKubeConfigLocation := path.Join(tshHome, uuid.NewString()) + wantLocalProxyKubeConfigLocation := filepath.Join(tshHome, uuid.NewString()) closeFn, actualKubeConfigLocation, err := maybeStartKubeLocalProxy(cf, withKubectlArgs(test.inputArgs), @@ -266,7 +266,7 @@ func Test_overwriteKubeconfigFlagInEnv(t *testing.T) { } func mustSetupKubeconfig(t *testing.T, tshHome, kubeCluster string) string { - kubeconfigLocation := path.Join(tshHome, "kubeconfig") + kubeconfigLocation := filepath.Join(tshHome, "kubeconfig") key, err := cryptosuites.GenerateKeyWithAlgorithm(cryptosuites.ECDSAP256) require.NoError(t, err) priv, err := keys.NewSoftwarePrivateKey(key) diff --git a/tool/tsh/common/proxy_test.go b/tool/tsh/common/proxy_test.go index d06b8bbeca673..639edf57c90f1 100644 --- a/tool/tsh/common/proxy_test.go +++ b/tool/tsh/common/proxy_test.go @@ -36,7 +36,6 @@ import ( "os" "os/exec" "os/user" - "path" "path/filepath" "strconv" "testing" @@ -85,8 +84,8 @@ func TestSSH(t *testing.T) { lib.SetInsecureDevMode(false) d := t.TempDir() - webCertPath := path.Join(d, "cert.pem") - webKeyPath := path.Join(d, "key.pem") + webCertPath := filepath.Join(d, "cert.pem") + webKeyPath := filepath.Join(d, "key.pem") generateWebPKICert(t, webCertPath, webKeyPath) s := newTestSuite(t, @@ -1028,7 +1027,7 @@ func mustLoginSetEnv(t *testing.T, s *suite, args ...string) (tshHome, kubeConfi } func mustLoginIdentity(t *testing.T, s *suite) string { - identityFile := path.Join(t.TempDir(), "identity.pem") + identityFile := filepath.Join(t.TempDir(), "identity.pem") mustLogin(t, s, "--out", identityFile) return identityFile } diff --git a/tool/tsh/common/recording_export_test.go b/tool/tsh/common/recording_export_test.go index 99f4a9019111b..ef779ad8e4e8c 100644 --- a/tool/tsh/common/recording_export_test.go +++ b/tool/tsh/common/recording_export_test.go @@ -23,7 +23,7 @@ import ( "encoding/base64" "encoding/binary" "os" - "path" + "path/filepath" "testing" "time" @@ -129,13 +129,13 @@ func TestWriteMovieWritesManyFrames(t *testing.T) { require.Equal(t, framesPerSecond, frames) } -// Calls writeMovie, and tells the test state to cleanup the created files upon completion. +// writeMovieWrapper calls writeMovie, and tells the test state to cleanup the created files upon completion. // Returns the writeMovie call results, as well as the path-qualified prefix to the created file. func writeMovieWrapper(t *testing.T, ctx context.Context, ss events.SessionStreamer, sid session.ID, prefix string, write func(format string, args ...any) (int, error)) (int, string, error) { tempDir := t.TempDir() - prefix = path.Join(tempDir, prefix) + prefix = filepath.Join(tempDir, prefix) frames, err := writeMovie(ctx, ss, sid, prefix, write, "") return frames, prefix, err } diff --git a/tool/tsh/common/workload_identity.go b/tool/tsh/common/workload_identity.go index 98ed763348ed3..d46ce7cf63412 100644 --- a/tool/tsh/common/workload_identity.go +++ b/tool/tsh/common/workload_identity.go @@ -24,7 +24,7 @@ import ( "encoding/pem" "fmt" "os" - "path" + "path/filepath" "time" "github.com/alecthomas/kingpin/v2" @@ -152,7 +152,7 @@ func (c *svidIssueCommand) run(cf *CLIConf) error { if err != nil { return trace.Wrap(err) } - keyPath := path.Join(c.outputDirectory, svidKeyPEMPath) + keyPath := filepath.Join(c.outputDirectory, svidKeyPEMPath) err = os.WriteFile( keyPath, pem.EncodeToMemory(&pem.Block{ @@ -166,7 +166,7 @@ func (c *svidIssueCommand) run(cf *CLIConf) error { } // Write SVID - svidPath := path.Join(c.outputDirectory, svidPEMPath) + svidPath := filepath.Join(c.outputDirectory, svidPEMPath) err = os.WriteFile( svidPath, pem.EncodeToMemory(&pem.Block{ @@ -195,7 +195,7 @@ func (c *svidIssueCommand) run(cf *CLIConf) error { } } } - trustBundlePath := path.Join(c.outputDirectory, svidTrustBundlePEMPath) + trustBundlePath := filepath.Join(c.outputDirectory, svidTrustBundlePEMPath) err = os.WriteFile( trustBundlePath, trustBundleBytes.Bytes(), diff --git a/tool/tsh/common/workload_identity_test.go b/tool/tsh/common/workload_identity_test.go index 485d0c210c9a0..e9eedeac8ab9f 100644 --- a/tool/tsh/common/workload_identity_test.go +++ b/tool/tsh/common/workload_identity_test.go @@ -26,7 +26,7 @@ import ( "encoding/pem" "net" "os" - "path" + "path/filepath" "testing" "github.com/stretchr/testify/require" @@ -81,7 +81,7 @@ func TestWorkloadIdentityIssue(t *testing.T) { ) require.NoError(t, err) - certPEM, err := os.ReadFile(path.Join(temp, "svid.pem")) + certPEM, err := os.ReadFile(filepath.Join(temp, "svid.pem")) require.NoError(t, err) certBlock, _ := pem.Decode(certPEM) cert, err := x509.ParseCertificate(certBlock.Bytes) @@ -95,7 +95,7 @@ func TestWorkloadIdentityIssue(t *testing.T) { // balanced-v1 algorithm suite). require.IsType(t, &ecdsa.PublicKey{}, cert.PublicKey) - keyPEM, err := os.ReadFile(path.Join(temp, "svid_key.pem")) + keyPEM, err := os.ReadFile(filepath.Join(temp, "svid_key.pem")) require.NoError(t, err) keyBlock, _ := pem.Decode(keyPEM) privateKey, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes) @@ -104,7 +104,7 @@ func TestWorkloadIdentityIssue(t *testing.T) { require.Implements(t, (*crypto.Signer)(nil), privateKey) require.Equal(t, cert.PublicKey, privateKey.(crypto.Signer).Public()) - bundlePEM, err := os.ReadFile(path.Join(temp, "svid_bundle.pem")) + bundlePEM, err := os.ReadFile(filepath.Join(temp, "svid_bundle.pem")) require.NoError(t, err) bundleBlock, _ := pem.Decode(bundlePEM) _, err = x509.ParseCertificate(bundleBlock.Bytes) From 0cffff42c7783b8d1911ab46de917bc2aa433705 Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Tue, 1 Oct 2024 16:24:48 -0600 Subject: [PATCH 2/5] tsh play --format=text (#46849) For sessions with print events, this command will write the text directly to standard out. This makes it easier to grep for a particular pattern or just dump a session recording to a file for manual analysis. Closes #11694 --- tool/tsh/common/play.go | 23 +++++++++++++++++++++-- tool/tsh/common/tsh.go | 4 ++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/tool/tsh/common/play.go b/tool/tsh/common/play.go index 14900ce485871..18b5078fb67ac 100644 --- a/tool/tsh/common/play.go +++ b/tool/tsh/common/play.go @@ -115,9 +115,10 @@ func exportSession(cf *CLIConf) error { } switch format { - case teleport.JSON, teleport.YAML: + case teleport.JSON, teleport.YAML, teleport.Text: default: - return trace.Errorf("Invalid format %s, only json and yaml are supported", format) + // this should be unreachable since kingpin validates the format flag + return trace.BadParameter("Invalid format %s", format) } sid, err := session.ParseID(cf.SessionID) @@ -144,6 +145,8 @@ func exportSession(cf *CLIConf) error { exporter = jsonSessionExporter{} case teleport.YAML: exporter = yamlSessionExporter{} + case teleport.Text: + exporter = textSessionExporter{} } exporter.WriteStart() @@ -233,6 +236,22 @@ func (yamlSessionExporter) WriteEvent(evt apievents.AuditEvent) error { return err } +type textSessionExporter struct{} + +func (textSessionExporter) WriteStart() error { return nil } +func (textSessionExporter) WriteEnd() error { return nil } +func (textSessionExporter) WriteSeparator() error { return nil } + +func (textSessionExporter) WriteEvent(evt apievents.AuditEvent) error { + printEvent, ok := evt.(*apievents.SessionPrint) + if !ok { + return nil + } + + _, err := os.Stdout.Write(printEvent.Data) + return trace.Wrap(err) +} + // exportFile converts the binary protobuf events from the file // identified by path to text (JSON/YAML) and writes the converted // events to standard out. diff --git a/tool/tsh/common/tsh.go b/tool/tsh/common/tsh.go index 500dcab53c79f..79bf18f491934 100644 --- a/tool/tsh/common/tsh.go +++ b/tool/tsh/common/tsh.go @@ -983,8 +983,8 @@ func Run(ctx context.Context, args []string, opts ...CliOption) error { play.Flag("speed", "Playback speed, applicable when streaming SSH or Kubernetes sessions.").Default("1x").EnumVar(&cf.PlaySpeed, "0.5x", "1x", "2x", "4x", "8x") play.Flag("skip-idle-time", "Quickly skip over idle time, applicable when streaming SSH or Kubernetes sessions.").BoolVar(&cf.NoWait) play.Flag("format", defaults.FormatFlagDescription( - teleport.PTY, teleport.JSON, teleport.YAML, - )).Short('f').Default(teleport.PTY).EnumVar(&cf.Format, teleport.PTY, teleport.JSON, teleport.YAML) + teleport.PTY, teleport.JSON, teleport.YAML, teleport.Text, + )).Short('f').Default(teleport.PTY).EnumVar(&cf.Format, teleport.PTY, teleport.JSON, teleport.YAML, teleport.Text) play.Arg("session-id", "ID or path to session file to play").Required().StringVar(&cf.SessionID) // scp From 82bbf364ba715fe70306be731047ec87320d1139 Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Tue, 1 Oct 2024 16:25:35 -0600 Subject: [PATCH 3/5] Disable session recording for TestDynamicClientReuse (#47004) Also removes references to boltdb, which hasn't been supported for several years. Closes #46958 --- lib/backend/backend.go | 4 ++-- lib/config/configuration_test.go | 4 ++-- lib/service/service_test.go | 2 +- lib/service/servicecfg/config.go | 3 +-- lib/services/local/doc.go | 3 +-- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/backend/backend.go b/lib/backend/backend.go index 55c386944c7e2..9b0b02007e902 100644 --- a/lib/backend/backend.go +++ b/lib/backend/backend.go @@ -268,9 +268,9 @@ func (e Event) String() string { } // Config is used for 'storage' config section. It's a combination of -// values for various backends: 'boltdb', 'etcd', 'filesystem' and 'dynamodb' +// values for various backends: 'etcd', 'filesystem', 'dynamodb', etc. type Config struct { - // Type can be "bolt" or "etcd" or "dynamodb" + // Type indicates which backend to use (etcd, dynamodb, etc) Type string `yaml:"type,omitempty"` // Params is a generic key/value property bag which allows arbitrary diff --git a/lib/config/configuration_test.go b/lib/config/configuration_test.go index 52c1a46b91c66..90802c056e5c9 100644 --- a/lib/config/configuration_test.go +++ b/lib/config/configuration_test.go @@ -321,7 +321,7 @@ func TestConfigReading(t *testing.T) { }, }, Storage: backend.Config{ - Type: "bolt", + Type: "sqlite", }, DataDir: "/path/to/data", CAPin: apiutils.Strings([]string{"rsa256:123", "rsa256:456"}), @@ -1538,7 +1538,7 @@ func makeConfigFixture() string { conf.Logger.Output = "stderr" conf.Logger.Severity = "INFO" conf.Logger.Format = LogFormat{Output: "text"} - conf.Storage.Type = "bolt" + conf.Storage.Type = "sqlite" conf.CAPin = []string{"rsa256:123", "rsa256:456"} // auth service: diff --git a/lib/service/service_test.go b/lib/service/service_test.go index 14e12c4c2b67c..1889b30b2fd82 100644 --- a/lib/service/service_test.go +++ b/lib/service/service_test.go @@ -195,8 +195,8 @@ func TestDynamicClientReuse(t *testing.T) { cfg.DiagnosticAddr = utils.NetAddr{AddrNetwork: "tcp", Addr: "127.0.0.1:0"} cfg.SetAuthServerAddress(utils.NetAddr{AddrNetwork: "tcp", Addr: "127.0.0.1:0"}) cfg.Auth.Enabled = true - cfg.Auth.StorageConfig.Params["path"] = t.TempDir() cfg.Auth.ListenAddr = utils.NetAddr{AddrNetwork: "tcp", Addr: "127.0.0.1:0"} + cfg.Auth.SessionRecordingConfig.SetMode(types.RecordOff) cfg.Proxy.Enabled = true cfg.Proxy.DisableWebInterface = true cfg.Proxy.WebAddr = utils.NetAddr{AddrNetwork: "tcp", Addr: "localhost:0"} diff --git a/lib/service/servicecfg/config.go b/lib/service/servicecfg/config.go index 8a769ace38223..f42c8824e6f5d 100644 --- a/lib/service/servicecfg/config.go +++ b/lib/service/servicecfg/config.go @@ -58,8 +58,7 @@ import ( type Config struct { // Teleport configuration version. Version string - // DataDir is the directory where teleport stores its permanent state - // (in case of auth server backed by BoltDB) or local state, e.g. keys + // DataDir is the directory where teleport stores its local state, e.g. keys DataDir string // Hostname is a node host name diff --git a/lib/services/local/doc.go b/lib/services/local/doc.go index 8e53a12ad982b..e841187268fa6 100644 --- a/lib/services/local/doc.go +++ b/lib/services/local/doc.go @@ -17,6 +17,5 @@ */ // Package local implements services interfaces using abstract -// key value backend provided by lib/backend, what makes it possible -// for teleport to run using boltdb or etcd +// key value backend provided by lib/backend. package local From 2e0d69021cd88fb52b0c0b9c49c506bad25471c9 Mon Sep 17 00:00:00 2001 From: Andrew Burke <31974658+atburke@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:47:20 -0700 Subject: [PATCH 4/5] Update static host user RFD (#47066) --- rfd/0175-static-host-users.md | 83 +++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/rfd/0175-static-host-users.md b/rfd/0175-static-host-users.md index 9d0f95b8709d0..f5969a71a6426 100644 --- a/rfd/0175-static-host-users.md +++ b/rfd/0175-static-host-users.md @@ -1,6 +1,6 @@ --- author: Andrew Burke (andrew.burke@goteleport.com) -state: draft +state: implemented (v16.3) --- # RFD 175 - Static Host Users @@ -26,30 +26,31 @@ a Teleport user needing to log in first. To create a static host user, an admin will create a `static_host_user` resource: ```yaml -# foo-dev.yaml +# foo.yaml kind: static_host_user metadata: - name: foo-dev + name: foo spec: - login: foo - node_labels: - env: dev + matchers: + - node_labels: + - name: env + values: [dev] ``` Then create it with `tctl`: ```code -$ tctl create foo-dev.yaml +$ tctl create foo.yaml ``` The user `foo` will eventually appear on nodes with label `env: dev` once the -`foo-dev` resource makes it through the cache. +`foo` resource makes it through the cache. -To update an existing static host user, an admin will update update `foo-dev.yaml`, +To update an existing static host user, an admin will update update `foo.yaml`, then update the resource in Teleport with `tctl`: ```code -$ tctl create -f foo-dev.yaml +$ tctl create -f foo.yaml ``` ### Resource @@ -61,21 +62,31 @@ to select specific nodes the user should be created on. ```yaml kind: static_host_user metadata: - name: hostuser + # The name of the resource is also the login that will be created. + name: user1 spec: - login: user1 - # groups and sudoers are identical to their role counterparts - groups: [abc, def] - sudoers: [ - # ... - ] - # same as from user traits - uid: "1234" - gid: "5678" - # same as allow rules in roles - node_labels: - # ... - node_labels_expression: # ... + matchers: + # Use either node_labels or node_labels_expression to select which servers + # to create the host user on. Only one is required. + - node_labels: + - name: foo + values: [bar] + node_labels_expression: "labels.foo == 'bar'" + # groups and sudoers are identical to their role counterparts + groups: [abc, def] + sudoers: [ + # ... + ] + # same as from user traits + uid: "1234" + gid: "5678" + # optional default shell + default_shell: /bin/bash + # optionally take ownership of an existing host user if it exists + take_ownership_if_user_exists: false + # More matchers can be specified to add the user to different nodes with + # different traits. + # - node_labels: ... ``` ```proto @@ -89,14 +100,18 @@ message StaticHostUser { } message StaticHostUserSpec { - string login = 1; - repeated string groups = 2; - repeated string sudoers = 3; - string uid = 4; - string gid = 5; - - wrappers.LabelValues node_labels = 6; - string node_labels_expression = 7; + repeated Matcher matchers = 1; +} + +message Matcher { + repeated teleport.label.v1.Label node_labels = 1; + string node_labels_expression = 2; + repeated string groups = 3; + repeated string sudoers = 4; + int64 uid = 5; + int64 gid = 6; + string default_shell = 7; + bool take_ownership_if_user_exists = 8; } service UsersService { @@ -165,6 +180,10 @@ override the existing user. When a `static_host_user` is deleted, any host users created by it are *not* deleted (same behavior as `keep` mode for current host user creation). +If a node matches multiple matchers in one `static_host_user` resource, the +node will do nothing and log a warning (since the correct traits to apply +are ambiguous). + Nodes that disable host user creation (by setting `ssh_service.disable_create_host_user` to true in their config) will ignore `static_host_user`s entirely. From 15f3c580c21298e24a854fc42155d1629b98b1d4 Mon Sep 17 00:00:00 2001 From: Steven Martin Date: Tue, 1 Oct 2024 19:54:19 -0400 Subject: [PATCH 5/5] docs: include terraform_cloud in join methods (#47057) Co-authored-by: Steven Martin --- docs/pages/enroll-resources/machine-id/faq.mdx | 1 + docs/pages/reference/machine-id/configuration.mdx | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/pages/enroll-resources/machine-id/faq.mdx b/docs/pages/enroll-resources/machine-id/faq.mdx index 82e520f1ed887..bd48f409c32e6 100644 --- a/docs/pages/enroll-resources/machine-id/faq.mdx +++ b/docs/pages/enroll-resources/machine-id/faq.mdx @@ -17,6 +17,7 @@ best where a supported join method exists. These are: - Azure - Kubernetes - Spacelift +- Terraform Cloud On CI/CD platforms where you control the runner environment (e.g self-hosted Jenkins runner), Machine ID can run as a daemon on the runner and the generated diff --git a/docs/pages/reference/machine-id/configuration.mdx b/docs/pages/reference/machine-id/configuration.mdx index dc3315cfd2a16..9bd2eb3c553fc 100644 --- a/docs/pages/reference/machine-id/configuration.mdx +++ b/docs/pages/reference/machine-id/configuration.mdx @@ -90,6 +90,7 @@ onboarding: # - `kubernetes` # - `spacelift` # - `tpm` + # - `terraform_cloud` join_method: "token" # ca_pins are used to validate the identity of the Teleport Auth Service on