bwrap: implement argument builder
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
parent
df29068d16
commit
ba76e2919b
|
@ -0,0 +1,64 @@
|
||||||
|
package bwrap
|
||||||
|
|
||||||
|
const (
|
||||||
|
UnshareAll = iota
|
||||||
|
UnshareUser
|
||||||
|
UnshareIPC
|
||||||
|
UnsharePID
|
||||||
|
UnshareNet
|
||||||
|
UnshareUTS
|
||||||
|
UnshareCGroup
|
||||||
|
ShareNet
|
||||||
|
|
||||||
|
UserNS
|
||||||
|
Clearenv
|
||||||
|
|
||||||
|
NewSession
|
||||||
|
DieWithParent
|
||||||
|
AsInit
|
||||||
|
|
||||||
|
boolC
|
||||||
|
)
|
||||||
|
|
||||||
|
var boolArgs = func() (b [boolC][]string) {
|
||||||
|
b[UnshareAll] = []string{"--unshare-all"}
|
||||||
|
b[UnshareUser] = []string{"--unshare-user"}
|
||||||
|
b[UnshareIPC] = []string{"--unshare-ipc"}
|
||||||
|
b[UnsharePID] = []string{"--unshare-pid"}
|
||||||
|
b[UnshareNet] = []string{"--unshare-net"}
|
||||||
|
b[UnshareUTS] = []string{"--unshare-uts"}
|
||||||
|
b[UnshareCGroup] = []string{"--unshare-cgroup"}
|
||||||
|
b[ShareNet] = []string{"--share-net"}
|
||||||
|
|
||||||
|
b[UserNS] = []string{"--disable-userns", "--assert-userns-disabled"}
|
||||||
|
b[Clearenv] = []string{"--clearenv"}
|
||||||
|
|
||||||
|
b[NewSession] = []string{"--new-session"}
|
||||||
|
b[DieWithParent] = []string{"--die-with-parent"}
|
||||||
|
b[AsInit] = []string{"--as-pid-1"}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
func (c *Config) boolArgs() (b [boolC]bool) {
|
||||||
|
if c.Unshare == nil {
|
||||||
|
b[UnshareAll] = true
|
||||||
|
b[ShareNet] = c.Net
|
||||||
|
} else {
|
||||||
|
b[UnshareUser] = c.Unshare.User
|
||||||
|
b[UnshareIPC] = c.Unshare.IPC
|
||||||
|
b[UnsharePID] = c.Unshare.PID
|
||||||
|
b[UnshareNet] = c.Unshare.Net
|
||||||
|
b[UnshareUTS] = c.Unshare.UTS
|
||||||
|
b[UnshareCGroup] = c.Unshare.CGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
b[UserNS] = !c.UserNS
|
||||||
|
b[Clearenv] = c.Clearenv
|
||||||
|
|
||||||
|
b[NewSession] = c.NewSession
|
||||||
|
b[DieWithParent] = c.DieWithParent
|
||||||
|
b[AsInit] = c.AsInit
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,265 @@
|
||||||
|
package bwrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Config) Args() (args []string) {
|
||||||
|
b := c.boolArgs()
|
||||||
|
n := c.intArgs()
|
||||||
|
s := c.stringArgs()
|
||||||
|
p := c.pairArgs()
|
||||||
|
g := c.interfaceArgs()
|
||||||
|
|
||||||
|
argc := 0
|
||||||
|
for i, arg := range b {
|
||||||
|
if arg {
|
||||||
|
argc += len(boolArgs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, arg := range n {
|
||||||
|
if arg != nil {
|
||||||
|
argc += 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, arg := range s {
|
||||||
|
argc += len(arg) * 2
|
||||||
|
}
|
||||||
|
for _, arg := range p {
|
||||||
|
argc += len(arg) * 3
|
||||||
|
}
|
||||||
|
|
||||||
|
args = make([]string, 0, argc)
|
||||||
|
for i, arg := range b {
|
||||||
|
if arg {
|
||||||
|
args = append(args, boolArgs[i]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, arg := range n {
|
||||||
|
if arg != nil {
|
||||||
|
args = append(args, intArgs[i], strconv.Itoa(*arg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, arg := range s {
|
||||||
|
for _, v := range arg {
|
||||||
|
args = append(args, stringArgs[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, arg := range p {
|
||||||
|
for _, v := range arg {
|
||||||
|
args = append(args, pairArgs[i], v[0], v[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, arg := range g {
|
||||||
|
for _, v := range arg {
|
||||||
|
args = append(args, v.Value(interfaceArgs[i])...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
// unshare every namespace we support by default if nil
|
||||||
|
// (--unshare-all)
|
||||||
|
Unshare *UnshareConfig `json:"unshare,omitempty"`
|
||||||
|
// retain the network namespace (can only combine with nil Unshare)
|
||||||
|
// (--share-net)
|
||||||
|
Net bool `json:"net"`
|
||||||
|
|
||||||
|
// disable further use of user namespaces inside sandbox and fail unless
|
||||||
|
// further use of user namespace inside sandbox is disabled if false
|
||||||
|
// (--disable-userns) (--assert-userns-disabled)
|
||||||
|
UserNS bool `json:"userns"`
|
||||||
|
|
||||||
|
// custom uid in the sandbox, requires new user namespace
|
||||||
|
// (--uid UID)
|
||||||
|
UID *int `json:"uid,omitempty"`
|
||||||
|
// custom gid in the sandbox, requires new user namespace
|
||||||
|
// (--gid GID)
|
||||||
|
GID *int `json:"gid,omitempty"`
|
||||||
|
// custom hostname in the sandbox, requires new uts namespace
|
||||||
|
// (--hostname NAME)
|
||||||
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
|
||||||
|
// change directory
|
||||||
|
// (--chdir DIR)
|
||||||
|
Chdir string `json:"chdir,omitempty"`
|
||||||
|
// unset all environment variables
|
||||||
|
// (--clearenv)
|
||||||
|
Clearenv bool `json:"clearenv"`
|
||||||
|
// set environment variable
|
||||||
|
// (--setenv VAR VALUE)
|
||||||
|
SetEnv map[string]string `json:"setenv,omitempty"`
|
||||||
|
// unset environment variables
|
||||||
|
// (--unsetenv VAR)
|
||||||
|
UnsetEnv []string `json:"unsetenv,omitempty"`
|
||||||
|
|
||||||
|
// take a lock on file while sandbox is running
|
||||||
|
// (--lock-file DEST)
|
||||||
|
LockFile []string `json:"lock_file,omitempty"`
|
||||||
|
|
||||||
|
// bind mount host path on sandbox
|
||||||
|
// (--bind SRC DEST)
|
||||||
|
Bind [][2]string `json:"bind,omitempty"`
|
||||||
|
// equal to Bind but ignores non-existent host path
|
||||||
|
// (--bind-try SRC DEST)
|
||||||
|
BindTry [][2]string `json:"bind_try,omitempty"`
|
||||||
|
|
||||||
|
// bind mount host path on sandbox, allowing device access
|
||||||
|
// (--dev-bind SRC DEST)
|
||||||
|
DevBind [][2]string `json:"dev_bind,omitempty"`
|
||||||
|
// equal to DevBind but ignores non-existent host path
|
||||||
|
// (--dev-bind-try SRC DEST)
|
||||||
|
DevBindTry [][2]string `json:"dev_bind_try,omitempty"`
|
||||||
|
|
||||||
|
// bind mount host path readonly on sandbox
|
||||||
|
// (--ro-bind SRC DEST)
|
||||||
|
ROBind [][2]string `json:"ro_bind,omitempty"`
|
||||||
|
// equal to ROBind but ignores non-existent host path
|
||||||
|
// (--ro-bind-try SRC DEST)
|
||||||
|
ROBindTry [][2]string `json:"ro_bind_try,omitempty"`
|
||||||
|
|
||||||
|
// remount path as readonly; does not recursively remount
|
||||||
|
// (--remount-ro DEST)
|
||||||
|
RemountRO []string `json:"remount_ro,omitempty"`
|
||||||
|
|
||||||
|
// mount new procfs in sandbox
|
||||||
|
// (--proc DEST)
|
||||||
|
Procfs []PermConfig[string] `json:"proc,omitempty"`
|
||||||
|
// mount new dev in sandbox
|
||||||
|
// (--dev DEST)
|
||||||
|
DevTmpfs []PermConfig[string] `json:"dev,omitempty"`
|
||||||
|
// mount new tmpfs in sandbox
|
||||||
|
// (--tmpfs DEST)
|
||||||
|
Tmpfs []PermConfig[TmpfsConfig] `json:"tmpfs,omitempty"`
|
||||||
|
// mount new mqueue in sandbox
|
||||||
|
// (--mqueue DEST)
|
||||||
|
Mqueue []PermConfig[string] `json:"mqueue,omitempty"`
|
||||||
|
// create dir in sandbox
|
||||||
|
// (--dir DEST)
|
||||||
|
Dir []PermConfig[string] `json:"dir,omitempty"`
|
||||||
|
// create symlink within sandbox
|
||||||
|
// (--symlink SRC DEST)
|
||||||
|
Symlink []PermConfig[[2]string] `json:"symlink,omitempty"`
|
||||||
|
|
||||||
|
// change permissions (must already exist)
|
||||||
|
// (--chmod OCTAL PATH)
|
||||||
|
Chmod map[string]os.FileMode `json:"chmod,omitempty"`
|
||||||
|
|
||||||
|
// create a new terminal session
|
||||||
|
// (--new-session)
|
||||||
|
NewSession bool `json:"new_session"`
|
||||||
|
// kills with SIGKILL child process (COMMAND) when bwrap or bwrap's parent dies.
|
||||||
|
// (--die-with-parent)
|
||||||
|
DieWithParent bool `json:"die_with_parent"`
|
||||||
|
// do not install a reaper process with PID=1
|
||||||
|
// (--as-pid-1)
|
||||||
|
AsInit bool `json:"as_init"`
|
||||||
|
|
||||||
|
/* unmapped options include:
|
||||||
|
--unshare-user-try Create new user namespace if possible else continue by skipping it
|
||||||
|
--unshare-cgroup-try Create new cgroup namespace if possible else continue by skipping it
|
||||||
|
--userns FD Use this user namespace (cannot combine with --unshare-user)
|
||||||
|
--userns2 FD After setup switch to this user namespace, only useful with --userns
|
||||||
|
--pidns FD Use this pid namespace (as parent namespace if using --unshare-pid)
|
||||||
|
--sync-fd FD Keep this fd open while sandbox is running
|
||||||
|
--exec-label LABEL Exec label for the sandbox
|
||||||
|
--file-label LABEL File label for temporary sandbox content
|
||||||
|
--file FD DEST Copy from FD to destination DEST
|
||||||
|
--bind-data FD DEST Copy from FD to file which is bind-mounted on DEST
|
||||||
|
--ro-bind-data FD DEST Copy from FD to file which is readonly bind-mounted on DEST
|
||||||
|
--seccomp FD Load and use seccomp rules from FD (not repeatable)
|
||||||
|
--add-seccomp-fd FD Load and use seccomp rules from FD (repeatable)
|
||||||
|
--block-fd FD Block on FD until some data to read is available
|
||||||
|
--userns-block-fd FD Block on FD until the user namespace is ready
|
||||||
|
--info-fd FD Write information about the running container to FD
|
||||||
|
--json-status-fd FD Write container status to FD as multiple JSON documents
|
||||||
|
--cap-add CAP Add cap CAP when running as privileged user
|
||||||
|
--cap-drop CAP Drop cap CAP when running as privileged user
|
||||||
|
|
||||||
|
among which --args is used internally for passing arguments */
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnshareConfig struct {
|
||||||
|
// (--unshare-user)
|
||||||
|
// create new user namespace
|
||||||
|
User bool `json:"user"`
|
||||||
|
// (--unshare-ipc)
|
||||||
|
// create new ipc namespace
|
||||||
|
IPC bool `json:"ipc"`
|
||||||
|
// (--unshare-pid)
|
||||||
|
// create new pid namespace
|
||||||
|
PID bool `json:"pid"`
|
||||||
|
// (--unshare-net)
|
||||||
|
// create new network namespace
|
||||||
|
Net bool `json:"net"`
|
||||||
|
// (--unshare-uts)
|
||||||
|
// create new uts namespace
|
||||||
|
UTS bool `json:"uts"`
|
||||||
|
// (--unshare-cgroup)
|
||||||
|
// create new cgroup namespace
|
||||||
|
CGroup bool `json:"cgroup"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TmpfsConfig struct {
|
||||||
|
// set size of tmpfs
|
||||||
|
// (--size BYTES)
|
||||||
|
Size int `json:"size,omitempty"`
|
||||||
|
// mount point of new tmpfs
|
||||||
|
// (--tmpfs DEST)
|
||||||
|
Dir string `json:"dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type argOf interface {
|
||||||
|
Value(arg string) (args []string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyToArgOfSlice[T [2]string | string | TmpfsConfig](src []PermConfig[T]) (dst []argOf) {
|
||||||
|
dst = make([]argOf, len(src))
|
||||||
|
for i, arg := range src {
|
||||||
|
dst[i] = arg
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type PermConfig[T [2]string | string | TmpfsConfig] struct {
|
||||||
|
// set permissions of next argument
|
||||||
|
// (--perms OCTAL)
|
||||||
|
Mode *os.FileMode `json:"mode,omitempty"`
|
||||||
|
// path to get the new permission
|
||||||
|
// (--bind-data, --file, etc.)
|
||||||
|
Path T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PermConfig[T]) Value(arg string) (args []string) {
|
||||||
|
// max possible size
|
||||||
|
if p.Mode != nil {
|
||||||
|
args = make([]string, 0, 6)
|
||||||
|
args = append(args, "--perms", strconv.Itoa(int(*p.Mode)))
|
||||||
|
} else {
|
||||||
|
args = make([]string, 0, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := any(p.Path).(type) {
|
||||||
|
case string:
|
||||||
|
args = append(args, arg, v)
|
||||||
|
return
|
||||||
|
case [2]string:
|
||||||
|
args = append(args, arg, v[0], v[1])
|
||||||
|
return
|
||||||
|
case TmpfsConfig:
|
||||||
|
if arg != "--tmpfs" {
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Size > 0 {
|
||||||
|
args = append(args, "--size", strconv.Itoa(v.Size))
|
||||||
|
}
|
||||||
|
args = append(args, arg, v.Dir)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package bwrap
|
||||||
|
|
||||||
|
const (
|
||||||
|
UID = iota
|
||||||
|
GID
|
||||||
|
|
||||||
|
intC
|
||||||
|
)
|
||||||
|
|
||||||
|
var intArgs = func() (n [intC]string) {
|
||||||
|
n[UID] = "--uid"
|
||||||
|
n[GID] = "--gid"
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
func (c *Config) intArgs() (n [intC]*int) {
|
||||||
|
n[UID] = c.UID
|
||||||
|
n[GID] = c.GID
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package bwrap
|
||||||
|
|
||||||
|
const (
|
||||||
|
Procfs = iota
|
||||||
|
DevTmpfs
|
||||||
|
Tmpfs
|
||||||
|
Mqueue
|
||||||
|
Dir
|
||||||
|
Symlink
|
||||||
|
|
||||||
|
interfaceC
|
||||||
|
)
|
||||||
|
|
||||||
|
var interfaceArgs = func() (g [interfaceC]string) {
|
||||||
|
g[Procfs] = "--proc"
|
||||||
|
g[DevTmpfs] = "--dev"
|
||||||
|
g[Tmpfs] = "--tmpfs"
|
||||||
|
g[Mqueue] = "--mqueue"
|
||||||
|
g[Dir] = "--dir"
|
||||||
|
g[Symlink] = "--symlink"
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
func (c *Config) interfaceArgs() (g [interfaceC][]argOf) {
|
||||||
|
g[Procfs] = copyToArgOfSlice(c.Procfs)
|
||||||
|
g[DevTmpfs] = copyToArgOfSlice(c.DevTmpfs)
|
||||||
|
g[Tmpfs] = copyToArgOfSlice(c.Tmpfs)
|
||||||
|
g[Mqueue] = copyToArgOfSlice(c.Mqueue)
|
||||||
|
g[Dir] = copyToArgOfSlice(c.Dir)
|
||||||
|
g[Symlink] = copyToArgOfSlice(c.Symlink)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package bwrap
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
const (
|
||||||
|
SetEnv = iota
|
||||||
|
|
||||||
|
Bind
|
||||||
|
BindTry
|
||||||
|
DevBind
|
||||||
|
DevBindTry
|
||||||
|
ROBind
|
||||||
|
ROBindTry
|
||||||
|
|
||||||
|
Chmod
|
||||||
|
|
||||||
|
pairC
|
||||||
|
)
|
||||||
|
|
||||||
|
var pairArgs = func() (n [pairC]string) {
|
||||||
|
n[SetEnv] = "--setenv"
|
||||||
|
|
||||||
|
n[Bind] = "--bind"
|
||||||
|
n[BindTry] = "--bind-try"
|
||||||
|
n[DevBind] = "--dev-bind"
|
||||||
|
n[DevBindTry] = "--dev-bind-try"
|
||||||
|
n[ROBind] = "--ro-bind"
|
||||||
|
n[ROBindTry] = "--ro-bind-try"
|
||||||
|
|
||||||
|
n[Chmod] = "--chmod"
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
func (c *Config) pairArgs() (n [pairC][][2]string) {
|
||||||
|
n[SetEnv] = make([][2]string, 0, len(c.SetEnv))
|
||||||
|
for k, v := range c.SetEnv {
|
||||||
|
n[SetEnv] = append(n[SetEnv], [2]string{k, v})
|
||||||
|
}
|
||||||
|
|
||||||
|
n[Bind] = c.Bind
|
||||||
|
n[BindTry] = c.BindTry
|
||||||
|
n[DevBind] = c.DevBind
|
||||||
|
n[DevBindTry] = c.DevBindTry
|
||||||
|
n[ROBind] = c.ROBind
|
||||||
|
n[ROBindTry] = c.ROBindTry
|
||||||
|
|
||||||
|
n[Chmod] = make([][2]string, 0, len(c.Chmod))
|
||||||
|
for path, octal := range c.Chmod {
|
||||||
|
n[Chmod] = append(n[Chmod], [2]string{strconv.Itoa(int(octal)), path})
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package bwrap
|
||||||
|
|
||||||
|
const (
|
||||||
|
Hostname = iota
|
||||||
|
Chdir
|
||||||
|
UnsetEnv
|
||||||
|
LockFile
|
||||||
|
RemountRO
|
||||||
|
|
||||||
|
stringC
|
||||||
|
)
|
||||||
|
|
||||||
|
var stringArgs = func() (n [stringC]string) {
|
||||||
|
n[Hostname] = "--hostname"
|
||||||
|
n[Chdir] = "--chdir"
|
||||||
|
n[UnsetEnv] = "--unsetenv"
|
||||||
|
n[LockFile] = "--lock-file"
|
||||||
|
n[RemountRO] = "--remount-ro"
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
func (c *Config) stringArgs() (n [stringC][]string) {
|
||||||
|
if c.Hostname != "" {
|
||||||
|
n[Hostname] = []string{c.Hostname}
|
||||||
|
}
|
||||||
|
if c.Chdir != "" {
|
||||||
|
n[Chdir] = []string{c.Chdir}
|
||||||
|
}
|
||||||
|
n[UnsetEnv] = c.UnsetEnv
|
||||||
|
n[LockFile] = c.LockFile
|
||||||
|
n[RemountRO] = c.RemountRO
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package bwrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfig_Args(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
conf *Config
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "xdg-dbus-proxy constraint sample",
|
||||||
|
conf: &Config{
|
||||||
|
Unshare: nil,
|
||||||
|
UserNS: false,
|
||||||
|
Clearenv: true,
|
||||||
|
Symlink: []PermConfig[[2]string]{
|
||||||
|
{Path: [2]string{"usr/bin", "/bin"}},
|
||||||
|
{Path: [2]string{"var/home", "/home"}},
|
||||||
|
{Path: [2]string{"usr/lib", "/lib"}},
|
||||||
|
{Path: [2]string{"usr/lib64", "/lib64"}},
|
||||||
|
{Path: [2]string{"run/media", "/media"}},
|
||||||
|
{Path: [2]string{"var/mnt", "/mnt"}},
|
||||||
|
{Path: [2]string{"var/opt", "/opt"}},
|
||||||
|
{Path: [2]string{"sysroot/ostree", "/ostree"}},
|
||||||
|
{Path: [2]string{"var/roothome", "/root"}},
|
||||||
|
{Path: [2]string{"usr/sbin", "/sbin"}},
|
||||||
|
{Path: [2]string{"var/srv", "/srv"}},
|
||||||
|
},
|
||||||
|
Bind: [][2]string{
|
||||||
|
{"/run", "/run"},
|
||||||
|
{"/tmp", "/tmp"},
|
||||||
|
{"/var", "/var"},
|
||||||
|
{"/run/user/1971/.dbus-proxy/", "/run/user/1971/.dbus-proxy/"},
|
||||||
|
},
|
||||||
|
ROBind: [][2]string{
|
||||||
|
{"/boot", "/boot"},
|
||||||
|
{"/dev", "/dev"},
|
||||||
|
{"/proc", "/proc"},
|
||||||
|
{"/sys", "/sys"},
|
||||||
|
{"/sysroot", "/sysroot"},
|
||||||
|
{"/usr", "/usr"},
|
||||||
|
{"/etc", "/etc"},
|
||||||
|
},
|
||||||
|
DieWithParent: true,
|
||||||
|
},
|
||||||
|
want: []string{
|
||||||
|
"--unshare-all",
|
||||||
|
"--disable-userns",
|
||||||
|
"--assert-userns-disabled",
|
||||||
|
"--clearenv",
|
||||||
|
"--die-with-parent",
|
||||||
|
"--bind", "/run", "/run",
|
||||||
|
"--bind", "/tmp", "/tmp",
|
||||||
|
"--bind", "/var", "/var",
|
||||||
|
"--bind", "/run/user/1971/.dbus-proxy/", "/run/user/1971/.dbus-proxy/",
|
||||||
|
"--ro-bind", "/boot", "/boot",
|
||||||
|
"--ro-bind", "/dev", "/dev",
|
||||||
|
"--ro-bind", "/proc", "/proc",
|
||||||
|
"--ro-bind", "/sys", "/sys",
|
||||||
|
"--ro-bind", "/sysroot", "/sysroot",
|
||||||
|
"--ro-bind", "/usr", "/usr",
|
||||||
|
"--ro-bind", "/etc", "/etc",
|
||||||
|
"--symlink", "usr/bin", "/bin",
|
||||||
|
"--symlink", "var/home", "/home",
|
||||||
|
"--symlink", "usr/lib", "/lib",
|
||||||
|
"--symlink", "usr/lib64", "/lib64",
|
||||||
|
"--symlink", "run/media", "/media",
|
||||||
|
"--symlink", "var/mnt", "/mnt",
|
||||||
|
"--symlink", "var/opt", "/opt",
|
||||||
|
"--symlink", "sysroot/ostree", "/ostree",
|
||||||
|
"--symlink", "var/roothome", "/root",
|
||||||
|
"--symlink", "usr/sbin", "/sbin",
|
||||||
|
"--symlink", "var/srv", "/srv"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
if got := tc.conf.Args(); !slices.Equal(got, tc.want) {
|
||||||
|
t.Errorf("Args() = %#v, want %#v", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue