Compare commits
5 Commits
d8e9d71f87
...
ea853e21d9
Author | SHA1 | Date | |
---|---|---|---|
ea853e21d9 | |||
0bd9b9e8fe | |||
39e32799b3 | |||
9953768de5 | |||
0d3652b793 |
@ -70,7 +70,7 @@
|
|||||||
echo 'output Virtual-1 res 1680x1050') > ~/.config/sway/config
|
echo 'output Virtual-1 res 1680x1050') > ~/.config/sway/config
|
||||||
|
|
||||||
sway --validate
|
sway --validate
|
||||||
systemd-cat --identifier=sway sway && touch /tmp/sway-exit-ok
|
systemd-cat --identifier=session sway && touch /tmp/sway-exit-ok
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
@ -2,17 +2,30 @@ package sandbox
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
assert = log.New(os.Stderr, "sandbox: ", 0)
|
assert = log.New(os.Stderr, "sandbox: ", 0)
|
||||||
|
printfFunc = assert.Printf
|
||||||
fatalfFunc = assert.Fatalf
|
fatalfFunc = assert.Fatalf
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func printf(format string, v ...any) { printfFunc(format, v...) }
|
||||||
func fatalf(format string, v ...any) { fatalfFunc(format, v...) }
|
func fatalf(format string, v ...any) { fatalfFunc(format, v...) }
|
||||||
|
|
||||||
|
func mustDecode(wantFile string, v any) {
|
||||||
|
if f, err := os.Open(wantFile); err != nil {
|
||||||
|
fatalf("cannot open %q: %v", wantFile, err)
|
||||||
|
} else if err = json.NewDecoder(f).Decode(v); err != nil {
|
||||||
|
fatalf("cannot decode %q: %v", wantFile, err)
|
||||||
|
} else if err = f.Close(); err != nil {
|
||||||
|
fatalf("cannot close %q: %v", wantFile, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MustAssertMounts(name, hostMountsFile, wantFile string) {
|
func MustAssertMounts(name, hostMountsFile, wantFile string) {
|
||||||
hostMounts := make([]*Mntent, 0, 128)
|
hostMounts := make([]*Mntent, 0, 128)
|
||||||
if err := IterMounts(hostMountsFile, func(e *Mntent) {
|
if err := IterMounts(hostMountsFile, func(e *Mntent) {
|
||||||
@ -22,13 +35,7 @@ func MustAssertMounts(name, hostMountsFile, wantFile string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var want []Mntent
|
var want []Mntent
|
||||||
if f, err := os.Open(wantFile); err != nil {
|
mustDecode(wantFile, &want)
|
||||||
fatalf("cannot open %q: %v", wantFile, err)
|
|
||||||
} else if err = json.NewDecoder(f).Decode(&want); err != nil {
|
|
||||||
fatalf("cannot decode %q: %v", wantFile, err)
|
|
||||||
} else if err = f.Close(); err != nil {
|
|
||||||
fatalf("cannot close %q: %v", wantFile, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range want {
|
for i := range want {
|
||||||
if want[i].Opts == "host_passthrough" {
|
if want[i].Opts == "host_passthrough" {
|
||||||
@ -53,9 +60,21 @@ func MustAssertMounts(name, hostMountsFile, wantFile string) {
|
|||||||
e, &want[i])
|
e, &want[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Printf("%s", e)
|
printf("%s", e)
|
||||||
i++
|
i++
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fatalf("cannot iterate mounts: %v", err)
|
fatalf("cannot iterate mounts: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MustAssertFS(e fs.FS, wantFile string) {
|
||||||
|
var want *FS
|
||||||
|
mustDecode(wantFile, &want)
|
||||||
|
if want == nil {
|
||||||
|
fatalf("invalid payload")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := want.Compare(".", e); err != nil {
|
||||||
|
fatalf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,32 @@
|
|||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
func ReplaceFatal(f func(format string, v ...any)) { fatalfFunc = f }
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type F func(format string, v ...any)
|
||||||
|
|
||||||
|
func SwapPrint(f F) (old F) { old = printfFunc; printfFunc = f; return }
|
||||||
|
func SwapFatal(f F) (old F) { old = fatalfFunc; fatalfFunc = f; return }
|
||||||
|
|
||||||
|
func MustWantFile(t *testing.T, v any) (wantFile string) {
|
||||||
|
wantFile = path.Join(t.TempDir(), "want.json")
|
||||||
|
if f, err := os.OpenFile(wantFile, os.O_CREATE|os.O_WRONLY, 0400); err != nil {
|
||||||
|
t.Fatalf("cannot create %q: %v", wantFile, err)
|
||||||
|
} else if err = json.NewEncoder(f).Encode(v); err != nil {
|
||||||
|
t.Fatalf("cannot encode to %q: %v", wantFile, err)
|
||||||
|
} else if err = f.Close(); err != nil {
|
||||||
|
t.Fatalf("cannot close %q: %v", wantFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := os.Remove(wantFile); err != nil {
|
||||||
|
t.Fatalf("cannot remove %q: %v", wantFile, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
writeShellScript "check-sandbox" ''
|
writeShellScript "check-sandbox" ''
|
||||||
set -e
|
set -e
|
||||||
${callPackage ./mount.nix { inherit version; }}/bin/test
|
${callPackage ./mount.nix { inherit version; }}/bin/test
|
||||||
|
${callPackage ./fs.nix { inherit version; }}/bin/test
|
||||||
|
|
||||||
touch /tmp/sandbox-ok
|
touch /tmp/sandbox-ok
|
||||||
''
|
''
|
||||||
|
98
test/sandbox/fs.go
Normal file
98
test/sandbox/fs.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package sandbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrFSBadLength = errors.New("bad dir length")
|
||||||
|
ErrFSBadData = errors.New("data differs")
|
||||||
|
ErrFSBadMode = errors.New("mode differs")
|
||||||
|
ErrFSInvalidEnt = errors.New("invalid entry condition")
|
||||||
|
)
|
||||||
|
|
||||||
|
type FS struct {
|
||||||
|
Mode fs.FileMode `json:"mode"`
|
||||||
|
Dir map[string]*FS `json:"dir"`
|
||||||
|
Data *string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func printDir(prefix string, dir []fs.DirEntry) {
|
||||||
|
names := make([]string, len(dir))
|
||||||
|
for i, ent := range dir {
|
||||||
|
name := ent.Name()
|
||||||
|
if ent.IsDir() {
|
||||||
|
name += "/"
|
||||||
|
}
|
||||||
|
names[i] = fmt.Sprintf("%q", name)
|
||||||
|
}
|
||||||
|
printf("[FAIL] d %q: %s", prefix, strings.Join(names, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FS) Compare(prefix string, e fs.FS) error {
|
||||||
|
if s.Data != nil {
|
||||||
|
if s.Dir != nil {
|
||||||
|
panic("invalid state")
|
||||||
|
}
|
||||||
|
panic("invalid compare call")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Dir == nil {
|
||||||
|
printf("[ OK ] s %s", prefix)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var dir []fs.DirEntry
|
||||||
|
if d, err := fs.ReadDir(e, prefix); err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(d) != len(s.Dir) {
|
||||||
|
printDir(prefix, d)
|
||||||
|
return ErrFSBadLength
|
||||||
|
} else {
|
||||||
|
dir = d
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, got := range dir {
|
||||||
|
name := got.Name()
|
||||||
|
|
||||||
|
if want, ok := s.Dir[name]; !ok {
|
||||||
|
printDir(prefix, dir)
|
||||||
|
return fs.ErrNotExist
|
||||||
|
} else if want.Dir != nil && !got.IsDir() {
|
||||||
|
printDir(prefix, dir)
|
||||||
|
return ErrFSInvalidEnt
|
||||||
|
} else {
|
||||||
|
name = path.Join(prefix, name)
|
||||||
|
|
||||||
|
if fi, err := got.Info(); err != nil {
|
||||||
|
return err
|
||||||
|
} else if fi.Mode() != want.Mode {
|
||||||
|
printf("[FAIL] m %q: %x, want %x",
|
||||||
|
name, uint32(fi.Mode()), uint32(want.Mode))
|
||||||
|
return ErrFSBadMode
|
||||||
|
}
|
||||||
|
|
||||||
|
if want.Data != nil {
|
||||||
|
if want.Dir != nil {
|
||||||
|
panic("invalid state")
|
||||||
|
}
|
||||||
|
if v, err := fs.ReadFile(e, name); err != nil {
|
||||||
|
return err
|
||||||
|
} else if string(v) != *want.Data {
|
||||||
|
printf("[FAIL] f %s", name)
|
||||||
|
return ErrFSBadData
|
||||||
|
}
|
||||||
|
printf("[ OK ] f %s", name)
|
||||||
|
} else if err := want.Compare(name, e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("[ OK ] d %s", prefix)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
214
test/sandbox/fs.nix
Normal file
214
test/sandbox/fs.nix
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
writeText,
|
||||||
|
buildGoModule,
|
||||||
|
|
||||||
|
version,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
wantFS =
|
||||||
|
let
|
||||||
|
fs = mode: dir: data: {
|
||||||
|
mode = lib.fromHexString mode;
|
||||||
|
inherit
|
||||||
|
dir
|
||||||
|
data
|
||||||
|
;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
fs "dead" {
|
||||||
|
".fortify" = fs "800001ed" {
|
||||||
|
etc = fs "800001ed" null null;
|
||||||
|
sbin = fs "800001c0" {
|
||||||
|
fortify = fs "16d" null null;
|
||||||
|
init = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
host-mounts = fs "124" null null;
|
||||||
|
} null;
|
||||||
|
bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
|
||||||
|
dev = fs "800001ed" {
|
||||||
|
core = fs "80001ff" null null;
|
||||||
|
dri = fs "800001ed" {
|
||||||
|
by-path = fs "800001ed" {
|
||||||
|
"pci-0000:00:09.0-card" = fs "80001ff" null null;
|
||||||
|
"pci-0000:00:09.0-render" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
card0 = fs "42001b0" null null;
|
||||||
|
renderD128 = fs "42001b6" null null;
|
||||||
|
} null;
|
||||||
|
fd = fs "80001ff" null null;
|
||||||
|
full = fs "42001b6" null null;
|
||||||
|
mqueue = fs "801001ff" { } null;
|
||||||
|
null = fs "42001b6" null "";
|
||||||
|
ptmx = fs "80001ff" null null;
|
||||||
|
pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null;
|
||||||
|
random = fs "42001b6" null null;
|
||||||
|
shm = fs "800001ed" { } null;
|
||||||
|
stderr = fs "80001ff" null null;
|
||||||
|
stdin = fs "80001ff" null null;
|
||||||
|
stdout = fs "80001ff" null null;
|
||||||
|
tty = fs "42001b6" null null;
|
||||||
|
urandom = fs "42001b6" null null;
|
||||||
|
zero = fs "42001b6" null null;
|
||||||
|
} null;
|
||||||
|
etc = fs "800001c0" {
|
||||||
|
".clean" = fs "80001ff" null null;
|
||||||
|
".updated" = fs "80001ff" null null;
|
||||||
|
"NIXOS" = fs "80001ff" null null;
|
||||||
|
"X11" = fs "80001ff" null null;
|
||||||
|
"alsa" = fs "80001ff" null null;
|
||||||
|
"bashrc" = fs "80001ff" null null;
|
||||||
|
"binfmt.d" = fs "80001ff" null null;
|
||||||
|
"dbus-1" = fs "80001ff" null null;
|
||||||
|
"default" = fs "80001ff" null null;
|
||||||
|
"dhcpcd.exit-hook" = fs "80001ff" null null;
|
||||||
|
"fonts" = fs "80001ff" null null;
|
||||||
|
"fstab" = fs "80001ff" null null;
|
||||||
|
"fsurc" = fs "80001ff" null null;
|
||||||
|
"fuse.conf" = fs "80001ff" null null;
|
||||||
|
"group" = fs "180" null "fortify:x:65534:\n";
|
||||||
|
"host.conf" = fs "80001ff" null null;
|
||||||
|
"hostname" = fs "80001ff" null null;
|
||||||
|
"hosts" = fs "80001ff" null null;
|
||||||
|
"inputrc" = fs "80001ff" null null;
|
||||||
|
"issue" = fs "80001ff" null null;
|
||||||
|
"kbd" = fs "80001ff" null null;
|
||||||
|
"locale.conf" = fs "80001ff" null null;
|
||||||
|
"login.defs" = fs "80001ff" null null;
|
||||||
|
"lsb-release" = fs "80001ff" null null;
|
||||||
|
"lvm" = fs "80001ff" null null;
|
||||||
|
"machine-id" = fs "80001ff" null null;
|
||||||
|
"man_db.conf" = fs "80001ff" null null;
|
||||||
|
"modprobe.d" = fs "80001ff" null null;
|
||||||
|
"modules-load.d" = fs "80001ff" null null;
|
||||||
|
"mtab" = fs "80001ff" null null;
|
||||||
|
"nanorc" = fs "80001ff" null null;
|
||||||
|
"netgroup" = fs "80001ff" null null;
|
||||||
|
"nix" = fs "80001ff" null null;
|
||||||
|
"nixos" = fs "80001ff" null null;
|
||||||
|
"nscd.conf" = fs "80001ff" null null;
|
||||||
|
"nsswitch.conf" = fs "80001ff" null null;
|
||||||
|
"os-release" = fs "80001ff" null null;
|
||||||
|
"pam" = fs "80001ff" null null;
|
||||||
|
"pam.d" = fs "80001ff" null null;
|
||||||
|
"passwd" = fs "180" null "u0_a1:x:65534:65534:Fortify:/var/lib/fortify/u0/a1:/run/current-system/sw/bin/bash\n";
|
||||||
|
"pipewire" = fs "80001ff" null null;
|
||||||
|
"pki" = fs "80001ff" null null;
|
||||||
|
"polkit-1" = fs "80001ff" null null;
|
||||||
|
"profile" = fs "80001ff" null null;
|
||||||
|
"profiles" = fs "80001ff" null null;
|
||||||
|
"protocols" = fs "80001ff" null null;
|
||||||
|
"resolv.conf" = fs "80001ff" null null;
|
||||||
|
"resolvconf.conf" = fs "80001ff" null null;
|
||||||
|
"rpc" = fs "80001ff" null null;
|
||||||
|
"services" = fs "80001ff" null null;
|
||||||
|
"set-environment" = fs "80001ff" null null;
|
||||||
|
"shadow" = fs "80001ff" null null;
|
||||||
|
"shells" = fs "80001ff" null null;
|
||||||
|
"ssh" = fs "80001ff" null null;
|
||||||
|
"ssl" = fs "80001ff" null null;
|
||||||
|
"static" = fs "80001ff" null null;
|
||||||
|
"subgid" = fs "80001ff" null null;
|
||||||
|
"subuid" = fs "80001ff" null null;
|
||||||
|
"sudoers" = fs "80001ff" null null;
|
||||||
|
"sway" = fs "80001ff" null null;
|
||||||
|
"sysctl.d" = fs "80001ff" null null;
|
||||||
|
"systemd" = fs "80001ff" null null;
|
||||||
|
"terminfo" = fs "80001ff" null null;
|
||||||
|
"tmpfiles.d" = fs "80001ff" null null;
|
||||||
|
"udev" = fs "80001ff" null null;
|
||||||
|
"vconsole.conf" = fs "80001ff" null null;
|
||||||
|
"xdg" = fs "80001ff" null null;
|
||||||
|
"zoneinfo" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
nix = fs "800001c0" { store = fs "801001fd" null null; } null;
|
||||||
|
proc = fs "8000016d" null null;
|
||||||
|
run = fs "800001c0" {
|
||||||
|
current-system = fs "8000016d" null null;
|
||||||
|
opengl-driver = fs "8000016d" null null;
|
||||||
|
user = fs "800001ed" {
|
||||||
|
"65534" = fs "800001ed" {
|
||||||
|
bus = fs "10001fd" null null;
|
||||||
|
pulse = fs "800001c0" { native = fs "10001b6" null null; } null;
|
||||||
|
wayland-0 = fs "1000038" null null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
sys = fs "800001c0" {
|
||||||
|
block = fs "800001ed" {
|
||||||
|
fd0 = fs "80001ff" null null;
|
||||||
|
loop0 = fs "80001ff" null null;
|
||||||
|
loop1 = fs "80001ff" null null;
|
||||||
|
loop2 = fs "80001ff" null null;
|
||||||
|
loop3 = fs "80001ff" null null;
|
||||||
|
loop4 = fs "80001ff" null null;
|
||||||
|
loop5 = fs "80001ff" null null;
|
||||||
|
loop6 = fs "80001ff" null null;
|
||||||
|
loop7 = fs "80001ff" null null;
|
||||||
|
sr0 = fs "80001ff" null null;
|
||||||
|
vda = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
bus = fs "800001ed" null null;
|
||||||
|
class = fs "800001ed" null null;
|
||||||
|
dev = fs "800001ed" {
|
||||||
|
block = fs "800001ed" null null;
|
||||||
|
char = fs "800001ed" null null;
|
||||||
|
} null;
|
||||||
|
devices = fs "800001ed" null null;
|
||||||
|
} null;
|
||||||
|
tmp = fs "800001f8" { } null;
|
||||||
|
usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
|
||||||
|
var = fs "800001c0" {
|
||||||
|
lib = fs "800001c0" {
|
||||||
|
fortify = fs "800001c0" {
|
||||||
|
u0 = fs "800001c0" {
|
||||||
|
a1 = fs "800001c0" {
|
||||||
|
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
||||||
|
".config" = fs "800001ed" { "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null; } null;
|
||||||
|
".local" = fs "800001ed" {
|
||||||
|
state = fs "800001ed" {
|
||||||
|
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
||||||
|
nix = fs "800001ed" {
|
||||||
|
profiles = fs "800001ed" {
|
||||||
|
home-manager = fs "80001ff" null null;
|
||||||
|
home-manager-1-link = fs "80001ff" null null;
|
||||||
|
profile = fs "80001ff" null null;
|
||||||
|
profile-1-link = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
".nix-defexpr" = fs "800001ed" {
|
||||||
|
channels = fs "80001ff" null null;
|
||||||
|
channels_root = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
".nix-profile" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
run = fs "800001ed" { nscd = fs "800001ed" { } null; } null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
|
||||||
|
mainFile = writeText "main.go" ''
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
import "git.gensokyo.uk/security/fortify/test/sandbox"
|
||||||
|
|
||||||
|
func main() { sandbox.MustAssertFS(os.DirFS("/"), "${writeText "want-fs.json" (builtins.toJSON wantFS)}") }
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
buildGoModule {
|
||||||
|
pname = "check-fs";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
src = ../.;
|
||||||
|
vendorHash = null;
|
||||||
|
|
||||||
|
preBuild = ''
|
||||||
|
go mod init git.gensokyo.uk/security/fortify/test >& /dev/null
|
||||||
|
cp ${mainFile} main.go
|
||||||
|
'';
|
||||||
|
}
|
84
test/sandbox/fs_test.go
Normal file
84
test/sandbox/fs_test.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package sandbox_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"testing/fstest"
|
||||||
|
|
||||||
|
"git.gensokyo.uk/security/fortify/test/sandbox"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fsPasswdSample = "u0_a20:x:65534:65534:Fortify:/var/lib/persist/module/fortify/u0/a20:/run/current-system/sw/bin/zsh"
|
||||||
|
fsGroupSample = "fortify:x:65534:"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCompare(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
|
||||||
|
sample fstest.MapFS
|
||||||
|
want *sandbox.FS
|
||||||
|
wantOut string
|
||||||
|
wantErr error
|
||||||
|
}{
|
||||||
|
{"skip", fstest.MapFS{}, &sandbox.FS{}, "[ OK ] s .\x00", nil},
|
||||||
|
{"simple pass", fstest.MapFS{".fortify": {Mode: 0x800001ed}},
|
||||||
|
&sandbox.FS{Dir: map[string]*sandbox.FS{".fortify": {Mode: 0x800001ed}}},
|
||||||
|
"[ OK ] s .fortify\x00[ OK ] d .\x00", nil},
|
||||||
|
{"bad length", fstest.MapFS{".fortify": {Mode: 0x800001ed}},
|
||||||
|
&sandbox.FS{Dir: make(map[string]*sandbox.FS)},
|
||||||
|
"[FAIL] d \".\": \".fortify/\"\x00", sandbox.ErrFSBadLength},
|
||||||
|
{"top level bad mode", fstest.MapFS{".fortify": {Mode: 0x800001ed}},
|
||||||
|
&sandbox.FS{Dir: map[string]*sandbox.FS{".fortify": {Mode: 0xdeadbeef}}},
|
||||||
|
"[FAIL] m \".fortify\": 800001ed, want deadbeef\x00", sandbox.ErrFSBadMode},
|
||||||
|
{"invalid entry condition", fstest.MapFS{"test": {Data: []byte{'0'}, Mode: 0644}},
|
||||||
|
&sandbox.FS{Dir: map[string]*sandbox.FS{"test": {Dir: make(map[string]*sandbox.FS)}}},
|
||||||
|
"[FAIL] d \".\": \"test\"\x00", sandbox.ErrFSInvalidEnt},
|
||||||
|
{"nonexistent", fstest.MapFS{"test": {Data: []byte{'0'}, Mode: 0644}},
|
||||||
|
&sandbox.FS{Dir: map[string]*sandbox.FS{".test": {}}},
|
||||||
|
"[FAIL] d \".\": \"test\"\x00", fs.ErrNotExist},
|
||||||
|
{"file", fstest.MapFS{"etc": {Mode: 0x800001c0},
|
||||||
|
"etc/passwd": {Data: []byte(fsPasswdSample), Mode: 0644},
|
||||||
|
"etc/group": {Data: []byte(fsGroupSample), Mode: 0644},
|
||||||
|
}, &sandbox.FS{Dir: map[string]*sandbox.FS{"etc": {Mode: 0x800001c0, Dir: map[string]*sandbox.FS{
|
||||||
|
"passwd": {Mode: 0x1a4, Data: &fsPasswdSample},
|
||||||
|
"group": {Mode: 0x1a4, Data: &fsGroupSample},
|
||||||
|
}}}}, "[ OK ] f etc/group\x00[ OK ] f etc/passwd\x00[ OK ] d etc\x00[ OK ] d .\x00", nil},
|
||||||
|
{"file differ", fstest.MapFS{"etc": {Mode: 0x800001c0},
|
||||||
|
"etc/passwd": {Data: []byte(fsPasswdSample), Mode: 0644},
|
||||||
|
"etc/group": {Data: []byte(fsGroupSample), Mode: 0644},
|
||||||
|
}, &sandbox.FS{Dir: map[string]*sandbox.FS{"etc": {Mode: 0x800001c0, Dir: map[string]*sandbox.FS{
|
||||||
|
"passwd": {Mode: 0x1a4, Data: &fsGroupSample},
|
||||||
|
"group": {Mode: 0x1a4, Data: &fsGroupSample},
|
||||||
|
}}}}, "[ OK ] f etc/group\x00[FAIL] f etc/passwd\x00", sandbox.ErrFSBadData},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
gotOut := new(strings.Builder)
|
||||||
|
oldPrint := sandbox.SwapPrint(func(format string, v ...any) { _, _ = fmt.Fprintf(gotOut, format+"\x00", v...) })
|
||||||
|
t.Cleanup(func() { sandbox.SwapPrint(oldPrint) })
|
||||||
|
|
||||||
|
err := tc.want.Compare(".", tc.sample)
|
||||||
|
if !errors.Is(err, tc.wantErr) {
|
||||||
|
t.Errorf("Compare: error = %v; wantErr %v",
|
||||||
|
err, tc.wantErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotOut.String() != tc.wantOut {
|
||||||
|
t.Errorf("Compare: output %q; want %q",
|
||||||
|
gotOut, tc.wantOut)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("assert", func(t *testing.T) {
|
||||||
|
oldFatal := sandbox.SwapFatal(t.Fatalf)
|
||||||
|
t.Cleanup(func() { sandbox.SwapFatal(oldFatal) })
|
||||||
|
sandbox.MustAssertFS(make(fstest.MapFS), sandbox.MustWantFile(t, &sandbox.FS{Mode: 0xDEADBEEF}))
|
||||||
|
})
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package sandbox_test
|
package sandbox_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
@ -111,22 +110,9 @@ overlay /.fortify/sbin/fortify overlay ro,nosuid,nodev,relatime,lowerdir=/mnt-ro
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run(tc.name+" assert", func(t *testing.T) {
|
t.Run(tc.name+" assert", func(t *testing.T) {
|
||||||
sandbox.ReplaceFatal(t.Fatalf)
|
oldFatal := sandbox.SwapFatal(t.Fatalf)
|
||||||
|
t.Cleanup(func() { sandbox.SwapFatal(oldFatal) })
|
||||||
wantFile := path.Join(t.TempDir(), "want.json")
|
sandbox.MustAssertMounts(name, name, sandbox.MustWantFile(t, tc.want))
|
||||||
if f, err := os.OpenFile(wantFile, os.O_CREATE|os.O_WRONLY, 0400); err != nil {
|
|
||||||
t.Fatalf("cannot create %q: %v", wantFile, err)
|
|
||||||
} else if err = json.NewEncoder(f).Encode(tc.want); err != nil {
|
|
||||||
t.Fatalf("cannot encode to %q: %v", wantFile, err)
|
|
||||||
} else if err = f.Close(); err != nil {
|
|
||||||
t.Fatalf("cannot close %q: %v", wantFile, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sandbox.MustAssertMounts(name, name, wantFile)
|
|
||||||
|
|
||||||
if err := os.Remove(wantFile); err != nil {
|
|
||||||
t.Fatalf("cannot remove %q: %v", wantFile, err)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := os.Remove(name); err != nil {
|
if err := os.Remove(name); err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user