Merge branch 'feat/aa'
Improve go apparmor lib. * aa: (62 commits) feat(aa): handle appending value to defined variables. chore(aa): cosmetic. fix: userspace prebuild test. chore: cleanup unit test. feat(aa): improve log conversion. feat(aa): move conversion function to its own file & add unit tests. fix: go linter issue & not defined variables. tests(aa): improve aa unit tests. tests(aa): improve rules unit tests. feat(aa): ensure the prebuild jobs are working. feat(aa): add more unit tests. chore(aa): cleanup. feat(aa): Move sort, merge and format methods to the rules interface. feat(aa): add the hat template. feat(aa): add the Kind struct to manage aa rules. feat(aa): cleanup rules methods. feat(aa): add function to resolve include preamble. feat(aa): updaqte mount flags order. feat(aa): update default tunable selection. feat(aa): parse apparmor preamble files. ...
This commit is contained in:
commit
89abbae6bd
90 changed files with 4995 additions and 2012 deletions
|
|
@ -30,6 +30,6 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
func (b ABI3) Apply(profile string) string {
|
||||
return regAbi4To3.Replace(profile)
|
||||
func (b ABI3) Apply(opt *Option, profile string) (string, error) {
|
||||
return regAbi4To3.Replace(profile), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
func (b Complain) Apply(profile string) string {
|
||||
func (b Complain) Apply(opt *Option, profile string) (string, error) {
|
||||
flags := []string{}
|
||||
matches := regFlags.FindStringSubmatch(profile)
|
||||
if len(matches) != 0 {
|
||||
flags = strings.Split(matches[1], ",")
|
||||
if slices.Contains(flags, "complain") {
|
||||
return profile
|
||||
return profile, nil
|
||||
}
|
||||
}
|
||||
flags = append(flags, "complain")
|
||||
|
|
@ -44,5 +44,5 @@ func (b Complain) Apply(profile string) string {
|
|||
|
||||
// Remove all flags definition, then set manifest' flags
|
||||
profile = regFlags.ReplaceAllLiteralString(profile, "")
|
||||
return regProfileHeader.ReplaceAllLiteralString(profile, strFlags)
|
||||
return regProfileHeader.ReplaceAllLiteralString(profile, strFlags), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package builder
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/roddhjav/apparmor.d/pkg/paths"
|
||||
"github.com/roddhjav/apparmor.d/pkg/prebuild/cfg"
|
||||
)
|
||||
|
||||
|
|
@ -21,7 +22,20 @@ var (
|
|||
// Main directive interface
|
||||
type Builder interface {
|
||||
cfg.BaseInterface
|
||||
Apply(profile string) string
|
||||
Apply(opt *Option, profile string) (string, error)
|
||||
}
|
||||
|
||||
// Builder options
|
||||
type Option struct {
|
||||
Name string
|
||||
File *paths.Path
|
||||
}
|
||||
|
||||
func NewOption(file *paths.Path) *Option {
|
||||
return &Option{
|
||||
Name: file.Base(),
|
||||
File: file,
|
||||
}
|
||||
}
|
||||
|
||||
func Register(names ...string) {
|
||||
|
|
@ -37,3 +51,15 @@ func Register(names ...string) {
|
|||
func RegisterBuilder(d Builder) {
|
||||
Builders[d.Name()] = d
|
||||
}
|
||||
|
||||
func Run(file *paths.Path, profile string) (string, error) {
|
||||
var err error
|
||||
opt := NewOption(file)
|
||||
for _, b := range Builds {
|
||||
profile, err = b.Apply(opt, profile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s %s: %w", b.Name(), opt.File, err)
|
||||
}
|
||||
}
|
||||
return profile, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ package builder
|
|||
import (
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/roddhjav/apparmor.d/pkg/prebuild/cfg"
|
||||
)
|
||||
|
||||
func TestBuilder_Apply(t *testing.T) {
|
||||
|
|
@ -15,6 +17,7 @@ func TestBuilder_Apply(t *testing.T) {
|
|||
b Builder
|
||||
profile string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "abi3",
|
||||
|
|
@ -215,7 +218,7 @@ func TestBuilder_Apply(t *testing.T) {
|
|||
}`,
|
||||
},
|
||||
{
|
||||
name: "userspace-1",
|
||||
name: "userspace-2",
|
||||
b: Builders["userspace"],
|
||||
profile: `
|
||||
profile foo /usr/bin/foo {
|
||||
|
|
@ -237,7 +240,13 @@ func TestBuilder_Apply(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.b.Apply(tt.profile); got != tt.want {
|
||||
opt := &Option{File: cfg.RootApparmord.Join(tt.name)}
|
||||
got, err := tt.b.Apply(opt, tt.profile)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Builder.Apply() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Builder.Apply() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
|
@ -257,7 +266,6 @@ func TestRegister(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
Register(tt.names...)
|
||||
for _, name := range tt.names {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,6 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
func (b Dev) Apply(profile string) string {
|
||||
return regDev.Replace(profile)
|
||||
func (b Dev) Apply(opt *Option, profile string) (string, error) {
|
||||
return regDev.Replace(profile), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,16 +24,16 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
func (b Enforce) Apply(profile string) string {
|
||||
func (b Enforce) Apply(opt *Option, profile string) (string, error) {
|
||||
matches := regFlags.FindStringSubmatch(profile)
|
||||
if len(matches) == 0 {
|
||||
return profile
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
flags := strings.Split(matches[1], ",")
|
||||
idx := slices.Index(flags, "complain")
|
||||
if idx == -1 {
|
||||
return profile
|
||||
return profile, nil
|
||||
}
|
||||
flags = slices.Delete(flags, idx, idx+1)
|
||||
strFlags := "{"
|
||||
|
|
@ -43,5 +43,5 @@ func (b Enforce) Apply(profile string) string {
|
|||
|
||||
// Remove all flags definition, then set new flags
|
||||
profile = regFlags.ReplaceAllLiteralString(profile, "")
|
||||
return regProfileHeader.ReplaceAllLiteralString(profile, strFlags)
|
||||
return regProfileHeader.ReplaceAllLiteralString(profile, strFlags), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,6 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
func (b FullSystemPolicy) Apply(profile string) string {
|
||||
return regFullSystemPolicy.Replace(profile)
|
||||
func (b FullSystemPolicy) Apply(opt *Option, profile string) (string, error) {
|
||||
return regFullSystemPolicy.Replace(profile), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,15 +29,26 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
func (b Userspace) Apply(profile string) string {
|
||||
p := aa.DefaultTunables()
|
||||
p.ParseVariables(profile)
|
||||
p.ResolveAttachments()
|
||||
att := p.NestAttachments()
|
||||
func (b Userspace) Apply(opt *Option, profile string) (string, error) {
|
||||
if ok, _ := opt.File.IsInsideDir(cfg.RootApparmord.Join("abstractions")); ok {
|
||||
return profile, nil
|
||||
}
|
||||
if ok, _ := opt.File.IsInsideDir(cfg.RootApparmord.Join("tunables")); ok {
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
f := aa.DefaultTunables()
|
||||
if err := f.Parse(profile); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := f.Resolve(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
att := f.GetDefaultProfile().GetAttachments()
|
||||
matches := regAttachments.FindAllString(profile, -1)
|
||||
if len(matches) > 0 {
|
||||
strheader := strings.Replace(matches[0], "@{exec_path}", att, -1)
|
||||
return regAttachments.ReplaceAllLiteralString(profile, strheader)
|
||||
return regAttachments.ReplaceAllLiteralString(profile, strheader), nil
|
||||
}
|
||||
return profile
|
||||
return profile, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ var (
|
|||
// Main directive interface
|
||||
type Directive interface {
|
||||
cfg.BaseInterface
|
||||
Apply(opt *Option, profile string) string
|
||||
Apply(opt *Option, profile string) (string, error)
|
||||
}
|
||||
|
||||
// Directive options
|
||||
|
|
@ -72,14 +72,18 @@ func RegisterDirective(d Directive) {
|
|||
Directives[d.Name()] = d
|
||||
}
|
||||
|
||||
func Run(file *paths.Path, profile string) string {
|
||||
func Run(file *paths.Path, profile string) (string, error) {
|
||||
var err error
|
||||
for _, match := range regDirective.FindAllStringSubmatch(profile, -1) {
|
||||
opt := NewOption(file, match)
|
||||
drtv, ok := Directives[opt.Name]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Unknown directive: %s", opt.Name))
|
||||
return "", fmt.Errorf("Unknown directive '%s' in %s", opt.Name, opt.File)
|
||||
}
|
||||
profile, err = drtv.Apply(opt, profile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s %s: %w", drtv.Name(), opt.File, err)
|
||||
}
|
||||
profile = drtv.Apply(opt, profile)
|
||||
}
|
||||
return profile
|
||||
return profile, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ func TestRun(t *testing.T) {
|
|||
file *paths.Path
|
||||
profile string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "none",
|
||||
|
|
@ -86,7 +87,12 @@ func TestRun(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := Run(tt.file, tt.profile); got != tt.want {
|
||||
got, err := Run(tt.file, tt.profile)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Run() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Run() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -50,41 +50,47 @@ func setInterfaces(rules map[string]string) []string {
|
|||
return interfaces
|
||||
}
|
||||
|
||||
func (d Dbus) Apply(opt *Option, profile string) string {
|
||||
var p *aa.AppArmorProfile
|
||||
func (d Dbus) Apply(opt *Option, profile string) (string, error) {
|
||||
var r aa.Rules
|
||||
|
||||
action := d.sanityCheck(opt)
|
||||
action, err := d.sanityCheck(opt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch action {
|
||||
case "own":
|
||||
p = d.own(opt.ArgMap)
|
||||
r = d.own(opt.ArgMap)
|
||||
case "talk":
|
||||
p = d.talk(opt.ArgMap)
|
||||
r = d.talk(opt.ArgMap)
|
||||
}
|
||||
|
||||
generatedDbus := p.String()
|
||||
aa.IndentationLevel = strings.Count(
|
||||
strings.SplitN(opt.Raw, Keyword, 1)[0], aa.Indentation,
|
||||
)
|
||||
generatedDbus := r.String()
|
||||
lenDbus := len(generatedDbus)
|
||||
generatedDbus = generatedDbus[:lenDbus-1]
|
||||
profile = strings.Replace(profile, opt.Raw, generatedDbus, -1)
|
||||
return profile
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
func (d Dbus) sanityCheck(opt *Option) string {
|
||||
func (d Dbus) sanityCheck(opt *Option) (string, error) {
|
||||
if len(opt.ArgList) < 1 {
|
||||
panic(fmt.Sprintf("Unknown dbus action: %s in %s", opt.Name, opt.File))
|
||||
return "", fmt.Errorf("Unknown dbus action: %s in %s", opt.Name, opt.File)
|
||||
}
|
||||
action := opt.ArgList[0]
|
||||
if action != "own" && action != "talk" {
|
||||
panic(fmt.Sprintf("Unknown dbus action: %s in %s", opt.Name, opt.File))
|
||||
return "", fmt.Errorf("Unknown dbus action: %s in %s", opt.Name, opt.File)
|
||||
}
|
||||
|
||||
if _, present := opt.ArgMap["name"]; !present {
|
||||
panic(fmt.Sprintf("Missing name for 'dbus: %s' in %s", action, opt.File))
|
||||
return "", fmt.Errorf("Missing name for 'dbus: %s' in %s", action, opt.File)
|
||||
}
|
||||
if _, present := opt.ArgMap["bus"]; !present {
|
||||
panic(fmt.Sprintf("Missing bus for '%s' in %s", opt.ArgMap["name"], opt.File))
|
||||
return "", fmt.Errorf("Missing bus for '%s' in %s", opt.ArgMap["name"], opt.File)
|
||||
}
|
||||
if _, present := opt.ArgMap["label"]; !present && action == "talk" {
|
||||
panic(fmt.Sprintf("Missing label for '%s' in %s", opt.ArgMap["name"], opt.File))
|
||||
return "", fmt.Errorf("Missing label for '%s' in %s", opt.ArgMap["name"], opt.File)
|
||||
}
|
||||
|
||||
// Set default values
|
||||
|
|
@ -92,66 +98,66 @@ func (d Dbus) sanityCheck(opt *Option) string {
|
|||
opt.ArgMap["path"] = "/" + strings.Replace(opt.ArgMap["name"], ".", "/", -1) + "{,/**}"
|
||||
}
|
||||
opt.ArgMap["name"] += "{,.*}"
|
||||
return action
|
||||
return action, nil
|
||||
}
|
||||
|
||||
func (d Dbus) own(rules map[string]string) *aa.AppArmorProfile {
|
||||
func (d Dbus) own(rules map[string]string) aa.Rules {
|
||||
interfaces := setInterfaces(rules)
|
||||
p := &aa.AppArmorProfile{}
|
||||
p.Rules = append(p.Rules, &aa.Dbus{
|
||||
Access: "bind", Bus: rules["bus"], Name: rules["name"],
|
||||
res := aa.Rules{}
|
||||
res = append(res, &aa.Dbus{
|
||||
Access: []string{"bind"}, Bus: rules["bus"], Name: rules["name"],
|
||||
})
|
||||
for _, iface := range interfaces {
|
||||
p.Rules = append(p.Rules, &aa.Dbus{
|
||||
Access: "receive",
|
||||
res = append(res, &aa.Dbus{
|
||||
Access: []string{"receive"},
|
||||
Bus: rules["bus"],
|
||||
Path: rules["path"],
|
||||
Interface: iface,
|
||||
Name: `":1.@{int}"`,
|
||||
PeerName: `":1.@{int}"`,
|
||||
})
|
||||
}
|
||||
for _, iface := range interfaces {
|
||||
p.Rules = append(p.Rules, &aa.Dbus{
|
||||
Access: "send",
|
||||
res = append(res, &aa.Dbus{
|
||||
Access: []string{"send"},
|
||||
Bus: rules["bus"],
|
||||
Path: rules["path"],
|
||||
Interface: iface,
|
||||
Name: `"{:1.@{int},org.freedesktop.DBus}"`,
|
||||
PeerName: `"{:1.@{int},org.freedesktop.DBus}"`,
|
||||
})
|
||||
}
|
||||
p.Rules = append(p.Rules, &aa.Dbus{
|
||||
Access: "receive",
|
||||
res = append(res, &aa.Dbus{
|
||||
Access: []string{"receive"},
|
||||
Bus: rules["bus"],
|
||||
Path: rules["path"],
|
||||
Interface: "org.freedesktop.DBus.Introspectable",
|
||||
Member: "Introspect",
|
||||
Name: `":1.@{int}"`,
|
||||
PeerName: `":1.@{int}"`,
|
||||
})
|
||||
return p
|
||||
return res
|
||||
}
|
||||
|
||||
func (d Dbus) talk(rules map[string]string) *aa.AppArmorProfile {
|
||||
func (d Dbus) talk(rules map[string]string) aa.Rules {
|
||||
interfaces := setInterfaces(rules)
|
||||
p := &aa.AppArmorProfile{}
|
||||
res := aa.Rules{}
|
||||
for _, iface := range interfaces {
|
||||
p.Rules = append(p.Rules, &aa.Dbus{
|
||||
Access: "send",
|
||||
res = append(res, &aa.Dbus{
|
||||
Access: []string{"send"},
|
||||
Bus: rules["bus"],
|
||||
Path: rules["path"],
|
||||
Interface: iface,
|
||||
Name: `"{:1.@{int},` + rules["name"] + `}"`,
|
||||
Label: rules["label"],
|
||||
PeerName: `"{:1.@{int},` + rules["name"] + `}"`,
|
||||
PeerLabel: rules["label"],
|
||||
})
|
||||
}
|
||||
for _, iface := range interfaces {
|
||||
p.Rules = append(p.Rules, &aa.Dbus{
|
||||
Access: "receive",
|
||||
res = append(res, &aa.Dbus{
|
||||
Access: []string{"receive"},
|
||||
Bus: rules["bus"],
|
||||
Path: rules["path"],
|
||||
Interface: iface,
|
||||
Name: `"{:1.@{int},` + rules["name"] + `}"`,
|
||||
Label: rules["label"],
|
||||
PeerName: `"{:1.@{int},` + rules["name"] + `}"`,
|
||||
PeerLabel: rules["label"],
|
||||
})
|
||||
}
|
||||
return p
|
||||
return res
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ func TestDbus_Apply(t *testing.T) {
|
|||
opt *Option
|
||||
profile string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "own",
|
||||
|
|
@ -137,7 +138,12 @@ func TestDbus_Apply(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := Directives["dbus"].Apply(tt.opt, tt.profile); got != tt.want {
|
||||
got, err := Directives["dbus"].Apply(tt.opt, tt.profile)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Dbus.Apply() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Dbus.Apply() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Copyright (C) 2021-2024 Alexandre Pujol <alexandre@pujol.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
// TODO: Local variables in profile header need to be resolved
|
||||
|
||||
package directive
|
||||
|
||||
import (
|
||||
|
|
@ -27,7 +29,7 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
func (d Exec) Apply(opt *Option, profile string) string {
|
||||
func (d Exec) Apply(opt *Option, profileRaw string) (string, error) {
|
||||
transition := "Px"
|
||||
transitions := []string{"P", "U", "p", "u", "PU", "pu"}
|
||||
t := opt.ArgList[0]
|
||||
|
|
@ -36,26 +38,34 @@ func (d Exec) Apply(opt *Option, profile string) string {
|
|||
delete(opt.ArgMap, t)
|
||||
}
|
||||
|
||||
p := &aa.AppArmorProfile{}
|
||||
rules := aa.Rules{}
|
||||
for name := range opt.ArgMap {
|
||||
profiletoTransition := util.MustReadFile(cfg.RootApparmord.Join(name))
|
||||
dstProfile := aa.DefaultTunables()
|
||||
dstProfile.ParseVariables(profiletoTransition)
|
||||
for _, variable := range dstProfile.Variables {
|
||||
if err := dstProfile.Parse(profiletoTransition); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := dstProfile.Resolve(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, variable := range dstProfile.Preamble.GetVariables() {
|
||||
if variable.Name == "exec_path" {
|
||||
for _, v := range variable.Values {
|
||||
p.Rules = append(p.Rules, &aa.File{
|
||||
rules = append(rules, &aa.File{
|
||||
Path: v,
|
||||
Access: transition,
|
||||
Access: []string{transition},
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
p.Sort()
|
||||
rules := p.String()
|
||||
lenRules := len(rules)
|
||||
rules = rules[:lenRules-1]
|
||||
return strings.Replace(profile, opt.Raw, rules, -1)
|
||||
|
||||
aa.IndentationLevel = strings.Count(
|
||||
strings.SplitN(opt.Raw, Keyword, 1)[0], aa.Indentation,
|
||||
)
|
||||
rules = rules.Sort()
|
||||
new := rules.String()
|
||||
new = new[:len(new)-1]
|
||||
return strings.Replace(profileRaw, opt.Raw, new, -1), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ func TestExec_Apply(t *testing.T) {
|
|||
opt *Option
|
||||
profile string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "exec",
|
||||
|
|
@ -30,8 +31,8 @@ func TestExec_Apply(t *testing.T) {
|
|||
Raw: " #aa:exec DiscoverNotifier",
|
||||
},
|
||||
profile: ` #aa:exec DiscoverNotifier`,
|
||||
want: ` @{lib}/@{multiarch}/{,libexec/}DiscoverNotifier Px,
|
||||
@{lib}/DiscoverNotifier Px,`,
|
||||
want: ` /{,usr/}lib{,exec,32,64}/*-linux-gnu*/{,libexec/}DiscoverNotifier Px,
|
||||
/{,usr/}lib{,exec,32,64}/DiscoverNotifier Px,`,
|
||||
},
|
||||
{
|
||||
name: "exec-unconfined",
|
||||
|
|
@ -44,15 +45,20 @@ func TestExec_Apply(t *testing.T) {
|
|||
Raw: " #aa:exec U polkit-agent-helper",
|
||||
},
|
||||
profile: ` #aa:exec U polkit-agent-helper`,
|
||||
want: ` @{lib}/polkit-[0-9]/polkit-agent-helper-[0-9] Ux,
|
||||
@{lib}/polkit-agent-helper-[0-9] Ux,`,
|
||||
want: ` /{,usr/}lib{,exec,32,64}/polkit-[0-9]/polkit-agent-helper-[0-9] Ux,
|
||||
/{,usr/}lib{,exec,32,64}/polkit-agent-helper-[0-9] Ux,`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg.RootApparmord = tt.rootApparmord
|
||||
if got := Directives["exec"].Apply(tt.opt, tt.profile); got != tt.want {
|
||||
t.Errorf("Exec.Apply() = %v, want %v", got, tt.want)
|
||||
got, err := Directives["exec"].Apply(tt.opt, tt.profile)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Exec.Apply() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Exec.Apply() = |%v|, want |%v|", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,12 +41,12 @@ func filterRuleForUs(opt *Option) bool {
|
|||
return slices.Contains(opt.ArgList, cfg.Distribution) || slices.Contains(opt.ArgList, cfg.Family)
|
||||
}
|
||||
|
||||
func filter(only bool, opt *Option, profile string) string {
|
||||
func filter(only bool, opt *Option, profile string) (string, error) {
|
||||
if only && filterRuleForUs(opt) {
|
||||
return opt.Clean(profile)
|
||||
return opt.Clean(profile), nil
|
||||
}
|
||||
if !only && !filterRuleForUs(opt) {
|
||||
return opt.Clean(profile)
|
||||
return opt.Clean(profile), nil
|
||||
}
|
||||
|
||||
inline := true
|
||||
|
|
@ -64,13 +64,13 @@ func filter(only bool, opt *Option, profile string) string {
|
|||
regRemoveParagraph := regexp.MustCompile(`(?s)` + opt.Raw + `\n.*?\n\n`)
|
||||
profile = regRemoveParagraph.ReplaceAllString(profile, "")
|
||||
}
|
||||
return profile
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
func (d FilterOnly) Apply(opt *Option, profile string) string {
|
||||
func (d FilterOnly) Apply(opt *Option, profile string) (string, error) {
|
||||
return filter(true, opt, profile)
|
||||
}
|
||||
|
||||
func (d FilterExclude) Apply(opt *Option, profile string) string {
|
||||
func (d FilterExclude) Apply(opt *Option, profile string) (string, error) {
|
||||
return filter(false, opt, profile)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ func TestFilterOnly_Apply(t *testing.T) {
|
|||
opt *Option
|
||||
profile string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "inline",
|
||||
|
|
@ -79,7 +80,12 @@ func TestFilterOnly_Apply(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg.Distribution = tt.dist
|
||||
cfg.Family = tt.family
|
||||
if got := Directives["only"].Apply(tt.opt, tt.profile); got != tt.want {
|
||||
got, err := Directives["only"].Apply(tt.opt, tt.profile)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("FilterOnly.Apply() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("FilterOnly.Apply() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
|
@ -94,6 +100,7 @@ func TestFilterExclude_Apply(t *testing.T) {
|
|||
opt *Option
|
||||
profile string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "inline",
|
||||
|
|
@ -128,7 +135,12 @@ func TestFilterExclude_Apply(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg.Distribution = tt.dist
|
||||
cfg.Family = tt.family
|
||||
if got := Directives["exclude"].Apply(tt.opt, tt.profile); got != tt.want {
|
||||
got, err := Directives["exclude"].Apply(tt.opt, tt.profile)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("FilterExclude.Apply() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("FilterExclude.Apply() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -38,13 +38,13 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
func (s Stack) Apply(opt *Option, profile string) string {
|
||||
func (s Stack) Apply(opt *Option, profile string) (string, error) {
|
||||
res := ""
|
||||
for name := range opt.ArgMap {
|
||||
stackedProfile := util.MustReadFile(cfg.RootApparmord.Join(name))
|
||||
m := regRules.FindStringSubmatch(stackedProfile)
|
||||
if len(m) < 2 {
|
||||
panic(fmt.Sprintf("No profile found in %s", name))
|
||||
return "", fmt.Errorf("No profile found in %s", name)
|
||||
}
|
||||
stackedRules := m[1]
|
||||
stackedRules = regCleanStakedRules.Replace(stackedRules)
|
||||
|
|
@ -54,9 +54,9 @@ func (s Stack) Apply(opt *Option, profile string) string {
|
|||
// Insert the stacked profile at the end of the current profile, remove the stack directive
|
||||
m := regEndOfRules.FindStringSubmatch(profile)
|
||||
if len(m) <= 1 {
|
||||
panic(fmt.Sprintf("No end of rules found in %s", opt.File))
|
||||
return "", fmt.Errorf("No end of rules found in %s", opt.File)
|
||||
}
|
||||
profile = strings.Replace(profile, m[0], res+m[0], -1)
|
||||
profile = strings.Replace(profile, opt.Raw, "", -1)
|
||||
return profile
|
||||
return profile, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ func TestStack_Apply(t *testing.T) {
|
|||
opt *Option
|
||||
profile string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "stack",
|
||||
|
|
@ -68,7 +69,12 @@ profile parent @{exec_path} {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg.RootApparmord = tt.rootApparmord
|
||||
if got := Directives["stack"].Apply(tt.opt, tt.profile); got != tt.want {
|
||||
got, err := Directives["stack"].Apply(tt.opt, tt.profile)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Stack.Apply() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Stack.Apply() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -83,10 +83,14 @@ func Build() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, b := range builder.Builds {
|
||||
profile = b.Apply(profile)
|
||||
profile, err = builder.Run(file, profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
profile, err = directive.Run(file, profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
profile = directive.Run(file, profile)
|
||||
if err := file.WriteFile([]byte(profile)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue