Skip to content

Commit b8fc6bb

Browse files
committed
update references to exec.command
1 parent cb70b07 commit b8fc6bb

File tree

5 files changed

+67
-18
lines changed

5 files changed

+67
-18
lines changed

agent/agentexec/exec.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"strconv"
1111

1212
"golang.org/x/xerrors"
13+
14+
"github.com/coder/coder/v2/pty"
1315
)
1416

1517
const (
@@ -25,19 +27,35 @@ const (
2527
// is returned. All instances of exec.Cmd should flow through this function to ensure
2628
// proper resource constraints are applied to the child process.
2729
func CommandContext(ctx context.Context, cmd string, args ...string) (*exec.Cmd, error) {
30+
cmd, args, err := agentExecCmd(cmd, args...)
31+
if err != nil {
32+
return nil, xerrors.Errorf("agent exec cmd: %w", err)
33+
}
34+
return exec.CommandContext(ctx, cmd, args...), nil
35+
}
36+
37+
func PTYCommandContext(ctx context.Context, cmd string, args ...string) (*pty.Cmd, error) {
38+
cmd, args, err := agentExecCmd(cmd, args...)
39+
if err != nil {
40+
return nil, xerrors.Errorf("agent exec cmd: %w", err)
41+
}
42+
return pty.CommandContext(ctx, cmd, args...), nil
43+
}
44+
45+
func agentExecCmd(cmd string, args ...string) (string, []string, error) {
2846
_, enabled := os.LookupEnv(EnvProcPrioMgmt)
2947
if runtime.GOOS != "linux" || !enabled {
30-
return exec.CommandContext(ctx, cmd, args...), nil
48+
return cmd, args, nil
3149
}
3250

3351
executable, err := os.Executable()
3452
if err != nil {
35-
return nil, xerrors.Errorf("get executable: %w", err)
53+
return "", nil, xerrors.Errorf("get executable: %w", err)
3654
}
3755

3856
bin, err := filepath.EvalSymlinks(executable)
3957
if err != nil {
40-
return nil, xerrors.Errorf("eval symlinks: %w", err)
58+
return "", nil, xerrors.Errorf("eval symlinks: %w", err)
4159
}
4260

4361
execArgs := []string{"agent-exec"}
@@ -51,7 +69,7 @@ func CommandContext(ctx context.Context, cmd string, args ...string) (*exec.Cmd,
5169
execArgs = append(execArgs, "--", cmd)
5270
execArgs = append(execArgs, args...)
5371

54-
return exec.CommandContext(ctx, bin, execArgs...), nil
72+
return bin, execArgs, nil
5573
}
5674

5775
// envValInt searches for a key in a list of environment variables and parses it to an int.

agent/agentssh/agentssh.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
"cdr.dev/slog"
3232

33+
"github.com/coder/coder/v2/agent/agentexec"
3334
"github.com/coder/coder/v2/agent/usershell"
3435
"github.com/coder/coder/v2/codersdk"
3536
"github.com/coder/coder/v2/pty"
@@ -725,7 +726,10 @@ func (s *Server) CreateCommand(ctx context.Context, script string, env []string)
725726
}
726727
}
727728

728-
cmd := pty.CommandContext(ctx, name, args...)
729+
cmd, err := agentexec.PTYCommandContext(ctx, name, args...)
730+
if err != nil {
731+
return nil, xerrors.Errorf("pty command context: %w", err)
732+
}
729733
cmd.Dir = s.config.WorkingDirectory()
730734

731735
// If the metadata directory doesn't exist, we run the command

agent/reconnectingpty/buffered.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"cdr.dev/slog"
1616

17+
"github.com/coder/coder/v2/agent/agentexec"
1718
"github.com/coder/coder/v2/pty"
1819
)
1920

@@ -58,7 +59,11 @@ func newBuffered(ctx context.Context, cmd *pty.Cmd, options *Options, logger slo
5859

5960
// Add TERM then start the command with a pty. pty.Cmd duplicates Path as the
6061
// first argument so remove it.
61-
cmdWithEnv := pty.CommandContext(ctx, cmd.Path, cmd.Args[1:]...)
62+
cmdWithEnv, err := agentexec.PTYCommandContext(ctx, cmd.Path, cmd.Args[1:]...)
63+
if err != nil {
64+
rpty.state.setState(StateDone, xerrors.Errorf("pty command context: %w", err))
65+
return rpty
66+
}
6267
cmdWithEnv.Env = append(rpty.command.Env, "TERM=xterm-256color")
6368
cmdWithEnv.Dir = rpty.command.Dir
6469
ptty, process, err := pty.Start(cmdWithEnv)

agent/reconnectingpty/screen.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"io"
1010
"net"
1111
"os"
12-
"os/exec"
1312
"path/filepath"
1413
"strings"
1514
"sync"
@@ -20,6 +19,7 @@ import (
2019
"golang.org/x/xerrors"
2120

2221
"cdr.dev/slog"
22+
"github.com/coder/coder/v2/agent/agentexec"
2323
"github.com/coder/coder/v2/pty"
2424
)
2525

@@ -210,7 +210,7 @@ func (rpty *screenReconnectingPTY) doAttach(ctx context.Context, conn net.Conn,
210210
logger.Debug(ctx, "spawning screen client", slog.F("screen_id", rpty.id))
211211

212212
// Wrap the command with screen and tie it to the connection's context.
213-
cmd := pty.CommandContext(ctx, "screen", append([]string{
213+
cmd, err := agentexec.PTYCommandContext(ctx, "screen", append([]string{
214214
// -S is for setting the session's name.
215215
"-S", rpty.id,
216216
// -U tells screen to use UTF-8 encoding.
@@ -223,6 +223,9 @@ func (rpty *screenReconnectingPTY) doAttach(ctx context.Context, conn net.Conn,
223223
rpty.command.Path,
224224
// pty.Cmd duplicates Path as the first argument so remove it.
225225
}, rpty.command.Args[1:]...)...)
226+
if err != nil {
227+
return nil, nil, xerrors.Errorf("pty command context: %w", err)
228+
}
226229
cmd.Env = append(rpty.command.Env, "TERM=xterm-256color")
227230
cmd.Dir = rpty.command.Dir
228231
ptty, process, err := pty.Start(cmd, pty.WithPTYOption(
@@ -327,29 +330,32 @@ func (rpty *screenReconnectingPTY) sendCommand(ctx context.Context, command stri
327330
defer cancel()
328331

329332
var lastErr error
330-
run := func() bool {
333+
run := func() (bool, error) {
331334
var stdout bytes.Buffer
332335
//nolint:gosec
333-
cmd := exec.CommandContext(ctx, "screen",
336+
cmd, err := agentexec.CommandContext(ctx, "screen",
334337
// -x targets an attached session.
335338
"-x", rpty.id,
336339
// -c is the flag for the config file.
337340
"-c", rpty.configFile,
338341
// -X runs a command in the matching session.
339342
"-X", command,
340343
)
344+
if err != nil {
345+
return false, xerrors.Errorf("command context: %w", err)
346+
}
341347
cmd.Env = append(rpty.command.Env, "TERM=xterm-256color")
342348
cmd.Dir = rpty.command.Dir
343349
cmd.Stdout = &stdout
344-
err := cmd.Run()
350+
err = cmd.Run()
345351
if err == nil {
346-
return true
352+
return true, nil
347353
}
348354

349355
stdoutStr := stdout.String()
350356
for _, se := range successErrors {
351357
if strings.Contains(stdoutStr, se) {
352-
return true
358+
return true, nil
353359
}
354360
}
355361

@@ -359,11 +365,15 @@ func (rpty *screenReconnectingPTY) sendCommand(ctx context.Context, command stri
359365
lastErr = xerrors.Errorf("`screen -x %s -X %s`: %w: %s", rpty.id, command, err, stdoutStr)
360366
}
361367

362-
return false
368+
return false, nil
363369
}
364370

365371
// Run immediately.
366-
if done := run(); done {
372+
done, err := run()
373+
if err != nil {
374+
return err
375+
}
376+
if done {
367377
return nil
368378
}
369379

@@ -379,7 +389,11 @@ func (rpty *screenReconnectingPTY) sendCommand(ctx context.Context, command stri
379389
}
380390
return errors.Join(ctx.Err(), lastErr)
381391
case <-ticker.C:
382-
if done := run(); done {
392+
done, err := run()
393+
if err != nil {
394+
return err
395+
}
396+
if done {
383397
return nil
384398
}
385399
}

scripts/rules.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,11 @@ func noExecInAgent(m dsl.Matcher) {
498498
`exec.Command($*_)`,
499499
`exec.CommandContext($*_)`,
500500
).
501-
Where(m.File().PkgPath.Matches("/agent/")).
501+
Where(
502+
m.File().PkgPath.Matches("/agent/") &&
503+
!m.File().PkgPath.Matches("/agentexec") &&
504+
!m.File().Name.Matches(`_test\.go$`),
505+
).
502506
Report("The agent and its subpackages should not use exec.Command or exec.CommandContext directly. Consider using agentexec.CommandContext instead.")
503507
}
504508

@@ -512,6 +516,10 @@ func noPTYInAgent(m dsl.Matcher) {
512516
`pty.Command($*_)`,
513517
`pty.CommandContext($*_)`,
514518
).
515-
Where(m.File().PkgPath.Matches(`/agent/`)).
519+
Where(
520+
m.File().PkgPath.Matches(`/agent/`) &&
521+
!m.File().PkgPath.Matches(`/agentexec`) &&
522+
!m.File().Name.Matches(`_test\.go$`),
523+
).
516524
Report("The agent and its subpackages should not use pty.Command or pty.CommandContext directly. Consider using agentexec.PTYCommandContext instead.")
517525
}

0 commit comments

Comments
 (0)