cli: adds env-inherit flag for SCRATCH images (#1117)
This adds an `env-inherit` boolean flag which adds all variables to the guest ENV. For example, the below `env-reader.wasm` guest will see the variable `STAR` and anything set via the runner (docker, podman, etc.): ``` --snip-- FROM scratch COPY --from=build /build/wazero/wazero /bin/wazero ENTRYPOINT ["/bin/wazero", "run", "-env-inherit", "-cachedir=/cache", "-mount=.:/"] ENV STAR=wazero COPY --from=wasm / . CMD ["env-reader.wasm"] ``` Note: This isn't appropriate otherwise as it will also propagate variables like PATH and TMPDIR which aren't likely valid on the guest, or in worst case may risk crashing. Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -13,4 +13,4 @@ RUN git clone --depth 1 https://github.com/tetratelabs/wazero.git \
|
||||
FROM scratch
|
||||
COPY --from=build /build/wazero/wazero /bin/wazero
|
||||
|
||||
ENTRYPOINT ["/bin/wazero", "run", "-cachedir=/cache", "-mount=.:/"]
|
||||
ENTRYPOINT ["/bin/wazero", "run", "-env-inherit", "-cachedir=/cache", "-mount=.:/"]
|
||||
|
||||
@@ -122,6 +122,11 @@ func doRun(args []string, stdOut io.Writer, stdErr logging.Writer, exit func(cod
|
||||
flags.Var(&envs, "env", "key=value pair of environment variable to expose to the binary. "+
|
||||
"Can be specified multiple times.")
|
||||
|
||||
var envExport bool
|
||||
flags.BoolVar(&envExport, "env-inherit", false,
|
||||
"inherits any environment variables from the calling process."+
|
||||
"Variables specified with the <env> flag are appended to the inherited list.")
|
||||
|
||||
var mounts sliceFlag
|
||||
flags.Var(&mounts, "mount",
|
||||
"filesystem path to expose to the binary in the form of <path>[:<wasm path>][:ro]. "+
|
||||
@@ -130,7 +135,7 @@ func doRun(args []string, stdOut io.Writer, stdErr logging.Writer, exit func(cod
|
||||
|
||||
var hostlogging logScopesFlag
|
||||
flags.Var(&hostlogging, "hostlogging",
|
||||
"A comma-separated list of host function scopes to log to stderr. "+
|
||||
"a comma-separated list of host function scopes to log to stderr. "+
|
||||
"This may be specified multiple times. Supported values: clock,exit,filesystem,memory,poll,random")
|
||||
|
||||
cacheDir := cacheDirFlag(flags)
|
||||
@@ -159,6 +164,9 @@ func doRun(args []string, stdOut io.Writer, stdErr logging.Writer, exit func(cod
|
||||
|
||||
// Don't use map to preserve order
|
||||
var env []string
|
||||
if envExport {
|
||||
envs = append(os.Environ(), envs...)
|
||||
}
|
||||
for _, e := range envs {
|
||||
fields := strings.SplitN(e, "=", 2)
|
||||
if len(fields) != 2 {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
@@ -117,10 +118,10 @@ func TestCompile(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
args := append([]string{"compile"}, tt.wazeroOpts...)
|
||||
args = append(args, wasmPath)
|
||||
exitCode, stdOut, stdErr := runMain(t, args)
|
||||
require.Zero(t, stdErr)
|
||||
require.Equal(t, 0, exitCode, stdErr)
|
||||
require.Zero(t, stdOut)
|
||||
exitCode, stdout, stderr := runMain(t, args)
|
||||
require.Zero(t, stderr)
|
||||
require.Equal(t, 0, exitCode, stderr)
|
||||
require.Zero(t, stdout)
|
||||
if test := tt.test; test != nil {
|
||||
test(t)
|
||||
}
|
||||
@@ -170,15 +171,32 @@ func TestCompile_Errors(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
tt := tc
|
||||
t.Run(tt.message, func(t *testing.T) {
|
||||
exitCode, _, stdErr := runMain(t, append([]string{"compile"}, tt.args...))
|
||||
exitCode, _, stderr := runMain(t, append([]string{"compile"}, tt.args...))
|
||||
|
||||
require.Equal(t, 1, exitCode)
|
||||
require.Contains(t, stdErr, tt.message)
|
||||
require.Contains(t, stderr, tt.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
// Restore env logic borrowed from TestClearenv
|
||||
defer func(origEnv []string) {
|
||||
for _, pair := range origEnv {
|
||||
// Environment variables on Windows can begin with =
|
||||
// https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
|
||||
i := strings.Index(pair[1:], "=") + 1
|
||||
if err := os.Setenv(pair[:i], pair[i+1:]); err != nil {
|
||||
t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i], pair[i+1:], err)
|
||||
}
|
||||
}
|
||||
}(os.Environ())
|
||||
|
||||
// Clear the environment first, so we can make strict assertions.
|
||||
os.Clearenv()
|
||||
os.Setenv("ANIMAL", "kitten")
|
||||
os.Setenv("INHERITED", "wazero")
|
||||
|
||||
tmpDir, oldwd := requireChdirToTemp(t)
|
||||
defer os.Chdir(oldwd) //nolint
|
||||
|
||||
@@ -232,6 +250,18 @@ func TestRun(t *testing.T) {
|
||||
wazeroOpts: []string{"--env=ANIMAL=bear", "--env=FOOD=sushi"},
|
||||
expectedStdout: "ANIMAL=bear\x00FOOD=sushi\x00",
|
||||
},
|
||||
{
|
||||
name: "env-inherit",
|
||||
wasm: wasmWasiEnv,
|
||||
wazeroOpts: []string{"-env-inherit"},
|
||||
expectedStdout: "ANIMAL=kitten\x00INHERITED=wazero\u0000",
|
||||
},
|
||||
{
|
||||
name: "env-inherit with env",
|
||||
wasm: wasmWasiEnv,
|
||||
wazeroOpts: []string{"-env-inherit", "--env=ANIMAL=bear"},
|
||||
expectedStdout: "ANIMAL=bear\x00INHERITED=wazero\u0000", // not ANIMAL=kitten
|
||||
},
|
||||
{
|
||||
name: "interpreter",
|
||||
wasm: wasmWasiArg,
|
||||
@@ -428,11 +458,11 @@ func TestRun(t *testing.T) {
|
||||
args := append([]string{"run"}, tc.wazeroOpts...)
|
||||
args = append(args, wasmPath)
|
||||
args = append(args, tc.wasmArgs...)
|
||||
exitCode, stdOut, stdErr := runMain(t, args)
|
||||
exitCode, stdout, stderr := runMain(t, args)
|
||||
|
||||
require.Equal(t, tc.expectedStderr, stdErr)
|
||||
require.Equal(t, tc.expectedExitCode, exitCode, stdErr)
|
||||
require.Equal(t, tc.expectedStdout, stdOut)
|
||||
require.Equal(t, tc.expectedStderr, stderr)
|
||||
require.Equal(t, tc.expectedExitCode, exitCode, stderr)
|
||||
require.Equal(t, tc.expectedStdout, stdout)
|
||||
if test := tc.test; test != nil {
|
||||
test(t)
|
||||
}
|
||||
@@ -441,10 +471,10 @@ func TestRun(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
exitCode, stdOut, stdErr := runMain(t, []string{"version"})
|
||||
exitCode, stdout, stderr := runMain(t, []string{"version"})
|
||||
require.Equal(t, 0, exitCode)
|
||||
require.Equal(t, version.GetWazeroVersion()+"\n", stdOut)
|
||||
require.Equal(t, "", stdErr)
|
||||
require.Equal(t, version.GetWazeroVersion()+"\n", stdout)
|
||||
require.Equal(t, "", stderr)
|
||||
}
|
||||
|
||||
func TestRun_Errors(t *testing.T) {
|
||||
@@ -487,10 +517,10 @@ func TestRun_Errors(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
tt := tc
|
||||
t.Run(tt.message, func(t *testing.T) {
|
||||
exitCode, _, stdErr := runMain(t, append([]string{"run"}, tt.args...))
|
||||
exitCode, _, stderr := runMain(t, append([]string{"run"}, tt.args...))
|
||||
|
||||
require.Equal(t, 1, exitCode)
|
||||
require.Contains(t, stdErr, tt.message)
|
||||
require.Contains(t, stderr, tt.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -621,9 +651,9 @@ func Test_logScopesFlag(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHelp(t *testing.T) {
|
||||
exitCode, _, stdErr := runMain(t, []string{"-h"})
|
||||
exitCode, _, stderr := runMain(t, []string{"-h"})
|
||||
require.Equal(t, 0, exitCode)
|
||||
fmt.Println(stdErr)
|
||||
fmt.Println(stderr)
|
||||
require.Equal(t, `wazero CLI
|
||||
|
||||
Usage:
|
||||
@@ -633,7 +663,7 @@ Commands:
|
||||
compile Pre-compiles a WebAssembly binary
|
||||
run Runs a WebAssembly binary
|
||||
version Displays the version of wazero CLI
|
||||
`, stdErr)
|
||||
`, stderr)
|
||||
}
|
||||
|
||||
func runMain(t *testing.T, args []string) (int, string, string) {
|
||||
@@ -645,8 +675,8 @@ func runMain(t *testing.T, args []string) (int, string, string) {
|
||||
os.Args = append([]string{"wazero"}, args...)
|
||||
|
||||
var exitCode int
|
||||
stdOut := &bytes.Buffer{}
|
||||
stdErr := &bytes.Buffer{}
|
||||
stdout := &bytes.Buffer{}
|
||||
stderr := &bytes.Buffer{}
|
||||
var exited bool
|
||||
func() {
|
||||
defer func() {
|
||||
@@ -655,7 +685,7 @@ func runMain(t *testing.T, args []string) (int, string, string) {
|
||||
}
|
||||
}()
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
|
||||
doMain(stdOut, stdErr, func(code int) {
|
||||
doMain(stdout, stderr, func(code int) {
|
||||
exitCode = code
|
||||
panic(code)
|
||||
})
|
||||
@@ -663,7 +693,7 @@ func runMain(t *testing.T, args []string) (int, string, string) {
|
||||
|
||||
require.True(t, exited)
|
||||
|
||||
return exitCode, stdOut.String(), stdErr.String()
|
||||
return exitCode, stdout.String(), stderr.String()
|
||||
}
|
||||
|
||||
// compileGoJS compiles "testdata/cat/cat.go" on demand as the binary generated
|
||||
|
||||
Reference in New Issue
Block a user