diff --git a/agent/agentcontainers/api.go b/agent/agentcontainers/api.go index a6c2167ca8685..4e8773792b7e5 100644 --- a/agent/agentcontainers/api.go +++ b/agent/agentcontainers/api.go @@ -28,6 +28,7 @@ import ( "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/agentsdk" + "github.com/coder/coder/v2/provisioner" "github.com/coder/quartz" ) @@ -1146,6 +1147,7 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c } var appsWithPossibleDuplicates []SubAgentApp + var possibleAgentName string if config, err := api.dccli.ReadConfig(ctx, dc.WorkspaceFolder, dc.ConfigPath, []string{ @@ -1173,6 +1175,19 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c appsWithPossibleDuplicates = append(appsWithPossibleDuplicates, customization.Apps...) } + + // NOTE(DanielleMaywood): + // We only want to take an agent name specified in the root customization layer. + // This restricts the ability for a feature to specify the agent name. We may revisit + // this in the future, but for now we want to restrict this behavior. + if name := config.Configuration.Customizations.Coder.Name; name != "" { + // We only want to pick this name if it is a valid name. + if provisioner.AgentNameRegex.Match([]byte(name)) { + possibleAgentName = name + } else { + logger.Warn(ctx, "invalid agent name in devcontainer customization, ignoring", slog.F("name", name)) + } + } } displayApps := make([]codersdk.DisplayApp, 0, len(displayAppsMap)) @@ -1204,6 +1219,10 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c subAgentConfig.DisplayApps = displayApps subAgentConfig.Apps = apps + + if possibleAgentName != "" { + subAgentConfig.Name = possibleAgentName + } } deleteSubAgent := proc.agent.ID != uuid.Nil && maybeRecreateSubAgent && !proc.agent.EqualConfig(subAgentConfig) diff --git a/agent/agentcontainers/api_test.go b/agent/agentcontainers/api_test.go index 3bf6206e2adce..bcd76c658a717 100644 --- a/agent/agentcontainers/api_test.go +++ b/agent/agentcontainers/api_test.go @@ -1556,17 +1556,18 @@ func TestAPI(t *testing.T) { } tests := []struct { - name string - customization []agentcontainers.CoderCustomization - afterCreate func(t *testing.T, subAgent agentcontainers.SubAgent) + name string + customization agentcontainers.CoderCustomization + mergedCustomizations []agentcontainers.CoderCustomization + afterCreate func(t *testing.T, subAgent agentcontainers.SubAgent) }{ { - name: "WithoutCustomization", - customization: nil, + name: "WithoutCustomization", + mergedCustomizations: nil, }, { - name: "WithDefaultDisplayApps", - customization: []agentcontainers.CoderCustomization{}, + name: "WithDefaultDisplayApps", + mergedCustomizations: []agentcontainers.CoderCustomization{}, afterCreate: func(t *testing.T, subAgent agentcontainers.SubAgent) { require.Len(t, subAgent.DisplayApps, 4) assert.Contains(t, subAgent.DisplayApps, codersdk.DisplayAppVSCodeDesktop) @@ -1577,7 +1578,7 @@ func TestAPI(t *testing.T) { }, { name: "WithAllDisplayApps", - customization: []agentcontainers.CoderCustomization{ + mergedCustomizations: []agentcontainers.CoderCustomization{ { DisplayApps: map[codersdk.DisplayApp]bool{ codersdk.DisplayAppSSH: true, @@ -1599,7 +1600,7 @@ func TestAPI(t *testing.T) { }, { name: "WithSomeDisplayAppsDisabled", - customization: []agentcontainers.CoderCustomization{ + mergedCustomizations: []agentcontainers.CoderCustomization{ { DisplayApps: map[codersdk.DisplayApp]bool{ codersdk.DisplayAppSSH: false, @@ -1631,7 +1632,7 @@ func TestAPI(t *testing.T) { }, { name: "WithApps", - customization: []agentcontainers.CoderCustomization{ + mergedCustomizations: []agentcontainers.CoderCustomization{ { Apps: []agentcontainers.SubAgentApp{ { @@ -1699,7 +1700,7 @@ func TestAPI(t *testing.T) { }, { name: "AppDeduplication", - customization: []agentcontainers.CoderCustomization{ + mergedCustomizations: []agentcontainers.CoderCustomization{ { Apps: []agentcontainers.SubAgentApp{ { @@ -1739,6 +1740,52 @@ func TestAPI(t *testing.T) { assert.Equal(t, int32(2), subAgent.Apps[1].Order) }, }, + { + name: "Name", + customization: agentcontainers.CoderCustomization{ + Name: "this-name", + }, + mergedCustomizations: []agentcontainers.CoderCustomization{ + { + Name: "not-this-name", + }, + { + Name: "or-this-name", + }, + }, + afterCreate: func(t *testing.T, subAgent agentcontainers.SubAgent) { + require.Equal(t, "this-name", subAgent.Name) + }, + }, + { + name: "NameIsOnlyUsedFromRoot", + mergedCustomizations: []agentcontainers.CoderCustomization{ + { + Name: "custom-name", + }, + }, + afterCreate: func(t *testing.T, subAgent agentcontainers.SubAgent) { + require.NotEqual(t, "custom-name", subAgent.Name) + }, + }, + { + name: "EmptyNameIsIgnored", + customization: agentcontainers.CoderCustomization{ + Name: "", + }, + afterCreate: func(t *testing.T, subAgent agentcontainers.SubAgent) { + require.NotEmpty(t, subAgent.Name) + }, + }, + { + name: "InvalidNameIsIgnored", + customization: agentcontainers.CoderCustomization{ + Name: "This--Is_An_Invalid--Name", + }, + afterCreate: func(t *testing.T, subAgent agentcontainers.SubAgent) { + require.NotEqual(t, "This--Is_An_Invalid--Name", subAgent.Name) + }, + }, } for _, tt := range tests { @@ -1756,11 +1803,16 @@ func TestAPI(t *testing.T) { } fDCCLI = &fakeDevcontainerCLI{ readConfig: agentcontainers.DevcontainerConfig{ - MergedConfiguration: agentcontainers.DevcontainerConfiguration{ + Configuration: agentcontainers.DevcontainerConfiguration{ Customizations: agentcontainers.DevcontainerCustomizations{ Coder: tt.customization, }, }, + MergedConfiguration: agentcontainers.DevcontainerMergedConfiguration{ + Customizations: agentcontainers.DevcontainerMergedCustomizations{ + Coder: tt.mergedCustomizations, + }, + }, }, execErrC: make(chan func(cmd string, args ...string) error, 1), } @@ -1825,7 +1877,6 @@ func TestAPI(t *testing.T) { // Then: We expected it to succeed require.Len(t, fSAC.created, 1) - assert.Equal(t, testContainer.FriendlyName, fSAC.created[0].Name) if tt.afterCreate != nil { tt.afterCreate(t, fSAC.created[0]) diff --git a/agent/agentcontainers/devcontainercli.go b/agent/agentcontainers/devcontainercli.go index 335be53648c2d..e302ff07d6dd9 100644 --- a/agent/agentcontainers/devcontainercli.go +++ b/agent/agentcontainers/devcontainercli.go @@ -20,7 +20,16 @@ import ( // Unfortunately we cannot make use of `dcspec` as the output doesn't appear to // match. type DevcontainerConfig struct { - MergedConfiguration DevcontainerConfiguration `json:"mergedConfiguration"` + MergedConfiguration DevcontainerMergedConfiguration `json:"mergedConfiguration"` + Configuration DevcontainerConfiguration `json:"configuration"` +} + +type DevcontainerMergedConfiguration struct { + Customizations DevcontainerMergedCustomizations `json:"customizations,omitempty"` +} + +type DevcontainerMergedCustomizations struct { + Coder []CoderCustomization `json:"coder,omitempty"` } type DevcontainerConfiguration struct { @@ -28,12 +37,13 @@ type DevcontainerConfiguration struct { } type DevcontainerCustomizations struct { - Coder []CoderCustomization `json:"coder,omitempty"` + Coder CoderCustomization `json:"coder,omitempty"` } type CoderCustomization struct { DisplayApps map[codersdk.DisplayApp]bool `json:"displayApps,omitempty"` Apps []SubAgentApp `json:"apps,omitempty"` + Name string `json:"name,omitempty"` } // DevcontainerCLI is an interface for the devcontainer CLI. diff --git a/agent/agentcontainers/devcontainercli_test.go b/agent/agentcontainers/devcontainercli_test.go index 311ec440e357a..821e6e8f95e76 100644 --- a/agent/agentcontainers/devcontainercli_test.go +++ b/agent/agentcontainers/devcontainercli_test.go @@ -256,8 +256,8 @@ func TestDevcontainerCLI_ArgsAndParsing(t *testing.T) { wantArgs: "read-configuration --include-merged-configuration --workspace-folder /test/workspace", wantError: false, wantConfig: agentcontainers.DevcontainerConfig{ - MergedConfiguration: agentcontainers.DevcontainerConfiguration{ - Customizations: agentcontainers.DevcontainerCustomizations{ + MergedConfiguration: agentcontainers.DevcontainerMergedConfiguration{ + Customizations: agentcontainers.DevcontainerMergedCustomizations{ Coder: []agentcontainers.CoderCustomization{ { DisplayApps: map[codersdk.DisplayApp]bool{ @@ -284,8 +284,8 @@ func TestDevcontainerCLI_ArgsAndParsing(t *testing.T) { wantArgs: "read-configuration --include-merged-configuration --workspace-folder /test/workspace --config /test/config.json", wantError: false, wantConfig: agentcontainers.DevcontainerConfig{ - MergedConfiguration: agentcontainers.DevcontainerConfiguration{ - Customizations: agentcontainers.DevcontainerCustomizations{ + MergedConfiguration: agentcontainers.DevcontainerMergedConfiguration{ + Customizations: agentcontainers.DevcontainerMergedCustomizations{ Coder: nil, }, }, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy