From c24bae0426c1a51a78f472a04576ddf397f6053d Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Fri, 14 Aug 2026 17:05:49 +0000 Subject: [PATCH] fix(agent/agentscripts): create missing log_path parent directory A coder_script whose log_path points under a directory that does not exist failed before execution because OpenFile creates the log file but not its parent directories. Create the parent directory with MkdirAll before opening the log file. --- agent/agentscripts/agentscripts.go | 5 +++ agent/agentscripts/agentscripts_test.go | 44 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/agent/agentscripts/agentscripts.go b/agent/agentscripts/agentscripts.go index 153bbaa51abaa..81fc50a1eb5f3 100644 --- a/agent/agentscripts/agentscripts.go +++ b/agent/agentscripts/agentscripts.go @@ -283,6 +283,11 @@ func (r *Runner) run(ctx context.Context, script codersdk.WorkspaceAgentScript, ) logger.Info(ctx, "running agent script", slog.F("script", script.Script)) + logDir := filepath.Dir(logPath) + if err = r.Filesystem.MkdirAll(logDir, 0o700); err != nil { + return xerrors.Errorf("create script log file directory %q: %w", logDir, err) + } + fileWriter, err := r.Filesystem.OpenFile(logPath, os.O_CREATE|os.O_RDWR, 0o600) if err != nil { return xerrors.Errorf("open %s script log file: %w", logPath, err) diff --git a/agent/agentscripts/agentscripts_test.go b/agent/agentscripts/agentscripts_test.go index c032ea1f83a1a..ed8cc5ffc6818 100644 --- a/agent/agentscripts/agentscripts_test.go +++ b/agent/agentscripts/agentscripts_test.go @@ -47,6 +47,50 @@ func TestExecuteBasic(t *testing.T) { require.Equal(t, "hello", log.Output) } +func TestExecuteCreatesMissingLogDir(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitShort) + + fs := afero.NewOsFs() + logger := testutil.Logger(t) + s, err := agentssh.NewServer(context.Background(), logger, prometheus.NewRegistry(), fs, agentexec.DefaultExecer, nil) + require.NoError(t, err) + t.Cleanup(func() { + _ = s.Close() + }) + + fLogger := newFakeScriptLogger() + runner := agentscripts.New(agentscripts.Options{ + LogDir: t.TempDir(), + DataDirBase: t.TempDir(), + Logger: logger, + SSHServer: s, + Filesystem: fs, + GetScriptLogger: func(uuid.UUID) agentscripts.ScriptLogger { + return fLogger + }, + }) + defer runner.Close() + + logPath := filepath.Join(t.TempDir(), "does", "not", "exist", "install.log") + + aAPI := agenttest.NewFakeAgentAPI(t, logger, nil, nil) + err = runner.Init([]codersdk.WorkspaceAgentScript{{ + LogSourceID: uuid.New(), + LogPath: logPath, + Script: "echo hello", + }}, aAPI.ScriptCompleted) + require.NoError(t, err) + require.NoError(t, runner.Execute(ctx, agentscripts.ExecuteAllScripts)) + + log := testutil.TryReceive(ctx, t, fLogger.logs) + require.Equal(t, "hello", log.Output) + + exists, err := afero.Exists(fs, logPath) + require.NoError(t, err) + require.True(t, exists, "expected log file to be created at %s", logPath) +} + func TestEnv(t *testing.T) { t.Parallel() fLogger := newFakeScriptLogger()