Give a build step's commands only the environment its caller names (issue 1497)
mesh/merge-gate head 1572e50e0ef0 merged into trunk 4024909a2960 — pass, with a note: builds mesh-sdk (+41 dependent(s)) → ace, g14, novox, shanks; no bus …
mesh/repo-check head 1572e50e0ef0 merged into trunk 4024909a2960 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript)…
mesh/delivery delivered
mesh/merge-gate head 1572e50e0ef0 merged into trunk 4024909a2960 — pass, with a note: builds mesh-sdk (+41 dependent(s)) → ace, g14, novox, shanks; no bus …
mesh/repo-check head 1572e50e0ef0 merged into trunk 4024909a2960 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript)…
mesh/delivery delivered
This commit is contained in:
+16
-3
@@ -37,18 +37,31 @@ func ExecRunner(ctx context.Context, env []string, name string, args ...string)
|
||||
// step's own context ends a command, and a fetch may outlast a tool call's thirty seconds.
|
||||
func ExecRunnerFor(bound time.Duration) Runner {
|
||||
return func(ctx context.Context, env []string, name string, args ...string) Ran {
|
||||
return execRun(ctx, bound, env, name, args...)
|
||||
return execRun(ctx, bound, false, env, name, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func execRun(ctx context.Context, bound time.Duration, env []string, name string, args ...string) Ran {
|
||||
// ExecRunnerClean is ExecRunnerFor whose commands get exactly the env argument as their environment, and nothing of
|
||||
// this process's (issue 1497; novox/hq ADR 0466 §4: no registry password in a fetch's environment). The caller
|
||||
// gives PATH and HOME itself. A directory is the command's own business (`git -C`, `go -C`).
|
||||
func ExecRunnerClean(bound time.Duration) Runner {
|
||||
return func(ctx context.Context, env []string, name string, args ...string) Ran {
|
||||
return execRun(ctx, bound, true, env, name, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func execRun(ctx context.Context, bound time.Duration, clean bool, env []string, name string, args ...string) Ran {
|
||||
if bound > 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, bound)
|
||||
defer cancel()
|
||||
}
|
||||
cmd := exec.CommandContext(ctx, name, args...)
|
||||
cmd.Env = append(os.Environ(), env...)
|
||||
if clean {
|
||||
cmd.Env = append([]string{}, env...) // non-nil, so an empty list is an empty environment
|
||||
} else {
|
||||
cmd.Env = append(os.Environ(), env...)
|
||||
}
|
||||
var out, errb bytes.Buffer
|
||||
cmd.Stdout, cmd.Stderr = &out, &errb
|
||||
err := cmd.Run()
|
||||
|
||||
@@ -2,6 +2,8 @@ package forgekey
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -43,3 +45,21 @@ func TestExecRunnerForZeroIsCutByItsContext(t *testing.T) {
|
||||
t.Errorf("ran = %+v after %v, want it cut", r, time.Since(began))
|
||||
}
|
||||
}
|
||||
|
||||
// 1497/AC4: ExecRunnerClean(0) runs env with only the given words: PATH and HOME, not the process's secret.
|
||||
func TestExecRunnerCleanGivesTheCommandOnlyTheEnvArgument(t *testing.T) {
|
||||
t.Setenv("MESH_TEST_SECRET", "x")
|
||||
r := ExecRunnerClean(0)(context.Background(), []string{"PATH=" + os.Getenv("PATH"), "HOME=/h"}, "env")
|
||||
if r.Status != 0 || !strings.Contains(r.Stdout, "HOME=/h") || !strings.Contains(r.Stdout, "PATH=") || strings.Contains(r.Stdout, "MESH_TEST_SECRET") {
|
||||
t.Errorf("ran = %+v", r)
|
||||
}
|
||||
}
|
||||
|
||||
// 1497/AC5: ExecRunnerFor(0) is unchanged: the env argument is added to the process's environment.
|
||||
func TestExecRunnerForAddsToTheProcessEnvironment(t *testing.T) {
|
||||
t.Setenv("MESH_TEST_SECRET", "x")
|
||||
r := ExecRunnerFor(0)(context.Background(), []string{"HOME=/h"}, "env")
|
||||
if !strings.Contains(r.Stdout, "MESH_TEST_SECRET=x") || !strings.Contains(r.Stdout, "HOME=/h") {
|
||||
t.Errorf("ran = %+v", r)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user