From 398c460f2c9af17e621e6b910fbe745022acb30c Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 20 Jun 2025 10:11:27 +0000 Subject: [PATCH 01/12] feat(agent/agentcontainers): fall back to workspace folder name This PR changes the logic for how we decide on an agent name. Previously it followed these steps: 1. Use a name from `customizations.coder.name` 2. Use a name from the terraform resource `coder_devcontainer` 3. Use the dev container's friendly name With this change it now does: 1. Use a name from `customizations.coder.name` 2. Use a name from the terraform resource `coder_devcontainer` 3. Use a name from the workspace folder 4. Use the dev container's friendly name We now attempt to construct a valid agent name from the workspace folder. Should we fail to construct a valid agent name from the workspace folder, we will fall back to the dev container's friendly name. --- agent/agentcontainers/api.go | 45 ++++++++++++++++++++++++--- agent/agentcontainers/api_test.go | 28 ++++++++--------- agent/agentcontainers/devcontainer.go | 2 -- 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index ef2b7aa7ebcd2..f2c33ee4034af 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -8,12 +8,14 @@ import ( "os" "path" "path/filepath" + "regexp" "runtime" "slices" "strings" "sync" "sync/atomic" "time" + "unicode" "github.com/fsnotify/fsnotify" "github.com/go-chi/chi/v5" @@ -583,10 +585,10 @@ func (api *API) processUpdatedContainersLocked(ctx context.Context, updated code if dc.Container != nil { if !api.devcontainerNames[dc.Name] { // If the devcontainer name wasn't set via terraform, we - // use the containers friendly name as a fallback which - // will keep changing as the devcontainer is recreated. - // TODO(mafredri): Parse the container label (i.e. devcontainer.json) for customization. - dc.Name = safeFriendlyName(dc.Container.FriendlyName) + // will attempt to create an agent name based on the workspace + // folder's name. If that is not possible, we will fall back + // to using the container's friendly name. + dc.Name = safeAgentName(filepath.Base(dc.WorkspaceFolder), dc.Container.FriendlyName) } } @@ -631,6 +633,39 @@ func (api *API) processUpdatedContainersLocked(ctx context.Context, updated code api.containersErr = nil } +var consecutiveHyphenRegex = regexp.MustCompile("-+") + +// safeAgentName returns an agent name safe version +// of a folder name, falling back to a safe version +// of the container name if unable to create a name. +func safeAgentName(name string, friendlyName string) string { + // Keep only letters and digits, replacing everything + // else with a hyphen. + var sb strings.Builder + for _, r := range strings.ToLower(name) { + if unicode.IsLetter(r) || unicode.IsDigit(r) { + sb.WriteRune(r) + } else { + sb.WriteRune('-') + } + } + + // Remove any consecutive hyphens, and then trim and leading + // and trailing hyphens. + name = consecutiveHyphenRegex.ReplaceAllString(sb.String(), "-") + name = strings.Trim(name, "-") + + name = strings.ToLower(name) + name = strings.ReplaceAll(name, " ", "-") + name = strings.ReplaceAll(name, "_", "-") + + if name == "" { + return safeFriendlyName(name) + } + + return name +} + // safeFriendlyName returns a API safe version of the container's // friendly name. // @@ -1189,6 +1224,8 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c appsWithPossibleDuplicates = append(appsWithPossibleDuplicates, customization.Apps...) } + subAgentConfig.Directory = config.Workspace.WorkspaceFolder + return nil }(); err != nil { api.logger.Error(ctx, "unable to read devcontainer config", slog.Error(err)) diff --git a/agent/agentcontainers/api_test.go b/agent/agentcontainers/api_test.go index 4e3e9e4077cd7..a59a3bfd6731e 100644 --- a/agent/agentcontainers/api_test.go +++ b/agent/agentcontainers/api_test.go @@ -897,8 +897,8 @@ func TestAPI(t *testing.T) { FriendlyName: "project1-container", Running: true, Labels: map[string]string{ - agentcontainers.DevcontainerLocalFolderLabel: "/workspace/project", - agentcontainers.DevcontainerConfigFileLabel: "/workspace/project/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/workspace/project1", + agentcontainers.DevcontainerConfigFileLabel: "/workspace/project1/.devcontainer/devcontainer.json", }, }, { @@ -906,8 +906,8 @@ func TestAPI(t *testing.T) { FriendlyName: "project2-container", Running: true, Labels: map[string]string{ - agentcontainers.DevcontainerLocalFolderLabel: "/home/user/project", - agentcontainers.DevcontainerConfigFileLabel: "/home/user/project/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/home/user/project2", + agentcontainers.DevcontainerConfigFileLabel: "/home/user/project2/.devcontainer/devcontainer.json", }, }, { @@ -915,8 +915,8 @@ func TestAPI(t *testing.T) { FriendlyName: "project3-container", Running: true, Labels: map[string]string{ - agentcontainers.DevcontainerLocalFolderLabel: "/var/lib/project", - agentcontainers.DevcontainerConfigFileLabel: "/var/lib/project/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/var/lib/project3", + agentcontainers.DevcontainerConfigFileLabel: "/var/lib/project3/.devcontainer/devcontainer.json", }, }, }, @@ -1326,7 +1326,7 @@ func TestAPI(t *testing.T) { // Allow initial agent creation and injection to succeed. testutil.RequireSend(ctx, t, fakeSAC.createErrC, nil) testutil.RequireSend(ctx, t, fakeDCCLI.readConfigErrC, func(envs []string) error { - assert.Contains(t, envs, "CODER_WORKSPACE_AGENT_NAME=test-container") + assert.Contains(t, envs, "CODER_WORKSPACE_AGENT_NAME=coder") assert.Contains(t, envs, "CODER_WORKSPACE_NAME=test-workspace") assert.Contains(t, envs, "CODER_WORKSPACE_OWNER_NAME=test-user") assert.Contains(t, envs, "CODER_URL=test-subagent-url") @@ -1349,7 +1349,7 @@ func TestAPI(t *testing.T) { // Verify agent was created. require.Len(t, fakeSAC.created, 1) - assert.Equal(t, "test-container", fakeSAC.created[0].Name) + assert.Equal(t, "coder", fakeSAC.created[0].Name) assert.Equal(t, "/workspaces/coder", fakeSAC.created[0].Directory) assert.Len(t, fakeSAC.deleted, 0) @@ -1405,7 +1405,7 @@ func TestAPI(t *testing.T) { WaitStartLoop: for { // Agent reinjection will succeed and we will not re-create the - // agent, nor re-probe pwd. + // agent. mCCLI.EXPECT().List(gomock.Any()).Return(codersdk.WorkspaceAgentListContainersResponse{ Containers: []codersdk.WorkspaceAgentContainer{testContainer}, }, nil).Times(1) // 1 update. @@ -1468,7 +1468,7 @@ func TestAPI(t *testing.T) { // Expect the agent to be recreated. testutil.RequireSend(ctx, t, fakeSAC.createErrC, nil) testutil.RequireSend(ctx, t, fakeDCCLI.readConfigErrC, func(envs []string) error { - assert.Contains(t, envs, "CODER_WORKSPACE_AGENT_NAME=test-container") + assert.Contains(t, envs, "CODER_WORKSPACE_AGENT_NAME=coder") assert.Contains(t, envs, "CODER_WORKSPACE_NAME=test-workspace") assert.Contains(t, envs, "CODER_WORKSPACE_OWNER_NAME=test-user") assert.Contains(t, envs, "CODER_URL=test-subagent-url") @@ -1910,8 +1910,8 @@ func TestAPI(t *testing.T) { Running: true, CreatedAt: time.Now(), Labels: map[string]string{ - agentcontainers.DevcontainerLocalFolderLabel: "/workspaces", - agentcontainers.DevcontainerConfigFileLabel: "/workspace/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/workspaces/coder", + agentcontainers.DevcontainerConfigFileLabel: "/workspaces/coder/.devcontainer/devcontainer.json", }, } ) @@ -1953,13 +1953,13 @@ func TestAPI(t *testing.T) { testutil.RequireSend(ctx, t, fSAC.createErrC, nil) testutil.RequireSend(ctx, t, fDCCLI.readConfigErrC, func(env []string) error { // We expect the wrong workspace agent name passed in first. - assert.Contains(t, env, "CODER_WORKSPACE_AGENT_NAME=test-container") + assert.Contains(t, env, "CODER_WORKSPACE_AGENT_NAME=coder") return nil }) testutil.RequireSend(ctx, t, fDCCLI.readConfigErrC, func(env []string) error { // We then expect the agent name passed here to have been read from the config. assert.Contains(t, env, "CODER_WORKSPACE_AGENT_NAME=custom-name") - assert.NotContains(t, env, "CODER_WORKSPACE_AGENT_NAME=test-container") + assert.NotContains(t, env, "CODER_WORKSPACE_AGENT_NAME=coder") return nil }) diff --git a/agent/agentcontainers/devcontainer.go b/agent/agentcontainers/devcontainer.go index f13963d7b63d7..09d4837d4b27a 100644 --- a/agent/agentcontainers/devcontainer.go +++ b/agent/agentcontainers/devcontainer.go @@ -18,8 +18,6 @@ const ( // DevcontainerConfigFileLabel is the label that contains the path to // the devcontainer.json configuration file. DevcontainerConfigFileLabel = "devcontainer.config_file" - // The default workspace folder inside the devcontainer. - DevcontainerDefaultContainerWorkspaceFolder = "/workspaces" ) const devcontainerUpScriptTemplate = ` From 32e732076e6ab2448a410c81e15c8659056be5ad Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 20 Jun 2025 11:32:11 +0000 Subject: [PATCH 02/12] chore: appease linter and add test case Appease the linter and make a test case for `safeAgentName`. --- agent/agentcontainers/api.go | 17 +- agent/agentcontainers/api_internal_test.go | 195 +++++++++++++++++++++ 2 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 agent/agentcontainers/api_internal_test.go diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index f2c33ee4034af..106148b3acca0 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -15,7 +15,6 @@ import ( "sync" "sync/atomic" "time" - "unicode" "github.com/fsnotify/fsnotify" "github.com/go-chi/chi/v5" @@ -639,28 +638,24 @@ var consecutiveHyphenRegex = regexp.MustCompile("-+") // of a folder name, falling back to a safe version // of the container name if unable to create a name. func safeAgentName(name string, friendlyName string) string { - // Keep only letters and digits, replacing everything + // Keep only ASCII letters and digits, replacing everything // else with a hyphen. var sb strings.Builder for _, r := range strings.ToLower(name) { - if unicode.IsLetter(r) || unicode.IsDigit(r) { - sb.WriteRune(r) + if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') { + _, _ = sb.WriteRune(r) } else { - sb.WriteRune('-') + _, _ = sb.WriteRune('-') } } - // Remove any consecutive hyphens, and then trim and leading + // Remove any consecutive hyphens, and then trim any leading // and trailing hyphens. name = consecutiveHyphenRegex.ReplaceAllString(sb.String(), "-") name = strings.Trim(name, "-") - name = strings.ToLower(name) - name = strings.ReplaceAll(name, " ", "-") - name = strings.ReplaceAll(name, "_", "-") - if name == "" { - return safeFriendlyName(name) + return safeFriendlyName(friendlyName) } return name diff --git a/agent/agentcontainers/api_internal_test.go b/agent/agentcontainers/api_internal_test.go new file mode 100644 index 0000000000000..65c3edf47bb4a --- /dev/null +++ b/agent/agentcontainers/api_internal_test.go @@ -0,0 +1,195 @@ +package agentcontainers + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/coder/coder/v2/provisioner" +) + +func TestSafeAgentName(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + folderName string + expected string + }{ + // Basic valid names + { + folderName: "simple", + expected: "simple", + }, + { + folderName: "with-hyphens", + expected: "with-hyphens", + }, + { + folderName: "123numbers", + expected: "123numbers", + }, + { + folderName: "mixed123", + expected: "mixed123", + }, + + // Names that need transformation + { + folderName: "With_Underscores", + expected: "with-underscores", + }, + { + folderName: "With Spaces", + expected: "with-spaces", + }, + { + folderName: "UPPERCASE", + expected: "uppercase", + }, + { + folderName: "Mixed_Case-Name", + expected: "mixed-case-name", + }, + + // Names with special characters that get replaced + { + folderName: "special@#$chars", + expected: "special-chars", + }, + { + folderName: "dots.and.more", + expected: "dots-and-more", + }, + { + folderName: "multiple___underscores", + expected: "multiple-underscores", + }, + { + folderName: "multiple---hyphens", + expected: "multiple-hyphens", + }, + + // Edge cases with leading/trailing special chars + { + folderName: "-leading-hyphen", + expected: "leading-hyphen", + }, + { + folderName: "trailing-hyphen-", + expected: "trailing-hyphen", + }, + { + folderName: "_leading_underscore", + expected: "leading-underscore", + }, + { + folderName: "trailing_underscore_", + expected: "trailing-underscore", + }, + { + folderName: "---multiple-leading", + expected: "multiple-leading", + }, + { + folderName: "trailing-multiple---", + expected: "trailing-multiple", + }, + + // Complex transformation cases + { + folderName: "___very---complex@@@name___", + expected: "very-complex-name", + }, + { + folderName: "my.project-folder_v2", + expected: "my-project-folder-v2", + }, + + // Empty and fallback cases - now correctly uses friendlyName fallback + { + folderName: "", + expected: "friendly-fallback", + }, + { + folderName: "---", + expected: "friendly-fallback", + }, + { + folderName: "___", + expected: "friendly-fallback", + }, + { + folderName: "@#$", + expected: "friendly-fallback", + }, + + // Additional edge cases + { + folderName: "a", + expected: "a", + }, + { + folderName: "1", + expected: "1", + }, + { + folderName: "a1b2c3", + expected: "a1b2c3", + }, + { + folderName: "CamelCase", + expected: "camelcase", + }, + { + folderName: "snake_case_name", + expected: "snake-case-name", + }, + { + folderName: "kebab-case-name", + expected: "kebab-case-name", + }, + { + folderName: "mix3d_C4s3-N4m3", + expected: "mix3d-c4s3-n4m3", + }, + { + folderName: "123-456-789", + expected: "123-456-789", + }, + { + folderName: "abc123def456", + expected: "abc123def456", + }, + { + folderName: " spaces everywhere ", + expected: "spaces-everywhere", + }, + { + folderName: "unicode-café-naïve", + expected: "unicode-caf-na-ve", + }, + { + folderName: "path/with/slashes", + expected: "path-with-slashes", + }, + { + folderName: "file.tar.gz", + expected: "file-tar-gz", + }, + { + folderName: "version-1.2.3-alpha", + expected: "version-1-2-3-alpha", + }, + } + + for _, tt := range tests { + t.Run(tt.folderName, func(t *testing.T) { + t.Parallel() + name := safeAgentName(tt.folderName, "friendly-fallback") + + assert.Equal(t, tt.expected, name) + assert.True(t, provisioner.AgentNameRegex.Match([]byte(name))) + }) + } +} From 7704238c0bfa5c74f4acb197c5c2f078fd18bd31 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 20 Jun 2025 12:39:19 +0100 Subject: [PATCH 03/12] chore: grammar Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- agent/agentcontainers/api.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index 106148b3acca0..7a884edd045c4 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -634,9 +634,8 @@ func (api *API) processUpdatedContainersLocked(ctx context.Context, updated code var consecutiveHyphenRegex = regexp.MustCompile("-+") -// safeAgentName returns an agent name safe version -// of a folder name, falling back to a safe version -// of the container name if unable to create a name. +// `safeAgentName` returns a safe agent name derived from a folder name, +// falling back to the container’s friendly name if needed. func safeAgentName(name string, friendlyName string) string { // Keep only ASCII letters and digits, replacing everything // else with a hyphen. From e0ffe69c21ab0062bbfaa0ffde1f2e876cca135c Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 20 Jun 2025 11:48:49 +0000 Subject: [PATCH 04/12] chore: move subAgentConfig.Directory assignment --- agent/agentcontainers/api.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index 7a884edd045c4..b962da50bee47 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -1218,8 +1218,6 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c appsWithPossibleDuplicates = append(appsWithPossibleDuplicates, customization.Apps...) } - subAgentConfig.Directory = config.Workspace.WorkspaceFolder - return nil }(); err != nil { api.logger.Error(ctx, "unable to read devcontainer config", slog.Error(err)) From a1a8957ac554dc664aa6f5d4e3b5ef5b81a5ab00 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Jun 2025 08:30:02 +0000 Subject: [PATCH 05/12] chore: re-add removed --- agent/agentcontainers/devcontainer.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/agent/agentcontainers/devcontainer.go b/agent/agentcontainers/devcontainer.go index 09d4837d4b27a..f13963d7b63d7 100644 --- a/agent/agentcontainers/devcontainer.go +++ b/agent/agentcontainers/devcontainer.go @@ -18,6 +18,8 @@ const ( // DevcontainerConfigFileLabel is the label that contains the path to // the devcontainer.json configuration file. DevcontainerConfigFileLabel = "devcontainer.config_file" + // The default workspace folder inside the devcontainer. + DevcontainerDefaultContainerWorkspaceFolder = "/workspaces" ) const devcontainerUpScriptTemplate = ` From 52875a4fac4bf2a405c182ae17bc8689b8d0f13e Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Jun 2025 09:39:08 +0000 Subject: [PATCH 06/12] chore: flip order --- agent/agentcontainers/api.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index b962da50bee47..f7f6a4839a274 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -653,11 +653,11 @@ func safeAgentName(name string, friendlyName string) string { name = consecutiveHyphenRegex.ReplaceAllString(sb.String(), "-") name = strings.Trim(name, "-") - if name == "" { - return safeFriendlyName(friendlyName) + if name != "" { + return name } - return name + return safeFriendlyName(friendlyName) } // safeFriendlyName returns a API safe version of the container's From ad39074c5b56bdfe2b103747393a6769caec77b1 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Jun 2025 09:40:12 +0000 Subject: [PATCH 07/12] chore: improve comment --- agent/agentcontainers/api.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index f7f6a4839a274..dfdd95d667655 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -585,8 +585,9 @@ func (api *API) processUpdatedContainersLocked(ctx context.Context, updated code if !api.devcontainerNames[dc.Name] { // If the devcontainer name wasn't set via terraform, we // will attempt to create an agent name based on the workspace - // folder's name. If that is not possible, we will fall back - // to using the container's friendly name. + // folder's name. If it is not possible to generate a valid + // agent name based off of the folder name (i.e. no valid characters), + // we will instead fall back to using the container's friendly name. dc.Name = safeAgentName(filepath.Base(dc.WorkspaceFolder), dc.Container.FriendlyName) } } From 0ea4b12fc26977bc1bf49b30233d95341c376c65 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Jun 2025 09:41:42 +0000 Subject: [PATCH 08/12] chore: filepath.Base -> filepath.ToSlash & path.Base --- agent/agentcontainers/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index dfdd95d667655..f4aa3de3f3b8d 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -588,7 +588,7 @@ func (api *API) processUpdatedContainersLocked(ctx context.Context, updated code // folder's name. If it is not possible to generate a valid // agent name based off of the folder name (i.e. no valid characters), // we will instead fall back to using the container's friendly name. - dc.Name = safeAgentName(filepath.Base(dc.WorkspaceFolder), dc.Container.FriendlyName) + dc.Name = safeAgentName(path.Base(filepath.ToSlash(dc.WorkspaceFolder)), dc.Container.FriendlyName) } } From 4fdb580257e43d70bf33261aeab90c855e47d2dd Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Jun 2025 10:34:21 +0000 Subject: [PATCH 09/12] chore: replace empty check with AgentNameRegex check --- agent/agentcontainers/api.go | 1 + 1 file changed, 1 insertion(+) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index f4aa3de3f3b8d..e77de68384fff 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -655,6 +655,7 @@ func safeAgentName(name string, friendlyName string) string { name = strings.Trim(name, "-") if name != "" { + if provisioner.AgentNameRegex.Match([]byte(name)) { return name } From d38339a453d43756be729097ea9c8a7f52cfb4a7 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Jun 2025 10:34:35 +0000 Subject: [PATCH 10/12] chore: truncate name if over 64 characters long --- agent/agentcontainers/api.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index e77de68384fff..feaf94e67fd3d 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -40,6 +40,8 @@ const ( // by tmpfs or other mounts. This assumes the container root filesystem is // read-write, which seems sensible for devcontainers. coderPathInsideContainer = "/.coder-agent/coder" + + maxAgentNameLength = 64 ) // API is responsible for container-related operations in the agent. @@ -654,7 +656,10 @@ func safeAgentName(name string, friendlyName string) string { name = consecutiveHyphenRegex.ReplaceAllString(sb.String(), "-") name = strings.Trim(name, "-") - if name != "" { + // Ensure the name of the agent doesn't exceed the maximum agent + // name length. + name = name[:maxAgentNameLength] + if provisioner.AgentNameRegex.Match([]byte(name)) { return name } From 5647a487a7ca1dae9fe397cbd6e0ffe7b9073231 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Jun 2025 10:37:28 +0000 Subject: [PATCH 11/12] chore: fix oops --- agent/agentcontainers/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index feaf94e67fd3d..8896c3217558f 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -658,7 +658,7 @@ func safeAgentName(name string, friendlyName string) string { // Ensure the name of the agent doesn't exceed the maximum agent // name length. - name = name[:maxAgentNameLength] + name = name[:min(len(name), maxAgentNameLength)] if provisioner.AgentNameRegex.Match([]byte(name)) { return name From ac8e24105fca7a01dad07be4da3b0cb14c214288 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Jun 2025 10:37:50 +0000 Subject: [PATCH 12/12] test: scenario with very long name --- agent/agentcontainers/api_internal_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/agent/agentcontainers/api_internal_test.go b/agent/agentcontainers/api_internal_test.go index 65c3edf47bb4a..bda6371f63e5e 100644 --- a/agent/agentcontainers/api_internal_test.go +++ b/agent/agentcontainers/api_internal_test.go @@ -181,6 +181,12 @@ func TestSafeAgentName(t *testing.T) { folderName: "version-1.2.3-alpha", expected: "version-1-2-3-alpha", }, + + // Truncation test for names exceeding 64 characters + { + folderName: "this-is-a-very-long-folder-name-that-exceeds-sixty-four-characters-limit-and-should-be-truncated", + expected: "this-is-a-very-long-folder-name-that-exceeds-sixty-four-characte", + }, } for _, tt := range tests {