Skip to content

Commit e6ec957

Browse files
stirbySasSwartDanielleMaywoodCopilotethanndickson
authored
Cherry-pick for release 2.25 (#19169)
Co-authored-by: Sas Swart <sas.swart.cdk@gmail.com> Co-authored-by: Danielle Maywood <danielle@themaywoods.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ethan <39577870+ethanndickson@users.noreply.github.com> Co-authored-by: Hugo Dutka <hugo@coder.com> Co-authored-by: Thomas Kosiewski <tk@coder.com> Co-authored-by: Cian Johnston <cian@coder.com>
1 parent f1cf81c commit e6ec957

File tree

14 files changed

+555
-28
lines changed

14 files changed

+555
-28
lines changed

.github/workflows/ci.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@ jobs:
340340
- name: Disable Spotlight Indexing
341341
if: runner.os == 'macOS'
342342
run: |
343+
enabled=$(sudo mdutil -a -s | grep "Indexing enabled" | wc -l)
344+
if [ $enabled -eq 0 ]; then
345+
echo "Spotlight indexing is already disabled"
346+
exit 0
347+
fi
343348
sudo mdutil -a -i off
344349
sudo mdutil -X /
345350
sudo launchctl bootout system /System/Library/LaunchDaemons/com.apple.metadata.mds.plist

.github/workflows/release.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
- name: Switch XCode Version
6161
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
6262
with:
63-
xcode-version: "16.0.0"
63+
xcode-version: "16.1.0"
6464

6565
- name: Setup Go
6666
uses: ./.github/actions/setup-go
@@ -655,7 +655,7 @@ jobs:
655655
detached_signature="${binary}.asc"
656656
gcloud storage cp "./site/out/bin/${binary}" "gs://releases.coder.com/coder-cli/${version}/${binary}"
657657
gcloud storage cp "./site/out/bin/${detached_signature}" "gs://releases.coder.com/coder-cli/${version}/${detached_signature}"
658-
done
658+
done
659659
660660
- name: Publish release
661661
run: |

agent/agentcontainers/api.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ type API struct {
7777
subAgentURL string
7878
subAgentEnv []string
7979

80-
projectDiscovery bool // If we should perform project discovery or not.
80+
projectDiscovery bool // If we should perform project discovery or not.
81+
discoveryAutostart bool // If we should autostart discovered projects.
8182

8283
ownerName string
8384
workspaceName string
@@ -144,7 +145,8 @@ func WithCommandEnv(ce CommandEnv) Option {
144145
strings.HasPrefix(s, "CODER_AGENT_TOKEN=") ||
145146
strings.HasPrefix(s, "CODER_AGENT_AUTH=") ||
146147
strings.HasPrefix(s, "CODER_AGENT_DEVCONTAINERS_ENABLE=") ||
147-
strings.HasPrefix(s, "CODER_AGENT_DEVCONTAINERS_PROJECT_DISCOVERY_ENABLE=")
148+
strings.HasPrefix(s, "CODER_AGENT_DEVCONTAINERS_PROJECT_DISCOVERY_ENABLE=") ||
149+
strings.HasPrefix(s, "CODER_AGENT_DEVCONTAINERS_DISCOVERY_AUTOSTART_ENABLE=")
148150
})
149151
return shell, dir, env, nil
150152
}
@@ -287,6 +289,14 @@ func WithProjectDiscovery(projectDiscovery bool) Option {
287289
}
288290
}
289291

292+
// WithDiscoveryAutostart sets if the API should attempt to autostart
293+
// projects that have been discovered
294+
func WithDiscoveryAutostart(discoveryAutostart bool) Option {
295+
return func(api *API) {
296+
api.discoveryAutostart = discoveryAutostart
297+
}
298+
}
299+
290300
// ScriptLogger is an interface for sending devcontainer logs to the
291301
// controlplane.
292302
type ScriptLogger interface {
@@ -542,11 +552,13 @@ func (api *API) discoverDevcontainersInProject(projectPath string) error {
542552
Container: nil,
543553
}
544554

545-
config, err := api.dccli.ReadConfig(api.ctx, workspaceFolder, path, []string{})
546-
if err != nil {
547-
logger.Error(api.ctx, "read project configuration", slog.Error(err))
548-
} else if config.Configuration.Customizations.Coder.AutoStart {
549-
dc.Status = codersdk.WorkspaceAgentDevcontainerStatusStarting
555+
if api.discoveryAutostart {
556+
config, err := api.dccli.ReadConfig(api.ctx, workspaceFolder, path, []string{})
557+
if err != nil {
558+
logger.Error(api.ctx, "read project configuration", slog.Error(err))
559+
} else if config.Configuration.Customizations.Coder.AutoStart {
560+
dc.Status = codersdk.WorkspaceAgentDevcontainerStatusStarting
561+
}
550562
}
551563

552564
api.knownDevcontainers[workspaceFolder] = dc

agent/agentcontainers/api_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3792,6 +3792,7 @@ func TestDevcontainerDiscovery(t *testing.T) {
37923792
agentcontainers.WithContainerCLI(&fakeContainerCLI{}),
37933793
agentcontainers.WithDevcontainerCLI(mDCCLI),
37943794
agentcontainers.WithProjectDiscovery(true),
3795+
agentcontainers.WithDiscoveryAutostart(true),
37953796
)
37963797
api.Start()
37973798
defer api.Close()
@@ -3813,5 +3814,74 @@ func TestDevcontainerDiscovery(t *testing.T) {
38133814
// Then: We expect the mock infra to not fail.
38143815
})
38153816
}
3817+
3818+
t.Run("Disabled", func(t *testing.T) {
3819+
t.Parallel()
3820+
var (
3821+
ctx = testutil.Context(t, testutil.WaitShort)
3822+
logger = testutil.Logger(t)
3823+
mClock = quartz.NewMock(t)
3824+
mDCCLI = acmock.NewMockDevcontainerCLI(gomock.NewController(t))
3825+
3826+
fs = map[string]string{
3827+
"/home/coder/.git/HEAD": "",
3828+
"/home/coder/.devcontainer/devcontainer.json": "",
3829+
}
3830+
3831+
r = chi.NewRouter()
3832+
)
3833+
3834+
// We expect that neither `ReadConfig`, nor `Up` are called as we
3835+
// have explicitly disabled the agentcontainers API from attempting
3836+
// to autostart devcontainers that it discovers.
3837+
mDCCLI.EXPECT().ReadConfig(gomock.Any(),
3838+
"/home/coder",
3839+
"/home/coder/.devcontainer/devcontainer.json",
3840+
[]string{},
3841+
).Return(agentcontainers.DevcontainerConfig{
3842+
Configuration: agentcontainers.DevcontainerConfiguration{
3843+
Customizations: agentcontainers.DevcontainerCustomizations{
3844+
Coder: agentcontainers.CoderCustomization{
3845+
AutoStart: true,
3846+
},
3847+
},
3848+
},
3849+
}, nil).Times(0)
3850+
3851+
mDCCLI.EXPECT().Up(gomock.Any(),
3852+
"/home/coder",
3853+
"/home/coder/.devcontainer/devcontainer.json",
3854+
gomock.Any(),
3855+
).Return("", nil).Times(0)
3856+
3857+
api := agentcontainers.NewAPI(logger,
3858+
agentcontainers.WithClock(mClock),
3859+
agentcontainers.WithWatcher(watcher.NewNoop()),
3860+
agentcontainers.WithFileSystem(initFS(t, fs)),
3861+
agentcontainers.WithManifestInfo("owner", "workspace", "parent-agent", "/home/coder"),
3862+
agentcontainers.WithContainerCLI(&fakeContainerCLI{}),
3863+
agentcontainers.WithDevcontainerCLI(mDCCLI),
3864+
agentcontainers.WithProjectDiscovery(true),
3865+
agentcontainers.WithDiscoveryAutostart(false),
3866+
)
3867+
api.Start()
3868+
defer api.Close()
3869+
r.Mount("/", api.Routes())
3870+
3871+
// When: All expected dev containers have been found.
3872+
require.Eventuallyf(t, func() bool {
3873+
req := httptest.NewRequest(http.MethodGet, "/", nil).WithContext(ctx)
3874+
rec := httptest.NewRecorder()
3875+
r.ServeHTTP(rec, req)
3876+
3877+
got := codersdk.WorkspaceAgentListContainersResponse{}
3878+
err := json.NewDecoder(rec.Body).Decode(&got)
3879+
require.NoError(t, err)
3880+
3881+
return len(got.Devcontainers) >= 1
3882+
}, testutil.WaitShort, testutil.IntervalFast, "dev containers never found")
3883+
3884+
// Then: We expect the mock infra to not fail.
3885+
})
38163886
})
38173887
}

cli/agent.go

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,24 @@ import (
4040

4141
func (r *RootCmd) workspaceAgent() *serpent.Command {
4242
var (
43-
auth string
44-
logDir string
45-
scriptDataDir string
46-
pprofAddress string
47-
noReap bool
48-
sshMaxTimeout time.Duration
49-
tailnetListenPort int64
50-
prometheusAddress string
51-
debugAddress string
52-
slogHumanPath string
53-
slogJSONPath string
54-
slogStackdriverPath string
55-
blockFileTransfer bool
56-
agentHeaderCommand string
57-
agentHeader []string
58-
devcontainers bool
59-
devcontainerProjectDiscovery bool
43+
auth string
44+
logDir string
45+
scriptDataDir string
46+
pprofAddress string
47+
noReap bool
48+
sshMaxTimeout time.Duration
49+
tailnetListenPort int64
50+
prometheusAddress string
51+
debugAddress string
52+
slogHumanPath string
53+
slogJSONPath string
54+
slogStackdriverPath string
55+
blockFileTransfer bool
56+
agentHeaderCommand string
57+
agentHeader []string
58+
devcontainers bool
59+
devcontainerProjectDiscovery bool
60+
devcontainerDiscoveryAutostart bool
6061
)
6162
cmd := &serpent.Command{
6263
Use: "agent",
@@ -366,6 +367,7 @@ func (r *RootCmd) workspaceAgent() *serpent.Command {
366367
DevcontainerAPIOptions: []agentcontainers.Option{
367368
agentcontainers.WithSubAgentURL(r.agentURL.String()),
368369
agentcontainers.WithProjectDiscovery(devcontainerProjectDiscovery),
370+
agentcontainers.WithDiscoveryAutostart(devcontainerDiscoveryAutostart),
369371
},
370372
})
371373

@@ -519,6 +521,13 @@ func (r *RootCmd) workspaceAgent() *serpent.Command {
519521
Description: "Allow the agent to search the filesystem for devcontainer projects.",
520522
Value: serpent.BoolOf(&devcontainerProjectDiscovery),
521523
},
524+
{
525+
Flag: "devcontainers-discovery-autostart-enable",
526+
Default: "false",
527+
Env: "CODER_AGENT_DEVCONTAINERS_DISCOVERY_AUTOSTART_ENABLE",
528+
Description: "Allow the agent to autostart devcontainer projects it discovers based on their configuration.",
529+
Value: serpent.BoolOf(&devcontainerDiscoveryAutostart),
530+
},
522531
}
523532

524533
return cmd

cli/testdata/coder_agent_--help.golden

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ OPTIONS:
3333
--debug-address string, $CODER_AGENT_DEBUG_ADDRESS (default: 127.0.0.1:2113)
3434
The bind address to serve a debug HTTP server.
3535

36+
--devcontainers-discovery-autostart-enable bool, $CODER_AGENT_DEVCONTAINERS_DISCOVERY_AUTOSTART_ENABLE (default: false)
37+
Allow the agent to autostart devcontainer projects it discovers based
38+
on their configuration.
39+
3640
--devcontainers-enable bool, $CODER_AGENT_DEVCONTAINERS_ENABLE (default: true)
3741
Allow the agent to automatically detect running devcontainers.
3842

coderd/dynamicparameters/error.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ func tagValidationError(diags hcl.Diagnostics) *DiagnosticError {
2626
}
2727
}
2828

29+
func presetValidationError(diags hcl.Diagnostics) *DiagnosticError {
30+
return &DiagnosticError{
31+
Message: "Unable to validate presets",
32+
Diagnostics: diags,
33+
KeyedDiagnostics: make(map[string]hcl.Diagnostics),
34+
}
35+
}
36+
2937
type DiagnosticError struct {
3038
// Message is the human-readable message that will be returned to the user.
3139
Message string

coderd/dynamicparameters/presets.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package dynamicparameters
2+
3+
import (
4+
"github.com/hashicorp/hcl/v2"
5+
6+
"github.com/coder/preview"
7+
)
8+
9+
// CheckPresets extracts the preset related diagnostics from a template version preset
10+
func CheckPresets(output *preview.Output, diags hcl.Diagnostics) *DiagnosticError {
11+
de := presetValidationError(diags)
12+
if output == nil {
13+
return de
14+
}
15+
16+
presets := output.Presets
17+
for _, preset := range presets {
18+
if hcl.Diagnostics(preset.Diagnostics).HasErrors() {
19+
de.Extend(preset.Name, hcl.Diagnostics(preset.Diagnostics))
20+
}
21+
}
22+
23+
if de.HasError() {
24+
return de
25+
}
26+
27+
return nil
28+
}

coderd/dynamicparameters/tags.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import (
1111

1212
func CheckTags(output *preview.Output, diags hcl.Diagnostics) *DiagnosticError {
1313
de := tagValidationError(diags)
14+
if output == nil {
15+
return de
16+
}
17+
1418
failedTags := output.WorkspaceTags.UnusableTags()
1519
if len(failedTags) == 0 && !de.HasError() {
1620
return nil // No errors, all is good!

coderd/templateversions.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,6 +1822,14 @@ func (api *API) dynamicTemplateVersionTags(ctx context.Context, rw http.Response
18221822
return nil, false
18231823
}
18241824

1825+
// Fails early if presets are invalid to prevent downstream workspace creation errors
1826+
presetErr := dynamicparameters.CheckPresets(output, nil)
1827+
if presetErr != nil {
1828+
code, resp := presetErr.Response()
1829+
httpapi.Write(ctx, rw, code, resp)
1830+
return nil, false
1831+
}
1832+
18251833
return output.WorkspaceTags.Tags(), true
18261834
}
18271835

0 commit comments

Comments
 (0)
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