diff --git a/docs/config.html b/docs/config.html index c7f8cb8b92..49408ee39d 100644 --- a/docs/config.html +++ b/docs/config.html @@ -884,6 +884,20 @@

+
  • +
    +

    + Remote (bool) +

    + +

    + Enables sandboxing for remotely executed actions. This requires an external + sandbox tool to be configured via the Tool + option, which the remote worker will invoke to wrap the action. Defaults to + False. +

    +
    +
  • diff --git a/src/core/config.go b/src/core/config.go index a54d97b6ca..0bfb6cb15a 100644 --- a/src/core/config.go +++ b/src/core/config.go @@ -559,6 +559,7 @@ type Configuration struct { Namespace string `help:"Set to 'always', to namespace all actions. Set to 'sandbox' to namespace only when sandboxing the build action. Defaults to 'never', under the assumption the sandbox tool will handle its own namespacing. If set, user namespacing will be enabled for all rules. Mount and network will only be enabled if the rule is to be sandboxed."` Build bool `help:"True to sandbox individual build actions, which isolates them from network access and some aspects of the filesystem. Currently only works on Linux." var:"BUILD_SANDBOX"` Test bool `help:"True to sandbox individual tests, which isolates them from network access, IPC and some aspects of the filesystem. Currently only works on Linux." var:"TEST_SANDBOX"` + Remote bool `help:"True to enable sandboxing for remotely executed actions. Requires an external sandbox tool to be configured via the Tool option." var:"REMOTE_SANDBOX"` ExcludeableTargets []BuildLabel `help:"If set, only targets that match these wildcards will be allowed to opt out of the sandbox"` } `help:"A config section describing settings relating to sandboxing of build actions."` Remote struct { diff --git a/src/remote/action.go b/src/remote/action.go index 2098ec48c3..fadcd9d68b 100644 --- a/src/remote/action.go +++ b/src/remote/action.go @@ -117,7 +117,7 @@ func (c *Client) buildCommand(target *core.BuildTarget, inputRoot *pb.Directory, Arguments: []string{ "fetch", strings.Join(target.AllURLs(state), " "), "verify", strings.Join(target.Hashes, " "), }, - EnvironmentVariables: c.buildEnv(target, map[string]string{}, false), + EnvironmentVariables: c.buildEnv(target, map[string]string{}, process.NoSandbox), OutputPaths: outs, }, nil } @@ -128,8 +128,8 @@ func (c *Client) buildCommand(target *core.BuildTarget, inputRoot *pb.Directory, cmd, err := core.ReplaceSequences(state, target, cmd) return &pb.Command{ Platform: c.targetPlatformProperties(target), - Arguments: process.BashCommand(c.shellPath, commandPrefixBuilder.String()+cmd, state.Config.Build.ExitOnError), - EnvironmentVariables: c.buildEnv(target, c.stampedBuildEnvironment(state, target, inputRoot, stamp, isTest || isRun), target.Sandbox), + Arguments: c.sandboxArgs(target.Sandbox, process.BashCommand(c.shellPath, commandPrefixBuilder.String()+cmd, state.Config.Build.ExitOnError)), + EnvironmentVariables: c.buildEnv(target, c.stampedBuildEnvironment(state, target, inputRoot, stamp, isTest || isRun), process.NewSandboxConfig(target.Sandbox, target.Sandbox)), OutputPaths: outs, }, err } @@ -168,8 +168,8 @@ func (c *Client) buildTestCommand(state *core.BuildState, target *core.BuildTarg }, }, }, - Arguments: process.BashCommand(c.shellPath, commandPrefix+cmd, state.Config.Build.ExitOnError), - EnvironmentVariables: c.buildEnv(nil, core.TestEnvironment(state, target, ".", run), target.Test.Sandbox), + Arguments: c.sandboxArgs(target.Test.Sandbox, process.BashCommand(c.shellPath, commandPrefix+cmd, state.Config.Build.ExitOnError)), + EnvironmentVariables: c.buildEnv(nil, core.TestEnvironment(state, target, ".", run), process.NewSandboxConfig(target.Test.Sandbox, target.Test.Sandbox)), OutputPaths: paths, }, err } @@ -183,7 +183,7 @@ func (c *Client) buildRunCommand(state *core.BuildState, target *core.BuildTarge return &pb.Command{ Platform: c.platform, Arguments: outs, - EnvironmentVariables: c.buildEnv(target, core.GeneralBuildEnvironment(state), false), + EnvironmentVariables: c.buildEnv(target, core.GeneralBuildEnvironment(state), process.NoSandbox), }, nil } @@ -573,10 +573,37 @@ func reallyTranslateOS(os string) string { } } +// sandboxArgs prepends the configured external sandbox tool to the given argument list, +// matching what local execution does in exec_linux.go for the non-plz-sandbox case. +// Returns args unchanged if sandboxing is disabled or no external tool is configured. +func (c *Client) sandboxArgs(sandbox bool, args []string) []string { + if !sandbox || !c.state.Config.Sandbox.Remote { + return args + } + tool := c.state.Config.Sandbox.Tool + if tool == "" { + // Built-in plz sandbox re-execs into the local plz binary; not supported remotely. + return args + } + return append([]string{tool}, args...) +} + // buildEnv translates the set of environment variables for this target to a proto. -func (c *Client) buildEnv(target *core.BuildTarget, env core.BuildEnv, sandbox bool) []*pb.Command_EnvironmentVariable { - if sandbox { +func (c *Client) buildEnv(target *core.BuildTarget, env core.BuildEnv, sandbox process.SandboxConfig) []*pb.Command_EnvironmentVariable { + if sandbox != process.NoSandbox && c.state.Config.Sandbox.Remote { env["SANDBOX"] = "true" + if c.state.Config.Sandbox.Tool != "" { + shareNetwork := "1" + if sandbox.Network { + shareNetwork = "0" + } + shareMount := "1" + if sandbox.Mount { + shareMount = "0" + } + env["SHARE_NETWORK"] = shareNetwork + env["SHARE_MOUNT"] = shareMount + } } if target != nil && target.IsBinary { env["_BINARY"] = "true"