From aaebb8f3abc10b4ef24a75a379db2e6fc91e68dc Mon Sep 17 00:00:00 2001 From: Ophestra Date: Fri, 14 Feb 2025 14:44:28 +0900 Subject: fortify: check print behaviour These output are supposed to be deterministic, so checking them is a good way to catch regressions. Signed-off-by: Ophestra --- print_test.go | 671 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 671 insertions(+) create mode 100644 print_test.go (limited to 'print_test.go') diff --git a/print_test.go b/print_test.go new file mode 100644 index 00000000..5d5e814b --- /dev/null +++ b/print_test.go @@ -0,0 +1,671 @@ +package main + +import ( + "strings" + "testing" + "time" + + "git.gensokyo.uk/security/fortify/dbus" + "git.gensokyo.uk/security/fortify/fst" + "git.gensokyo.uk/security/fortify/internal/state" +) + +var ( + testID = fst.ID{ + 0x8e, 0x2c, 0x76, 0xb0, + 0x66, 0xda, 0xbe, 0x57, + 0x4c, 0xf0, 0x73, 0xbd, + 0xb4, 0x6e, 0xb5, 0xc1, + } + testState = &state.State{ + ID: testID, + PID: 0xDEADBEEF, + Config: fst.Template(), + Time: testAppTime, + } + testTime = time.Unix(3752, 1).UTC() + testAppTime = time.Unix(0, 9).UTC() +) + +func Test_printShowInstance(t *testing.T) { + testCases := []struct { + name string + instance *state.State + config *fst.Config + short, json bool + want string + }{ + {"config", nil, fst.Template(), false, false, `App + ID: 9 (org.chromium.Chromium) + Enablements: Wayland, D-Bus, PulseAudio + Groups: ["video"] + Directory: /var/lib/persist/home/org.chromium.Chromium + Hostname: "localhost" + Flags: userns net dev tty mapuid autoetc + Etc: /etc + Overrides: /var/run/nscd + Command: chromium --ignore-gpu-blocklist --disable-smooth-scrolling --enable-features=UseOzonePlatform --ozone-platform=wayland + +Filesystem + +/nix/store + +/run/current-system + +/run/opengl-driver + +/var/db/nix-channels + w*/var/lib/fortify/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium + d+/dev/dri + +Extra ACL + --x+:/var/lib/fortify/u0 + rwx:/var/lib/fortify/u0/org.chromium.Chromium + +Session bus + Filter: true + Talk: ["org.freedesktop.Notifications" "org.freedesktop.FileManager1" "org.freedesktop.ScreenSaver" "org.freedesktop.secrets" "org.kde.kwalletd5" "org.kde.kwalletd6" "org.gnome.SessionManager"] + Own: ["org.chromium.Chromium.*" "org.mpris.MediaPlayer2.org.chromium.Chromium.*" "org.mpris.MediaPlayer2.chromium.*"] + Call: map["org.freedesktop.portal.*":"*"] + Broadcast: map["org.freedesktop.portal.*":"@/org/freedesktop/portal/*"] + +System bus + Filter: true + Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"] + +`}, + {"config pd", nil, new(fst.Config), false, false, `Warning: this configuration uses permissive defaults! + +App + ID: 0 + Enablements: (No enablements) + Directory: + Command: + +`}, + {"config flag none", nil, &fst.Config{Confinement: fst.ConfinementConfig{Sandbox: new(fst.SandboxConfig)}}, false, false, `App + ID: 0 + Enablements: (No enablements) + Directory: + Flags: none + Etc: /etc + Command: + +`}, + {"config nil entries", nil, &fst.Config{Confinement: fst.ConfinementConfig{Sandbox: &fst.SandboxConfig{Filesystem: make([]*fst.FilesystemConfig, 1)}, ExtraPerms: make([]*fst.ExtraPermConfig, 1)}}, false, false, `App + ID: 0 + Enablements: (No enablements) + Directory: + Flags: none + Etc: /etc + Command: + +Filesystem + +Extra ACL + +`}, + {"config pd dbus see", nil, &fst.Config{Confinement: fst.ConfinementConfig{SessionBus: &dbus.Config{See: []string{"org.example.test"}}}}, false, false, `Warning: this configuration uses permissive defaults! + +App + ID: 0 + Enablements: (No enablements) + Directory: + Command: + +Session bus + Filter: false + See: ["org.example.test"] + +`}, + + {"instance", testState, fst.Template(), false, false, `State + Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559) + Uptime: 1h2m32s + +App + ID: 9 (org.chromium.Chromium) + Enablements: Wayland, D-Bus, PulseAudio + Groups: ["video"] + Directory: /var/lib/persist/home/org.chromium.Chromium + Hostname: "localhost" + Flags: userns net dev tty mapuid autoetc + Etc: /etc + Overrides: /var/run/nscd + Command: chromium --ignore-gpu-blocklist --disable-smooth-scrolling --enable-features=UseOzonePlatform --ozone-platform=wayland + +Filesystem + +/nix/store + +/run/current-system + +/run/opengl-driver + +/var/db/nix-channels + w*/var/lib/fortify/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium + d+/dev/dri + +Extra ACL + --x+:/var/lib/fortify/u0 + rwx:/var/lib/fortify/u0/org.chromium.Chromium + +Session bus + Filter: true + Talk: ["org.freedesktop.Notifications" "org.freedesktop.FileManager1" "org.freedesktop.ScreenSaver" "org.freedesktop.secrets" "org.kde.kwalletd5" "org.kde.kwalletd6" "org.gnome.SessionManager"] + Own: ["org.chromium.Chromium.*" "org.mpris.MediaPlayer2.org.chromium.Chromium.*" "org.mpris.MediaPlayer2.chromium.*"] + Call: map["org.freedesktop.portal.*":"*"] + Broadcast: map["org.freedesktop.portal.*":"@/org/freedesktop/portal/*"] + +System bus + Filter: true + Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"] + +`}, + {"instance pd", testState, new(fst.Config), false, false, `Warning: this configuration uses permissive defaults! + +State + Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559) + Uptime: 1h2m32s + +App + ID: 0 + Enablements: (No enablements) + Directory: + Command: + +`}, + + {"json nil", nil, nil, false, true, `null +`}, + {"json instance", testState, nil, false, true, `{ + "instance": [ + 142, + 44, + 118, + 176, + 102, + 218, + 190, + 87, + 76, + 240, + 115, + 189, + 180, + 110, + 181, + 193 + ], + "pid": 3735928559, + "config": { + "id": "org.chromium.Chromium", + "command": [ + "chromium", + "--ignore-gpu-blocklist", + "--disable-smooth-scrolling", + "--enable-features=UseOzonePlatform", + "--ozone-platform=wayland" + ], + "confinement": { + "app_id": 9, + "groups": [ + "video" + ], + "username": "chronos", + "home_inner": "/var/lib/fortify", + "home": "/var/lib/persist/home/org.chromium.Chromium", + "sandbox": { + "hostname": "localhost", + "userns": true, + "net": true, + "dev": true, + "syscall": { + "compat": false, + "deny_devel": true, + "multiarch": true, + "linux32": false, + "can": false, + "bluetooth": false + }, + "no_new_session": true, + "map_real_uid": true, + "env": { + "GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY", + "GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com", + "GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT" + }, + "filesystem": [ + { + "src": "/nix/store" + }, + { + "src": "/run/current-system" + }, + { + "src": "/run/opengl-driver" + }, + { + "src": "/var/db/nix-channels" + }, + { + "dst": "/data/data/org.chromium.Chromium", + "src": "/var/lib/fortify/u0/org.chromium.Chromium", + "write": true, + "require": true + }, + { + "src": "/dev/dri", + "dev": true + } + ], + "symlink": [ + [ + "/run/user/65534", + "/run/user/150" + ] + ], + "etc": "/etc", + "auto_etc": true, + "override": [ + "/var/run/nscd" + ] + }, + "extra_perms": [ + { + "ensure": true, + "path": "/var/lib/fortify/u0", + "x": true + }, + { + "path": "/var/lib/fortify/u0/org.chromium.Chromium", + "r": true, + "w": true, + "x": true + } + ], + "system_bus": { + "see": null, + "talk": [ + "org.bluez", + "org.freedesktop.Avahi", + "org.freedesktop.UPower" + ], + "own": null, + "call": null, + "broadcast": null, + "filter": true + }, + "session_bus": { + "see": null, + "talk": [ + "org.freedesktop.Notifications", + "org.freedesktop.FileManager1", + "org.freedesktop.ScreenSaver", + "org.freedesktop.secrets", + "org.kde.kwalletd5", + "org.kde.kwalletd6", + "org.gnome.SessionManager" + ], + "own": [ + "org.chromium.Chromium.*", + "org.mpris.MediaPlayer2.org.chromium.Chromium.*", + "org.mpris.MediaPlayer2.chromium.*" + ], + "call": { + "org.freedesktop.portal.*": "*" + }, + "broadcast": { + "org.freedesktop.portal.*": "@/org/freedesktop/portal/*" + }, + "filter": true + }, + "enablements": 13 + } + }, + "time": "1970-01-01T00:00:00.000000009Z" +} +`}, + {"json config", nil, fst.Template(), false, true, `{ + "id": "org.chromium.Chromium", + "command": [ + "chromium", + "--ignore-gpu-blocklist", + "--disable-smooth-scrolling", + "--enable-features=UseOzonePlatform", + "--ozone-platform=wayland" + ], + "confinement": { + "app_id": 9, + "groups": [ + "video" + ], + "username": "chronos", + "home_inner": "/var/lib/fortify", + "home": "/var/lib/persist/home/org.chromium.Chromium", + "sandbox": { + "hostname": "localhost", + "userns": true, + "net": true, + "dev": true, + "syscall": { + "compat": false, + "deny_devel": true, + "multiarch": true, + "linux32": false, + "can": false, + "bluetooth": false + }, + "no_new_session": true, + "map_real_uid": true, + "env": { + "GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY", + "GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com", + "GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT" + }, + "filesystem": [ + { + "src": "/nix/store" + }, + { + "src": "/run/current-system" + }, + { + "src": "/run/opengl-driver" + }, + { + "src": "/var/db/nix-channels" + }, + { + "dst": "/data/data/org.chromium.Chromium", + "src": "/var/lib/fortify/u0/org.chromium.Chromium", + "write": true, + "require": true + }, + { + "src": "/dev/dri", + "dev": true + } + ], + "symlink": [ + [ + "/run/user/65534", + "/run/user/150" + ] + ], + "etc": "/etc", + "auto_etc": true, + "override": [ + "/var/run/nscd" + ] + }, + "extra_perms": [ + { + "ensure": true, + "path": "/var/lib/fortify/u0", + "x": true + }, + { + "path": "/var/lib/fortify/u0/org.chromium.Chromium", + "r": true, + "w": true, + "x": true + } + ], + "system_bus": { + "see": null, + "talk": [ + "org.bluez", + "org.freedesktop.Avahi", + "org.freedesktop.UPower" + ], + "own": null, + "call": null, + "broadcast": null, + "filter": true + }, + "session_bus": { + "see": null, + "talk": [ + "org.freedesktop.Notifications", + "org.freedesktop.FileManager1", + "org.freedesktop.ScreenSaver", + "org.freedesktop.secrets", + "org.kde.kwalletd5", + "org.kde.kwalletd6", + "org.gnome.SessionManager" + ], + "own": [ + "org.chromium.Chromium.*", + "org.mpris.MediaPlayer2.org.chromium.Chromium.*", + "org.mpris.MediaPlayer2.chromium.*" + ], + "call": { + "org.freedesktop.portal.*": "*" + }, + "broadcast": { + "org.freedesktop.portal.*": "@/org/freedesktop/portal/*" + }, + "filter": true + }, + "enablements": 13 + } +} +`}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + { + v := flagJSON + t.Cleanup(func() { flagJSON = v }) + flagJSON = tc.json + } + + output := new(strings.Builder) + printShowInstance(output, testTime, tc.instance, tc.config, tc.short) + if got := output.String(); got != tc.want { + t.Errorf("printShowInstance: got\n%s\nwant\n%s", + got, tc.want) + return + } + }) + } +} + +func Test_printPs(t *testing.T) { + testCases := []struct { + name string + entries state.Entries + short, json bool + want string + }{ + {"no entries", make(state.Entries), false, false, ` Instance PID App Uptime Enablements Command + +`}, + {"no entries short", make(state.Entries), true, false, ``}, + {"nil instance", state.Entries{testID: nil}, false, false, ` Instance PID App Uptime Enablements Command + +`}, + {"state corruption", state.Entries{fst.ID{}: testState}, false, false, ` Instance PID App Uptime Enablements Command + +`}, + + {"valid", state.Entries{testID: testState}, false, false, ` Instance PID App Uptime Enablements Command + 8e2c76b0 3735928559 9 1h2m32s Wayland, D-Bus, PulseAudio ["chromium" "--ignore-gpu-blocklist" "--disable-smooth-scrolling" "--enable-features=UseOzonePlatform" "--ozone-platform=wayland"] + +`}, + {"valid short", state.Entries{testID: testState}, true, false, `8e2c76b0 +`}, + {"valid json", state.Entries{testID: testState}, false, true, `{ + "8e2c76b066dabe574cf073bdb46eb5c1": { + "instance": [ + 142, + 44, + 118, + 176, + 102, + 218, + 190, + 87, + 76, + 240, + 115, + 189, + 180, + 110, + 181, + 193 + ], + "pid": 3735928559, + "config": { + "id": "org.chromium.Chromium", + "command": [ + "chromium", + "--ignore-gpu-blocklist", + "--disable-smooth-scrolling", + "--enable-features=UseOzonePlatform", + "--ozone-platform=wayland" + ], + "confinement": { + "app_id": 9, + "groups": [ + "video" + ], + "username": "chronos", + "home_inner": "/var/lib/fortify", + "home": "/var/lib/persist/home/org.chromium.Chromium", + "sandbox": { + "hostname": "localhost", + "userns": true, + "net": true, + "dev": true, + "syscall": { + "compat": false, + "deny_devel": true, + "multiarch": true, + "linux32": false, + "can": false, + "bluetooth": false + }, + "no_new_session": true, + "map_real_uid": true, + "env": { + "GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY", + "GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com", + "GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT" + }, + "filesystem": [ + { + "src": "/nix/store" + }, + { + "src": "/run/current-system" + }, + { + "src": "/run/opengl-driver" + }, + { + "src": "/var/db/nix-channels" + }, + { + "dst": "/data/data/org.chromium.Chromium", + "src": "/var/lib/fortify/u0/org.chromium.Chromium", + "write": true, + "require": true + }, + { + "src": "/dev/dri", + "dev": true + } + ], + "symlink": [ + [ + "/run/user/65534", + "/run/user/150" + ] + ], + "etc": "/etc", + "auto_etc": true, + "override": [ + "/var/run/nscd" + ] + }, + "extra_perms": [ + { + "ensure": true, + "path": "/var/lib/fortify/u0", + "x": true + }, + { + "path": "/var/lib/fortify/u0/org.chromium.Chromium", + "r": true, + "w": true, + "x": true + } + ], + "system_bus": { + "see": null, + "talk": [ + "org.bluez", + "org.freedesktop.Avahi", + "org.freedesktop.UPower" + ], + "own": null, + "call": null, + "broadcast": null, + "filter": true + }, + "session_bus": { + "see": null, + "talk": [ + "org.freedesktop.Notifications", + "org.freedesktop.FileManager1", + "org.freedesktop.ScreenSaver", + "org.freedesktop.secrets", + "org.kde.kwalletd5", + "org.kde.kwalletd6", + "org.gnome.SessionManager" + ], + "own": [ + "org.chromium.Chromium.*", + "org.mpris.MediaPlayer2.org.chromium.Chromium.*", + "org.mpris.MediaPlayer2.chromium.*" + ], + "call": { + "org.freedesktop.portal.*": "*" + }, + "broadcast": { + "org.freedesktop.portal.*": "@/org/freedesktop/portal/*" + }, + "filter": true + }, + "enablements": 13 + } + }, + "time": "1970-01-01T00:00:00.000000009Z" + } +} +`}, + {"valid short json", state.Entries{testID: testState}, true, true, `["8e2c76b066dabe574cf073bdb46eb5c1"] +`}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + { + v := flagJSON + t.Cleanup(func() { flagJSON = v }) + flagJSON = tc.json + } + + output := new(strings.Builder) + printPs(output, testTime, stubStore(tc.entries), tc.short) + if got := output.String(); got != tc.want { + t.Errorf("printPs: got\n%s\nwant\n%s", + got, tc.want) + return + } + }) + } +} + +// stubStore implements [state.Store] and returns test samples via [state.Joiner]. +type stubStore state.Entries + +func (s stubStore) Join() (state.Entries, error) { return state.Entries(s), nil } +func (s stubStore) Do(int, func(c state.Cursor)) (bool, error) { panic("unreachable") } +func (s stubStore) List() ([]int, error) { panic("unreachable") } +func (s stubStore) Close() error { return nil } -- cgit v1.3.1