1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
// Copyright (c) 2020-2022, Sylabs Inc. All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE.md file distributed with the sources of this project regarding your
// rights to use or distribute this software.
package generate
import (
"io"
"reflect"
"sync"
"testing"
"github.com/sylabs/singularity/v4/pkg/util/capabilities"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sylabs/singularity/v4/internal/pkg/test"
)
//nolint:maintidx
func TestGenerate(t *testing.T) {
test.DropPrivilege(t)
defer test.ResetPrivilege(t)
g := New(nil)
config := g.Config
args := []string{"arg1", "arg2", "arg3"}
g.SetProcessArgs(args)
if !reflect.DeepEqual(args, config.Process.Args) {
t.Fatalf("OCI process arguments are not identical")
}
prof := "test"
g.SetProcessApparmorProfile(prof)
if config.Process.ApparmorProfile != prof {
t.Fatalf("wrong OCI app armor process: %s instead of %s", config.Process.ApparmorProfile, prof)
}
cwd := "/"
g.SetProcessCwd(cwd)
if config.Process.Cwd != cwd {
t.Fatalf("wrong OCI process cwd: %s instead of %s", config.Process.Cwd, prof)
}
terminal := true
g.SetProcessTerminal(terminal)
if config.Process.Terminal != terminal {
t.Fatalf("wrong OCI process terminal: %v instead of %v", config.Process.Terminal, terminal)
}
noNewPriv := true
g.SetProcessNoNewPrivileges(noNewPriv)
if config.Process.NoNewPrivileges != noNewPriv {
t.Fatalf("wrong OCI process no new privs: %v instead of %v", config.Process.NoNewPrivileges, noNewPriv)
}
selinux := "test"
g.SetProcessSelinuxLabel(selinux)
if config.Process.SelinuxLabel != selinux {
t.Fatalf("wrong OCI process selinux label: %v instead of %v", config.Process.SelinuxLabel, selinux)
}
root := "/tmp"
g.SetRootPath(root)
if config.Root.Path != root {
t.Fatalf("wrong OCI root path: %s instead of %v", config.Root.Path, root)
}
g.SetupPrivileged(false)
if config.Process.SelinuxLabel != selinux {
t.Fatalf("wrong OCI process selinux label: %v instead of %v", config.Process.SelinuxLabel, selinux)
}
g.SetupPrivileged(true)
if config.Process.SelinuxLabel != "" {
t.Fatalf("wrong OCI process selinux label: %v instead of empty", config.Process.SelinuxLabel)
}
if len(g.Config.Process.Capabilities.Bounding) != len(capabilities.Map) {
t.Fatalf("wrong OCI capabilities while privileged")
}
if config.Process.SelinuxLabel != "" || config.Process.ApparmorProfile != "" || config.Linux.Seccomp != nil {
t.Fatalf("wrong OCI privileged configuration")
}
g.AddLinuxUIDMapping(1000, 0, 1)
g.AddLinuxUIDMapping(1001, 1, 1)
if len(config.Linux.UIDMappings) != 2 {
t.Fatalf("wrong OCI uid mapping size: %d instead of 2", len(config.Linux.UIDMappings))
}
mapping := config.Linux.UIDMappings[1]
if mapping.HostID != 1001 || mapping.ContainerID != 1 || mapping.Size != 1 {
t.Fatalf("wrong OCI uid mapping: %v", mapping)
}
g.AddLinuxGIDMapping(1000, 0, 1)
g.AddLinuxGIDMapping(1001, 1, 1)
if len(config.Linux.GIDMappings) != 2 {
t.Fatalf("wrong OCI gid mapping size: %d instead of 2", len(config.Linux.GIDMappings))
}
mapping = config.Linux.GIDMappings[1]
if mapping.HostID != 1001 || mapping.ContainerID != 1 || mapping.Size != 1 {
t.Fatalf("wrong OCI uid mapping: %v", mapping)
}
mnt := specs.Mount{
Source: "/etc2",
Destination: "/etc",
Type: "bind",
}
g.AddMount(mnt)
g.AddMount(mnt)
if len(config.Mounts) != 2 {
t.Fatalf("wrong OCI mount size: %d instead of 2", len(config.Mounts))
}
mount := config.Mounts[0]
if mount.Destination != mnt.Destination || mount.Source != mnt.Source || mount.Type != mnt.Type {
t.Fatalf("wrong OCI mount entry: %v", mount)
}
g.AddProcessEnv("FOO", "bar")
if len(config.Process.Env) != 1 {
t.Fatalf("wrong OCI process environment size: %d instead of 1", len(config.Process.Env))
} else if config.Process.Env[0] != "FOO=bar" {
t.Fatalf("wrong OCI process environment FOO value: %v instead of FOO=bar", config.Process.Env[0])
}
g.AddProcessEnv("FOO", "foo")
if len(config.Process.Env) != 1 {
t.Fatalf("wrong OCI process environment size: %d instead of 1", len(config.Process.Env))
} else if config.Process.Env[0] != "FOO=foo" {
t.Fatalf("wrong OCI process environment FOO value: %v instead of FOO=foo", config.Process.Env[0])
}
g.AddProcessEnv("FOO2", "bar2")
if len(config.Process.Env) != 2 {
t.Fatalf("wrong OCI process environment size: %d instead of 2", len(config.Process.Env))
}
g.RemoveProcessEnv("FOO2")
if len(config.Process.Env) != 1 {
t.Fatalf("wrong OCI process environment size: %d instead of 1", len(config.Process.Env))
}
g.AddOrReplaceLinuxNamespace("bad", "")
if len(config.Linux.Namespaces) != 0 {
t.Fatalf("wrong OCI process namespace size: %d instead of 0", len(config.Linux.Namespaces))
}
g.AddOrReplaceLinuxNamespace(specs.PIDNamespace, "")
if len(config.Linux.Namespaces) != 1 {
t.Fatalf("wrong OCI process namespace size: %d instead of 1", len(config.Linux.Namespaces))
} else if config.Linux.Namespaces[0].Type != specs.PIDNamespace || config.Linux.Namespaces[0].Path != "" {
t.Fatalf("wrong OCI process pid namespace entry: %v", config.Linux.Namespaces[0])
}
selfPid := "/proc/self/ns/pid"
g.AddOrReplaceLinuxNamespace(specs.PIDNamespace, selfPid)
if config.Linux.Namespaces[0].Type != specs.PIDNamespace || config.Linux.Namespaces[0].Path != selfPid {
t.Fatalf("wrong OCI process pid namespace entry: %v", config.Linux.Namespaces[0])
}
g.AddOrReplaceLinuxNamespace(specs.UserNamespace, "")
if len(config.Linux.Namespaces) != 2 {
t.Fatalf("wrong OCI process namespace size: %d instead of 2", len(config.Linux.Namespaces))
}
g.AddProcessRlimits("A_LIMIT", 1024, 128)
if len(config.Process.Rlimits) != 1 {
t.Fatalf("wrong OCI process rlimit size: %d instead of 1", len(config.Process.Rlimits))
}
g.AddProcessRlimits("A_SEC_LIMIT", 2048, 1024)
if len(config.Process.Rlimits) != 2 {
t.Fatalf("wrong OCI process rlimit size: %d instead of 2", len(config.Process.Rlimits))
}
rlimit := config.Process.Rlimits[1]
if rlimit.Type != "A_SEC_LIMIT" || rlimit.Hard != 2048 || rlimit.Soft != 1024 {
t.Fatalf("wrong OCI process rlimit entry: %v", rlimit)
}
}
var ociJSON = `{
"ociVersion": "` + specs.Version + `",
"root": {
"path": "/"
}
}`
func TestSave(t *testing.T) {
test.DropPrivilege(t)
defer test.ResetPrivilege(t)
var wg sync.WaitGroup
g := New(nil)
g.SetRootPath("/")
g.Config.Linux = &specs.Linux{}
r, w := io.Pipe()
wg.Add(1)
go func() {
defer r.Close()
defer wg.Done()
d, err := io.ReadAll(r)
if err != nil {
t.Errorf("while reading pipe: %s", err)
return
}
content := string(d)
if content != ociJSON {
t.Errorf("bad OCI JSON output")
}
}()
g.Save(w)
w.Close()
wg.Wait()
path := "/a/fake/file"
err := g.SaveToFile(path)
if err == nil {
t.Fatalf("unexpected success while writing OCI config to %s", path)
}
}
|