From 5f64bb4e0cfc6444ec584a48165533ec58bbc2ba Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Wed, 29 May 2024 21:17:21 +0100 Subject: [PATCH] tests(aa): improve rules unit tests. --- pkg/aa/parse_test.go | 4 +- pkg/aa/rules.go | 18 +- pkg/aa/rules_test.go | 1080 +++++++++++++++++------------------------- 3 files changed, 441 insertions(+), 661 deletions(-) diff --git a/pkg/aa/parse_test.go b/pkg/aa/parse_test.go index c5f0f084..eae45a06 100644 --- a/pkg/aa/parse_test.go +++ b/pkg/aa/parse_test.go @@ -12,7 +12,7 @@ import ( ) func Test_tokenizeRule(t *testing.T) { - for _, tt := range testRules { + for _, tt := range testTokenRules { t.Run(tt.name, func(t *testing.T) { if got := tokenize(tt.raw); !reflect.DeepEqual(got, tt.tokens) { t.Errorf("tokenize() = %v, want %v", got, tt.tokens) @@ -37,7 +37,7 @@ func Test_AppArmorProfileFile_Parse(t *testing.T) { var ( // Test cases for tokenize - testRules = []struct { + testTokenRules = []struct { name string raw string tokens []string diff --git a/pkg/aa/rules.go b/pkg/aa/rules.go index bc0f847c..8f432635 100644 --- a/pkg/aa/rules.go +++ b/pkg/aa/rules.go @@ -54,6 +54,9 @@ type Rules []Rule func (r Rules) Validate() error { for _, rule := range r { + if rule == nil { + continue + } if err := rule.Validate(); err != nil { return err } @@ -66,9 +69,12 @@ func (r Rules) String() string { } // Index returns the index of the first occurrence of rule rin r, or -1 if not present. -func (r Rules) Index(rule Rule) int { - for idx, rr := range r { - if rr.Kind() == rule.Kind() && rr.Equals(rule) { +func (r Rules) Index(item Rule) int { + for idx, rule := range r { + if rule == nil { + continue + } + if rule.Kind() == item.Kind() && rule.Equals(item) { return idx } } @@ -94,6 +100,9 @@ func (r Rules) Delete(i int) Rules { func (r Rules) DeleteKind(kind Kind) Rules { res := make(Rules, 0) for _, rule := range r { + if rule == nil { + continue + } if rule.Kind() != kind { res = append(res, rule) } @@ -104,6 +113,9 @@ func (r Rules) DeleteKind(kind Kind) Rules { func (r Rules) Filter(filter Kind) Rules { res := make(Rules, 0) for _, rule := range r { + if rule == nil { + continue + } if rule.Kind() != filter { res = append(res, rule) } diff --git a/pkg/aa/rules_test.go b/pkg/aa/rules_test.go index 4278da8f..2b944005 100644 --- a/pkg/aa/rules_test.go +++ b/pkg/aa/rules_test.go @@ -10,686 +10,454 @@ import ( ) func TestRules_FromLog(t *testing.T) { - tests := []struct { - name string - fromLog func(map[string]string) Rule - log map[string]string - want Rule - }{ - { - name: "capbability", - fromLog: newCapabilityFromLog, - log: capability1Log, - want: capability1, - }, - { - name: "network", - fromLog: newNetworkFromLog, - log: network1Log, - want: network1, - }, - { - name: "mount", - fromLog: newMountFromLog, - log: mount1Log, - want: mount1, - }, - { - name: "umount", - fromLog: newUmountFromLog, - log: umount1Log, - want: umount1, - }, - { - name: "pivotroot", - fromLog: newPivotRootFromLog, - log: pivotroot1Log, - want: pivotroot1, - }, - { - name: "changeprofile", - fromLog: newChangeProfileFromLog, - log: changeprofile1Log, - want: changeprofile1, - }, - { - name: "signal", - fromLog: newSignalFromLog, - log: signal1Log, - want: signal1, - }, - { - name: "ptrace/xdg-document-portal", - fromLog: newPtraceFromLog, - log: ptrace1Log, - want: ptrace1, - }, - { - name: "ptrace/snap-update-ns.firefox", - fromLog: newPtraceFromLog, - log: ptrace2Log, - want: ptrace2, - }, - { - name: "unix", - fromLog: newUnixFromLog, - log: unix1Log, - want: unix1, - }, - { - name: "dbus", - fromLog: newDbusFromLog, - log: dbus1Log, - want: dbus1, - }, - { - name: "file", - fromLog: newFileFromLog, - log: file1Log, - want: file1, - }, - { - name: "link", - fromLog: newLinkFromLog, - log: link1Log, - want: link1, - }, - { - name: "link", - fromLog: newFileFromLog, - log: link3Log, - want: link3, - }, - } - for _, tt := range tests { + for _, tt := range testRule { + if tt.fromLog == nil { + continue + } t.Run(tt.name, func(t *testing.T) { - if got := tt.fromLog(tt.log); !reflect.DeepEqual(got, tt.want) { - t.Errorf("RuleFromLog() = %v, want %v", got, tt.want) + if got := tt.fromLog(tt.log); !reflect.DeepEqual(got, tt.rule) { + t.Errorf("RuleFromLog() = %v, want %v", got, tt.rule) + } + }) + } +} + +func TestRules_Validate(t *testing.T) { + for _, tt := range testRule { + t.Run(tt.name, func(t *testing.T) { + if err := tt.rule.Validate(); (err != nil) != tt.wValidErr { + t.Errorf("Rules.Validate() error = %v, wantErr %v", err, tt.wValidErr) } }) } } func TestRules_Less(t *testing.T) { - tests := []struct { - name string - rule Rule - other Rule - want bool - }{ - { - name: "comment", - rule: comment1, - other: comment2, - want: false, - }, - { - name: "abi", - rule: abi1, - other: abi2, - want: false, - }, - { - name: "include1", - rule: include1, - other: includeLocal1, - want: false, - }, - { - name: "include2", - rule: include1, - other: include2, - want: false, - }, - { - name: "include3", - rule: include1, - other: include3, - want: false, - }, - { - name: "variable", - rule: variable2, - other: variable1, - want: false, - }, - { - name: "all", - rule: all1, - other: all2, - want: false, - }, - { - name: "rlimit", - rule: rlimit1, - other: rlimit2, - want: false, - }, - { - name: "rlimit2", - rule: rlimit2, - other: rlimit2, - want: false, - }, - { - name: "rlimit3", - rule: rlimit1, - other: rlimit3, - want: false, - }, - { - name: "userns", - rule: userns1, - other: userns2, - want: true, - }, - { - name: "capability", - rule: capability1, - other: capability2, - want: true, - }, - { - name: "network", - rule: network1, - other: network2, - want: false, - }, - { - name: "mount", - rule: mount1, - other: mount2, - want: false, - }, - { - name: "remount", - rule: remount1, - other: remount2, - want: true, - }, - { - name: "umount", - rule: umount1, - other: umount2, - want: true, - }, - { - name: "pivot_root1", - rule: pivotroot2, - other: pivotroot1, - want: true, - }, - { - name: "pivot_root2", - rule: pivotroot1, - other: pivotroot3, - want: false, - }, - { - name: "change_profile1", - rule: changeprofile1, - other: changeprofile2, - want: false, - }, - { - name: "change_profile2", - rule: changeprofile1, - other: changeprofile3, - want: true, - }, - { - name: "mqueue", - rule: mqueue1, - other: mqueue2, - want: true, - }, - { - name: "iouring", - rule: iouring1, - other: iouring2, - want: false, - }, - { - name: "signal", - rule: signal1, - other: signal2, - want: false, - }, - { - name: "ptrace/less", - rule: ptrace1, - other: ptrace2, - want: false, - }, - { - name: "ptrace/more", - rule: ptrace2, - other: ptrace1, - want: false, - }, - { - name: "unix", - rule: unix1, - other: unix1, - want: false, - }, - { - name: "dbus", - rule: dbus1, - other: dbus1, - want: false, - }, - { - name: "dbus2", - rule: dbus2, - other: dbus3, - want: false, - }, - { - name: "file", - rule: file1, - other: file2, - want: true, - }, - { - name: "file/empty", - rule: &File{}, - other: &File{}, - want: false, - }, - { - name: "file/equal", - rule: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, - other: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, - want: false, - }, - { - name: "file/owner", - rule: &File{Path: "/usr/share/poppler/cMap/Identity-H", Owner: true}, - other: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, - want: true, - }, - { - name: "file/access", - rule: &File{Path: "/usr/share/poppler/cMap/Identity-H", Access: []string{"r"}}, - other: &File{Path: "/usr/share/poppler/cMap/Identity-H", Access: []string{"w"}}, - want: false, - }, - { - name: "file/close", - rule: &File{Path: "/usr/share/poppler/cMap/"}, - other: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, - want: true, - }, - { - name: "link", - rule: link1, - other: link2, - want: true, - }, - { - name: "profile", - rule: profile1, - other: profile2, - want: true, - }, - { - name: "hat", - rule: hat1, - other: hat2, - want: false, - }, - } - for _, tt := range tests { + for _, tt := range testRule { + if tt.oLess == nil { + continue + } t.Run(tt.name, func(t *testing.T) { - r := tt.rule - if got := r.Less(tt.other); got != tt.want { - t.Errorf("Rule.Less() = %v, want %v", got, tt.want) + if got := tt.rule.Less(tt.oLess); got != tt.wLessErr { + t.Errorf("Rule.Less() = %v, want %v", got, tt.wLessErr) } }) } } func TestRules_Equals(t *testing.T) { - tests := []struct { - name string - rule Rule - other Rule - want bool - }{ - { - name: "comment", - rule: comment1, - other: comment2, - want: false, - }, - { - name: "abi", - rule: abi1, - other: abi1, - want: true, - }, - { - name: "alias", - rule: alias1, - other: alias2, - want: false, - }, - { - name: "include", - rule: include1, - other: includeLocal1, - want: false, - }, - { - name: "variable", - rule: variable1, - other: variable2, - want: false, - }, - { - name: "all", - rule: all1, - other: all2, - want: false, - }, - { - name: "rlimit", - rule: rlimit1, - other: rlimit1, - want: true, - }, - { - name: "userns", - rule: userns1, - other: userns1, - want: true, - }, - { - name: "capability/equal", - rule: capability1, - other: capability1, - want: true, - }, - { - name: "network/equal", - rule: network1, - other: network1, - want: true, - }, - { - name: "mount", - rule: mount1, - other: mount2, - want: false, - }, - { - name: "remount", - rule: remount2, - other: remount2, - want: true, - }, - { - name: "umount", - rule: umount1, - other: umount1, - want: true, - }, - { - name: "pivot_root", - rule: pivotroot1, - other: pivotroot2, - want: false, - }, - { - name: "change_profile", - rule: changeprofile1, - other: changeprofile2, - want: false, - }, - { - name: "mqueue", - rule: mqueue1, - other: mqueue1, - want: true, - }, - { - name: "iouring", - rule: iouring1, - other: iouring2, - want: false, - }, - { - name: "signal1/equal", - rule: signal1, - other: signal1, - want: true, - }, - { - name: "ptrace/equal", - rule: ptrace1, - other: ptrace1, - want: true, - }, - { - name: "ptrace/not_equal", - rule: ptrace1, - other: ptrace2, - want: false, - }, - { - name: "unix", - rule: unix1, - other: unix1, - want: true, - }, - { - name: "dbus", - rule: dbus1, - other: dbus2, - want: false, - }, - { - name: "file", - rule: file2, - other: file2, - want: true, - }, - { - name: "link", - rule: link1, - other: link3, - want: false, - }, - { - name: "profile", - rule: profile1, - other: profile1, - want: true, - }, - { - name: "hat", - rule: hat1, - other: hat1, - want: true, - }, - } - for _, tt := range tests { + for _, tt := range testRule { + if tt.oEqual == nil { + continue + } t.Run(tt.name, func(t *testing.T) { r := tt.rule - if got := r.Equals(tt.other); got != tt.want { - t.Errorf("Rule.Equals() = %v, want %v", got, tt.want) + if got := r.Equals(tt.oEqual); got != tt.wEqualErr { + t.Errorf("Rule.Equals() = %v, want %v", got, tt.wEqualErr) } }) } } func TestRules_String(t *testing.T) { - tests := []struct { - name string - rule Rule - want string - }{ - { - name: "comment", - rule: comment1, - want: "#comment", - }, - { - name: "abi", - rule: abi1, - want: "abi ,", - }, - { - name: "alias", - rule: alias1, - want: "alias /mnt/usr -> /usr,", - }, - { - name: "include", - rule: include1, - want: "include ", - }, - { - name: "include-local", - rule: includeLocal1, - want: "include if exists ", - }, - { - name: "include-abs", - rule: &Include{Path: "/usr/share/apparmor.d/", IsMagic: false}, - want: `include "/usr/share/apparmor.d/"`, - }, - { - name: "variable", - rule: variable1, - want: "@{bin} = /{,usr/}{,s}bin", - }, - { - name: "all", - rule: all1, - want: "all,", - }, - { - name: "rlimit", - rule: rlimit1, - want: "set rlimit nproc <= 200,", - }, - { - name: "userns", - rule: userns1, - want: "userns,", - }, - { - name: "capability", - rule: capability1, - want: "capability net_admin,", - }, - { - name: "capability/multi", - rule: &Capability{Names: []string{"dac_override", "dac_read_search"}}, - want: "capability dac_override dac_read_search,", - }, - { - name: "capability/all", - rule: &Capability{}, - want: "capability,", - }, - { - name: "network", - rule: network1, - want: "network netlink raw,", - }, - { - name: "mount", - rule: mount1, - want: "mount fstype=overlay overlay -> /var/lib/docker/overlay2/opaque-bug-check1209538631/merged/, # failed perms check", - }, - { - name: "remount", - rule: remount1, - want: "remount /,", - }, - { - name: "umount", - rule: umount1, - want: "umount /,", - }, - { - name: "pivot_root", - rule: pivotroot1, - want: "pivot_root oldroot=@{run}/systemd/mount-rootfs/ @{run}/systemd/mount-rootfs/,", - }, - { - name: "change_profile", - rule: changeprofile1, - want: "change_profile -> systemd-user,", - }, - { - name: "mqeue", - rule: mqueue1, - want: "mqueue r type=posix /,", - }, - { - name: "iouring", - rule: iouring1, - want: "io_uring sqpoll label=foo,", - }, - { - name: "signal", - rule: signal1, - want: "signal receive set=kill peer=firefox//&firejail-default,", - }, - { - name: "ptrace", - rule: ptrace1, - want: "ptrace read peer=nautilus,", - }, - { - name: "unix", - rule: unix1, - want: "unix (send receive) type=stream protocol=0 addr=none peer=(label=dbus-daemon, addr=@/tmp/dbus-AaKMpxzC4k),", - }, - { - name: "dbus", - rule: dbus1, - want: `dbus receive bus=session path=/org/gtk/vfs/metadata - interface=org.gtk.vfs.Metadata - member=Remove - peer=(name=:1.15, label=tracker-extract),`, - }, - { - name: "dbus-bind", - rule: &Dbus{Access: []string{"bind"}, Bus: "session", Name: "org.gnome.*"}, - want: `dbus bind bus=session name=org.gnome.*,`, - }, - { - name: "dbus-full", - rule: &Dbus{Bus: "accessibility"}, - want: `dbus bus=accessibility,`, - }, - { - name: "file", - rule: file1, - want: "/usr/share/poppler/cMap/Identity-H r,", - }, - { - name: "link", - rule: link3, - want: "owner link @{user_config_dirs}/kiorc -> @{user_config_dirs}/#3954,", - }, - { - name: "hat", - rule: hat1, - want: "hat user {\n}", - }, - } - for _, tt := range tests { + for _, tt := range testRule { t.Run(tt.name, func(t *testing.T) { - r := tt.rule - if got := r.String(); got != tt.want { - t.Errorf("Rule.String() = %v, want %v", got, tt.want) + if got := tt.rule.String(); got != tt.wString { + t.Errorf("Rule.String() = %v, want %v", got, tt.wString) } }) } } + +var ( + // Test cases for the Rule interface + testRule = []struct { + name string + fromLog func(map[string]string) Rule + log map[string]string + rule Rule + wValidErr bool + oLess Rule + wLessErr bool + oEqual Rule + wEqualErr bool + wString string + }{ + { + name: "comment", + rule: comment1, + oLess: comment2, + wLessErr: false, + oEqual: comment2, + wEqualErr: false, + wString: "#comment", + }, + { + name: "abi", + rule: abi1, + oLess: abi2, + wLessErr: false, + oEqual: abi1, + wEqualErr: true, + wString: "abi ,", + }, + { + name: "alias", + rule: alias1, + oLess: alias2, + wLessErr: true, + oEqual: alias2, + wEqualErr: false, + wString: "alias /mnt/usr -> /usr,", + }, + { + name: "include1", + rule: include1, + oLess: includeLocal1, + wLessErr: false, + oEqual: includeLocal1, + wEqualErr: false, + wString: "include ", + }, + { + name: "include2", + rule: include1, + oLess: include2, + wLessErr: false, + wString: "include ", + }, + { + name: "include-local", + rule: includeLocal1, + oLess: include1, + wLessErr: true, + wString: "include if exists ", + }, + { + name: "include/abs", + rule: &Include{Path: "/usr/share/apparmor.d/", IsMagic: false}, + wString: `include "/usr/share/apparmor.d/"`, + }, + { + name: "variable", + rule: variable1, + oLess: variable2, + wLessErr: true, + oEqual: variable1, + wEqualErr: true, + wString: "@{bin} = /{,usr/}{,s}bin", + }, + { + name: "all", + rule: all1, + oLess: all2, + wLessErr: false, + oEqual: all2, + wEqualErr: false, + wString: "all,", + }, + { + name: "rlimit", + rule: rlimit1, + oLess: rlimit2, + wLessErr: false, + oEqual: rlimit1, + wEqualErr: true, + wString: "set rlimit nproc <= 200,", + }, + { + name: "rlimit2", + rule: rlimit2, + oLess: rlimit2, + wLessErr: false, + wString: "set rlimit cpu <= 2,", + }, + { + name: "rlimit3", + rule: rlimit3, + oLess: rlimit1, + wLessErr: true, + + wString: "set rlimit nproc < 2,", + }, + { + name: "userns", + rule: userns1, + oLess: userns2, + wLessErr: true, + oEqual: userns1, + wEqualErr: true, + wString: "userns,", + }, + { + name: "capbability", + fromLog: newCapabilityFromLog, + log: capability1Log, + rule: capability1, + oLess: capability2, + wLessErr: true, + oEqual: capability1, + wEqualErr: true, + wString: "capability net_admin,", + }, + { + name: "capability/multi", + rule: &Capability{Names: []string{"dac_override", "dac_read_search"}}, + wString: "capability dac_override dac_read_search,", + }, + { + name: "capability/all", + rule: &Capability{}, + wString: "capability,", + }, + { + name: "network", + fromLog: newNetworkFromLog, + log: network1Log, + rule: network1, + wValidErr: true, + oLess: network2, + wLessErr: false, + oEqual: network1, + wEqualErr: true, + wString: "network netlink raw,", + }, + { + name: "mount", + fromLog: newMountFromLog, + log: mount1Log, + rule: mount1, + oEqual: mount2, + wEqualErr: false, + wString: "mount fstype=overlay overlay -> /var/lib/docker/overlay2/opaque-bug-check1209538631/merged/, # failed perms check", + }, + { + name: "remount", + rule: remount1, + oLess: remount2, + wLessErr: true, + oEqual: remount1, + wEqualErr: true, + wString: "remount /,", + }, + { + name: "umount", + fromLog: newUmountFromLog, + log: umount1Log, + rule: umount1, + oLess: umount2, + wLessErr: true, + oEqual: umount1, + wEqualErr: true, + wString: "umount /,", + }, + { + name: "pivot_root1", + fromLog: newPivotRootFromLog, + log: pivotroot1Log, + rule: pivotroot1, + oLess: pivotroot2, + wLessErr: false, + oEqual: pivotroot2, + wEqualErr: false, + wString: "pivot_root oldroot=@{run}/systemd/mount-rootfs/ @{run}/systemd/mount-rootfs/,", + }, + { + name: "pivot_root2", + rule: pivotroot1, + oLess: pivotroot3, + wLessErr: false, + wString: "pivot_root oldroot=@{run}/systemd/mount-rootfs/ @{run}/systemd/mount-rootfs/,", + }, + { + name: "change_profile1", + fromLog: newChangeProfileFromLog, + log: changeprofile1Log, + rule: changeprofile1, + oLess: changeprofile2, + wLessErr: false, + wString: "change_profile -> systemd-user,", + }, + { + name: "change_profile2", + rule: changeprofile2, + oLess: changeprofile3, + wLessErr: true, + oEqual: changeprofile1, + wEqualErr: false, + wString: "change_profile -> brwap,", + }, + { + name: "mqueue", + rule: mqueue1, + oLess: mqueue2, + wLessErr: true, + oEqual: mqueue1, + wEqualErr: true, + wString: "mqueue r type=posix /,", + }, + { + name: "iouring", + rule: iouring1, + oLess: iouring2, + wLessErr: false, + oEqual: iouring2, + wEqualErr: false, + wString: "io_uring sqpoll label=foo,", + }, + { + name: "signal", + fromLog: newSignalFromLog, + log: signal1Log, + rule: signal1, + oLess: signal2, + wLessErr: false, + oEqual: signal1, + wEqualErr: true, + wString: "signal receive set=kill peer=firefox//&firejail-default,", + }, + { + name: "ptrace/xdg-document-portal", + fromLog: newPtraceFromLog, + log: ptrace1Log, + rule: ptrace1, + oLess: ptrace2, + wLessErr: false, + oEqual: ptrace1, + wEqualErr: true, + wString: "ptrace read peer=nautilus,", + }, + { + name: "ptrace/snap-update-ns.firefox", + fromLog: newPtraceFromLog, + log: ptrace2Log, + rule: ptrace2, + oLess: ptrace1, + wLessErr: false, + oEqual: ptrace1, + wEqualErr: false, + wString: "ptrace readby peer=systemd-journald,", + }, + { + name: "unix", + fromLog: newUnixFromLog, + log: unix1Log, + rule: unix1, + oLess: unix1, + wLessErr: false, + oEqual: unix1, + wEqualErr: true, + wString: "unix (send receive) type=stream protocol=0 addr=none peer=(label=dbus-daemon, addr=@/tmp/dbus-AaKMpxzC4k),", + }, + { + name: "dbus", + fromLog: newDbusFromLog, + log: dbus1Log, + rule: dbus1, + oLess: dbus1, + wLessErr: false, + oEqual: dbus2, + wEqualErr: false, + wString: "dbus receive bus=session path=/org/gtk/vfs/metadata\n interface=org.gtk.vfs.Metadata\n member=Remove\n peer=(name=:1.15, label=tracker-extract),", + }, + { + name: "dbus2", + rule: dbus2, + oLess: dbus3, + wLessErr: false, + wString: "dbus bind bus=session name=org.gnome.evolution.dataserver.Sources5,", + }, + { + name: "dbus/bind", + rule: &Dbus{Access: []string{"bind"}, Bus: "session", Name: "org.gnome.*"}, + wString: `dbus bind bus=session name=org.gnome.*,`, + }, + { + name: "dbus/full", + rule: &Dbus{Bus: "accessibility"}, + wString: `dbus bus=accessibility,`, + }, + { + name: "file", + fromLog: newFileFromLog, + log: file1Log, + rule: file1, + oLess: file2, + wLessErr: true, + oEqual: file2, + wEqualErr: false, + wString: "/usr/share/poppler/cMap/Identity-H r,", + }, + { + name: "file/empty", + rule: &File{}, + oLess: &File{}, + wLessErr: false, + wString: " ,", + }, + { + name: "file/equal", + rule: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, + oLess: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, + wLessErr: false, + wString: "/usr/share/poppler/cMap/Identity-H ,", + }, + { + name: "file/owner", + rule: &File{Path: "/usr/share/poppler/cMap/Identity-H", Owner: true}, + oLess: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, + wLessErr: true, + wString: "owner /usr/share/poppler/cMap/Identity-H ,", + }, + { + name: "file/access", + rule: &File{Path: "/usr/share/poppler/cMap/Identity-H", Access: []string{"r"}}, + oLess: &File{Path: "/usr/share/poppler/cMap/Identity-H", Access: []string{"w"}}, + wLessErr: false, + wString: "/usr/share/poppler/cMap/Identity-H r,", + }, + { + name: "file/close", + rule: &File{Path: "/usr/share/poppler/cMap/"}, + oLess: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, + wLessErr: true, + wString: "/usr/share/poppler/cMap/ ,", + }, + { + name: "link", + fromLog: newLinkFromLog, + log: link1Log, + rule: link1, + oLess: link2, + wLessErr: true, + oEqual: link3, + wEqualErr: false, + wString: "link /tmp/mkinitcpio.QDWtza/early@{lib}/firmware/i915/dg1_dmc_ver2_02.bin.zst -> /tmp/mkinitcpio.QDWtza/root@{lib}/firmware/i915/dg1_dmc_ver2_02.bin.zst,", + }, + { + name: "link", + fromLog: newFileFromLog, + log: link3Log, + rule: link3, + wString: "owner link @{user_config_dirs}/kiorc -> @{user_config_dirs}/#3954,", + }, + { + name: "profile", + rule: profile1, + oLess: profile2, + wLessErr: true, + oEqual: profile1, + wEqualErr: true, + wString: "profile sudo {\n}", + }, + { + name: "hat", + rule: hat1, + oLess: hat2, + wLessErr: false, + oEqual: hat1, + wEqualErr: true, + wString: "hat user {\n}", + }, + } +)