From 3cf4dd3eaa9dcc9d13a556b36cb5b7b9f18b99ce Mon Sep 17 00:00:00 2001 From: Yasmin Valim Date: Fri, 8 Sep 2023 17:49:15 -0300 Subject: [PATCH 1/4] fcos/v1_6_exp: Add new sugar for Selinux Modules. --- config/common/errors.go | 4 ++ config/fcos/v1_6_exp/schema.go | 10 +++ config/fcos/v1_6_exp/translate.go | 78 +++++++++++++++++++-- config/fcos/v1_6_exp/translate_test.go | 94 ++++++++++++++++++++++++++ config/fcos/v1_6_exp/validate.go | 17 +++++ config/fcos/v1_6_exp/validate_test.go | 46 +++++++++++++ 6 files changed, 244 insertions(+), 5 deletions(-) diff --git a/config/common/errors.go b/config/common/errors.go index 922111ab..ea238e68 100644 --- a/config/common/errors.go +++ b/config/common/errors.go @@ -96,6 +96,10 @@ var ( // Kernel arguments ErrGeneralKernelArgumentSupport = errors.New("kernel argument customization is not supported in this spec version") + + // Selinux Module + ErrSelinuxContentNotSpecified = errors.New("field \"content\" is required") + ErrSelinuxNameNotSpecified = errors.New("field \"name\" is required") ) type ErrUnmarshal struct { diff --git a/config/fcos/v1_6_exp/schema.go b/config/fcos/v1_6_exp/schema.go index 52cdfb43..ea5bc8d6 100644 --- a/config/fcos/v1_6_exp/schema.go +++ b/config/fcos/v1_6_exp/schema.go @@ -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 { @@ -50,3 +51,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"` +} diff --git a/config/fcos/v1_6_exp/translate.go b/config/fcos/v1_6_exp/translate.go index a7c0a679..e297ead4 100644 --- a/config/fcos/v1_6_exp/translate.go +++ b/config/fcos/v1_6_exp/translate.go @@ -85,11 +85,8 @@ func (c Config) ToIgn3_5Unvalidated(options common.TranslateOptions) (types.Conf } } - retp, tsp, rp := c.handleUserGrubCfg(options) - retConfig, ts := baseutil.MergeTranslatedConfigs(retp, tsp, ret, ts) - ret = retConfig.(types.Config) - r.Merge(rp) - return ret, ts, r + return mergeAndHandleOptions(c, ret, ts, r, options) + } // ToIgn3_5 translates the config to an Ignition config. It returns a @@ -108,6 +105,20 @@ func ToIgn3_5Bytes(input []byte, options common.TranslateBytesOptions) ([]byte, return cutil.TranslateBytes(input, &Config{}, "ToIgn3_5", options) } +func mergeAndHandleOptions(c Config, ret types.Config, ts translate.TranslationSet, r report.Report, options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) { + retp, tsp, rp := c.handleUserGrubCfg(options) + retConfig, ts := baseutil.MergeTranslatedConfigs(retp, tsp, ret, ts) + ret = retConfig.(types.Config) + r.Merge(rp) + + 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 +} + func (c Config) processBootDevice(config *types.Config, ts *translate.TranslationSet, options common.TranslateOptions) report.Report { var rendered types.Config renderedTranslations := translate.NewTranslationSet("yaml", "json") @@ -376,3 +387,60 @@ 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 _, module := range c.Selinux.Module { + rendered = processModule(rendered, module, options, ts, r, path.New("yaml", "selinux", "module")) + } + 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 + } + + // Create module file + modulePath := 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: modulePath, + }, + FileEmbedded1: types.FileEmbedded1{ + Append: []types.Resource{ + { + Source: util.StrToPtr(src), + Compression: compression, + }, + }, + }, + }) + ts.AddFromCommonSource(yamlPath, path.New("json", "storage"), rendered.Storage) + + // Create systemd unit to import module + cmdToExecute := "/usr/sbin/semodule -i" + modulePath + + rendered.Systemd.Units = append(rendered.Systemd.Units, types.Unit{ + Name: module.Name + ".conf", + Contents: util.StrToPtr( + "[Unit]\n" + + "Description=Import SELinux module\n" + + "[Service]\n" + + "Type=oneshot\n" + + "RemainAfterExit=yes\n" + + "ExecStart=" + cmdToExecute + "\n" + + "[Install]\n" + + "WantedBy=multi-user.target\n"), + Enabled: util.BoolToPtr(true), + }) + ts.AddFromCommonSource(yamlPath, path.New("json", "systemd"), rendered.Systemd) + + return rendered +} diff --git a/config/fcos/v1_6_exp/translate_test.go b/config/fcos/v1_6_exp/translate_test.go index 87620a77..325d420d 100644 --- a/config/fcos/v1_6_exp/translate_test.go +++ b/config/fcos/v1_6_exp/translate_test.go @@ -1637,3 +1637,97 @@ func TestTranslateGrub(t *testing.T) { }) } } + +func TestTranslateSelinux(t *testing.T) { + cmdToExecute := "/usr/sbin/semodule -i" + "/etc/selinux/targeted/modules/active/extra/some_name.cil" + 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")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0)}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "path")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "append")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "append", 0)}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "append", 0, "source")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "append", 0, "compression")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units", 0, "name")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units", 0, "contents")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units", 0, "enabled")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units", 0)}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units")}, + {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd")}, + } + tests := []struct { + in Config + out types.Config + exceptions []translate.Translation + }{ + // 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{ + 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(""), + }, + }, + }, + }, + }, + }, + Systemd: types.Systemd{ + Units: []types.Unit{ + { + Name: "some_name" + ".conf", + Enabled: util.BoolToPtr(true), + Contents: util.StrToPtr( + "[Unit]\n" + + "Description=Import SELinux module\n" + + "[Service]\n" + + "Type=oneshot\n" + + "RemainAfterExit=yes\n" + + "ExecStart=" + cmdToExecute + "\n" + + "[Install]\n" + + "WantedBy=multi-user.target\n"), + }, + }, + }, + }, + translations, + }, + } + + for i, test := range tests { + t.Run(fmt.Sprintf("translate %d", i), func(t *testing.T) { + out, translations, r := test.in.ToIgn3_5Unvalidated(common.TranslateOptions{}) + r = confutil.TranslateReportPaths(r, translations) + baseutil.VerifyReport(t, test.in, r) + assert.Equal(t, test.out, out, "bad output") + assert.Equal(t, report.Report{}, r, "expected empty report") + baseutil.VerifyTranslations(t, translations, test.exceptions) + assert.NoError(t, translations.DebugVerifyCoverage(out), "incomplete TranslationSet coverage") + }) + } + +} diff --git a/config/fcos/v1_6_exp/validate.go b/config/fcos/v1_6_exp/validate.go index 481e3d84..c1e2f68c 100644 --- a/config/fcos/v1_6_exp/validate.go +++ b/config/fcos/v1_6_exp/validate.go @@ -98,3 +98,20 @@ 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("name"), common.ErrSelinuxContentNotSpecified) + r.AddOnError(c.Append("content"), common.ErrSelinuxContentNotSpecified) + } else { + if m.Name == "" { + r.AddOnError(c.Append("name"), common.ErrSelinuxNameNotSpecified) + } + + if m.Content == "" { + r.AddOnError(c.Append("content"), common.ErrSelinuxContentNotSpecified) + } + } + + return r +} diff --git a/config/fcos/v1_6_exp/validate_test.go b/config/fcos/v1_6_exp/validate_test.go index 2c850580..19df624a 100644 --- a/config/fcos/v1_6_exp/validate_test.go +++ b/config/fcos/v1_6_exp/validate_test.go @@ -479,3 +479,49 @@ func TestValidateConfig(t *testing.T) { }) } } + +func TestValidateModule(t *testing.T) { + tests := []struct { + in Module + out error + errPath path.ContextPath + }{ + { + // valid module + in: Module{ + Content: "some content", + Name: "some name", + }, + out: nil, + errPath: path.New("yaml"), + }, + { + // content is not specified + in: Module{ + Content: "", + Name: "some name", + }, + out: common.ErrSelinuxContentNotSpecified, + errPath: path.New("yaml", "content"), + }, + { + // name is not specified + in: Module{ + Name: "", + Content: "some content", + }, + out: common.ErrSelinuxNameNotSpecified, + errPath: path.New("yaml", "name"), + }, + } + + 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") + }) + } +} From 363a23e0a02ac28933096afc511667cf428d1056 Mon Sep 17 00:00:00 2001 From: Yasmin Valim Date: Tue, 16 Jan 2024 14:05:52 -0300 Subject: [PATCH 2/4] fcos/v1_6_exp: Add code reviews insights --- config/common/errors.go | 4 +-- config/fcos/v1_6_exp/schema.go | 26 +++++++++++++-- config/fcos/v1_6_exp/translate.go | 46 ++++++++++++++++++-------- config/fcos/v1_6_exp/translate_test.go | 45 +++++++++++++------------ config/fcos/v1_6_exp/validate.go | 15 +++------ config/fcos/v1_6_exp/validate_test.go | 24 +++++++++----- 6 files changed, 101 insertions(+), 59 deletions(-) diff --git a/config/common/errors.go b/config/common/errors.go index ea238e68..ee94daf9 100644 --- a/config/common/errors.go +++ b/config/common/errors.go @@ -98,8 +98,8 @@ var ( ErrGeneralKernelArgumentSupport = errors.New("kernel argument customization is not supported in this spec version") // Selinux Module - ErrSelinuxContentNotSpecified = errors.New("field \"content\" is required") - ErrSelinuxNameNotSpecified = errors.New("field \"name\" is required") + ErrSelinuxContentsNotSpecified = errors.New("field \"contents\" is required") + ErrSelinuxNameNotSpecified = errors.New("field \"name\" is required") ) type ErrUnmarshal struct { diff --git a/config/fcos/v1_6_exp/schema.go b/config/fcos/v1_6_exp/schema.go index ea5bc8d6..c5806abc 100644 --- a/config/fcos/v1_6_exp/schema.go +++ b/config/fcos/v1_6_exp/schema.go @@ -53,10 +53,30 @@ type GrubUser struct { } type Selinux struct { - Module []Module `yaml:"module"` + Modules []Module `yaml:"modules"` } type Module struct { - Name string `yaml:"name"` - Content string `yaml:"content"` + Name string `yaml:"name"` + Contents Resource `yaml:"contents"` +} + +type Resource struct { + Compression *string `yaml:"compression"` + HTTPHeaders HTTPHeaders `yaml:"http_headers"` + Source *string `yaml:"source"` + Inline *string `yaml:"inline"` // Added, not in ignition spec + Local *string `yaml:"local"` // Added, not in ignition spec + Verification Verification `yaml:"verification"` +} + +type HTTPHeader struct { + Name string `yaml:"name"` + Value *string `yaml:"value"` +} + +type HTTPHeaders []HTTPHeader + +type Verification struct { + Hash *string `yaml:"hash"` } diff --git a/config/fcos/v1_6_exp/translate.go b/config/fcos/v1_6_exp/translate.go index e297ead4..2e51200e 100644 --- a/config/fcos/v1_6_exp/translate.go +++ b/config/fcos/v1_6_exp/translate.go @@ -17,6 +17,7 @@ package v1_6_exp import ( "fmt" "strings" + "text/template" baseutil "github.com/coreos/butane/base/util" "github.com/coreos/butane/config/common" @@ -55,6 +56,20 @@ const ( bootV1SizeMiB = 384 ) +var ( + mountUnitTemplate = template.Must(template.New("unit").Parse(` +# Generated by Butane +[Unit] +Description=Import SELinux module - {{.ModuleName}} +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart={{.CmdToExecute}} +[Install] +WantedBy=multi-user.target +`)) +) + // Return FieldFilters for this spec. func (c Config) FieldFilters() *cutil.FieldFilters { return nil @@ -393,14 +408,14 @@ func (c Config) handleSelinux(options common.TranslateOptions) (types.Config, tr ts := translate.NewTranslationSet("yaml", "json") var r report.Report - for _, module := range c.Selinux.Module { - rendered = processModule(rendered, module, options, ts, r, path.New("yaml", "selinux", "module")) + for i, module := range c.Selinux.Modules { + rendered = processModule(rendered, module, options, ts, r, path.New("yaml", "selinux", "module", i)) } 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) + src, compression, err := baseutil.MakeDataURL(([]byte(*module.Contents.Inline)), nil, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(yamlPath, err) return rendered @@ -427,18 +442,21 @@ func processModule(rendered types.Config, module Module, options common.Translat // Create systemd unit to import module cmdToExecute := "/usr/sbin/semodule -i" + modulePath + var contents strings.Builder + err = mountUnitTemplate.Execute(&contents, map[string]interface{}{ + "ModuleName": module.Name, + "CmdToExecute": cmdToExecute, + }) + if err != nil { + panic(err) + } + + result := contents.String() + rendered.Systemd.Units = append(rendered.Systemd.Units, types.Unit{ - Name: module.Name + ".conf", - Contents: util.StrToPtr( - "[Unit]\n" + - "Description=Import SELinux module\n" + - "[Service]\n" + - "Type=oneshot\n" + - "RemainAfterExit=yes\n" + - "ExecStart=" + cmdToExecute + "\n" + - "[Install]\n" + - "WantedBy=multi-user.target\n"), - Enabled: util.BoolToPtr(true), + Name: module.Name + ".conf", + Contents: util.StrToPtr(result), + Enabled: util.BoolToPtr(true), }) ts.AddFromCommonSource(yamlPath, path.New("json", "systemd"), rendered.Systemd) diff --git a/config/fcos/v1_6_exp/translate_test.go b/config/fcos/v1_6_exp/translate_test.go index 325d420d..6a7d5d46 100644 --- a/config/fcos/v1_6_exp/translate_test.go +++ b/config/fcos/v1_6_exp/translate_test.go @@ -1642,20 +1642,20 @@ func TestTranslateSelinux(t *testing.T) { cmdToExecute := "/usr/sbin/semodule -i" + "/etc/selinux/targeted/modules/active/extra/some_name.cil" 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")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0)}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "path")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "append")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "append", 0)}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "append", 0, "source")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "storage", "files", 0, "append", 0, "compression")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units", 0, "name")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units", 0, "contents")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units", 0, "enabled")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units", 0)}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd", "units")}, - {From: path.New("yaml", "selinux", "module"), To: path.New("json", "systemd")}, + {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")}, + {From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "systemd", "units", 0, "name")}, + {From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "systemd", "units", 0, "contents")}, + {From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "systemd", "units", 0, "enabled")}, + {From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "systemd", "units", 0)}, + {From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "systemd", "units")}, + {From: path.New("yaml", "selinux", "module", 0), To: path.New("json", "systemd")}, } tests := []struct { in Config @@ -1666,10 +1666,12 @@ func TestTranslateSelinux(t *testing.T) { { Config{ Selinux: Selinux{ - Module: []Module{ + Modules: []Module{ { - Name: "some_name", - Content: "some content here", + Name: "some_name", + Contents: Resource{ + Inline: util.StrToPtr("some contents here"), + }, }, }, }, @@ -1688,7 +1690,7 @@ func TestTranslateSelinux(t *testing.T) { FileEmbedded1: types.FileEmbedded1{ Append: []types.Resource{ { - Source: util.StrToPtr("data:,some%20content%20here"), + Source: util.StrToPtr("data:,some%20contents%20here"), Compression: util.StrToPtr(""), }, }, @@ -1699,11 +1701,12 @@ func TestTranslateSelinux(t *testing.T) { Systemd: types.Systemd{ Units: []types.Unit{ { - Name: "some_name" + ".conf", + Name: "some_name.conf", Enabled: util.BoolToPtr(true), Contents: util.StrToPtr( - "[Unit]\n" + - "Description=Import SELinux module\n" + + "\n# Generated by Butane\n" + + "[Unit]\n" + + "Description=Import SELinux module - " + "some_name" + "\n" + "[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" + diff --git a/config/fcos/v1_6_exp/validate.go b/config/fcos/v1_6_exp/validate.go index c1e2f68c..9f6695f5 100644 --- a/config/fcos/v1_6_exp/validate.go +++ b/config/fcos/v1_6_exp/validate.go @@ -100,17 +100,12 @@ func (user GrubUser) Validate(c path.ContextPath) (r report.Report) { } func (m Module) Validate(c path.ContextPath) (r report.Report) { - if m.Name == "" && m.Content == "" { - r.AddOnError(c.Append("name"), common.ErrSelinuxContentNotSpecified) - r.AddOnError(c.Append("content"), common.ErrSelinuxContentNotSpecified) - } else { - if m.Name == "" { - r.AddOnError(c.Append("name"), common.ErrSelinuxNameNotSpecified) - } + if m.Name == "" { + r.AddOnError(c.Append("name"), common.ErrSelinuxNameNotSpecified) + } - if m.Content == "" { - r.AddOnError(c.Append("content"), common.ErrSelinuxContentNotSpecified) - } + if m.Contents.Inline == nil || *m.Contents.Inline == "" { + r.AddOnError(c.Append("contents"), common.ErrSelinuxContentsNotSpecified) } return r diff --git a/config/fcos/v1_6_exp/validate_test.go b/config/fcos/v1_6_exp/validate_test.go index 19df624a..07474704 100644 --- a/config/fcos/v1_6_exp/validate_test.go +++ b/config/fcos/v1_6_exp/validate_test.go @@ -489,26 +489,32 @@ func TestValidateModule(t *testing.T) { { // valid module in: Module{ - Content: "some content", - Name: "some name", + Contents: Resource{ + Inline: util.StrToPtr("some contents"), + }, + Name: "some name", }, out: nil, errPath: path.New("yaml"), }, { - // content is not specified + // contents is not specified in: Module{ - Content: "", - Name: "some name", + Contents: Resource{ + Inline: util.StrToPtr(""), + }, + Name: "some name", }, - out: common.ErrSelinuxContentNotSpecified, - errPath: path.New("yaml", "content"), + out: common.ErrSelinuxContentsNotSpecified, + errPath: path.New("yaml", "contents"), }, { // name is not specified in: Module{ - Name: "", - Content: "some content", + Name: "", + Contents: Resource{ + Inline: util.StrToPtr("some contents"), + }, }, out: common.ErrSelinuxNameNotSpecified, errPath: path.New("yaml", "name"), From 47441f1344ba627e791394de9136dfa65e9ae920 Mon Sep 17 00:00:00 2001 From: Yasmin Valim Date: Mon, 19 Feb 2024 19:16:49 -0300 Subject: [PATCH 3/4] fcos/v1_6_exp: Remove validations --- config/fcos/v1_6_exp/translate.go | 3 +- config/fcos/v1_6_exp/validate.go | 12 ------- config/fcos/v1_6_exp/validate_test.go | 52 --------------------------- 3 files changed, 2 insertions(+), 65 deletions(-) diff --git a/config/fcos/v1_6_exp/translate.go b/config/fcos/v1_6_exp/translate.go index 2e51200e..ecde4656 100644 --- a/config/fcos/v1_6_exp/translate.go +++ b/config/fcos/v1_6_exp/translate.go @@ -448,7 +448,8 @@ func processModule(rendered types.Config, module Module, options common.Translat "CmdToExecute": cmdToExecute, }) if err != nil { - panic(err) + r.AddOnError(yamlPath, err) + return rendered } result := contents.String() diff --git a/config/fcos/v1_6_exp/validate.go b/config/fcos/v1_6_exp/validate.go index 9f6695f5..481e3d84 100644 --- a/config/fcos/v1_6_exp/validate.go +++ b/config/fcos/v1_6_exp/validate.go @@ -98,15 +98,3 @@ func (user GrubUser) Validate(c path.ContextPath) (r report.Report) { } return } - -func (m Module) Validate(c path.ContextPath) (r report.Report) { - if m.Name == "" { - r.AddOnError(c.Append("name"), common.ErrSelinuxNameNotSpecified) - } - - if m.Contents.Inline == nil || *m.Contents.Inline == "" { - r.AddOnError(c.Append("contents"), common.ErrSelinuxContentsNotSpecified) - } - - return r -} diff --git a/config/fcos/v1_6_exp/validate_test.go b/config/fcos/v1_6_exp/validate_test.go index 07474704..2c850580 100644 --- a/config/fcos/v1_6_exp/validate_test.go +++ b/config/fcos/v1_6_exp/validate_test.go @@ -479,55 +479,3 @@ func TestValidateConfig(t *testing.T) { }) } } - -func TestValidateModule(t *testing.T) { - tests := []struct { - in Module - out error - errPath path.ContextPath - }{ - { - // valid module - in: Module{ - Contents: Resource{ - Inline: util.StrToPtr("some contents"), - }, - Name: "some name", - }, - out: nil, - errPath: path.New("yaml"), - }, - { - // contents is not specified - in: Module{ - Contents: Resource{ - Inline: util.StrToPtr(""), - }, - Name: "some name", - }, - out: common.ErrSelinuxContentsNotSpecified, - errPath: path.New("yaml", "contents"), - }, - { - // name is not specified - in: Module{ - Name: "", - Contents: Resource{ - Inline: util.StrToPtr("some contents"), - }, - }, - out: common.ErrSelinuxNameNotSpecified, - errPath: path.New("yaml", "name"), - }, - } - - 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") - }) - } -} From ad0fd81bd8ae0ff6b62bebbabb8cb811da15ed8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Ravier?= Date: Tue, 20 Feb 2024 12:42:10 +0100 Subject: [PATCH 4/4] docs: Move s390x boot_devices sugar to ocp 4.16.0-experimental It depends on fcos 1.6.0-experimental See: https://github.com/coreos/butane/pull/484 See: https://github.com/coreos/butane/pull/514 Fixes: https://github.com/coreos/butane/pull/517 --- docs/config-openshift-v4_15.md | 2 +- docs/release-notes.md | 3 ++- internal/doc/butane.yaml | 13 ++++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/config-openshift-v4_15.md b/docs/config-openshift-v4_15.md index 4ca3be1f..5dd4e431 100644 --- a/docs/config-openshift-v4_15.md +++ b/docs/config-openshift-v4_15.md @@ -156,7 +156,7 @@ The OpenShift configuration is a YAML document conforming to the following speci * **_ssh_authorized_keys_** (list of strings): a list of SSH keys to be added as an SSH key fragment at `.ssh/authorized_keys.d/ignition` in the user's home directory. All SSH keys must be unique. * **_ssh_authorized_keys_local_** (list of strings): a list of local paths to SSH key files, relative to the directory specified by the `--files-dir` command-line argument, to be added as SSH key fragments at `.ssh/authorized_keys.d/ignition` in the user's home directory. All SSH keys must be unique. Each file may contain multiple SSH keys, one per line. * **_boot_device_** (object): describes the desired boot device configuration. At least one of `luks` or `mirror` must be specified. - * **_layout_** (string): the disk layout of the target OS image. Supported values are `aarch64`, `ppc64le`, `s390x-eckd`, `s390x-virt`, `s390x-zfcp`, and `x86_64`. Defaults to `x86_64`. + * **_layout_** (string): the disk layout of the target OS image. Supported values are `aarch64`, `ppc64le`, and `x86_64`. Defaults to `x86_64`. * **_luks_** (object): describes the clevis configuration for encrypting the root filesystem. * **_tang_** (list of objects): describes a tang server. Every server must have a unique `url`. * **url** (string): url of the tang server. diff --git a/docs/release-notes.md b/docs/release-notes.md index e6804eb2..54f516e4 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,6 +12,7 @@ nav_order: 9 ### Features +- Add SElinux sugar to butane which will allow users import costum SElinux modules. ### Bug fixes @@ -33,7 +34,7 @@ key](https://getfedora.org/security/). ### Features -- Support s390x layouts in `boot_device` section (fcos 1.6.0-exp, openshift 4.15.0-exp) +- Support s390x layouts in `boot_device` section (fcos 1.6.0-exp, openshift 4.16.0-exp) - Stabilize OpenShift spec 4.15.0, targeting Ignition spec 3.4.0 - Add OpenShift spec 4.16.0-experimental, targeting Ignition spec 3.5.0-experimental diff --git a/internal/doc/butane.yaml b/internal/doc/butane.yaml index bd92b4b7..f40b5e15 100644 --- a/internal/doc/butane.yaml +++ b/internal/doc/butane.yaml @@ -330,7 +330,7 @@ root: - variant: fcos min: 1.6.0-experimental - variant: openshift - min: 4.15.0-experimental + min: 4.16.0-experimental - name: luks desc: describes the clevis configuration for encrypting the root filesystem. children: @@ -386,6 +386,17 @@ root: if: - variant: openshift max: 4.15.0 + - name: selinux + after: $ + desc: simplifies security policy configuration through direct integration with Ignition, facilitating the generation of SELinux modules. + children: + - name: modules + desc: a module retains the data necessary for generating SELinux files. + children: + - name: name + desc: module name + - name: contents + desc: all the information provided that will be the configuration of the SELinux module - name: openshift after: $ desc: describes miscellaneous OpenShift configuration. Respected when rendering to a MachineConfig, ignored when rendering directly to an Ignition config.