@@ -43,16 +43,14 @@ var (
43
43
ErrFailedStarting = errors .New ("command failed starting" )
44
44
// ErrSignaled is returned by Wait() if a signal was sent to the command while running.
45
45
ErrSignaled = errors .New ("command execution signaled" )
46
- // ErrExecutionFailed is returned by Wait() when a command executes but returns a non-zero error
47
- // code.
46
+ // ErrExecutionFailed is returned by Wait() when a command executes but returns a non-zero error code.
48
47
ErrExecutionFailed = errors .New ("command returned a non-zero exit code" )
49
48
// ErrFailedSendingSignal may happen if sending a signal to an already terminated process.
50
49
ErrFailedSendingSignal = errors .New ("failed sending signal" )
51
50
52
51
// ErrExecAlreadyStarted is a system error normally indicating a bogus double call to Run().
53
52
ErrExecAlreadyStarted = errors .New ("command has already been started (double `Run`)" )
54
- // ErrExecNotStarted is a system error normally indicating that Wait() has been called without
55
- // first calling Run().
53
+ // ErrExecNotStarted is a system error normally indicating that Wait() has been called without first calling Run().
56
54
ErrExecNotStarted = errors .New ("command has not been started (call `Run` first)" )
57
55
// ErrExecAlreadyFinished is a system error indicating a double call to Wait().
58
56
ErrExecAlreadyFinished = errors .New ("command is already finished" )
@@ -75,7 +73,7 @@ type Result struct {
75
73
}
76
74
77
75
type execution struct {
78
- //nolint:containedctx
76
+ //nolint:containedctx // Is there a way around this?
79
77
context context.Context
80
78
cancel context.CancelFunc
81
79
command * exec.Cmd
@@ -93,10 +91,10 @@ type Command struct {
93
91
WrapArgs []string
94
92
Timeout time.Duration
95
93
96
- WorkingDir string
97
- Env map [string ]string
98
- // FIXME: EnvBlackList might change for a better mechanism (regexp and/or whitelist + blacklist)
94
+ WorkingDir string
95
+ Env map [string ]string
99
96
EnvBlackList []string
97
+ EnvWhiteList []string
100
98
101
99
writers []func () io.Reader
102
100
@@ -122,6 +120,7 @@ func (gc *Command) Clone() *Command {
122
120
WorkingDir : gc .WorkingDir ,
123
121
Env : map [string ]string {},
124
122
EnvBlackList : append ([]string (nil ), gc .EnvBlackList ... ),
123
+ EnvWhiteList : append ([]string (nil ), gc .EnvWhiteList ... ),
125
124
126
125
writers : append ([]func () io.Reader (nil ), gc .writers ... ),
127
126
@@ -137,27 +136,24 @@ func (gc *Command) Clone() *Command {
137
136
return com
138
137
}
139
138
140
- // WithPTY requests that the command be executed with a pty for std streams. Parameters allow
141
- // showing which streams
142
- // are to be tied to the pty.
139
+ // WithPTY requests that the command be executed with a pty for std streams.
140
+ // Parameters allow showing which streams are to be tied to the pty.
143
141
// This command has no effect if Run has already been called.
144
142
func (gc * Command ) WithPTY (stdin , stdout , stderr bool ) {
145
143
gc .ptyStdout = stdout
146
144
gc .ptyStderr = stderr
147
145
gc .ptyStdin = stdin
148
146
}
149
147
150
- // WithFeeder ensures that the provider function will be executed and its output fed to the command
151
- // stdin. WithFeeder, like Feed, can be used multiple times, and writes will be performed
152
- // sequentially, in order.
148
+ // WithFeeder ensures that the provider function will be executed and its output fed to the command stdin.
149
+ // WithFeeder, like Feed, can be used multiple times, and writes will be performed sequentially, in order.
153
150
// This command has no effect if Run has already been called.
154
151
func (gc * Command ) WithFeeder (writers ... func () io.Reader ) {
155
152
gc .writers = append (gc .writers , writers ... )
156
153
}
157
154
158
155
// Feed ensures that the provider reader will be copied on the command stdin.
159
- // Feed, like WithFeeder, can be used multiple times, and writes will be performed in sequentially,
160
- // in order.
156
+ // Feed, like WithFeeder, can be used multiple times, and writes will be performed in sequentially, in order.
161
157
// This command has no effect if Run has already been called.
162
158
func (gc * Command ) Feed (reader io.Reader ) {
163
159
gc .writers = append (gc .writers , func () io.Reader {
@@ -197,7 +193,6 @@ func (gc *Command) Run(parentCtx context.Context) error {
197
193
198
194
// Create a contextual command, set the logger
199
195
cmd = gc .buildCommand (ctx )
200
-
201
196
// Get a debug-logger from the context
202
197
var (
203
198
log logger.Logger
@@ -338,8 +333,7 @@ func (gc *Command) wrap() error {
338
333
err error
339
334
)
340
335
341
- // XXXgolang: this is troubling. cmd.ProcessState.ExitCode() is always fine, even if
342
- // cmd.ProcessState is nil.
336
+ // XXXgolang: this is troubling. cmd.ProcessState.ExitCode() is always fine, even if cmd.ProcessState is nil.
343
337
exitCode = cmd .ProcessState .ExitCode ()
344
338
345
339
if cmd .ProcessState != nil {
@@ -356,7 +350,7 @@ func (gc *Command) wrap() error {
356
350
}
357
351
}
358
352
359
- // Catch-up on the context
353
+ // Catch-up on the context.
360
354
switch ctx .Err () {
361
355
case context .DeadlineExceeded :
362
356
err = ErrTimeout
@@ -365,7 +359,7 @@ func (gc *Command) wrap() error {
365
359
default :
366
360
}
367
361
368
- // Stuff everything in Result and return err
362
+ // Stuff everything in Result and return err.
369
363
gc .result = & Result {
370
364
ExitCode : exitCode ,
371
365
Stdout : pipes .fromStdout ,
@@ -382,7 +376,7 @@ func (gc *Command) wrap() error {
382
376
}
383
377
384
378
func (gc * Command ) buildCommand (ctx context.Context ) * exec.Cmd {
385
- // Build arguments and binary
379
+ // Build arguments and binary.
386
380
args := gc .Args
387
381
if gc .PrependArgs != nil {
388
382
args = append (gc .PrependArgs , args ... )
@@ -399,26 +393,55 @@ func (gc *Command) buildCommand(ctx context.Context) *exec.Cmd {
399
393
//nolint:gosec
400
394
cmd := exec .CommandContext (ctx , binary , args ... )
401
395
402
- // Add dir
396
+ // Add dir.
403
397
cmd .Dir = gc .WorkingDir
404
398
405
- // Set wait delay after waits returns
399
+ // Set wait delay after waits returns.
406
400
cmd .WaitDelay = delayAfterWait
407
401
408
- // Build env
402
+ // Build env.
409
403
cmd .Env = []string {}
410
- // TODO: replace with regexps? and/or whitelist?
404
+
405
+ const (
406
+ star = "*"
407
+ equal = "="
408
+ )
409
+
411
410
for _ , envValue := range os .Environ () {
412
411
add := true
413
412
414
- for _ , b := range gc .EnvBlackList {
415
- if b == "*" || strings .HasPrefix (envValue , b + "=" ) {
413
+ for _ , needle := range gc .EnvBlackList {
414
+ if strings .HasSuffix (needle , star ) {
415
+ needle = strings .TrimSuffix (needle , star )
416
+ } else if needle != star && ! strings .Contains (needle , equal ) {
417
+ needle += equal
418
+ }
419
+
420
+ if needle == star || strings .HasPrefix (envValue , needle ) {
416
421
add = false
417
422
418
423
break
419
424
}
420
425
}
421
426
427
+ if len (gc .EnvWhiteList ) > 0 {
428
+ add = false
429
+
430
+ for _ , needle := range gc .EnvWhiteList {
431
+ if strings .HasSuffix (needle , star ) {
432
+ needle = strings .TrimSuffix (needle , star )
433
+ } else if needle != star && ! strings .Contains (needle , equal ) {
434
+ needle += equal
435
+ }
436
+
437
+ if needle == star || strings .HasPrefix (envValue , needle ) {
438
+ add = true
439
+
440
+ break
441
+ }
442
+ }
443
+ }
444
+
422
445
if add {
423
446
cmd .Env = append (cmd .Env , envValue )
424
447
}
@@ -429,12 +452,12 @@ func (gc *Command) buildCommand(ctx context.Context) *exec.Cmd {
429
452
cmd .Env = append (cmd .Env , k + "=" + v )
430
453
}
431
454
432
- // Attach platform ProcAttr and get optional custom cancellation routine
455
+ // Attach platform ProcAttr and get optional custom cancellation routine.
433
456
if cancellation := addAttr (cmd ); cancellation != nil {
434
457
cmd .Cancel = func () error {
435
458
gc .exec .log .Log ("command cancelled" )
436
459
437
- // Call the platform dependent cancellation routine
460
+ // Call the platform dependent cancellation routine.
438
461
return cancellation ()
439
462
}
440
463
}
0 commit comments