diff --git a/cmd/driver/cleanup/cleanup_suite_test.go b/cmd/driver/cleanup/cleanup_suite_test.go new file mode 100644 index 000000000..6099ba49b --- /dev/null +++ b/cmd/driver/cleanup/cleanup_suite_test.go @@ -0,0 +1,69 @@ +// 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 drivercleanup_test + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/spf13/cobra" + + "github.com/falcosecurity/falcoctl/cmd" + commonoptions "github.com/falcosecurity/falcoctl/pkg/options" + testutils "github.com/falcosecurity/falcoctl/pkg/test" +) + +var ( + ctx = context.Background() + output = gbytes.NewBuffer() + rootCmd *cobra.Command + opt *commonoptions.Common + configFile string + err error + args []string +) + +func TestCleanup(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Cleanup Suite") +} + +var _ = BeforeSuite(func() { + + // Create and configure the common options. + opt = commonoptions.NewOptions() + opt.Initialize(commonoptions.WithWriter(output)) + + // Create temporary directory used to save the configuration file. + configFile, err = testutils.CreateEmptyFile("falcoctl.yaml") + Expect(err).Should(Succeed()) +}) + +var _ = AfterSuite(func() { + configDir := filepath.Dir(configFile) + Expect(os.RemoveAll(configDir)).Should(Succeed()) +}) + +func executeRoot(args []string) error { + rootCmd.SetArgs(args) + rootCmd.SetOut(output) + return cmd.Execute(rootCmd, opt) +} diff --git a/cmd/driver/cleanup/cleanup_test.go b/cmd/driver/cleanup/cleanup_test.go new file mode 100644 index 000000000..d91593673 --- /dev/null +++ b/cmd/driver/cleanup/cleanup_test.go @@ -0,0 +1,100 @@ +// 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 drivercleanup_test + +import ( + "regexp" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + + "github.com/falcosecurity/falcoctl/cmd" +) + +var driverCleanupHelp = `[Preview] Cleans a driver up, eg for kmod, by removing it from dkms. +** This command is in preview and under development. ** + +Usage: + falcoctl driver cleanup [flags] + +Flags: + -h, --help help for cleanup + +Global Flags: + --config string config file to be used for falcoctl (default "/etc/falcoctl/falcoctl.yaml") + --host-root string Driver host root to be used. (default "/") + --log-format string Set formatting for logs (color, text, json) (default "color") + --log-level string Set level for logs (info, warn, debug, trace) (default "info") + --name string Driver name to be used. (default "falco") + --repo strings Driver repo to be used. (default [https://download.falco.org/driver]) + --type string Driver type to be used (auto, ebpf, kmod, modern_ebpf) (default "kmod") + --version string Driver version to be used. +` + +var addAssertFailedBehavior = func(specificError string) { + It("check that fails and the usage is not printed", func() { + Expect(err).To(HaveOccurred()) + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(specificError))) + }) +} + +var _ = Describe("cleanup", func() { + + var ( + driverCmd = "driver" + cleanupCmd = "cleanup" + ) + + // Each test gets its own root command and runs it. + // The err variable is asserted by each test. + JustBeforeEach(func() { + rootCmd = cmd.New(ctx, opt) + err = executeRoot(args) + }) + + JustAfterEach(func() { + Expect(output.Clear()).ShouldNot(HaveOccurred()) + }) + + Context("help message", func() { + BeforeEach(func() { + args = []string{driverCmd, cleanupCmd, "--help"} + }) + + It("should match the saved one", func() { + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(driverCleanupHelp))) + }) + }) + + // Here we are testing failure cases for cleaning a driver. + Context("failure", func() { + When("with non absolute host-root", func() { + BeforeEach(func() { + args = []string{driverCmd, cleanupCmd, "--config", configFile, "--host-root", "foo/"} + }) + addAssertFailedBehavior("ERROR host-root must be an absolute path (foo/)") + }) + + When("with invalid driver type", func() { + BeforeEach(func() { + args = []string{driverCmd, cleanupCmd, "--config", configFile, "--type", "foo"} + }) + addAssertFailedBehavior(`ERROR invalid argument "foo" for "--type" flag: invalid argument "foo",` + + ` please provide one of (auto, ebpf, kmod, modern_ebpf)`) + }) + }) +}) diff --git a/cmd/driver/install/install_suite_test.go b/cmd/driver/install/install_suite_test.go new file mode 100644 index 000000000..fb178e6af --- /dev/null +++ b/cmd/driver/install/install_suite_test.go @@ -0,0 +1,69 @@ +// 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 driverinstall_test + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/spf13/cobra" + + "github.com/falcosecurity/falcoctl/cmd" + commonoptions "github.com/falcosecurity/falcoctl/pkg/options" + testutils "github.com/falcosecurity/falcoctl/pkg/test" +) + +var ( + ctx = context.Background() + output = gbytes.NewBuffer() + rootCmd *cobra.Command + opt *commonoptions.Common + configFile string + err error + args []string +) + +func TestInstall(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Install Suite") +} + +var _ = BeforeSuite(func() { + + // Create and configure the common options. + opt = commonoptions.NewOptions() + opt.Initialize(commonoptions.WithWriter(output)) + + // Create temporary directory used to save the configuration file. + configFile, err = testutils.CreateEmptyFile("falcoctl.yaml") + Expect(err).Should(Succeed()) +}) + +var _ = AfterSuite(func() { + configDir := filepath.Dir(configFile) + Expect(os.RemoveAll(configDir)).Should(Succeed()) +}) + +func executeRoot(args []string) error { + rootCmd.SetArgs(args) + rootCmd.SetOut(output) + return cmd.Execute(rootCmd, opt) +} diff --git a/cmd/driver/install/install_test.go b/cmd/driver/install/install_test.go new file mode 100644 index 000000000..f94fd8a20 --- /dev/null +++ b/cmd/driver/install/install_test.go @@ -0,0 +1,123 @@ +// 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 driverinstall_test + +import ( + "regexp" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + + "github.com/falcosecurity/falcoctl/cmd" +) + +//nolint:lll // no need to check for line length. +var driverInstallHelp = `[Preview] Install previously configured driver, either downloading it or attempting a build. +** This command is in preview and under development. ** + +Usage: + falcoctl driver install [flags] + +Flags: + --compile Whether to enable local compilation of drivers (default true) + --download Whether to enable download of prebuilt drivers (default true) + -h, --help help for install + --http-insecure Whether you want to allow insecure downloads or not + --http-timeout duration Timeout for each http try (default 1m0s) + --kernelrelease string Specify the kernel release for which to download/build the driver in the same format used by 'uname -r' (e.g. '6.1.0-10-cloud-amd64') + --kernelversion string Specify the kernel version for which to download/build the driver in the same format used by 'uname -v' (e.g. '#1 SMP PREEMPT_DYNAMIC Debian 6.1.38-2 (2023-07-27)') + +Global Flags: + --config string config file to be used for falcoctl (default "/etc/falcoctl/falcoctl.yaml") + --host-root string Driver host root to be used. (default "/") + --log-format string Set formatting for logs (color, text, json) (default "color") + --log-level string Set level for logs (info, warn, debug, trace) (default "info") + --name string Driver name to be used. (default "falco") + --repo strings Driver repo to be used. (default [https://download.falco.org/driver]) + --type string Driver type to be used (auto, ebpf, kmod, modern_ebpf) (default "kmod") + --version string Driver version to be used. +` + +var addAssertFailedBehavior = func(specificError string) { + It("check that fails and the usage is not printed", func() { + Expect(err).To(HaveOccurred()) + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(specificError))) + }) +} + +var addAssertOkBehavior = func(specificOut string) { + It("check that does not fail and the usage is not printed", func() { + Succeed() + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(specificOut))) + }) +} + +var _ = Describe("install", func() { + + var ( + driverCmd = "driver" + installCmd = "install" + ) + + // Each test gets its own root command and runs it. + // The err variable is asserted by each test. + JustBeforeEach(func() { + rootCmd = cmd.New(ctx, opt) + err = executeRoot(args) + }) + + JustAfterEach(func() { + Expect(output.Clear()).ShouldNot(HaveOccurred()) + }) + + Context("help message", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--help"} + }) + + It("should match the saved one", func() { + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(driverInstallHelp))) + }) + }) + + // Here we are testing failure cases for installing a driver. + Context("failure", func() { + When("with non absolute host-root", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--config", configFile, "--host-root", "foo/"} + }) + addAssertFailedBehavior("ERROR host-root must be an absolute path (foo/)") + }) + + When("with invalid driver type", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--config", configFile, "--type", "foo"} + }) + addAssertFailedBehavior(`ERROR invalid argument "foo" for "--type" flag: invalid argument "foo",` + + ` please provide one of (auto, ebpf, kmod, modern_ebpf)`) + }) + }) + + Context("nothing-to-do", func() { + When("with false download and compile", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--config", configFile, "--download=false", "--compile=false"} + }) + addAssertOkBehavior("INFO Nothing to do: download and compile disabled.") + }) + }) +}) diff --git a/cmd/driver/printenv/printenv_suite_test.go b/cmd/driver/printenv/printenv_suite_test.go new file mode 100644 index 000000000..a48a9e264 --- /dev/null +++ b/cmd/driver/printenv/printenv_suite_test.go @@ -0,0 +1,69 @@ +// 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 driverprintenv_test + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/spf13/cobra" + + "github.com/falcosecurity/falcoctl/cmd" + commonoptions "github.com/falcosecurity/falcoctl/pkg/options" + testutils "github.com/falcosecurity/falcoctl/pkg/test" +) + +var ( + ctx = context.Background() + output = gbytes.NewBuffer() + rootCmd *cobra.Command + opt *commonoptions.Common + configFile string + err error + args []string +) + +func TestPrintenv(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Printenv Suite") +} + +var _ = BeforeSuite(func() { + + // Create and configure the common options. + opt = commonoptions.NewOptions() + opt.Initialize(commonoptions.WithWriter(output)) + + // Create temporary directory used to save the configuration file. + configFile, err = testutils.CreateEmptyFile("falcoctl.yaml") + Expect(err).Should(Succeed()) +}) + +var _ = AfterSuite(func() { + configDir := filepath.Dir(configFile) + Expect(os.RemoveAll(configDir)).Should(Succeed()) +}) + +func executeRoot(args []string) error { + rootCmd.SetArgs(args) + rootCmd.SetOut(output) + return cmd.Execute(rootCmd, opt) +} diff --git a/cmd/driver/printenv/printenv_test.go b/cmd/driver/printenv/printenv_test.go new file mode 100644 index 000000000..0ea8278ca --- /dev/null +++ b/cmd/driver/printenv/printenv_test.go @@ -0,0 +1,138 @@ +// 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 driverprintenv_test + +import ( + "bufio" + "os" + "regexp" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + + "github.com/falcosecurity/falcoctl/cmd" +) + +var driverPrintenvHelp = `[Preview] Print variables used by driver as env vars. +** This command is in preview and under development. ** + +Usage: + falcoctl driver printenv [flags] + +Flags: + -h, --help help for printenv + +Global Flags: + --config string config file to be used for falcoctl (default "/etc/falcoctl/falcoctl.yaml") + --host-root string Driver host root to be used. (default "/") + --log-format string Set formatting for logs (color, text, json) (default "color") + --log-level string Set level for logs (info, warn, debug, trace) (default "info") + --name string Driver name to be used. (default "falco") + --repo strings Driver repo to be used. (default [https://download.falco.org/driver]) + --type string Driver type to be used (auto, ebpf, kmod, modern_ebpf) (default "kmod") + --version string Driver version to be used. +` + +var driverPrintenvDefaultConfig = `DRIVER="kmod" +DRIVERS_REPO="https:\/\/download\.falco\.org\/driver" +DRIVER_VERSION=".*" +DRIVER_NAME="falco" +HOST_ROOT="\/" +TARGET_ID=".*" +ARCH="x86_64|aarch64" +KERNEL_RELEASE=".*" +KERNEL_VERSION=".*" +FIXED_KERNEL_RELEASE=".*" +FIXED_KERNEL_VERSION=".*" +` + +var addAssertFailedBehavior = func(specificError string) { + It("check that fails and the usage is not printed", func() { + Expect(err).To(HaveOccurred()) + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(specificError))) + }) +} + +var _ = Describe("printenv", func() { + + var ( + driverCmd = "driver" + printenvCmd = "printenv" + ) + + // Each test gets its own root command and runs it. + // The err variable is asserted by each test. + JustBeforeEach(func() { + rootCmd = cmd.New(ctx, opt) + err = executeRoot(args) + }) + + JustAfterEach(func() { + Expect(output.Clear()).ShouldNot(HaveOccurred()) + }) + + Context("help message", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--help"} + }) + + It("should match the saved one", func() { + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(driverPrintenvHelp))) + }) + }) + + // Here we are testing failure cases for cleaning a driver. + Context("failure", func() { + When("with non absolute host-root", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--config", configFile, "--host-root", "foo/"} + }) + addAssertFailedBehavior("ERROR host-root must be an absolute path (foo/)") + }) + + When("with invalid driver type", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--config", configFile, "--type", "foo"} + }) + addAssertFailedBehavior(`ERROR invalid argument "foo" for "--type" flag: invalid argument "foo",` + + ` please provide one of (auto, ebpf, kmod, modern_ebpf)`) + }) + }) + + Context("success", func() { + When("with default config values", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--config", configFile} + }) + + It("should match the saved one", func() { + Succeed() + MatchRegexp(driverPrintenvDefaultConfig) + Expect(string(output.Contents())).To(MatchRegexp(driverPrintenvDefaultConfig)) + // Expect that output is bash setenv compatible + scanner := bufio.NewScanner(output) + for scanner.Scan() { + vals := strings.Split(scanner.Text(), "=") + Expect(vals).Should(HaveLen(2)) + err := os.Setenv(vals[0], vals[1]) + Expect(err).Should(BeNil()) + } + }) + }) + }) +})