From 866ccabb69cd02c35a678d5eff94c1b47efd94c1 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Thu, 23 Nov 2023 11:07:19 +0100 Subject: [PATCH] new(pkg/driver): added tests for driver distros implementations. Moreover, fixed some discovered issues. Signed-off-by: Federico Di Pierro --- pkg/driver/distro/amzn.go | 9 +- pkg/driver/distro/amzn_test.go | 73 +++++++++ pkg/driver/distro/bottlerocket.go | 13 +- pkg/driver/distro/bottlerocket_test.go | 79 +++++++++ pkg/driver/distro/centos_test.go | 82 ++++++++++ pkg/driver/distro/cos.go | 12 +- pkg/driver/distro/cos_test.go | 63 ++++++++ pkg/driver/distro/debian_test.go | 130 +++++++++++++++ pkg/driver/distro/distro.go | 5 +- pkg/driver/distro/distro_test.go | 214 +++++++++++++++++++++++++ pkg/driver/distro/flatcar.go | 9 +- pkg/driver/distro/flatcar_test.go | 64 ++++++++ pkg/driver/distro/minikube.go | 2 +- pkg/driver/distro/minikube_test.go | 88 ++++++++++ pkg/driver/distro/rhel_test.go | 82 ++++++++++ pkg/driver/distro/talos.go | 7 +- pkg/driver/distro/talos_test.go | 68 ++++++++ pkg/driver/distro/ubuntu_test.go | 87 ++++++++++ 18 files changed, 1055 insertions(+), 32 deletions(-) create mode 100644 pkg/driver/distro/amzn_test.go create mode 100644 pkg/driver/distro/bottlerocket_test.go create mode 100644 pkg/driver/distro/centos_test.go create mode 100644 pkg/driver/distro/cos_test.go create mode 100644 pkg/driver/distro/debian_test.go create mode 100644 pkg/driver/distro/distro_test.go create mode 100644 pkg/driver/distro/flatcar_test.go create mode 100644 pkg/driver/distro/minikube_test.go create mode 100644 pkg/driver/distro/rhel_test.go create mode 100644 pkg/driver/distro/talos_test.go create mode 100644 pkg/driver/distro/ubuntu_test.go diff --git a/pkg/driver/distro/amzn.go b/pkg/driver/distro/amzn.go index 4f3a487d..d02cf08c 100644 --- a/pkg/driver/distro/amzn.go +++ b/pkg/driver/distro/amzn.go @@ -16,8 +16,6 @@ package driverdistro import ( - "fmt" - "github.com/falcosecurity/driverkit/pkg/kernelrelease" "gopkg.in/ini.v1" ) @@ -32,10 +30,9 @@ type amzn struct { //nolint:gocritic // the method shall not be able to modify kr func (a *amzn) init(kr kernelrelease.KernelRelease, _ string, cfg *ini.File) error { - idKey := cfg.Section("").Key("VERSION_ID") - if idKey == nil { - // OS-release without `VERSION_ID` (can it happen?) - return fmt.Errorf("no VERSION_ID present for amzn") + idKey, err := cfg.Section("").GetKey("VERSION_ID") + if err != nil { + return err } // overwrite id newID := "" diff --git a/pkg/driver/distro/amzn_test.go b/pkg/driver/distro/amzn_test.go new file mode 100644 index 00000000..7ac9cbfe --- /dev/null +++ b/pkg/driver/distro/amzn_test.go @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/ini.v1" +) + +func TestDistroAmznInit(t *testing.T) { + type config struct { + VersionID string `ini:"VERSION_ID"` + } + type testCase struct { + cfg interface{} + strExpected string + errExpected bool + } + testCases := []testCase{ + { + cfg: &config{VersionID: ""}, + strExpected: "amazonlinux", + }, + { + cfg: &config{VersionID: "2"}, + strExpected: "amazonlinux2", + }, + { + cfg: &config{VersionID: "2022"}, + strExpected: "amazonlinux2022", + }, + { + cfg: &config{VersionID: "2023"}, + strExpected: "amazonlinux2023", + }, + { + cfg: &struct{}{}, + errExpected: true, + }, + } + for _, tCase := range testCases { + al := &amzn{generic: &generic{}} + cfg := ini.Empty() + err := cfg.ReflectFrom(tCase.cfg) + require.NoError(t, err) + + kr := kernelrelease.KernelRelease{} + err = al.init(kr, "", cfg) + if tCase.errExpected { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tCase.strExpected, al.String()) + } + } +} diff --git a/pkg/driver/distro/bottlerocket.go b/pkg/driver/distro/bottlerocket.go index 7638b5c5..9a02d908 100644 --- a/pkg/driver/distro/bottlerocket.go +++ b/pkg/driver/distro/bottlerocket.go @@ -35,16 +35,15 @@ type bottlerocket struct { //nolint:gocritic // the method shall not be able to modify kr func (b *bottlerocket) init(kr kernelrelease.KernelRelease, id string, cfg *ini.File) error { - idKey := cfg.Section("").Key("VERSION_ID") - if idKey == nil { - // OS-release without `VERSION_ID` (can it happen?) - return fmt.Errorf("no VERSION_ID present for bottlerocket") + idKey, err := cfg.Section("").GetKey("VERSION_ID") + if err != nil { + return err } b.versionID = idKey.String() - idKey = cfg.Section("").Key("VARIANT_ID") - if idKey == nil { - return fmt.Errorf("no VARIANT_ID present for bottlerocket") + idKey, err = cfg.Section("").GetKey("VARIANT_ID") + if err != nil { + return err } b.variantID = strings.Split(idKey.String(), "-")[0] diff --git a/pkg/driver/distro/bottlerocket_test.go b/pkg/driver/distro/bottlerocket_test.go new file mode 100644 index 00000000..0e4df2b6 --- /dev/null +++ b/pkg/driver/distro/bottlerocket_test.go @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/ini.v1" +) + +func TestDistroBottlerocketFixup(t *testing.T) { + type config struct { + VersionID string `ini:"VERSION_ID"` + VariantID string `ini:"VARIANT_ID"` + } + type nonVersionConfig struct { + VariantID string `ini:"VARIANT_ID"` + } + type nonVariantConfig struct { + VersionID string `ini:"VERSION_ID"` + } + + type testCase struct { + cfg interface{} + kvExpected string + errExpected bool + } + testCases := []testCase{ + { + cfg: &config{VersionID: "1.11.0", VariantID: "aws-k8s-1.15"}, + kvExpected: "1_1.11.0-aws", + }, + { + cfg: &config{VersionID: "1.17.0", VariantID: "aws"}, + kvExpected: "1_1.17.0-aws", + }, + { + cfg: &nonVersionConfig{VariantID: "aws"}, + errExpected: true, + }, + { + cfg: &nonVariantConfig{VersionID: "1.11.0"}, + errExpected: true, + }, + } + + for _, tCase := range testCases { + br := &bottlerocket{generic: &generic{}} + cfg := ini.Empty() + err := cfg.ReflectFrom(tCase.cfg) + require.NoError(t, err) + + kr := kernelrelease.KernelRelease{} + err = br.init(kr, "", cfg) + if tCase.errExpected { + assert.Error(t, err) + } else { + assert.NoError(t, err) + fixedKr := br.FixupKernel(kr) + assert.Equal(t, tCase.kvExpected, fixedKr.KernelVersion) + } + } +} diff --git a/pkg/driver/distro/centos_test.go b/pkg/driver/distro/centos_test.go new file mode 100644 index 00000000..9f60a318 --- /dev/null +++ b/pkg/driver/distro/centos_test.go @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDistroCentosCheck(t *testing.T) { + type testCase struct { + hostRoot string + preFn func() error + postFn func() + retExpected bool + } + testCases := []testCase{ + { + // No centos-release file + hostRoot: "/foo", + preFn: func() error { + return nil + }, + postFn: func() {}, + retExpected: false, + }, + { + // centos-release file present under hostroot + hostRoot: ".", + preFn: func() error { + if err := os.MkdirAll("./etc/", 0o755); err != nil { + return err + } + _, err := os.Create("./etc/centos-release") + return err + }, + postFn: func() { + _ = os.RemoveAll("./etc/centos-release") + }, + retExpected: true, + }, + { + // centos-release file present but not under hostroot + hostRoot: "/foo", + preFn: func() error { + if err := os.MkdirAll("./etc/", 0o755); err != nil { + return err + } + _, err := os.Create("./etc/centos-release") + return err + }, + postFn: func() { + _ = os.RemoveAll("./etc/centos-release") + }, + retExpected: false, + }, + } + + for _, tCase := range testCases { + c := ¢os{generic: &generic{}} + err := tCase.preFn() + require.NoError(t, err) + assert.Equal(t, tCase.retExpected, c.check(tCase.hostRoot)) + tCase.postFn() + } +} diff --git a/pkg/driver/distro/cos.go b/pkg/driver/distro/cos.go index 1dcd87df..dfe3c75c 100644 --- a/pkg/driver/distro/cos.go +++ b/pkg/driver/distro/cos.go @@ -44,13 +44,13 @@ type cos struct { } //nolint:gocritic // the method shall not be able to modify kr -func (c *cos) init(kr kernelrelease.KernelRelease, _ string, cfg *ini.File) error { - idKey := cfg.Section("").Key("BUILD_ID") - if idKey == nil { - // OS-release without `VERSION_ID` (can it happen?) - return fmt.Errorf("no BUILD_ID present for COS") +func (c *cos) init(kr kernelrelease.KernelRelease, id string, cfg *ini.File) error { + idKey, err := cfg.Section("").GetKey("BUILD_ID") + if err != nil { + return err } - return c.generic.init(kr, idKey.String(), cfg) + c.buildID = idKey.String() + return c.generic.init(kr, id, cfg) } //nolint:gocritic // the method shall not be able to modify kr diff --git a/pkg/driver/distro/cos_test.go b/pkg/driver/distro/cos_test.go new file mode 100644 index 00000000..8556a917 --- /dev/null +++ b/pkg/driver/distro/cos_test.go @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/ini.v1" +) + +func TestDistroCosInit(t *testing.T) { + type config struct { + BuildID string `ini:"BUILD_ID"` + } + + type testCase struct { + cfg interface{} + buildID string + errExpected bool + } + testCases := []testCase{ + { + cfg: &config{BuildID: "17162.127.33"}, + buildID: "17162.127.33", + }, + { + cfg: &struct{}{}, + errExpected: true, + }, + } + + for _, tCase := range testCases { + co := &cos{generic: &generic{}} + cfg := ini.Empty() + err := cfg.ReflectFrom(tCase.cfg) + require.NoError(t, err) + + kr := kernelrelease.KernelRelease{} + err = co.init(kr, "", cfg) + if tCase.errExpected { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tCase.buildID, co.buildID) + } + } +} diff --git a/pkg/driver/distro/debian_test.go b/pkg/driver/distro/debian_test.go new file mode 100644 index 00000000..9fae29fe --- /dev/null +++ b/pkg/driver/distro/debian_test.go @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "os" + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDistroDebianCheck(t *testing.T) { + type testCase struct { + hostRoot string + preFn func() error + postFn func() + retExpected bool + } + testCases := []testCase{ + { + // No debian_version file + hostRoot: "/foo", + preFn: func() error { + return nil + }, + postFn: func() {}, + retExpected: false, + }, + { + // debian_version file present under hostroot + hostRoot: ".", + preFn: func() error { + if err := os.MkdirAll("./etc/", 0o755); err != nil { + return err + } + _, err := os.Create("./etc/debian_version") + return err + }, + postFn: func() { + _ = os.RemoveAll("./etc/debian_version") + }, + retExpected: true, + }, + { + // debian_version file present but not under hostroot + hostRoot: "/foo", + preFn: func() error { + if err := os.MkdirAll("./etc/", 0o755); err != nil { + return err + } + _, err := os.Create("./etc/debian_version") + return err + }, + postFn: func() { + _ = os.RemoveAll("./etc/debian_version") + }, + retExpected: false, + }, + } + + for _, tCase := range testCases { + deb := &debian{generic: &generic{}} + err := tCase.preFn() + require.NoError(t, err) + assert.Equal(t, tCase.retExpected, deb.check(tCase.hostRoot)) + tCase.postFn() + } +} + +func TestDistroDebianFixup(t *testing.T) { + type testCase struct { + krInput string + kvInput string + krExpected string + } + testCases := []testCase{ + { + // Substitution needed since kernelversion contains the real kernelrelease + krInput: "5.10.0-0.deb10.22-rt-amd64", + kvInput: "5.10.178-3", + krExpected: "5.10.178-3-rt-amd64", + }, + { + // Substitution needed since kernelversion contains the real kernelrelease + krInput: "5.10.0-0.deb10.22-amd64", + kvInput: "5.10.178-3", + krExpected: "5.10.178-3-amd64", + }, + { + // Substitution NOT needed + krInput: "5.10.0-0.deb10.22-amd64", + kvInput: "1", + krExpected: "5.10.0-0.deb10.22-amd64", + }, + { + // Substitution NOT needed + krInput: "5.10.0-0", + kvInput: "1", + krExpected: "5.10.0-0", + }, + { + // Substitution NOT needed + krInput: "6.5.3-1~bpo12+1-rt-amd64", + kvInput: "1", + krExpected: "6.5.3-1~bpo12+1-rt-amd64", + }, + } + for _, tCase := range testCases { + deb := &debian{generic: &generic{}} + kr := kernelrelease.FromString(tCase.krInput) + kr.KernelVersion = tCase.kvInput + fixedKr := deb.FixupKernel(kr) + assert.Equal(t, tCase.krExpected, fixedKr.String()) + } +} diff --git a/pkg/driver/distro/distro.go b/pkg/driver/distro/distro.go index 77600be4..8d00056c 100644 --- a/pkg/driver/distro/distro.go +++ b/pkg/driver/distro/distro.go @@ -95,9 +95,8 @@ func getOSReleaseDistro(kr *kernelrelease.KernelRelease, hostRoot string) (Distr if err != nil { return nil, err } - idKey := cfg.Section("").Key("ID") - if idKey == nil { - // OS-release without `ID` (can it happen?) + idKey, err := cfg.Section("").GetKey("ID") + if err != nil { return nil, nil } id := strings.ToLower(idKey.String()) diff --git a/pkg/driver/distro/distro_test.go b/pkg/driver/distro/distro_test.go new file mode 100644 index 00000000..08b7e4cb --- /dev/null +++ b/pkg/driver/distro/distro_test.go @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "os" + "path/filepath" + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/ini.v1" +) + +func TestDiscoverDistro(t *testing.T) { + hostRoot := "." + etcDir := filepath.Join(hostRoot, "etc") + osReleaseFile := filepath.Join(etcDir, "os-release") + + type osID struct { + OsID string `ini:"ID"` + } + + type testCase struct { + krInput string + preFn func() error + postFn func() + distroExpected interface{} + errExpected bool + } + testCases := []testCase{ + { + // No os-release + krInput: "5.10.0", + preFn: func() error { + return nil + }, + postFn: func() {}, + distroExpected: nil, + errExpected: true, + }, + { + // os-release empty (without ID) + krInput: "5.10.0", + preFn: func() error { + _, err := os.Create(osReleaseFile) + return err + }, + postFn: func() { + _ = os.Remove(osReleaseFile) + }, + distroExpected: nil, + errExpected: false, + }, + { + // os-release ID "foo" mapped to generic + krInput: "5.10.0", + preFn: func() error { + f := ini.Empty() + err := f.ReflectFrom(&osID{"foo"}) + if err != nil { + return err + } + return f.SaveTo(osReleaseFile) + }, + postFn: func() { + _ = os.Remove(osReleaseFile) + }, + distroExpected: &generic{}, + errExpected: false, + }, + { + // os-release ID "centos" mapped to centos + krInput: "5.10.0", + preFn: func() error { + f := ini.Empty() + err := f.ReflectFrom(&osID{"centos"}) + if err != nil { + return err + } + return f.SaveTo(osReleaseFile) + }, + postFn: func() { + _ = os.Remove(osReleaseFile) + }, + distroExpected: ¢os{}, + errExpected: false, + }, + { + // os-release ID "talos" fails to map to talos because no VERSION_ID is present in the ini + krInput: "5.10.0", + preFn: func() error { + f := ini.Empty() + err := f.ReflectFrom(&osID{"talos"}) + if err != nil { + return err + } + return f.SaveTo(osReleaseFile) + }, + postFn: func() { + _ = os.Remove(osReleaseFile) + }, + distroExpected: &generic{}, + errExpected: false, + }, + { + // os-release ID "talos" maps to talos + krInput: "5.10.0", + preFn: func() error { + type talosCfg struct { + OsID string `ini:"ID"` + VersionID string `ini:"VERSION_ID"` + } + f := ini.Empty() + err := f.ReflectFrom(&talosCfg{ + OsID: "talos", + VersionID: "1.10.0", + }) + if err != nil { + return err + } + return f.SaveTo(osReleaseFile) + }, + postFn: func() { + _ = os.Remove(osReleaseFile) + }, + distroExpected: &talos{}, + errExpected: false, + }, + { + // os-release ID "bottlerocket" maps to bottlerocket + krInput: "5.10.0", + preFn: func() error { + type brCfg struct { + OsID string `ini:"ID"` + VersionID string `ini:"VERSION_ID"` + VariantID string `ini:"VARIANT_ID"` + } + f := ini.Empty() + err := f.ReflectFrom(&brCfg{ + OsID: "bottlerocket", + VersionID: "1.10.0", + VariantID: "aws", + }) + if err != nil { + return err + } + return f.SaveTo(osReleaseFile) + }, + postFn: func() { + _ = os.Remove(osReleaseFile) + }, + distroExpected: &bottlerocket{}, + errExpected: false, + }, + { + // No os-release but "centos-release" file present maps to centos + krInput: "5.10.0", + preFn: func() error { + _, err := os.Create(filepath.Join(etcDir, "centos-release")) + return err + }, + postFn: func() { + _ = os.Remove(filepath.Join(etcDir, "centos-release")) + }, + distroExpected: ¢os{}, + errExpected: false, + }, + { + // No os-release but "VERSION" file present maps to minikube + krInput: "5.10.0", + preFn: func() error { + return os.WriteFile(filepath.Join(etcDir, "VERSION"), []byte("v1.26.0-1655407986-14197"), os.ModePerm) + }, + postFn: func() { + _ = os.Remove(filepath.Join(etcDir, "VERSION")) + }, + distroExpected: &minikube{}, + errExpected: false, + }, + } + + if err := os.MkdirAll(etcDir, 0o755); err != nil { + t.Fatal(err) + } + defer os.RemoveAll(etcDir) + + for _, tCase := range testCases { + err := tCase.preFn() + require.NoError(t, err) + kr := kernelrelease.FromString(tCase.krInput) + d, err := DiscoverDistro(kr, hostRoot) + if tCase.errExpected { + assert.Error(t, err) + } else { + assert.IsType(t, tCase.distroExpected, d) + } + tCase.postFn() + } +} diff --git a/pkg/driver/distro/flatcar.go b/pkg/driver/distro/flatcar.go index e0bd5991..c3aba182 100644 --- a/pkg/driver/distro/flatcar.go +++ b/pkg/driver/distro/flatcar.go @@ -16,7 +16,6 @@ package driverdistro import ( - "fmt" "os/exec" "github.com/blang/semver" @@ -65,10 +64,9 @@ type flatcar struct { //nolint:gocritic // the method shall not be able to modify kr func (f *flatcar) init(kr kernelrelease.KernelRelease, id string, cfg *ini.File) error { - idKey := cfg.Section("").Key("VERSION_ID") - if idKey == nil { - // OS-release without `VERSION_ID` (can it happen?) - return fmt.Errorf("no VERSION_ID present for flatcar") + idKey, err := cfg.Section("").GetKey("VERSION_ID") + if err != nil { + return err } f.versionID = idKey.String() return f.generic.init(kr, id, cfg) @@ -77,6 +75,7 @@ func (f *flatcar) init(kr kernelrelease.KernelRelease, id string, cfg *ini.File) //nolint:gocritic // the method shall not be able to modify kr func (f *flatcar) FixupKernel(kr kernelrelease.KernelRelease) kernelrelease.KernelRelease { kr.Version = semver.MustParse(f.versionID) + kr.Fullversion = kr.Version.String() return kr } diff --git a/pkg/driver/distro/flatcar_test.go b/pkg/driver/distro/flatcar_test.go new file mode 100644 index 00000000..070b906f --- /dev/null +++ b/pkg/driver/distro/flatcar_test.go @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/ini.v1" +) + +func TestDistroFlatcarInitFixup(t *testing.T) { + type config struct { + VersionID string `ini:"VERSION_ID"` + } + + type testCase struct { + cfg interface{} + krExpected string + errExpected bool + } + testCases := []testCase{ + { + cfg: &config{VersionID: "3185.0.0"}, + krExpected: "3185.0.0", + }, + { + cfg: &struct{}{}, + errExpected: true, + }, + } + + for _, tCase := range testCases { + fl := &flatcar{generic: &generic{}} + cfg := ini.Empty() + err := cfg.ReflectFrom(tCase.cfg) + require.NoError(t, err) + + kr := kernelrelease.KernelRelease{} + err = fl.init(kr, "", cfg) + if tCase.errExpected { + assert.Error(t, err) + } else { + assert.NoError(t, err) + fixedKr := fl.FixupKernel(kr) + assert.Equal(t, tCase.krExpected, fixedKr.String()) + } + } +} diff --git a/pkg/driver/distro/minikube.go b/pkg/driver/distro/minikube.go index b43fc06a..4d09fe50 100644 --- a/pkg/driver/distro/minikube.go +++ b/pkg/driver/distro/minikube.go @@ -38,7 +38,7 @@ type minikube struct { version string } -var minikubeVersionRegex = regexp.MustCompile(`(\\d+(\\.\\d+){2})`) +var minikubeVersionRegex = regexp.MustCompile(`(\d+(\.\d+){2})`) // check() will also load minikube version, because minikube has a different // code path from other "checker" distros. diff --git a/pkg/driver/distro/minikube_test.go b/pkg/driver/distro/minikube_test.go new file mode 100644 index 00000000..74346830 --- /dev/null +++ b/pkg/driver/distro/minikube_test.go @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "os" + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDistroMinikubeInitFixup(t *testing.T) { + type testCase struct { + hostRoot string + preFn func() error + postFn func() + retExpected bool + kvExpected string + } + testCases := []testCase{ + { + // No VERSION file + hostRoot: "/foo", + preFn: func() error { + return nil + }, + postFn: func() {}, + retExpected: false, + }, + { + // VERSION file present under hostroot + hostRoot: ".", + preFn: func() error { + if err := os.MkdirAll("./etc/", 0o755); err != nil { + return err + } + return os.WriteFile("./etc/VERSION", []byte("v1.26.0-1655407986-14197"), os.ModePerm) + }, + postFn: func() { + _ = os.RemoveAll("./etc/VERSION") + }, + retExpected: true, + kvExpected: "1_1.26.0", + }, + { + // VERSION file present but not under hostroot + hostRoot: "/foo", + preFn: func() error { + if err := os.MkdirAll("./etc/", 0o755); err != nil { + return err + } + return os.WriteFile("./etc/VERSION", []byte("v1.26.0-1655407986-14197"), os.ModePerm) + }, + postFn: func() { + _ = os.RemoveAll("./etc/VERSION") + }, + retExpected: false, + }, + } + + for _, tCase := range testCases { + mn := &minikube{generic: &generic{}} + err := tCase.preFn() + require.NoError(t, err) + assert.Equal(t, tCase.retExpected, mn.check(tCase.hostRoot)) + if tCase.retExpected { + kr := kernelrelease.KernelRelease{} + fixedKr := mn.FixupKernel(kr) + assert.Equal(t, tCase.kvExpected, fixedKr.KernelVersion) + } + tCase.postFn() + } +} diff --git a/pkg/driver/distro/rhel_test.go b/pkg/driver/distro/rhel_test.go new file mode 100644 index 00000000..315e0de4 --- /dev/null +++ b/pkg/driver/distro/rhel_test.go @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDistroRhelCheck(t *testing.T) { + type testCase struct { + hostRoot string + preFn func() error + postFn func() + retExpected bool + } + testCases := []testCase{ + { + // No redhat-release file + hostRoot: "/foo", + preFn: func() error { + return nil + }, + postFn: func() {}, + retExpected: false, + }, + { + // redhat-release file present under hostroot + hostRoot: ".", + preFn: func() error { + if err := os.MkdirAll("./etc/", 0o755); err != nil { + return err + } + _, err := os.Create("./etc/redhat-release") + return err + }, + postFn: func() { + _ = os.RemoveAll("./etc/redhat-release") + }, + retExpected: true, + }, + { + // redhat-release file present but not under hostroot + hostRoot: "/foo", + preFn: func() error { + if err := os.MkdirAll("./etc/", 0o755); err != nil { + return err + } + _, err := os.Create("./etc/redhat-release") + return err + }, + postFn: func() { + _ = os.RemoveAll("./etc/redhat-release") + }, + retExpected: false, + }, + } + + for _, tCase := range testCases { + r := &rhel{generic: &generic{}} + err := tCase.preFn() + require.NoError(t, err) + assert.Equal(t, tCase.retExpected, r.check(tCase.hostRoot)) + tCase.postFn() + } +} diff --git a/pkg/driver/distro/talos.go b/pkg/driver/distro/talos.go index adbde48f..3824db30 100644 --- a/pkg/driver/distro/talos.go +++ b/pkg/driver/distro/talos.go @@ -33,10 +33,9 @@ type talos struct { //nolint:gocritic // the method shall not be able to modify kr func (t *talos) init(kr kernelrelease.KernelRelease, id string, cfg *ini.File) error { - idKey := cfg.Section("").Key("VERSION_ID") - if idKey == nil { - // OS-release without `VERSION_ID` (can it happen?) - return fmt.Errorf("no VERSION_ID present for talos") + idKey, err := cfg.Section("").GetKey("VERSION_ID") + if err != nil { + return err } t.versionID = idKey.String() diff --git a/pkg/driver/distro/talos_test.go b/pkg/driver/distro/talos_test.go new file mode 100644 index 00000000..8caa9450 --- /dev/null +++ b/pkg/driver/distro/talos_test.go @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/ini.v1" +) + +func TestDistroTalosInitFixup(t *testing.T) { + type config struct { + VersionID string `ini:"VERSION_ID"` + } + + type testCase struct { + cfg interface{} + kvExpected string + errExpected bool + } + testCases := []testCase{ + { + cfg: &config{VersionID: "1.11.0"}, + kvExpected: "1_1.11.0", + }, + { + cfg: &config{VersionID: "1.17.0"}, + kvExpected: "1_1.17.0", + }, + { + cfg: &struct{}{}, + errExpected: true, + }, + } + + for _, tCase := range testCases { + tl := &talos{generic: &generic{}} + cfg := ini.Empty() + err := cfg.ReflectFrom(tCase.cfg) + require.NoError(t, err) + + kr := kernelrelease.KernelRelease{} + err = tl.init(kr, "", cfg) + if tCase.errExpected { + assert.Error(t, err) + } else { + assert.NoError(t, err) + fixedKr := tl.FixupKernel(kr) + assert.Equal(t, tCase.kvExpected, fixedKr.KernelVersion) + } + } +} diff --git a/pkg/driver/distro/ubuntu_test.go b/pkg/driver/distro/ubuntu_test.go new file mode 100644 index 00000000..07729e8e --- /dev/null +++ b/pkg/driver/distro/ubuntu_test.go @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverdistro + +import ( + "testing" + + "github.com/falcosecurity/driverkit/pkg/kernelrelease" + "github.com/stretchr/testify/assert" +) + +func TestDistroUbuntuInitFixup(t *testing.T) { + type testCase struct { + krInput string + kvInput string + flavorExpected string + kvExpected string + } + testCases := []testCase{ + { + krInput: "5.0.0-1028-aws-5.0", + kvInput: "26~22.04.1-Ubuntu", + flavorExpected: "ubuntu-aws", + kvExpected: "26~22.04.1", + }, + { + krInput: "5.0.0-1028-aws-5.0", + kvInput: "26", + flavorExpected: "ubuntu-aws", + kvExpected: "26", + }, + { + krInput: "5.0.0-1028-aws-5.0", + kvInput: "26-Ubuntu", + flavorExpected: "ubuntu-aws", + kvExpected: "26", + }, + { + krInput: "5.0.0", + kvInput: "26", + flavorExpected: "ubuntu-generic", + kvExpected: "26", + }, + { + krInput: "6.5.0-9-lowlatency", + kvInput: "9.1", + flavorExpected: "ubuntu-lowlatency", + kvExpected: "9.1", + }, + { + krInput: "6.5.0-1008-gcp", + kvInput: "8", + flavorExpected: "ubuntu-gcp", + kvExpected: "8", + }, + { + krInput: "6.5.0-1008-aws", + kvInput: "8~22.04.1", + flavorExpected: "ubuntu-aws", + kvExpected: "8~22.04.1", + }, + } + + for _, tCase := range testCases { + ub := &ubuntu{generic: &generic{}} + kr := kernelrelease.FromString(tCase.krInput) + kr.KernelVersion = tCase.kvInput + err := ub.init(kr, "", nil) + assert.NoError(t, err) + assert.Equal(t, tCase.flavorExpected, ub.String()) + fixedKr := ub.FixupKernel(kr) + assert.Equal(t, tCase.kvExpected, fixedKr.KernelVersion) + } +}