Skip to content

Commit

Permalink
fcos/v1_6_exp: Add new sugar for Selinux Modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
yasminvalim committed Nov 10, 2023
1 parent 0a1b18e commit 48ed3ac
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 0 deletions.
5 changes: 5 additions & 0 deletions config/common/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ var (

// Kernel arguments
ErrGeneralKernelArgumentSupport = errors.New("kernel argument customization is not supported in this spec version")

// Selinux Module
ErrContentInvalid = errors.New("Content is empty, please provide content.")
ErrNameInvalid = errors.New("Name is empty, please provide a valid name.")
ErrFieldInvalid = errors.New("Please, provide valid information.")
)

type ErrUnmarshal struct {
Expand Down
10 changes: 10 additions & 0 deletions config/fcos/v1_6_exp/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Config struct {
base.Config `yaml:",inline"`
BootDevice BootDevice `yaml:"boot_device"`
Grub Grub `yaml:"grub"`
Selinux Selinux `yaml:"selinux"`
}

type BootDevice struct {
Expand Down Expand Up @@ -49,3 +50,12 @@ type GrubUser struct {
Name string `yaml:"name"`
PasswordHash *string `yaml:"password_hash"`
}

type Selinux struct {
Module []Module `yaml:"module"`
}

type Module struct {
Name string `yaml:"name"`
Content string `yaml:"content"`
}
73 changes: 73 additions & 0 deletions config/fcos/v1_6_exp/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package v1_6_exp

import (
"fmt"
"os/exec"
"strings"

baseutil "github.com/coreos/butane/base/util"
Expand Down Expand Up @@ -89,6 +90,13 @@ func (c Config) ToIgn3_5Unvalidated(options common.TranslateOptions) (types.Conf
retConfig, ts := baseutil.MergeTranslatedConfigs(retp, tsp, ret, ts)
ret = retConfig.(types.Config)
r.Merge(rp)

// Clean this as it needs to not be so confusing
retr, trs, rr := c.handleSelinux(options)
returnConfig, ts := baseutil.MergeTranslatedConfigs(retr, trs, ret, ts)
ret = returnConfig.(types.Config)
r.Merge(rr)

return ret, ts, r
}

Expand Down Expand Up @@ -367,3 +375,68 @@ func buildGrubConfig(gb Grub) string {
superUserCmd := fmt.Sprintf("set superusers=\"%s\"\n", strings.Join(allUsers, " "))
return "# Generated by Butane\n\n" + superUserCmd + strings.Join(cmds, "\n") + "\n"
}

func (c Config) handleSelinux(options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) {
rendered := types.Config{}
ts := translate.NewTranslationSet("yaml", "json")
var r report.Report

for i, module := range c.Selinux.Module {
yamlPath := path.New("yaml", "selinux", "module", i)
if module.Name != "" && module.Content != "" {
rendered = processModule(rendered, module, options, ts, r, yamlPath)
} else {
r.AddOnWarn(path.New("yaml", "selinux", "module", len(rendered.Storage.Files)), common.ErrFieldInvalid)
}
}

if len(rendered.Storage.Files) != 0 {
rendered.Storage.Filesystems = append(rendered.Storage.Filesystems,
types.Filesystem{
Device: "/dev/disk/by-label/boot",
Format: util.StrToPtr("ext4"),
Path: util.StrToPtr("/boot"),
})
ts.AddFromCommonSource(path.New("yaml", "selinux", "module"), path.New("json", "storage"), rendered.Storage)

}

return rendered, ts, r
}

func processModule(rendered types.Config, module Module, options common.TranslateOptions, ts translate.TranslationSet, r report.Report, yamlPath path.ContextPath) types.Config {
src, compression, err := baseutil.MakeDataURL([]byte(module.Content), nil, !options.NoResourceAutoCompression)
if err != nil {
r.AddOnError(yamlPath, err)
return rendered
}
filePath := fmt.Sprintf("/etc/selinux/targeted/modules/active/extra/%s.cil", module.Name)

rendered.Storage.Files = append(rendered.Storage.Files,
types.File{
Node: types.Node{
Path: filePath,
},
FileEmbedded1: types.FileEmbedded1{
Append: []types.Resource{
{
Source: util.StrToPtr(src),
Compression: compression,
},
},
},
})

commandToExecute := "semodule -i"
cmd := exec.Command(commandToExecute, filePath)
err = cmd.Run()
if err != nil {
fmt.Printf("Error running semodule %v", module.Name)
}

fmt.Printf("SELinux module file imported successfully\n")

ts.AddFromCommonSource(yamlPath, path.New("json", "storage"), rendered.Storage)

return rendered
}
82 changes: 82 additions & 0 deletions config/fcos/v1_6_exp/translate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1637,3 +1637,85 @@ func TestTranslateGrub(t *testing.T) {
})
}
}

func TestTranslateSelinux(t *testing.T) {
translations := []translate.Translation{
{From: path.New("yaml", "version"), To: path.New("json", "ignition", "version")},
{From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "filesystems")},
{From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "filesystems", 0)},
{From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "filesystems", 0, "path")},
{From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "filesystems", 0, "device")},
{From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "filesystems", 0, "format")},
{From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "storage")},
{From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "storage", "files")},
{From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "storage", "files", 0)},
{From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "storage", "files", 0, "path")},
{From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "storage", "files", 0, "append")},
{From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "storage", "files", 0, "append", 0)},
{From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "storage", "files", 0, "append", 0, "source")},
{From: path.New("yaml", "selinux", "module", .0), To: path.New("json", "storage", "files", 0, "append", 0, "compression")},
}
tests := []struct {
in Config
out types.Config
exceptions []translate.Translation
report report.Report
}{
// config with one module
{
Config{
Selinux: Selinux{
Module: []Module{
{
Name: "some_name",
Content: "some content here",
},
},
},
},
types.Config{
Ignition: types.Ignition{
Version: "3.5.0-experimental",
},
Storage: types.Storage{
Filesystems: []types.Filesystem{
{
Device: "/dev/disk/by-label/boot",
Format: util.StrToPtr("ext4"),
Path: util.StrToPtr("/boot"),
},
},
Files: []types.File{
{
Node: types.Node{
Path: "/etc/selinux/targeted/modules/active/extra/some_name.cil",
},
FileEmbedded1: types.FileEmbedded1{
Append: []types.Resource{
{
Source: util.StrToPtr("data:,some%20content%20here"),
Compression: util.StrToPtr(""),
},
},
},
},
},
},
},
translations,
report.Report{},
},
}

for i, test := range tests {
t.Run(fmt.Sprintf("translate %d", i), func(t *testing.T) {
actual, translations, r := test.in.ToIgn3_5Unvalidated(common.TranslateOptions{})
r = confutil.TranslateReportPaths(r, translations)
baseutil.VerifyReport(t, test.in, r)
assert.Equal(t, test.out, actual, "translation mismatch")
assert.Equal(t, test.report, r, "report mismatch")
baseutil.VerifyTranslations(t, translations, test.exceptions)
assert.NoError(t, translations.DebugVerifyCoverage(actual), "incomplete TranslationSet coverage")
})
}
}
11 changes: 11 additions & 0 deletions config/fcos/v1_6_exp/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,14 @@ func (user GrubUser) Validate(c path.ContextPath) (r report.Report) {
}
return
}

func (m Module) Validate(c path.ContextPath) (r report.Report) {
if m.Name != "" && m.Content == "" {
r.AddOnError(c.Append("content"), common.ErrContentInvalid)
}

if m.Content != "" && m.Name == "" {
r.AddOnError(c.Append("name"), common.ErrNameInvalid)
}
return r
}
52 changes: 52 additions & 0 deletions config/fcos/v1_6_exp/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,55 @@ func TestValidateConfig(t *testing.T) {
})
}
}

func TestValidateModule(t *testing.T) {
tests := []struct {
in Module
out error
errPath path.ContextPath
}{
{
// content is empty, path is specified
in: Module{
Content: "",
Name: "some name",
},
out: common.ErrContentInvalid,
errPath: path.New("yaml", "content"),
},
{
// name is empty, content is specified
in: Module{
Name: "",
Content: "some content",
},
out: common.ErrNameInvalid,
errPath: path.New("yaml", "name"),
},
{
// name and content are empty
in: Module{},
out: nil,
errPath: path.New("yaml"),
},
{
// name and content are specified
in: Module{
Content: "some content",
Name: "some name",
},
out: nil,
errPath: path.New("yaml"),
},
}

for i, test := range tests {
t.Run(fmt.Sprintf("validate %d", i), func(t *testing.T) {
actual := test.in.Validate(path.New("yaml"))
baseutil.VerifyReport(t, test.in, actual)
expected := report.Report{}
expected.AddOnError(test.errPath, test.out)
assert.Equal(t, expected, actual, "bad report")
})
}
}

0 comments on commit 48ed3ac

Please sign in to comment.