From 68fdf42f8d3b7bfb20a9b9947654fc9183a5cade Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Mon, 4 Dec 2023 22:42:28 +0000 Subject: [PATCH 1/9] schutz: update `osbuild` commit --- Schutzfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Schutzfile b/Schutzfile index d990be4671..a5f2a71df1 100644 --- a/Schutzfile +++ b/Schutzfile @@ -2,7 +2,7 @@ "fedora-38": { "dependencies": { "osbuild": { - "commit": "f3d740aaf8531e55b99632f579f2fae13f1511b7" + "commit": "0767ebccc120eb4a43e274fec64eb95646a66761" } }, "repos": [ @@ -76,4 +76,4 @@ } ] } -} \ No newline at end of file +} From 2e725fc827dcf164ede7360e1255575edc156bfb Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Wed, 13 Dec 2023 13:48:57 +0000 Subject: [PATCH 2/9] pkg/distro: generalise default datastream Refactor the way in which the default datastream is obtained. This will make it easier to generalise and simplify the creation of the OpenSCAP remediation & tailoring stage options. Jira: https://issues.redhat.com/browse/COMPOSER-1994 --- pkg/blueprint/customizations.go | 2 +- pkg/blueprint/customizations_test.go | 2 +- pkg/customizations/oscap/oscap.go | 34 ++++++++++++++++++++-------- pkg/distro/fedora/images.go | 5 +--- pkg/distro/rhel7/images.go | 2 +- pkg/distro/rhel8/images.go | 5 +--- pkg/distro/rhel9/images.go | 5 +--- 7 files changed, 30 insertions(+), 25 deletions(-) diff --git a/pkg/blueprint/customizations.go b/pkg/blueprint/customizations.go index d83ed2ebbd..d00487a0e3 100644 --- a/pkg/blueprint/customizations.go +++ b/pkg/blueprint/customizations.go @@ -109,7 +109,7 @@ type ServicesCustomization struct { } type OpenSCAPCustomization struct { - DataStream string `json:"datastream,omitempty" toml:"datastream,omitempty"` + Datastream string `json:"datastream,omitempty" toml:"datastream,omitempty"` ProfileID string `json:"profile_id,omitempty" toml:"profile_id,omitempty"` Tailoring *OpenSCAPTailoringCustomizations `json:"tailoring,omitempty" toml:"tailoring,omitempty"` } diff --git a/pkg/blueprint/customizations_test.go b/pkg/blueprint/customizations_test.go index d6828113c6..00c718b138 100644 --- a/pkg/blueprint/customizations_test.go +++ b/pkg/blueprint/customizations_test.go @@ -375,7 +375,7 @@ func TestGetFilesystemsMinSizeNonSectorSize(t *testing.T) { func TestGetOpenSCAPConfig(t *testing.T) { expectedOscap := OpenSCAPCustomization{ - DataStream: "test-data-stream.xml", + Datastream: "test-data-stream.xml", ProfileID: "test_profile", Tailoring: &OpenSCAPTailoringCustomizations{ Selected: []string{"quick_rule"}, diff --git a/pkg/customizations/oscap/oscap.go b/pkg/customizations/oscap/oscap.go index ffc06db9c6..13af59ac8c 100644 --- a/pkg/customizations/oscap/oscap.go +++ b/pkg/customizations/oscap/oscap.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/osbuild/images/pkg/customizations/fsnode" + "github.com/osbuild/images/pkg/distro" ) type Profile string @@ -44,24 +45,37 @@ const ( tailoringDirPath string = "/usr/share/xml/osbuild-openscap-data" ) -func DefaultFedoraDatastream() string { - return defaultFedoraDatastream -} +func GetDatastream(datastream string, d distro.Distro) string { + if datastream != "" { + return datastream + } -func DefaultRHEL8Datastream(isRHEL bool) string { - if isRHEL { - return defaultRHEL8Datastream + s := strings.ToLower(d.Name()) + if strings.HasPrefix(s, "fedora") { + return defaultFedoraDatastream + } + + if strings.HasPrefix(s, "centos") { + return defaultCentosDatastream(d.Releasever()) } - return defaultCentos8Datastream + + return defaultRHELDatastream(d.Releasever()) } -func DefaultRHEL9Datastream(isRHEL bool) string { - if isRHEL { - return defaultRHEL9Datastream +func defaultCentosDatastream(releaseVer string) string { + if releaseVer == "8" { + return defaultCentos8Datastream } return defaultCentos9Datastream } +func defaultRHELDatastream(releaseVer string) string { + if releaseVer == "8" { + return defaultRHEL8Datastream + } + return defaultRHEL9Datastream +} + func IsProfileAllowed(profile string, allowlist []Profile) bool { for _, a := range allowlist { if a.String() == profile { diff --git a/pkg/distro/fedora/images.go b/pkg/distro/fedora/images.go index 6943789c26..feba7f9108 100644 --- a/pkg/distro/fedora/images.go +++ b/pkg/distro/fedora/images.go @@ -175,10 +175,7 @@ func osCustomizations( osc.Directories = append(osc.Directories, dataDirNode) - var datastream = oscapConfig.DataStream - if datastream == "" { - datastream = oscap.DefaultFedoraDatastream() - } + datastream := oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) oscapStageOptions := osbuild.OscapConfig{ Datastream: datastream, diff --git a/pkg/distro/rhel7/images.go b/pkg/distro/rhel7/images.go index dfc5415313..33c6aa5e83 100644 --- a/pkg/distro/rhel7/images.go +++ b/pkg/distro/rhel7/images.go @@ -133,7 +133,7 @@ func osCustomizations( osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions( oscapDataDir, osbuild.OscapConfig{ - Datastream: oscapConfig.DataStream, + Datastream: oscapConfig.Datastream, ProfileID: oscapConfig.ProfileID, Compression: true, }, diff --git a/pkg/distro/rhel8/images.go b/pkg/distro/rhel8/images.go index 1eeae9a35d..8c0e57ec8e 100644 --- a/pkg/distro/rhel8/images.go +++ b/pkg/distro/rhel8/images.go @@ -196,10 +196,7 @@ func osCustomizations( osc.Directories = append(osc.Directories, dataDirNode) - var datastream = oscapConfig.DataStream - if datastream == "" { - datastream = oscap.DefaultRHEL8Datastream(t.arch.distro.isRHEL()) - } + datastream := oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) oscapStageOptions := osbuild.OscapConfig{ Datastream: datastream, diff --git a/pkg/distro/rhel9/images.go b/pkg/distro/rhel9/images.go index 225e7a06b3..2a1b895e81 100644 --- a/pkg/distro/rhel9/images.go +++ b/pkg/distro/rhel9/images.go @@ -193,10 +193,7 @@ func osCustomizations( osc.Directories = append(osc.Directories, dataDirNode) - var datastream = oscapConfig.DataStream - if datastream == "" { - datastream = oscap.DefaultRHEL9Datastream(t.arch.distro.isRHEL()) - } + var datastream = oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) oscapStageOptions := osbuild.OscapConfig{ Datastream: datastream, From bd1244207ec72aa5bc25ca2fde454a56e662b5f4 Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Wed, 13 Dec 2023 14:00:04 +0000 Subject: [PATCH 3/9] pkg/distro: simplify directory creation Extract the creation of the required OpenSCAP directories into the OpenSCAP package. Simplify the directory creation into a single function which returns all the required directories for both the remediation and tailoring stages. Jira: https://issues.redhat.com/browse/COMPOSER-1994 --- pkg/customizations/oscap/oscap.go | 14 +++------- pkg/customizations/oscap/stage_options.go | 31 +++++++++++++++++++++++ pkg/distro/fedora/images.go | 24 +++++++----------- pkg/distro/rhel8/images.go | 23 ++++++----------- pkg/distro/rhel9/images.go | 24 +++++++----------- 5 files changed, 61 insertions(+), 55 deletions(-) create mode 100644 pkg/customizations/oscap/stage_options.go diff --git a/pkg/customizations/oscap/oscap.go b/pkg/customizations/oscap/oscap.go index 13af59ac8c..f044830459 100644 --- a/pkg/customizations/oscap/oscap.go +++ b/pkg/customizations/oscap/oscap.go @@ -5,7 +5,6 @@ import ( "path/filepath" "strings" - "github.com/osbuild/images/pkg/customizations/fsnode" "github.com/osbuild/images/pkg/distro" ) @@ -41,7 +40,8 @@ const ( defaultRHEL8Datastream string = "/usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml" defaultRHEL9Datastream string = "/usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml" - // tailoring directory path + // directory paths + dataDirPath string = "/oscap_data" tailoringDirPath string = "/usr/share/xml/osbuild-openscap-data" ) @@ -92,14 +92,8 @@ func IsProfileAllowed(profile string, allowlist []Profile) bool { return false } -func GetTailoringFile(profile string) (string, string, *fsnode.Directory, error) { +func GetTailoringFile(profile string) (string, string) { newProfile := fmt.Sprintf("%s_osbuild_tailoring", profile) path := filepath.Join(tailoringDirPath, "tailoring.xml") - - tailoringDir, err := fsnode.NewDirectory(tailoringDirPath, nil, nil, nil, true) - if err != nil { - return "", "", nil, err - } - - return newProfile, path, tailoringDir, nil + return newProfile, path } diff --git a/pkg/customizations/oscap/stage_options.go b/pkg/customizations/oscap/stage_options.go new file mode 100644 index 0000000000..70a65e01e6 --- /dev/null +++ b/pkg/customizations/oscap/stage_options.go @@ -0,0 +1,31 @@ +package oscap + +import ( + "fmt" + + "github.com/osbuild/images/pkg/customizations/fsnode" +) + +func CreateRequiredDirectories(createTailoring bool) ([]*fsnode.Directory, error) { + var directories []*fsnode.Directory + + // although the osbuild stage will create this directory, + // it's probably better to ensure that it is created here + dataDirNode, err := fsnode.NewDirectory(dataDirPath, nil, nil, nil, true) + if err != nil { + return nil, fmt.Errorf("unexpected error creating OpenSCAP data directory: %s", err) + } + + directories = append(directories, dataDirNode) + + if createTailoring { + tailoringDirNode, err := fsnode.NewDirectory(tailoringDirPath, nil, nil, nil, true) + if err != nil { + return nil, fmt.Errorf("unexpected error creating OpenSCAP tailoring directory: %s", err) + } + + directories = append(directories, tailoringDirNode) + } + + return directories, nil +} diff --git a/pkg/distro/fedora/images.go b/pkg/distro/fedora/images.go index feba7f9108..4f89e41842 100644 --- a/pkg/distro/fedora/images.go +++ b/pkg/distro/fedora/images.go @@ -166,15 +166,6 @@ func osCustomizations( panic("unexpected oscap options for ostree image type") } - // although the osbuild stage will create this directory, - // it's probably better to ensure that it is created here - dataDirNode, err := fsnode.NewDirectory(oscapDataDir, nil, nil, nil, true) - if err != nil { - panic("unexpected error creating OpenSCAP data directory") - } - - osc.Directories = append(osc.Directories, dataDirNode) - datastream := oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) oscapStageOptions := osbuild.OscapConfig{ @@ -184,10 +175,7 @@ func osCustomizations( } if oscapConfig.Tailoring != nil { - newProfile, tailoringFilepath, tailoringDir, err := oscap.GetTailoringFile(oscapConfig.ProfileID) - if err != nil { - panic(fmt.Sprintf("unexpected error creating tailoring file options: %v", err)) - } + newProfile, tailoringFilepath := oscap.GetTailoringFile(oscapConfig.ProfileID) tailoringOptions := osbuild.OscapAutotailorConfig{ NewProfile: newProfile, @@ -205,9 +193,15 @@ func osCustomizations( // overwrite the profile id with the new tailoring id oscapStageOptions.ProfileID = newProfile oscapStageOptions.Tailoring = tailoringFilepath + } + + directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring != nil) + if err != nil { + panic(err) + } - // add the parent directory for the tailoring file - osc.Directories = append(osc.Directories, tailoringDir) + if len(directories) > 0 { + osc.Directories = append(osc.Directories, directories...) } osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions(oscapDataDir, oscapStageOptions) diff --git a/pkg/distro/rhel8/images.go b/pkg/distro/rhel8/images.go index 8c0e57ec8e..a70e27a0d4 100644 --- a/pkg/distro/rhel8/images.go +++ b/pkg/distro/rhel8/images.go @@ -187,15 +187,6 @@ func osCustomizations( panic("unexpected oscap options for ostree image type") } - // although the osbuild stage will create this directory, - // it's probably better to ensure that it is created here - dataDirNode, err := fsnode.NewDirectory(oscapDataDir, nil, nil, nil, true) - if err != nil { - panic("unexpected error creating OpenSCAP data directory") - } - - osc.Directories = append(osc.Directories, dataDirNode) - datastream := oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) oscapStageOptions := osbuild.OscapConfig{ @@ -205,10 +196,7 @@ func osCustomizations( } if oscapConfig.Tailoring != nil { - newProfile, tailoringFilepath, tailoringDir, err := oscap.GetTailoringFile(oscapConfig.ProfileID) - if err != nil { - panic(fmt.Sprintf("unexpected error creating tailoring file options: %v", err)) - } + newProfile, tailoringFilepath := oscap.GetTailoringFile(oscapConfig.ProfileID) tailoringOptions := osbuild.OscapAutotailorConfig{ NewProfile: newProfile, @@ -226,11 +214,16 @@ func osCustomizations( // overwrite the profile id with the new tailoring id oscapStageOptions.ProfileID = newProfile oscapStageOptions.Tailoring = tailoringFilepath + } - // add the parent directory for the tailoring file - osc.Directories = append(osc.Directories, tailoringDir) + directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring != nil) + if err != nil { + panic(err) } + if len(directories) > 0 { + osc.Directories = append(osc.Directories, directories...) + } osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions(oscapDataDir, oscapStageOptions) } diff --git a/pkg/distro/rhel9/images.go b/pkg/distro/rhel9/images.go index 2a1b895e81..31b51e7b7e 100644 --- a/pkg/distro/rhel9/images.go +++ b/pkg/distro/rhel9/images.go @@ -184,15 +184,6 @@ func osCustomizations( panic("unexpected oscap options for ostree image type") } - // although the osbuild stage will create this directory, - // it's probably better to ensure that it is created here - dataDirNode, err := fsnode.NewDirectory(oscapDataDir, nil, nil, nil, true) - if err != nil { - panic("unexpected error creating OpenSCAP data directory") - } - - osc.Directories = append(osc.Directories, dataDirNode) - var datastream = oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) oscapStageOptions := osbuild.OscapConfig{ @@ -202,10 +193,7 @@ func osCustomizations( } if oscapConfig.Tailoring != nil { - newProfile, tailoringFilepath, tailoringDir, err := oscap.GetTailoringFile(oscapConfig.ProfileID) - if err != nil { - panic(fmt.Sprintf("unexpected error creating tailoring file options: %v", err)) - } + newProfile, tailoringFilepath := oscap.GetTailoringFile(oscapConfig.ProfileID) tailoringOptions := osbuild.OscapAutotailorConfig{ NewProfile: newProfile, @@ -223,9 +211,15 @@ func osCustomizations( // overwrite the profile id with the new tailoring id oscapStageOptions.ProfileID = newProfile oscapStageOptions.Tailoring = tailoringFilepath + } + + directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring == nil) + if err != nil { + panic(err) + } - // add the parent directory for the tailoring file - osc.Directories = append(osc.Directories, tailoringDir) + if len(directories) > 0 { + osc.Directories = append(osc.Directories, directories...) } osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions(oscapDataDir, oscapStageOptions) From ee3e8c328b1cf0f0e816500ddfcf30c100961b98 Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Wed, 13 Dec 2023 14:14:22 +0000 Subject: [PATCH 4/9] pkg/distro: simplify tailoring stage options Generalise the tailoring stage options so it can be re-used by each of the distros. Before this, there was a lot of repetition for each distro when creating the stage options. This simplification also allowed some decoupling from the remediation stage options. Jira: https://issues.redhat.com/browse/COMPOSER-1994 --- pkg/customizations/oscap/oscap.go | 8 ------ pkg/customizations/oscap/stage_options.go | 35 +++++++++++++++++++++++ pkg/distro/fedora/images.go | 27 ++++++----------- pkg/distro/rhel8/images.go | 27 ++++++----------- pkg/distro/rhel9/images.go | 27 ++++++----------- 5 files changed, 59 insertions(+), 65 deletions(-) diff --git a/pkg/customizations/oscap/oscap.go b/pkg/customizations/oscap/oscap.go index f044830459..8a83f07188 100644 --- a/pkg/customizations/oscap/oscap.go +++ b/pkg/customizations/oscap/oscap.go @@ -1,8 +1,6 @@ package oscap import ( - "fmt" - "path/filepath" "strings" "github.com/osbuild/images/pkg/distro" @@ -91,9 +89,3 @@ func IsProfileAllowed(profile string, allowlist []Profile) bool { return false } - -func GetTailoringFile(profile string) (string, string) { - newProfile := fmt.Sprintf("%s_osbuild_tailoring", profile) - path := filepath.Join(tailoringDirPath, "tailoring.xml") - return newProfile, path -} diff --git a/pkg/customizations/oscap/stage_options.go b/pkg/customizations/oscap/stage_options.go index 70a65e01e6..440d4bae3a 100644 --- a/pkg/customizations/oscap/stage_options.go +++ b/pkg/customizations/oscap/stage_options.go @@ -2,8 +2,12 @@ package oscap import ( "fmt" + "path/filepath" + "github.com/osbuild/images/pkg/blueprint" "github.com/osbuild/images/pkg/customizations/fsnode" + "github.com/osbuild/images/pkg/distro" + "github.com/osbuild/images/pkg/osbuild" ) func CreateRequiredDirectories(createTailoring bool) ([]*fsnode.Directory, error) { @@ -29,3 +33,34 @@ func CreateRequiredDirectories(createTailoring bool) ([]*fsnode.Directory, error return directories, nil } + +func getTailoringProfileID(profileID string) string { + return fmt.Sprintf("%s_osbuild_tailoring", profileID) +} + +func CreateTailoringStageOptions(oscapConfig *blueprint.OpenSCAPCustomization, d distro.Distro) *osbuild.OscapAutotailorStageOptions { + if oscapConfig == nil { + return nil + } + + datastream := GetDatastream(oscapConfig.Datastream, d) + + tailoringConfig := oscapConfig.Tailoring + if tailoringConfig == nil { + return nil + } + + newProfile := getTailoringProfileID(oscapConfig.ProfileID) + path := filepath.Join(tailoringDirPath, "tailoring.xml") + + return osbuild.NewOscapAutotailorStageOptions( + path, + osbuild.OscapAutotailorConfig{ + ProfileID: oscapConfig.ProfileID, + Datastream: datastream, + Selected: tailoringConfig.Selected, + Unselected: tailoringConfig.Unselected, + NewProfile: newProfile, + }, + ) +} diff --git a/pkg/distro/fedora/images.go b/pkg/distro/fedora/images.go index 4f89e41842..558f2213b6 100644 --- a/pkg/distro/fedora/images.go +++ b/pkg/distro/fedora/images.go @@ -174,25 +174,14 @@ func osCustomizations( Compression: true, } - if oscapConfig.Tailoring != nil { - newProfile, tailoringFilepath := oscap.GetTailoringFile(oscapConfig.ProfileID) - - tailoringOptions := osbuild.OscapAutotailorConfig{ - NewProfile: newProfile, - Datastream: datastream, - ProfileID: oscapConfig.ProfileID, - Selected: oscapConfig.Tailoring.Selected, - Unselected: oscapConfig.Tailoring.Unselected, - } - - osc.OpenSCAPTailorConfig = osbuild.NewOscapAutotailorStageOptions( - tailoringFilepath, - tailoringOptions, - ) - - // overwrite the profile id with the new tailoring id - oscapStageOptions.ProfileID = newProfile - oscapStageOptions.Tailoring = tailoringFilepath + osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( + oscapConfig, + t.arch.distro, + ) + + if tailorConfig := osc.OpenSCAPTailorConfig; tailorConfig != nil { + oscapStageOptions.ProfileID = tailorConfig.Config.NewProfile + oscapStageOptions.Tailoring = tailorConfig.Filepath } directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring != nil) diff --git a/pkg/distro/rhel8/images.go b/pkg/distro/rhel8/images.go index a70e27a0d4..12cd22b0d9 100644 --- a/pkg/distro/rhel8/images.go +++ b/pkg/distro/rhel8/images.go @@ -195,25 +195,14 @@ func osCustomizations( Compression: true, } - if oscapConfig.Tailoring != nil { - newProfile, tailoringFilepath := oscap.GetTailoringFile(oscapConfig.ProfileID) - - tailoringOptions := osbuild.OscapAutotailorConfig{ - NewProfile: newProfile, - Datastream: datastream, - ProfileID: oscapConfig.ProfileID, - Selected: oscapConfig.Tailoring.Selected, - Unselected: oscapConfig.Tailoring.Unselected, - } - - osc.OpenSCAPTailorConfig = osbuild.NewOscapAutotailorStageOptions( - tailoringFilepath, - tailoringOptions, - ) - - // overwrite the profile id with the new tailoring id - oscapStageOptions.ProfileID = newProfile - oscapStageOptions.Tailoring = tailoringFilepath + osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( + oscapConfig, + t.arch.distro, + ) + + if tailorConfig := osc.OpenSCAPTailorConfig; tailorConfig != nil { + oscapStageOptions.ProfileID = tailorConfig.Config.NewProfile + oscapStageOptions.Tailoring = tailorConfig.Filepath } directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring != nil) diff --git a/pkg/distro/rhel9/images.go b/pkg/distro/rhel9/images.go index 31b51e7b7e..2c74d5af74 100644 --- a/pkg/distro/rhel9/images.go +++ b/pkg/distro/rhel9/images.go @@ -192,25 +192,14 @@ func osCustomizations( Compression: true, } - if oscapConfig.Tailoring != nil { - newProfile, tailoringFilepath := oscap.GetTailoringFile(oscapConfig.ProfileID) - - tailoringOptions := osbuild.OscapAutotailorConfig{ - NewProfile: newProfile, - Datastream: datastream, - ProfileID: oscapConfig.ProfileID, - Selected: oscapConfig.Tailoring.Selected, - Unselected: oscapConfig.Tailoring.Unselected, - } - - osc.OpenSCAPTailorConfig = osbuild.NewOscapAutotailorStageOptions( - tailoringFilepath, - tailoringOptions, - ) - - // overwrite the profile id with the new tailoring id - oscapStageOptions.ProfileID = newProfile - oscapStageOptions.Tailoring = tailoringFilepath + osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( + oscapConfig, + t.arch.distro, + ) + + if tailorConfig := osc.OpenSCAPTailorConfig; tailorConfig != nil { + oscapStageOptions.ProfileID = tailorConfig.Config.NewProfile + oscapStageOptions.Tailoring = tailorConfig.Filepath } directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring == nil) From a03aaa878814115ed30fa2cfac08e76e4ab66807 Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Wed, 13 Dec 2023 14:24:34 +0000 Subject: [PATCH 5/9] pkg/distro: simplify remediation stage options Generalise the creation of the remediation stage options and extract the function to the `oscap` package. This function also slightly reduces the tight coupling with the `tailoring` stage options. However, this stage still depends on some of the config from the `tailoring` stage. Jira: https://issues.redhat.com/browse/COMPOSER-1994 --- pkg/customizations/oscap/oscap.go | 2 +- pkg/customizations/oscap/stage_options.go | 39 ++++++++++++++++++- pkg/distro/fedora/distro.go | 3 -- pkg/distro/fedora/images.go | 47 ++++++++--------------- pkg/distro/rhel8/images.go | 46 ++++++++-------------- pkg/distro/rhel8/imagetype.go | 3 -- pkg/distro/rhel9/images.go | 47 ++++++++--------------- pkg/distro/rhel9/imagetype.go | 3 -- 8 files changed, 83 insertions(+), 107 deletions(-) diff --git a/pkg/customizations/oscap/oscap.go b/pkg/customizations/oscap/oscap.go index 8a83f07188..e840df2829 100644 --- a/pkg/customizations/oscap/oscap.go +++ b/pkg/customizations/oscap/oscap.go @@ -43,7 +43,7 @@ const ( tailoringDirPath string = "/usr/share/xml/osbuild-openscap-data" ) -func GetDatastream(datastream string, d distro.Distro) string { +func getDatastream(datastream string, d distro.Distro) string { if datastream != "" { return datastream } diff --git a/pkg/customizations/oscap/stage_options.go b/pkg/customizations/oscap/stage_options.go index 440d4bae3a..e91af54356 100644 --- a/pkg/customizations/oscap/stage_options.go +++ b/pkg/customizations/oscap/stage_options.go @@ -10,7 +10,7 @@ import ( "github.com/osbuild/images/pkg/osbuild" ) -func CreateRequiredDirectories(createTailoring bool) ([]*fsnode.Directory, error) { +func createRequiredDirectories(createTailoring bool) ([]*fsnode.Directory, error) { var directories []*fsnode.Directory // although the osbuild stage will create this directory, @@ -43,7 +43,7 @@ func CreateTailoringStageOptions(oscapConfig *blueprint.OpenSCAPCustomization, d return nil } - datastream := GetDatastream(oscapConfig.Datastream, d) + datastream := getDatastream(oscapConfig.Datastream, d) tailoringConfig := oscapConfig.Tailoring if tailoringConfig == nil { @@ -64,3 +64,38 @@ func CreateTailoringStageOptions(oscapConfig *blueprint.OpenSCAPCustomization, d }, ) } + +func CreateRemediationStageOptions( + oscapConfig *blueprint.OpenSCAPCustomization, + isOSTree bool, + d distro.Distro, +) (*osbuild.OscapRemediationStageOptions, []*fsnode.Directory, error) { + if oscapConfig == nil { + return nil, nil, nil + } + + if isOSTree { + return nil, nil, fmt.Errorf("unexpected oscap options for ostree image type") + } + + datastream := getDatastream(oscapConfig.Datastream, d) + + profileID := oscapConfig.ProfileID + if oscapConfig.Tailoring != nil { + profileID = getTailoringProfileID(profileID) + } + + directories, err := createRequiredDirectories(oscapConfig.Tailoring == nil) + if err != nil { + return nil, nil, err + } + + return osbuild.NewOscapRemediationStageOptions( + dataDirPath, + osbuild.OscapConfig{ + Datastream: datastream, + ProfileID: profileID, + Compression: true, + }, + ), directories, nil +} diff --git a/pkg/distro/fedora/distro.go b/pkg/distro/fedora/distro.go index ec397266a3..c9c78a1c62 100644 --- a/pkg/distro/fedora/distro.go +++ b/pkg/distro/fedora/distro.go @@ -38,9 +38,6 @@ const ( // Added kernel command line options for ami, qcow2, openstack, vhd and vmdk types cloudKernelOptions = "ro no_timer_check console=ttyS0,115200n8 biosdevname=0 net.ifnames=0" - - // location for saving openscap remediation data - oscapDataDir = "/oscap_data" ) var ( diff --git a/pkg/distro/fedora/images.go b/pkg/distro/fedora/images.go index 558f2213b6..d276c3f9b9 100644 --- a/pkg/distro/fedora/images.go +++ b/pkg/distro/fedora/images.go @@ -161,39 +161,22 @@ func osCustomizations( osc.YUMRepos = append(osc.YUMRepos, osbuild.NewYumReposStageOptions(filename, repos)) } - if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil { - if t.rpmOstree { - panic("unexpected oscap options for ostree image type") - } - - datastream := oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) - - oscapStageOptions := osbuild.OscapConfig{ - Datastream: datastream, - ProfileID: oscapConfig.ProfileID, - Compression: true, - } - - osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( - oscapConfig, - t.arch.distro, - ) - - if tailorConfig := osc.OpenSCAPTailorConfig; tailorConfig != nil { - oscapStageOptions.ProfileID = tailorConfig.Config.NewProfile - oscapStageOptions.Tailoring = tailorConfig.Filepath - } - - directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring != nil) - if err != nil { - panic(err) - } - - if len(directories) > 0 { - osc.Directories = append(osc.Directories, directories...) - } + var directories []*fsnode.Directory + osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( + c.GetOpenSCAP(), + t.arch.distro, + ) + osc.OpenSCAPConfig, directories, err = oscap.CreateRemediationStageOptions( + c.GetOpenSCAP(), + t.rpmOstree, + t.arch.distro, + ) + if err != nil { + panic(err) + } - osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions(oscapDataDir, oscapStageOptions) + if len(directories) > 0 { + osc.Directories = append(osc.Directories, directories...) } osc.ShellInit = imageConfig.ShellInit diff --git a/pkg/distro/rhel8/images.go b/pkg/distro/rhel8/images.go index 12cd22b0d9..d908aba17f 100644 --- a/pkg/distro/rhel8/images.go +++ b/pkg/distro/rhel8/images.go @@ -182,38 +182,22 @@ func osCustomizations( osc.YUMRepos = append(osc.YUMRepos, osbuild.NewYumReposStageOptions(filename, repos)) } - if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil { - if t.rpmOstree { - panic("unexpected oscap options for ostree image type") - } - - datastream := oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) - - oscapStageOptions := osbuild.OscapConfig{ - Datastream: datastream, - ProfileID: oscapConfig.ProfileID, - Compression: true, - } - - osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( - oscapConfig, - t.arch.distro, - ) - - if tailorConfig := osc.OpenSCAPTailorConfig; tailorConfig != nil { - oscapStageOptions.ProfileID = tailorConfig.Config.NewProfile - oscapStageOptions.Tailoring = tailorConfig.Filepath - } - - directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring != nil) - if err != nil { - panic(err) - } + var directories []*fsnode.Directory + osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( + c.GetOpenSCAP(), + t.arch.distro, + ) + osc.OpenSCAPConfig, directories, err = oscap.CreateRemediationStageOptions( + c.GetOpenSCAP(), + t.rpmOstree, + t.arch.distro, + ) + if err != nil { + panic(err) + } - if len(directories) > 0 { - osc.Directories = append(osc.Directories, directories...) - } - osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions(oscapDataDir, oscapStageOptions) + if len(directories) > 0 { + osc.Directories = append(osc.Directories, directories...) } osc.ShellInit = imageConfig.ShellInit diff --git a/pkg/distro/rhel8/imagetype.go b/pkg/distro/rhel8/imagetype.go index 88bd787093..cdf4db8e4e 100644 --- a/pkg/distro/rhel8/imagetype.go +++ b/pkg/distro/rhel8/imagetype.go @@ -37,9 +37,6 @@ const ( // blueprint package set name blueprintPkgsKey = "blueprint" - - // location for saving openscap remediation data - oscapDataDir = "/oscap_data" ) type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error) diff --git a/pkg/distro/rhel9/images.go b/pkg/distro/rhel9/images.go index 2c74d5af74..0dfa75bb81 100644 --- a/pkg/distro/rhel9/images.go +++ b/pkg/distro/rhel9/images.go @@ -179,39 +179,22 @@ func osCustomizations( osc.YUMRepos = append(osc.YUMRepos, osbuild.NewYumReposStageOptions(filename, repos)) } - if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil { - if t.rpmOstree { - panic("unexpected oscap options for ostree image type") - } - - var datastream = oscap.GetDatastream(oscapConfig.Datastream, t.arch.distro) - - oscapStageOptions := osbuild.OscapConfig{ - Datastream: datastream, - ProfileID: oscapConfig.ProfileID, - Compression: true, - } - - osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( - oscapConfig, - t.arch.distro, - ) - - if tailorConfig := osc.OpenSCAPTailorConfig; tailorConfig != nil { - oscapStageOptions.ProfileID = tailorConfig.Config.NewProfile - oscapStageOptions.Tailoring = tailorConfig.Filepath - } - - directories, err := oscap.CreateRequiredDirectories(oscapConfig.Tailoring == nil) - if err != nil { - panic(err) - } - - if len(directories) > 0 { - osc.Directories = append(osc.Directories, directories...) - } + var directories []*fsnode.Directory + osc.OpenSCAPTailorConfig = oscap.CreateTailoringStageOptions( + c.GetOpenSCAP(), + t.arch.distro, + ) + osc.OpenSCAPConfig, directories, err = oscap.CreateRemediationStageOptions( + c.GetOpenSCAP(), + t.rpmOstree, + t.arch.distro, + ) + if err != nil { + panic(err) + } - osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions(oscapDataDir, oscapStageOptions) + if len(directories) > 0 { + osc.Directories = append(osc.Directories, directories...) } osc.ShellInit = imageConfig.ShellInit diff --git a/pkg/distro/rhel9/imagetype.go b/pkg/distro/rhel9/imagetype.go index 6d8b6e9dc6..f279ca27da 100644 --- a/pkg/distro/rhel9/imagetype.go +++ b/pkg/distro/rhel9/imagetype.go @@ -40,9 +40,6 @@ const ( // blueprint package set name blueprintPkgsKey = "blueprint" - - // location for saving openscap remediation data - oscapDataDir = "/oscap_data" ) type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error) From 770a6c75f855388d1317694f1ba415ce96388a46 Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Mon, 4 Dec 2023 22:21:01 +0000 Subject: [PATCH 6/9] pkg/blueprints: add tailoring overrides Expose a field in the blueprints to be able to override rule values using the OpenSCAP autotailor feature. The customization exposes an array with two values, the name of the var to overwrite and the value to write to the var. Jira: https://issues.redhat.com/browse/COMPOSER-1994 --- pkg/blueprint/customizations.go | 18 --- pkg/blueprint/customizations_test.go | 20 --- pkg/blueprint/openscap_customizations.go | 78 ++++++++++ pkg/blueprint/openscap_customizations_test.go | 143 ++++++++++++++++++ 4 files changed, 221 insertions(+), 38 deletions(-) create mode 100644 pkg/blueprint/openscap_customizations.go create mode 100644 pkg/blueprint/openscap_customizations_test.go diff --git a/pkg/blueprint/customizations.go b/pkg/blueprint/customizations.go index d00487a0e3..216f6f21de 100644 --- a/pkg/blueprint/customizations.go +++ b/pkg/blueprint/customizations.go @@ -108,17 +108,6 @@ type ServicesCustomization struct { Disabled []string `json:"disabled,omitempty" toml:"disabled,omitempty"` } -type OpenSCAPCustomization struct { - Datastream string `json:"datastream,omitempty" toml:"datastream,omitempty"` - ProfileID string `json:"profile_id,omitempty" toml:"profile_id,omitempty"` - Tailoring *OpenSCAPTailoringCustomizations `json:"tailoring,omitempty" toml:"tailoring,omitempty"` -} - -type OpenSCAPTailoringCustomizations struct { - Selected []string `json:"selected,omitempty" toml:"selected,omitempty"` - Unselected []string `json:"unselected,omitempty" toml:"unselected,omitempty"` -} - type CustomizationError struct { Message string } @@ -316,13 +305,6 @@ func (c *Customizations) GetFDO() *FDOCustomization { return c.FDO } -func (c *Customizations) GetOpenSCAP() *OpenSCAPCustomization { - if c == nil { - return nil - } - return c.OpenSCAP -} - func (c *Customizations) GetIgnition() *IgnitionCustomization { if c == nil { return nil diff --git a/pkg/blueprint/customizations_test.go b/pkg/blueprint/customizations_test.go index 00c718b138..7cc3afdece 100644 --- a/pkg/blueprint/customizations_test.go +++ b/pkg/blueprint/customizations_test.go @@ -371,23 +371,3 @@ func TestGetFilesystemsMinSizeNonSectorSize(t *testing.T) { assert.EqualValues(t, uint64(5632), retFilesystemsSize) } - -func TestGetOpenSCAPConfig(t *testing.T) { - - expectedOscap := OpenSCAPCustomization{ - Datastream: "test-data-stream.xml", - ProfileID: "test_profile", - Tailoring: &OpenSCAPTailoringCustomizations{ - Selected: []string{"quick_rule"}, - Unselected: []string{"very_slow_rule"}, - }, - } - - TestCustomizations := Customizations{ - OpenSCAP: &expectedOscap, - } - - retOpenSCAPCustomiztions := TestCustomizations.GetOpenSCAP() - - assert.EqualValues(t, expectedOscap, *retOpenSCAPCustomiztions) -} diff --git a/pkg/blueprint/openscap_customizations.go b/pkg/blueprint/openscap_customizations.go new file mode 100644 index 0000000000..8eed19b57d --- /dev/null +++ b/pkg/blueprint/openscap_customizations.go @@ -0,0 +1,78 @@ +package blueprint + +import ( + "encoding/json" + "fmt" +) + +type OpenSCAPCustomization struct { + Datastream string `json:"datastream,omitempty" toml:"datastream,omitempty"` + ProfileID string `json:"profile_id,omitempty" toml:"profile_id,omitempty"` + Tailoring *OpenSCAPTailoringCustomizations `json:"tailoring,omitempty" toml:"tailoring,omitempty"` +} + +type OpenSCAPTailoringCustomizations struct { + Selected []string `json:"selected,omitempty" toml:"selected,omitempty"` + Unselected []string `json:"unselected,omitempty" toml:"unselected,omitempty"` + Overrides []OpenSCAPTailoringOverride `json:"overrides,omitempty" toml:"overrides,omitempty"` +} + +type OpenSCAPTailoringOverride struct { + Var string `json:"var,omitempty" toml:"var,omitempty"` + Value interface{} `json:"value,omitempty" toml:"value,omitempty"` +} + +func (c *Customizations) GetOpenSCAP() *OpenSCAPCustomization { + if c == nil { + return nil + } + return c.OpenSCAP +} + +func (ot *OpenSCAPTailoringOverride) UnmarshalTOML(data interface{}) error { + d, _ := data.(map[string]interface{}) + + switch d["var"].(type) { + case string: + ot.Var = d["var"].(string) + default: + return fmt.Errorf("TOML unmarshal: override var must be string, got %v of type %T", d["var"], d["var"]) + } + + switch d["value"].(type) { + case int64: + ot.Value = uint64(d["value"].(int64)) + case string: + ot.Value = d["value"].(string) + default: + return fmt.Errorf("TOML unmarshal: override value must be integer or string, got %v of type %T", d["value"], d["value"]) + } + + return nil +} + +func (ot *OpenSCAPTailoringOverride) UnmarshalJSON(data []byte) error { + var v interface{} + if err := json.Unmarshal(data, &v); err != nil { + return err + } + d, _ := v.(map[string]interface{}) + + switch d["var"].(type) { + case string: + ot.Var = d["var"].(string) + default: + return fmt.Errorf("JSON unmarshal: override var must be string, got %v of type %T", d["var"], d["var"]) + } + + switch d["value"].(type) { + case float64: + ot.Value = uint64(d["value"].(float64)) + case string: + ot.Value = d["value"].(string) + default: + return fmt.Errorf("JSON unmarshal: override var must be float64 number or string, got %v of type %T", d["value"], d["value"]) + } + + return nil +} diff --git a/pkg/blueprint/openscap_customizations_test.go b/pkg/blueprint/openscap_customizations_test.go new file mode 100644 index 0000000000..369ec4ec32 --- /dev/null +++ b/pkg/blueprint/openscap_customizations_test.go @@ -0,0 +1,143 @@ +package blueprint + +import ( + "encoding/json" + "testing" + + "github.com/BurntSushi/toml" + "github.com/stretchr/testify/assert" +) + +func TestGetOpenSCAPConfig(t *testing.T) { + + expectedOscap := OpenSCAPCustomization{ + Datastream: "test-data-stream.xml", + ProfileID: "test_profile", + Tailoring: &OpenSCAPTailoringCustomizations{ + Selected: []string{"quick_rule"}, + Unselected: []string{"very_slow_rule"}, + Overrides: []OpenSCAPTailoringOverride{ + OpenSCAPTailoringOverride{ + Var: "rule_id", + Value: 50, + }, + }, + }, + } + + TestCustomizations := Customizations{ + OpenSCAP: &expectedOscap, + } + + retOpenSCAPCustomiztions := TestCustomizations.GetOpenSCAP() + + assert.EqualValues(t, expectedOscap, *retOpenSCAPCustomiztions) +} + +func TestOpenSCAPOverrideTOMLUnmarshaler(t *testing.T) { + tests := []struct { + name string + TOML string + want *OpenSCAPTailoringOverride + wantErr bool + }{ + { + name: "string based rule", + TOML: ` +var = "sshd_idle_timeout_value" +value = "600" + `, + want: &OpenSCAPTailoringOverride{ + Var: "sshd_idle_timeout_value", + Value: "600", + }, + wantErr: false, + }, + { + name: "integer based rule", + TOML: ` +var = "sshd_idle_timeout_value" +value = 600 + `, + want: &OpenSCAPTailoringOverride{ + Var: "sshd_idle_timeout_value", + Value: uint64(600), + }, + wantErr: false, + }, + { + name: "invalid rule", + TOML: ` +var = "sshd_idle_timeout_value" + `, + want: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + var override OpenSCAPTailoringOverride + err := toml.Unmarshal([]byte(tt.TOML), &override) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.NotNil(t, override) + assert.Equal(t, tt.want, &override) + } + } +} + +func TestOpenSCAPOverrideJSONUnmarshaler(t *testing.T) { + tests := []struct { + name string + JSON string + want *OpenSCAPTailoringOverride + wantErr bool + }{ + { + name: "string based rule", + JSON: `{ + "var": "sshd_idle_timeout_value", + "value": "600" + }`, + want: &OpenSCAPTailoringOverride{ + Var: "sshd_idle_timeout_value", + Value: "600", + }, + wantErr: false, + }, + { + name: "integer based rule", + JSON: `{ + "var": "sshd_idle_timeout_value", + "value": 600 + }`, + want: &OpenSCAPTailoringOverride{ + Var: "sshd_idle_timeout_value", + Value: uint64(600), + }, + wantErr: false, + }, + { + name: "invalid rule", + JSON: `{ + "var": "sshd_idle_timeout_value" + }`, + want: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + var override OpenSCAPTailoringOverride + err := json.Unmarshal([]byte(tt.JSON), &override) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.NotNil(t, override) + assert.Equal(t, tt.want, &override) + } + } +} From fefcc4c267da2904e8724f5adf3800d308c6b86a Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Mon, 4 Dec 2023 22:21:13 +0000 Subject: [PATCH 7/9] pkg/osbuild: enable OpenSCAP tailoring overrides Expose the overrides field in the OpenSCAP autotailor stage. This parses the input and adds the relevant fields to the osbuild json schema. Jira: https://issues.redhat.com/browse/COMPOSER-1994 --- pkg/osbuild/oscap_autotailor_stage.go | 28 +++++++++-- pkg/osbuild/oscap_autotailor_stage_test.go | 56 ++++++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/pkg/osbuild/oscap_autotailor_stage.go b/pkg/osbuild/oscap_autotailor_stage.go index 36b3d6544e..d77494f5d2 100644 --- a/pkg/osbuild/oscap_autotailor_stage.go +++ b/pkg/osbuild/oscap_autotailor_stage.go @@ -8,11 +8,17 @@ type OscapAutotailorStageOptions struct { } type OscapAutotailorConfig struct { - NewProfile string `json:"new_profile"` - Datastream string `json:"datastream" toml:"datastream"` - ProfileID string `json:"profile_id" toml:"profile_id"` - Selected []string `json:"selected,omitempty"` - Unselected []string `json:"unselected,omitempty"` + NewProfile string `json:"new_profile"` + Datastream string `json:"datastream" toml:"datastream"` + ProfileID string `json:"profile_id" toml:"profile_id"` + Selected []string `json:"selected,omitempty"` + Unselected []string `json:"unselected,omitempty"` + Overrides []OscapAutotailorOverride `json:"overrides,omitempty"` +} + +type OscapAutotailorOverride struct { + Var string `json:"var"` + Value interface{} `json:"value"` } func (OscapAutotailorStageOptions) isStageOptions() {} @@ -27,6 +33,17 @@ func (c OscapAutotailorConfig) validate() error { if c.NewProfile == "" { return fmt.Errorf("'new_profile' must be specified") } + for _, override := range c.Overrides { + if _, ok := override.Value.(uint64); ok { + continue + } + + if _, ok := override.Value.(string); ok { + continue + } + + return fmt.Errorf("override 'value' must be an integere or a string") + } return nil } @@ -50,6 +67,7 @@ func NewOscapAutotailorStageOptions(filepath string, autotailorOptions OscapAuto ProfileID: autotailorOptions.ProfileID, Selected: autotailorOptions.Selected, Unselected: autotailorOptions.Unselected, + Overrides: autotailorOptions.Overrides, }, } } diff --git a/pkg/osbuild/oscap_autotailor_stage_test.go b/pkg/osbuild/oscap_autotailor_stage_test.go index 166e687996..92f9b8f492 100644 --- a/pkg/osbuild/oscap_autotailor_stage_test.go +++ b/pkg/osbuild/oscap_autotailor_stage_test.go @@ -15,6 +15,12 @@ func TestNewOscapAutotailorStage(t *testing.T) { NewProfile: "test_profile_osbuild_profile", Selected: []string{"fast_rule"}, Unselected: []string{"slow_rule"}, + Overrides: []OscapAutotailorOverride{ + { + Var: "rule1", + Value: "value1", + }, + }, }, } @@ -65,6 +71,56 @@ func TestOscapAutotailorStageOptionsValidate(t *testing.T) { }, err: true, }, + { + name: "invalid-override-value", + options: OscapAutotailorStageOptions{ + Config: OscapAutotailorConfig{ + ProfileID: "test-profile", + Datastream: "test-datastream", + NewProfile: "test-profile-osbuild-profile", + Overrides: []OscapAutotailorOverride{ + { + Var: "test-var", + }, + }, + }, + }, + err: true, + }, + { + name: "invalid-override-value-string", + options: OscapAutotailorStageOptions{ + Config: OscapAutotailorConfig{ + ProfileID: "test-profile", + Datastream: "test-datastream", + NewProfile: "test-profile-osbuild-profile", + Overrides: []OscapAutotailorOverride{ + { + Var: "test-var", + Value: "30", + }, + }, + }, + }, + err: false, + }, + { + name: "valid-override-value-int", + options: OscapAutotailorStageOptions{ + Config: OscapAutotailorConfig{ + ProfileID: "test-profile", + Datastream: "test-datastream", + NewProfile: "test-profile-osbuild-profile", + Overrides: []OscapAutotailorOverride{ + { + Var: "test-var", + Value: uint64(30), + }, + }, + }, + }, + err: false, + }, { name: "valid-data", options: OscapAutotailorStageOptions{ From be317b5eeb5d58d5786048ce2fbaee195b16b19f Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Wed, 13 Dec 2023 14:25:33 +0000 Subject: [PATCH 8/9] pkg/customizations: enable tailor overrides Enable override rules for the `tailoring` stage. These rules allow users to specify a key/value pair for rule values that they would like to override. Jira: https://issues.redhat.com/browse/COMPOSER-1994 --- pkg/customizations/oscap/stage_options.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/customizations/oscap/stage_options.go b/pkg/customizations/oscap/stage_options.go index e91af54356..82be9304b6 100644 --- a/pkg/customizations/oscap/stage_options.go +++ b/pkg/customizations/oscap/stage_options.go @@ -53,6 +53,14 @@ func CreateTailoringStageOptions(oscapConfig *blueprint.OpenSCAPCustomization, d newProfile := getTailoringProfileID(oscapConfig.ProfileID) path := filepath.Join(tailoringDirPath, "tailoring.xml") + var overrides []osbuild.OscapAutotailorOverride + for _, override := range tailoringConfig.Overrides { + overrides = append(overrides, osbuild.OscapAutotailorOverride{ + Var: override.Var, + Value: override.Value, + }) + } + return osbuild.NewOscapAutotailorStageOptions( path, osbuild.OscapAutotailorConfig{ @@ -60,6 +68,7 @@ func CreateTailoringStageOptions(oscapConfig *blueprint.OpenSCAPCustomization, d Datastream: datastream, Selected: tailoringConfig.Selected, Unselected: tailoringConfig.Unselected, + Overrides: overrides, NewProfile: newProfile, }, ) From 3b6b310be7ddd90805450f1fb1c1c3d7288e32c1 Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Mon, 4 Dec 2023 22:25:21 +0000 Subject: [PATCH 9/9] test/configs: update OpenSCAP tests Update the OpenSCAP tests with the autotailor overrides Jira: https://issues.redhat.com/browse/COMPOSER-1994 --- test/configs/all-with-oscap.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/configs/all-with-oscap.json b/test/configs/all-with-oscap.json index 05d22c495f..e5a976b890 100644 --- a/test/configs/all-with-oscap.json +++ b/test/configs/all-with-oscap.json @@ -9,6 +9,10 @@ { "name": "bluez", "version": "*" + }, + { + "name": "openscap-utils", + "version": "*" } ], "modules": [], @@ -146,6 +150,12 @@ "unselected": [ "rpm_verify_hashes", "enable_fips_mode" + ], + "overrides": [ + { + "var": "sshd_idle_timeout_value", + "value": 600 + } ] } }