diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index 564ee17a..15504ec4 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04] - go: ["1.21.8", "1.22.1"] + go: ["1.21.9", "1.22.2"] goos: [linux] goarch: [amd64, arm64] diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 57ea6fc3..45c48969 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -17,7 +17,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: "1.21.8" + go-version: "1.21.9" - name: Build release binaries env: diff --git a/Dockerfile b/Dockerfile index 366159e3..9fa874be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Stage 1 (Build) -FROM golang:1.21.8-alpine AS builder +FROM golang:1.21.9-alpine AS builder ARG VERSION RUN apk add --update --no-cache git make diff --git a/config/config.go b/config/config.go index f089958f..cc03ed44 100644 --- a/config/config.go +++ b/config/config.go @@ -1,726 +1 @@ -package config - -import ( - "context" - "crypto/tls" - "fmt" - "os" - "os/exec" - "os/user" - "path" - "path/filepath" - "regexp" - "strings" - "sync" - "sync/atomic" - "text/template" - "time" - - "emperror.dev/errors" - "github.com/acobaugh/osrelease" - "github.com/apex/log" - "github.com/creasty/defaults" - "github.com/gbrlsnchs/jwt/v3" - "golang.org/x/sys/unix" - "gopkg.in/yaml.v2" - - "github.com/pelican-dev/wings/system" -) - -const DefaultLocation = "/etc/pelican/config.yml" - -// DefaultTLSConfig sets sane defaults to use when configuring the internal -// webserver to listen for public connections. -// -// @see https://blog.cloudflare.com/exposing-go-on-the-internet -var DefaultTLSConfig = &tls.Config{ - NextProtos: []string{"h2", "http/1.1"}, - CipherSuites: []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - }, - PreferServerCipherSuites: true, - MinVersion: tls.VersionTLS12, - MaxVersion: tls.VersionTLS13, - CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256}, -} - -var ( - mu sync.RWMutex - _config *Configuration - _jwtAlgo *jwt.HMACSHA - _debugViaFlag bool -) - -// Locker specific to writing the configuration to the disk, this happens -// in areas that might already be locked, so we don't want to crash the process. -var _writeLock sync.Mutex - -// SftpConfiguration defines the configuration of the internal SFTP server. -type SftpConfiguration struct { - // The bind address of the SFTP server. - Address string `default:"0.0.0.0" json:"bind_address" yaml:"bind_address"` - // The bind port of the SFTP server. - Port int `default:"2022" json:"bind_port" yaml:"bind_port"` - // If set to true, no write actions will be allowed on the SFTP server. - ReadOnly bool `default:"false" yaml:"read_only"` -} - -// ApiConfiguration defines the configuration for the internal API that is -// exposed by the Wings webserver. -type ApiConfiguration struct { - // The interface that the internal webserver should bind to. - Host string `default:"0.0.0.0" yaml:"host"` - - // The port that the internal webserver should bind to. - Port int `default:"8080" yaml:"port"` - - // SSL configuration for the daemon. - Ssl struct { - Enabled bool `json:"enabled" yaml:"enabled"` - CertificateFile string `json:"cert" yaml:"cert"` - KeyFile string `json:"key" yaml:"key"` - } - - // Determines if functionality for allowing remote download of files into server directories - // is enabled on this instance. If set to "true" remote downloads will not be possible for - // servers. - DisableRemoteDownload bool `json:"disable_remote_download" yaml:"disable_remote_download"` - - // The maximum size for files uploaded through the Panel in MB. - UploadLimit int64 `default:"100" json:"upload_limit" yaml:"upload_limit"` - - // A list of IP address of proxies that may send a X-Forwarded-For header to set the true clients IP - TrustedProxies []string `json:"trusted_proxies" yaml:"trusted_proxies"` -} - -// RemoteQueryConfiguration defines the configuration settings for remote requests -// from Wings to the Panel. -type RemoteQueryConfiguration struct { - // The amount of time in seconds that Wings should allow for a request to the Panel API - // to complete. If this time passes the request will be marked as failed. If your requests - // are taking longer than 30 seconds to complete it is likely a performance issue that - // should be resolved on the Panel, and not something that should be resolved by upping this - // number. - Timeout int `default:"30" yaml:"timeout"` - - // The number of servers to load in a single request to the Panel API when booting the - // Wings instance. A single request is initially made to the Panel to get this number - // of servers, and then the pagination status is checked and additional requests are - // fired off in parallel to request the remaining pages. - // - // It is not recommended to change this from the default as you will likely encounter - // memory limits on your Panel instance. In the grand scheme of things 4 requests for - // 50 servers is likely just as quick as two for 100 or one for 400, and will certainly - // be less likely to cause performance issues on the Panel. - BootServersPerPage int `default:"50" yaml:"boot_servers_per_page"` -} - -// SystemConfiguration defines basic system configuration settings. -type SystemConfiguration struct { - // The root directory where all of the pelican data is stored at. - RootDirectory string `default:"/var/lib/pelican" yaml:"root_directory"` - - // Directory where logs for server installations and other wings events are logged. - LogDirectory string `default:"/var/log/pelican" yaml:"log_directory"` - - // Directory where the server data is stored at. - Data string `default:"/var/lib/pelican/volumes" yaml:"data"` - - // Directory where server archives for transferring will be stored. - ArchiveDirectory string `default:"/var/lib/pelican/archives" yaml:"archive_directory"` - - // Directory where local backups will be stored on the machine. - BackupDirectory string `default:"/var/lib/pelican/backups" yaml:"backup_directory"` - - // TmpDirectory specifies where temporary files for pelican installation processes - // should be created. This supports environments running docker-in-docker. - TmpDirectory string `default:"/tmp/pelican" yaml:"tmp_directory"` - - // The user that should own all of the server files, and be used for containers. - Username string `default:"pelican" yaml:"username"` - - // The timezone for this Wings instance. This is detected by Wings automatically if possible, - // and falls back to UTC if not able to be detected. If you need to set this manually, that - // can also be done. - // - // This timezone value is passed into all containers created by Wings. - Timezone string `yaml:"timezone"` - - // Definitions for the user that gets created to ensure that we can quickly access - // this information without constantly having to do a system lookup. - User struct { - // Rootless controls settings related to rootless container daemons. - Rootless struct { - // Enabled controls whether rootless containers are enabled. - Enabled bool `yaml:"enabled" default:"false"` - // ContainerUID controls the UID of the user inside the container. - // This should likely be set to 0 so the container runs as the user - // running Wings. - ContainerUID int `yaml:"container_uid" default:"0"` - // ContainerGID controls the GID of the user inside the container. - // This should likely be set to 0 so the container runs as the user - // running Wings. - ContainerGID int `yaml:"container_gid" default:"0"` - } `yaml:"rootless"` - - Uid int `yaml:"uid"` - Gid int `yaml:"gid"` - - // Passwd controls weather a passwd file is mounted in the container - // at /etc/passwd to resolve missing user issues - Passwd bool `json:"mount_passwd" yaml:"mount_passwd" default:"true"` - PasswdFile string `json:"passwd_file" yaml:"passwd_file" default:"/etc/pelican/passwd"` - } `yaml:"user"` - - // The amount of time in seconds that can elapse before a server's disk space calculation is - // considered stale and a re-check should occur. DANGER: setting this value too low can seriously - // impact system performance and cause massive I/O bottlenecks and high CPU usage for the Wings - // process. - // - // Set to 0 to disable disk checking entirely. This will always return 0 for the disk space used - // by a server and should only be set in extreme scenarios where performance is critical and - // disk usage is not a concern. - DiskCheckInterval int64 `default:"150" yaml:"disk_check_interval"` - - // ActivitySendInterval is the amount of time that should ellapse between aggregated server activity - // being sent to the Panel. By default this will send activity collected over the last minute. Keep - // in mind that only a fixed number of activity log entries, defined by ActivitySendCount, will be sent - // in each run. - ActivitySendInterval int `default:"60" yaml:"activity_send_interval"` - - // ActivitySendCount is the number of activity events to send per batch. - ActivitySendCount int `default:"100" yaml:"activity_send_count"` - - // If set to true, file permissions for a server will be checked when the process is - // booted. This can cause boot delays if the server has a large amount of files. In most - // cases disabling this should not have any major impact unless external processes are - // frequently modifying a servers' files. - CheckPermissionsOnBoot bool `default:"true" yaml:"check_permissions_on_boot"` - - // If set to false Wings will not attempt to write a log rotate configuration to the disk - // when it boots and one is not detected. - EnableLogRotate bool `default:"true" yaml:"enable_log_rotate"` - - // The number of lines to send when a server connects to the websocket. - WebsocketLogCount int `default:"150" yaml:"websocket_log_count"` - - Sftp SftpConfiguration `yaml:"sftp"` - - CrashDetection CrashDetection `yaml:"crash_detection"` - - Backups Backups `yaml:"backups"` - - Transfers Transfers `yaml:"transfers"` - - OpenatMode string `default:"auto" yaml:"openat_mode"` -} - -type CrashDetection struct { - // CrashDetectionEnabled sets if crash detection is enabled globally for all servers on this node. - CrashDetectionEnabled bool `default:"true" yaml:"enabled"` - - // Determines if Wings should detect a server that stops with a normal exit code of - // "0" as being crashed if the process stopped without any Wings interaction. E.g. - // the user did not press the stop button, but the process stopped cleanly. - DetectCleanExitAsCrash bool `default:"true" yaml:"detect_clean_exit_as_crash"` - - // Timeout specifies the timeout between crashes that will not cause the server - // to be automatically restarted, this value is used to prevent servers from - // becoming stuck in a boot-loop after multiple consecutive crashes. - Timeout int `default:"60" json:"timeout"` -} - -type Backups struct { - // WriteLimit imposes a Disk I/O write limit on backups to the disk, this affects all - // backup drivers as the archiver must first write the file to the disk in order to - // upload it to any external storage provider. - // - // If the value is less than 1, the write speed is unlimited, - // if the value is greater than 0, the write speed is the value in MiB/s. - // - // Defaults to 0 (unlimited) - WriteLimit int `default:"0" yaml:"write_limit"` - - // CompressionLevel determines how much backups created by wings should be compressed. - // - // "none" -> no compression will be applied - // "best_speed" -> uses gzip level 1 for fast speed - // "best_compression" -> uses gzip level 9 for minimal disk space useage - // - // Defaults to "best_speed" (level 1) - CompressionLevel string `default:"best_speed" yaml:"compression_level"` -} - -type Transfers struct { - // DownloadLimit imposes a Network I/O read limit when downloading a transfer archive. - // - // If the value is less than 1, the write speed is unlimited, - // if the value is greater than 0, the write speed is the value in MiB/s. - // - // Defaults to 0 (unlimited) - DownloadLimit int `default:"0" yaml:"download_limit"` -} - -type ConsoleThrottles struct { - // Whether or not the throttler is enabled for this instance. - Enabled bool `json:"enabled" yaml:"enabled" default:"true"` - - // The total number of lines that can be output in a given Period period before - // a warning is triggered and counted against the server. - Lines uint64 `json:"lines" yaml:"lines" default:"2000"` - - // The amount of time after which the number of lines processed is reset to 0. This runs in - // a constant loop and is not affected by the current console output volumes. By default, this - // will reset the processed line count back to 0 every 100ms. - Period uint64 `json:"line_reset_interval" yaml:"line_reset_interval" default:"100"` -} - -type Configuration struct { - // The location from which this configuration instance was instantiated. - path string - - // Determines if wings should be running in debug mode. This value is ignored - // if the debug flag is passed through the command line arguments. - Debug bool - - AppName string `default:"pelican" json:"app_name" yaml:"app_name"` - - // A unique identifier for this node in the Panel. - Uuid string - - // An identifier for the token which must be included in any requests to the panel - // so that the token can be looked up correctly. - AuthenticationTokenId string `json:"token_id" yaml:"token_id"` - - // The token used when performing operations. Requests to this instance must - // validate against it. - AuthenticationToken string `json:"token" yaml:"token"` - - Api ApiConfiguration `json:"api" yaml:"api"` - System SystemConfiguration `json:"system" yaml:"system"` - Docker DockerConfiguration `json:"docker" yaml:"docker"` - - // Defines internal throttling configurations for server processes to prevent - // someone from running an endless loop that spams data to logs. - Throttles ConsoleThrottles - - // The location where the panel is running that this daemon should connect to - // to collect data and send events. - PanelLocation string `json:"remote" yaml:"remote"` - RemoteQuery RemoteQueryConfiguration `json:"remote_query" yaml:"remote_query"` - - // AllowedMounts is a list of allowed host-system mount points. - // This is required to have the "Server Mounts" feature work properly. - AllowedMounts []string `json:"-" yaml:"allowed_mounts"` - - // AllowedOrigins is a list of allowed request origins. - // The Panel URL is automatically allowed, this is only needed for adding - // additional origins. - AllowedOrigins []string `json:"allowed_origins" yaml:"allowed_origins"` - - // AllowCORSPrivateNetwork sets the `Access-Control-Request-Private-Network` header which - // allows client browsers to make requests to internal IP addresses over HTTP. This setting - // is only required by users running Wings without SSL certificates and using internal IP - // addresses in order to connect. Most users should NOT enable this setting. - AllowCORSPrivateNetwork bool `json:"allow_cors_private_network" yaml:"allow_cors_private_network"` - - // IgnorePanelConfigUpdates causes confiuration updates that are sent by the panel to be ignored. - IgnorePanelConfigUpdates bool `json:"ignore_panel_config_updates" yaml:"ignore_panel_config_updates"` -} - -// NewAtPath creates a new struct and set the path where it should be stored. -// This function does not modify the currently stored global configuration. -func NewAtPath(path string) (*Configuration, error) { - var c Configuration - // Configures the default values for many of the configuration options present - // in the structs. Values set in the configuration file take priority over the - // default values. - if err := defaults.Set(&c); err != nil { - return nil, err - } - // Track the location where we created this configuration. - c.path = path - return &c, nil -} - -// Set the global configuration instance. This is a blocking operation such that -// anything trying to set a different configuration value, or read the configuration -// will be paused until it is complete. -func Set(c *Configuration) { - mu.Lock() - if _config == nil || _config.AuthenticationToken != c.AuthenticationToken { - _jwtAlgo = jwt.NewHS256([]byte(c.AuthenticationToken)) - } - _config = c - mu.Unlock() -} - -// SetDebugViaFlag tracks if the application is running in debug mode because of -// a command line flag argument. If so we do not want to store that configuration -// change to the disk. -func SetDebugViaFlag(d bool) { - mu.Lock() - _config.Debug = d - _debugViaFlag = d - mu.Unlock() -} - -// Get returns the global configuration instance. This is a thread-safe operation -// that will block if the configuration is presently being modified. -// -// Be aware that you CANNOT make modifications to the currently stored configuration -// by modifying the struct returned by this function. The only way to make -// modifications is by using the Update() function and passing data through in -// the callback. -func Get() *Configuration { - mu.RLock() - // Create a copy of the struct so that all modifications made beyond this - // point are immutable. - //goland:noinspection GoVetCopyLock - c := *_config - mu.RUnlock() - return &c -} - -// Update performs an in-situ update of the global configuration object using -// a thread-safe mutex lock. This is the correct way to make modifications to -// the global configuration. -func Update(callback func(c *Configuration)) { - mu.Lock() - callback(_config) - mu.Unlock() -} - -// GetJwtAlgorithm returns the in-memory JWT algorithm. -func GetJwtAlgorithm() *jwt.HMACSHA { - mu.RLock() - defer mu.RUnlock() - return _jwtAlgo -} - -// WriteToDisk writes the configuration to the disk. This is a thread safe operation -// and will only allow one write at a time. Additional calls while writing are -// queued up. -func WriteToDisk(c *Configuration) error { - _writeLock.Lock() - defer _writeLock.Unlock() - - //goland:noinspection GoVetCopyLock - ccopy := *c - // If debugging is set with the flag, don't save that to the configuration file, - // otherwise you'll always end up in debug mode. - if _debugViaFlag { - ccopy.Debug = false - } - if c.path == "" { - return errors.New("cannot write configuration, no path defined in struct") - } - b, err := yaml.Marshal(&ccopy) - if err != nil { - return err - } - if err := os.WriteFile(c.path, b, 0o600); err != nil { - return err - } - return nil -} - -// EnsurePelicanUser ensures that the Pelican core user exists on the -// system. This user will be the owner of all data in the root data directory -// and is used as the user within containers. If files are not owned by this -// user there will be issues with permissions on Docker mount points. -// -// This function IS NOT thread safe and should only be called in the main thread -// when the application is booting. -func EnsurePelicanUser() error { - sysName, err := getSystemName() - if err != nil { - return err - } - - // Our way of detecting if wings is running inside of Docker. - if sysName == "distroless" { - _config.System.Username = system.FirstNotEmpty(os.Getenv("WINGS_USERNAME"), "pelican") - _config.System.User.Uid = system.MustInt(system.FirstNotEmpty(os.Getenv("WINGS_UID"), "988")) - _config.System.User.Gid = system.MustInt(system.FirstNotEmpty(os.Getenv("WINGS_GID"), "988")) - return nil - } - - if _config.System.User.Rootless.Enabled { - log.Info("rootless mode is enabled, skipping user creation...") - u, err := user.Current() - if err != nil { - return err - } - _config.System.Username = u.Username - _config.System.User.Uid = system.MustInt(u.Uid) - _config.System.User.Gid = system.MustInt(u.Gid) - return nil - } - - log.WithField("username", _config.System.Username).Info("checking for pelican system user") - u, err := user.Lookup(_config.System.Username) - // If an error is returned but it isn't the unknown user error just abort - // the process entirely. If we did find a user, return it immediately. - if err != nil { - if _, ok := err.(user.UnknownUserError); !ok { - return err - } - } else { - _config.System.User.Uid = system.MustInt(u.Uid) - _config.System.User.Gid = system.MustInt(u.Gid) - return nil - } - - command := fmt.Sprintf("useradd --system --no-create-home --shell /usr/sbin/nologin %s", _config.System.Username) - // Alpine Linux is the only OS we currently support that doesn't work with the useradd - // command, so in those cases we just modify the command a bit to work as expected. - if strings.HasPrefix(sysName, "alpine") { - command = fmt.Sprintf("adduser -S -D -H -G %[1]s -s /sbin/nologin %[1]s", _config.System.Username) - // We have to create the group first on Alpine, so do that here before continuing on - // to the user creation process. - if _, err := exec.Command("addgroup", "-S", _config.System.Username).Output(); err != nil { - return err - } - } - - split := strings.Split(command, " ") - if _, err := exec.Command(split[0], split[1:]...).Output(); err != nil { - return err - } - u, err = user.Lookup(_config.System.Username) - if err != nil { - return err - } - _config.System.User.Uid = system.MustInt(u.Uid) - _config.System.User.Gid = system.MustInt(u.Gid) - return nil -} - -// FromFile reads the configuration from the provided file and stores it in the -// global singleton for this instance. -func FromFile(path string) error { - b, err := os.ReadFile(path) - if err != nil { - return err - } - c, err := NewAtPath(path) - if err != nil { - return err - } - - if err := yaml.Unmarshal(b, c); err != nil { - return err - } - - // Store this configuration in the global state. - Set(c) - return nil -} - -// ConfigureDirectories ensures that all the system directories exist on the -// system. These directories are created so that only the owner can read the data, -// and no other users. -// -// This function IS NOT thread-safe. -func ConfigureDirectories() error { - root := _config.System.RootDirectory - log.WithField("path", root).Debug("ensuring root data directory exists") - if err := os.MkdirAll(root, 0o700); err != nil { - return err - } - - log.WithField("filepath", _config.System.User.PasswdFile).Debug("ensuring passwd file exists") - if passwd, err := os.Create(_config.System.User.PasswdFile); err != nil { - return err - } else { - // the WriteFile method returns an error if unsuccessful - err := os.WriteFile(passwd.Name(), []byte(fmt.Sprintf("container:x:%d:%d::/home/container:/usr/sbin/nologin", _config.System.User.Uid, _config.System.User.Gid)), 0644) - // handle this error - if err != nil { - // print it out - fmt.Println(err) - } - } - - // There are a non-trivial number of users out there whose data directories are actually a - // symlink to another location on the disk. If we do not resolve that final destination at this - // point things will appear to work, but endless errors will be encountered when we try to - // verify accessed paths since they will all end up resolving outside the expected data directory. - // - // For the sake of automating away as much of this as possible, see if the data directory is a - // symlink, and if so resolve to its final real path, and then update the configuration to use - // that. - if d, err := filepath.EvalSymlinks(_config.System.Data); err != nil { - if !os.IsNotExist(err) { - return err - } - } else if d != _config.System.Data { - _config.System.Data = d - } - - log.WithField("path", _config.System.Data).Debug("ensuring server data directory exists") - if err := os.MkdirAll(_config.System.Data, 0o700); err != nil { - return err - } - - log.WithField("path", _config.System.ArchiveDirectory).Debug("ensuring archive data directory exists") - if err := os.MkdirAll(_config.System.ArchiveDirectory, 0o700); err != nil { - return err - } - - log.WithField("path", _config.System.BackupDirectory).Debug("ensuring backup data directory exists") - if err := os.MkdirAll(_config.System.BackupDirectory, 0o700); err != nil { - return err - } - - return nil -} - -// EnableLogRotation writes a logrotate file for wings to the system logrotate -// configuration directory if one exists and a logrotate file is not found. This -// allows us to basically automate away the log rotation for most installs, but -// also enable users to make modifications on their own. -// -// This function IS NOT thread-safe. -func EnableLogRotation() error { - if !_config.System.EnableLogRotate { - log.Info("skipping log rotate configuration, disabled in wings config file") - return nil - } - - if st, err := os.Stat("/etc/logrotate.d"); err != nil && !os.IsNotExist(err) { - return err - } else if (err != nil && os.IsNotExist(err)) || !st.IsDir() { - return nil - } - if _, err := os.Stat("/etc/logrotate.d/wings"); err == nil || !os.IsNotExist(err) { - return err - } - - log.Info("no log rotation configuration found: adding file now") - // If we've gotten to this point it means the logrotate directory exists on the system - // but there is not a file for wings already. In that case, let us write a new file to - // it so files can be rotated easily. - f, err := os.Create("/etc/logrotate.d/wings") - if err != nil { - return err - } - defer f.Close() - - t, err := template.New("logrotate").Parse(`{{.LogDirectory}}/wings.log { - size 10M - compress - delaycompress - dateext - maxage 7 - missingok - notifempty - postrotate - /usr/bin/systemctl kill -s HUP wings.service >/dev/null 2>&1 || true - endscript -}`) - if err != nil { - return err - } - - return errors.Wrap(t.Execute(f, _config.System), "config: failed to write logrotate to disk") -} - -// GetStatesPath returns the location of the JSON file that tracks server states. -func (sc *SystemConfiguration) GetStatesPath() string { - return path.Join(sc.RootDirectory, "/states.json") -} - -// ConfigureTimezone sets the timezone data for the configuration if it is -// currently missing. If a value has been set, this functionality will only run -// to validate that the timezone being used is valid. -// -// This function IS NOT thread-safe. -func ConfigureTimezone() error { - tz := os.Getenv("TZ") - if _config.System.Timezone == "" && tz != "" { - _config.System.Timezone = tz - } - if _config.System.Timezone == "" { - b, err := os.ReadFile("/etc/timezone") - if err != nil { - if !os.IsNotExist(err) { - return errors.WithMessage(err, "config: failed to open timezone file") - } - - _config.System.Timezone = "UTC" - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - // Okay, file isn't found on this OS, we will try using timedatectl to handle this. If this - // command fails, exit, but if it returns a value use that. If no value is returned we will - // fall through to UTC to get Wings booted at least. - out, err := exec.CommandContext(ctx, "timedatectl").Output() - if err != nil { - log.WithField("error", err).Warn("failed to execute \"timedatectl\" to determine system timezone, falling back to UTC") - return nil - } - - r := regexp.MustCompile(`Time zone: ([\w/]+)`) - matches := r.FindSubmatch(out) - if len(matches) != 2 || string(matches[1]) == "" { - log.Warn("failed to parse timezone from \"timedatectl\" output, falling back to UTC") - return nil - } - _config.System.Timezone = string(matches[1]) - } else { - _config.System.Timezone = string(b) - } - } - - _config.System.Timezone = regexp.MustCompile(`(?i)[^a-z_/]+`).ReplaceAllString(_config.System.Timezone, "") - _, err := time.LoadLocation(_config.System.Timezone) - - return errors.WithMessage(err, fmt.Sprintf("the supplied timezone %s is invalid", _config.System.Timezone)) -} - -// Gets the system release name. -func getSystemName() (string, error) { - // use osrelease to get release version and ID - release, err := osrelease.Read() - if err != nil { - return "", err - } - return release["ID"], nil -} - -var openat2 atomic.Bool -var openat2Set atomic.Bool - -func UseOpenat2() bool { - if openat2Set.Load() { - return openat2.Load() - } - defer openat2Set.Store(true) - - c := Get() - openatMode := c.System.OpenatMode - switch openatMode { - case "openat2": - openat2.Store(true) - return true - case "openat": - openat2.Store(false) - return false - default: - fd, err := unix.Openat2(unix.AT_FDCWD, "/", &unix.OpenHow{}) - if err != nil { - log.WithError(err).Warn("error occurred while checking for openat2 support, falling back to openat") - openat2.Store(false) - return false - } - _ = unix.Close(fd) - openat2.Store(true) - return true - } -} +package config import ( "context" "crypto/tls" "fmt" "github.com/gbrlsnchs/jwt/v3" "os" "os/exec" "os/user" "path" "path/filepath" "regexp" "strings" "sync" "sync/atomic" "text/template" "time" "emperror.dev/errors" "github.com/acobaugh/osrelease" "github.com/apex/log" "github.com/creasty/defaults" "golang.org/x/sys/unix" "gopkg.in/yaml.v2" "github.com/pelican-dev/wings/system" ) const DefaultLocation = "/etc/pelican/config.yml" // DefaultTLSConfig sets sane defaults to use when configuring the internal // webserver to listen for public connections. // // @see https://blog.cloudflare.com/exposing-go-on-the-internet var DefaultTLSConfig = &tls.Config{ NextProtos: []string{"h2", "http/1.1"}, CipherSuites: []uint16{ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, }, PreferServerCipherSuites: true, MinVersion: tls.VersionTLS12, MaxVersion: tls.VersionTLS13, CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256}, } var ( mu sync.RWMutex _config *Configuration _jwtAlgo *jwt.HMACSHA _debugViaFlag bool ) // Locker specific to writing the configuration to the disk, this happens // in areas that might already be locked, so we don't want to crash the process. var _writeLock sync.Mutex // SftpConfiguration defines the configuration of the internal SFTP server. type SftpConfiguration struct { // The bind address of the SFTP server. Address string `default:"0.0.0.0" json:"bind_address" yaml:"bind_address"` // The bind port of the SFTP server. Port int `default:"2022" json:"bind_port" yaml:"bind_port"` // If set to true, no write actions will be allowed on the SFTP server. ReadOnly bool `default:"false" yaml:"read_only"` } // ApiConfiguration defines the configuration for the internal API that is // exposed by the Wings webserver. type ApiConfiguration struct { // The interface that the internal webserver should bind to. Host string `default:"0.0.0.0" yaml:"host"` // The port that the internal webserver should bind to. Port int `default:"8080" yaml:"port"` // SSL configuration for the daemon. Ssl struct { Enabled bool `json:"enabled" yaml:"enabled"` CertificateFile string `json:"cert" yaml:"cert"` KeyFile string `json:"key" yaml:"key"` } // Determines if functionality for allowing remote download of files into server directories // is enabled on this instance. If set to "true" remote downloads will not be possible for // servers. DisableRemoteDownload bool `json:"-" yaml:"disable_remote_download"` // The maximum size for files uploaded through the Panel in MB. UploadLimit int64 `default:"100" json:"upload_limit" yaml:"upload_limit"` // A list of IP address of proxies that may send a X-Forwarded-For header to set the true clients IP TrustedProxies []string `json:"trusted_proxies" yaml:"trusted_proxies"` } // RemoteQueryConfiguration defines the configuration settings for remote requests // from Wings to the Panel. type RemoteQueryConfiguration struct { // The amount of time in seconds that Wings should allow for a request to the Panel API // to complete. If this time passes the request will be marked as failed. If your requests // are taking longer than 30 seconds to complete it is likely a performance issue that // should be resolved on the Panel, and not something that should be resolved by upping this // number. Timeout int `default:"30" yaml:"timeout"` // The number of servers to load in a single request to the Panel API when booting the // Wings instance. A single request is initially made to the Panel to get this number // of servers, and then the pagination status is checked and additional requests are // fired off in parallel to request the remaining pages. // // It is not recommended to change this from the default as you will likely encounter // memory limits on your Panel instance. In the grand scheme of things 4 requests for // 50 servers is likely just as quick as two for 100 or one for 400, and will certainly // be less likely to cause performance issues on the Panel. BootServersPerPage int `default:"50" yaml:"boot_servers_per_page"` } // SystemConfiguration defines basic system configuration settings. type SystemConfiguration struct { // The root directory where all of the pelican data is stored at. RootDirectory string `default:"/var/lib/pelican" json:"-" yaml:"root_directory"` // Directory where logs for server installations and other wings events are logged. LogDirectory string `default:"/var/log/pelican" json:"-" yaml:"log_directory"` // Directory where the server data is stored at. Data string `default:"/var/lib/pelican/volumes" json:"-" yaml:"data"` // Directory where server archives for transferring will be stored. ArchiveDirectory string `default:"/var/lib/pelican/archives" json:"-" yaml:"archive_directory"` // Directory where local backups will be stored on the machine. BackupDirectory string `default:"/var/lib/pelican/backups" json:"-" yaml:"backup_directory"` // TmpDirectory specifies where temporary files for pelican installation processes // should be created. This supports environments running docker-in-docker. TmpDirectory string `default:"/tmp/pelican" json:"-" yaml:"tmp_directory"` // The user that should own all of the server files, and be used for containers. Username string `default:"pelican" yaml:"username"` // The timezone for this Wings instance. This is detected by Wings automatically if possible, // and falls back to UTC if not able to be detected. If you need to set this manually, that // can also be done. // // This timezone value is passed into all containers created by Wings. Timezone string `yaml:"timezone"` // Definitions for the user that gets created to ensure that we can quickly access // this information without constantly having to do a system lookup. User struct { // Rootless controls settings related to rootless container daemons. Rootless struct { // Enabled controls whether rootless containers are enabled. Enabled bool `yaml:"enabled" default:"false"` // ContainerUID controls the UID of the user inside the container. // This should likely be set to 0 so the container runs as the user // running Wings. ContainerUID int `yaml:"container_uid" default:"0"` // ContainerGID controls the GID of the user inside the container. // This should likely be set to 0 so the container runs as the user // running Wings. ContainerGID int `yaml:"container_gid" default:"0"` } `yaml:"rootless"` Uid int `yaml:"uid"` Gid int `yaml:"gid"` // Passwd controls weather a passwd file is mounted in the container // at /etc/passwd to resolve missing user issues Passwd bool `json:"mount_passwd" yaml:"mount_passwd" default:"true"` PasswdFile string `json:"passwd_file" yaml:"passwd_file" default:"/etc/pelican/passwd"` } `yaml:"user"` // The amount of time in seconds that can elapse before a server's disk space calculation is // considered stale and a re-check should occur. DANGER: setting this value too low can seriously // impact system performance and cause massive I/O bottlenecks and high CPU usage for the Wings // process. // // Set to 0 to disable disk checking entirely. This will always return 0 for the disk space used // by a server and should only be set in extreme scenarios where performance is critical and // disk usage is not a concern. DiskCheckInterval int64 `default:"150" yaml:"disk_check_interval"` // ActivitySendInterval is the amount of time that should ellapse between aggregated server activity // being sent to the Panel. By default this will send activity collected over the last minute. Keep // in mind that only a fixed number of activity log entries, defined by ActivitySendCount, will be sent // in each run. ActivitySendInterval int `default:"60" yaml:"activity_send_interval"` // ActivitySendCount is the number of activity events to send per batch. ActivitySendCount int `default:"100" yaml:"activity_send_count"` // If set to true, file permissions for a server will be checked when the process is // booted. This can cause boot delays if the server has a large amount of files. In most // cases disabling this should not have any major impact unless external processes are // frequently modifying a servers' files. CheckPermissionsOnBoot bool `default:"true" yaml:"check_permissions_on_boot"` // If set to false Wings will not attempt to write a log rotate configuration to the disk // when it boots and one is not detected. EnableLogRotate bool `default:"true" yaml:"enable_log_rotate"` // The number of lines to send when a server connects to the websocket. WebsocketLogCount int `default:"150" yaml:"websocket_log_count"` Sftp SftpConfiguration `yaml:"sftp"` CrashDetection CrashDetection `yaml:"crash_detection"` Backups Backups `yaml:"backups"` Transfers Transfers `yaml:"transfers"` OpenatMode string `default:"auto" yaml:"openat_mode"` } type CrashDetection struct { // CrashDetectionEnabled sets if crash detection is enabled globally for all servers on this node. CrashDetectionEnabled bool `default:"true" yaml:"enabled"` // Determines if Wings should detect a server that stops with a normal exit code of // "0" as being crashed if the process stopped without any Wings interaction. E.g. // the user did not press the stop button, but the process stopped cleanly. DetectCleanExitAsCrash bool `default:"true" yaml:"detect_clean_exit_as_crash"` // Timeout specifies the timeout between crashes that will not cause the server // to be automatically restarted, this value is used to prevent servers from // becoming stuck in a boot-loop after multiple consecutive crashes. Timeout int `default:"60" json:"timeout"` } type Backups struct { // WriteLimit imposes a Disk I/O write limit on backups to the disk, this affects all // backup drivers as the archiver must first write the file to the disk in order to // upload it to any external storage provider. // // If the value is less than 1, the write speed is unlimited, // if the value is greater than 0, the write speed is the value in MiB/s. // // Defaults to 0 (unlimited) WriteLimit int `default:"0" yaml:"write_limit"` // CompressionLevel determines how much backups created by wings should be compressed. // // "none" -> no compression will be applied // "best_speed" -> uses gzip level 1 for fast speed // "best_compression" -> uses gzip level 9 for minimal disk space useage // // Defaults to "best_speed" (level 1) CompressionLevel string `default:"best_speed" yaml:"compression_level"` } type Transfers struct { // DownloadLimit imposes a Network I/O read limit when downloading a transfer archive. // // If the value is less than 1, the write speed is unlimited, // if the value is greater than 0, the write speed is the value in MiB/s. // // Defaults to 0 (unlimited) DownloadLimit int `default:"0" yaml:"download_limit"` } type ConsoleThrottles struct { // Whether or not the throttler is enabled for this instance. Enabled bool `json:"enabled" yaml:"enabled" default:"true"` // The total number of lines that can be output in a given Period period before // a warning is triggered and counted against the server. Lines uint64 `json:"lines" yaml:"lines" default:"2000"` // The amount of time after which the number of lines processed is reset to 0. This runs in // a constant loop and is not affected by the current console output volumes. By default, this // will reset the processed line count back to 0 every 100ms. Period uint64 `json:"line_reset_interval" yaml:"line_reset_interval" default:"100"` } type Configuration struct { // The location from which this configuration instance was instantiated. path string // Determines if wings should be running in debug mode. This value is ignored // if the debug flag is passed through the command line arguments. Debug bool AppName string `default:"pelican" json:"app_name" yaml:"app_name"` // A unique identifier for this node in the Panel. Uuid string // An identifier for the token which must be included in any requests to the panel // so that the token can be looked up correctly. AuthenticationTokenId string `json:"token_id" yaml:"token_id"` // The token used when performing operations. Requests to this instance must // validate against it. AuthenticationToken string `json:"token" yaml:"token"` Api ApiConfiguration `json:"api" yaml:"api"` System SystemConfiguration `json:"system" yaml:"system"` Docker DockerConfiguration `json:"docker" yaml:"docker"` // Defines internal throttling configurations for server processes to prevent // someone from running an endless loop that spams data to logs. Throttles ConsoleThrottles // The location where the panel is running that this daemon should connect to // to collect data and send events. PanelLocation string `json:"-" yaml:"remote"` RemoteQuery RemoteQueryConfiguration `json:"remote_query" yaml:"remote_query"` // AllowedMounts is a list of allowed host-system mount points. // This is required to have the "Server Mounts" feature work properly. AllowedMounts []string `json:"-" yaml:"allowed_mounts"` // AllowedOrigins is a list of allowed request origins. // The Panel URL is automatically allowed, this is only needed for adding // additional origins. AllowedOrigins []string `json:"allowed_origins" yaml:"allowed_origins"` // AllowCORSPrivateNetwork sets the `Access-Control-Request-Private-Network` header which // allows client browsers to make requests to internal IP addresses over HTTP. This setting // is only required by users running Wings without SSL certificates and using internal IP // addresses in order to connect. Most users should NOT enable this setting. AllowCORSPrivateNetwork bool `json:"allow_cors_private_network" yaml:"allow_cors_private_network"` // IgnorePanelConfigUpdates causes confiuration updates that are sent by the panel to be ignored. IgnorePanelConfigUpdates bool `json:"ignore_panel_config_updates" yaml:"ignore_panel_config_updates"` } // NewAtPath creates a new struct and set the path where it should be stored. // This function does not modify the currently stored global configuration. func NewAtPath(path string) (*Configuration, error) { var c Configuration // Configures the default values for many of the configuration options present // in the structs. Values set in the configuration file take priority over the // default values. if err := defaults.Set(&c); err != nil { return nil, err } // Track the location where we created this configuration. c.path = path return &c, nil } // Set the global configuration instance. This is a blocking operation such that // anything trying to set a different configuration value, or read the configuration // will be paused until it is complete. func Set(c *Configuration) { mu.Lock() if _config == nil || _config.AuthenticationToken != c.AuthenticationToken { _jwtAlgo = jwt.NewHS256([]byte(c.AuthenticationToken)) } _config = c mu.Unlock() } // SetDebugViaFlag tracks if the application is running in debug mode because of // a command line flag argument. If so we do not want to store that configuration // change to the disk. func SetDebugViaFlag(d bool) { mu.Lock() _config.Debug = d _debugViaFlag = d mu.Unlock() } // Get returns the global configuration instance. This is a thread-safe operation // that will block if the configuration is presently being modified. // // Be aware that you CANNOT make modifications to the currently stored configuration // by modifying the struct returned by this function. The only way to make // modifications is by using the Update() function and passing data through in // the callback. func Get() *Configuration { mu.RLock() // Create a copy of the struct so that all modifications made beyond this // point are immutable. //goland:noinspection GoVetCopyLock c := *_config mu.RUnlock() return &c } // Update performs an in-situ update of the global configuration object using // a thread-safe mutex lock. This is the correct way to make modifications to // the global configuration. func Update(callback func(c *Configuration)) { mu.Lock() callback(_config) mu.Unlock() } // GetJwtAlgorithm returns the in-memory JWT algorithm. func GetJwtAlgorithm() *jwt.HMACSHA { mu.RLock() defer mu.RUnlock() return _jwtAlgo } // WriteToDisk writes the configuration to the disk. This is a thread safe operation // and will only allow one write at a time. Additional calls while writing are // queued up. func WriteToDisk(c *Configuration) error { _writeLock.Lock() defer _writeLock.Unlock() //goland:noinspection GoVetCopyLock ccopy := *c // If debugging is set with the flag, don't save that to the configuration file, // otherwise you'll always end up in debug mode. if _debugViaFlag { ccopy.Debug = false } if c.path == "" { return errors.New("cannot write configuration, no path defined in struct") } b, err := yaml.Marshal(&ccopy) if err != nil { return err } if err := os.WriteFile(c.path, b, 0o600); err != nil { return err } return nil } // EnsurePelicanUser ensures that the Pelican core user exists on the // system. This user will be the owner of all data in the root data directory // and is used as the user within containers. If files are not owned by this // user there will be issues with permissions on Docker mount points. // // This function IS NOT thread safe and should only be called in the main thread // when the application is booting. func EnsurePelicanUser() error { sysName, err := getSystemName() if err != nil { return err } // Our way of detecting if wings is running inside of Docker. if sysName == "distroless" { _config.System.Username = system.FirstNotEmpty(os.Getenv("WINGS_USERNAME"), "pelican") _config.System.User.Uid = system.MustInt(system.FirstNotEmpty(os.Getenv("WINGS_UID"), "988")) _config.System.User.Gid = system.MustInt(system.FirstNotEmpty(os.Getenv("WINGS_GID"), "988")) return nil } if _config.System.User.Rootless.Enabled { log.Info("rootless mode is enabled, skipping user creation...") u, err := user.Current() if err != nil { return err } _config.System.Username = u.Username _config.System.User.Uid = system.MustInt(u.Uid) _config.System.User.Gid = system.MustInt(u.Gid) return nil } log.WithField("username", _config.System.Username).Info("checking for pelican system user") u, err := user.Lookup(_config.System.Username) // If an error is returned but it isn't the unknown user error just abort // the process entirely. If we did find a user, return it immediately. if err != nil { if _, ok := err.(user.UnknownUserError); !ok { return err } } else { _config.System.User.Uid = system.MustInt(u.Uid) _config.System.User.Gid = system.MustInt(u.Gid) return nil } command := fmt.Sprintf("useradd --system --no-create-home --shell /usr/sbin/nologin %s", _config.System.Username) // Alpine Linux is the only OS we currently support that doesn't work with the useradd // command, so in those cases we just modify the command a bit to work as expected. if strings.HasPrefix(sysName, "alpine") { command = fmt.Sprintf("adduser -S -D -H -G %[1]s -s /sbin/nologin %[1]s", _config.System.Username) // We have to create the group first on Alpine, so do that here before continuing on // to the user creation process. if _, err := exec.Command("addgroup", "-S", _config.System.Username).Output(); err != nil { return err } } split := strings.Split(command, " ") if _, err := exec.Command(split[0], split[1:]...).Output(); err != nil { return err } u, err = user.Lookup(_config.System.Username) if err != nil { return err } _config.System.User.Uid = system.MustInt(u.Uid) _config.System.User.Gid = system.MustInt(u.Gid) return nil } // FromFile reads the configuration from the provided file and stores it in the // global singleton for this instance. func FromFile(path string) error { b, err := os.ReadFile(path) if err != nil { return err } c, err := NewAtPath(path) if err != nil { return err } if err := yaml.Unmarshal(b, c); err != nil { return err } // Store this configuration in the global state. Set(c) return nil } // ConfigureDirectories ensures that all the system directories exist on the // system. These directories are created so that only the owner can read the data, // and no other users. // // This function IS NOT thread-safe. func ConfigureDirectories() error { root := _config.System.RootDirectory log.WithField("path", root).Debug("ensuring root data directory exists") if err := os.MkdirAll(root, 0o700); err != nil { return err } log.WithField("filepath", _config.System.User.PasswdFile).Debug("ensuring passwd file exists") if passwd, err := os.Create(_config.System.User.PasswdFile); err != nil { return err } else { // the WriteFile method returns an error if unsuccessful err := os.WriteFile(passwd.Name(), []byte(fmt.Sprintf("container:x:%d:%d::/home/container:/usr/sbin/nologin", _config.System.User.Uid, _config.System.User.Gid)), 0644) // handle this error if err != nil { // print it out fmt.Println(err) } } // There are a non-trivial number of users out there whose data directories are actually a // symlink to another location on the disk. If we do not resolve that final destination at this // point things will appear to work, but endless errors will be encountered when we try to // verify accessed paths since they will all end up resolving outside the expected data directory. // // For the sake of automating away as much of this as possible, see if the data directory is a // symlink, and if so resolve to its final real path, and then update the configuration to use // that. if d, err := filepath.EvalSymlinks(_config.System.Data); err != nil { if !os.IsNotExist(err) { return err } } else if d != _config.System.Data { _config.System.Data = d } log.WithField("path", _config.System.Data).Debug("ensuring server data directory exists") if err := os.MkdirAll(_config.System.Data, 0o700); err != nil { return err } log.WithField("path", _config.System.ArchiveDirectory).Debug("ensuring archive data directory exists") if err := os.MkdirAll(_config.System.ArchiveDirectory, 0o700); err != nil { return err } log.WithField("path", _config.System.BackupDirectory).Debug("ensuring backup data directory exists") if err := os.MkdirAll(_config.System.BackupDirectory, 0o700); err != nil { return err } return nil } // EnableLogRotation writes a logrotate file for wings to the system logrotate // configuration directory if one exists and a logrotate file is not found. This // allows us to basically automate away the log rotation for most installs, but // also enable users to make modifications on their own. // // This function IS NOT thread-safe. func EnableLogRotation() error { if !_config.System.EnableLogRotate { log.Info("skipping log rotate configuration, disabled in wings config file") return nil } if st, err := os.Stat("/etc/logrotate.d"); err != nil && !os.IsNotExist(err) { return err } else if (err != nil && os.IsNotExist(err)) || !st.IsDir() { return nil } if _, err := os.Stat("/etc/logrotate.d/wings"); err == nil || !os.IsNotExist(err) { return err } log.Info("no log rotation configuration found: adding file now") // If we've gotten to this point it means the logrotate directory exists on the system // but there is not a file for wings already. In that case, let us write a new file to // it so files can be rotated easily. f, err := os.Create("/etc/logrotate.d/wings") if err != nil { return err } defer f.Close() t, err := template.New("logrotate").Parse(`{{.LogDirectory}}/wings.log { size 10M compress delaycompress dateext maxage 7 missingok notifempty postrotate /usr/bin/systemctl kill -s HUP wings.service >/dev/null 2>&1 || true endscript }`) if err != nil { return err } return errors.Wrap(t.Execute(f, _config.System), "config: failed to write logrotate to disk") } // GetStatesPath returns the location of the JSON file that tracks server states. func (sc *SystemConfiguration) GetStatesPath() string { return path.Join(sc.RootDirectory, "/states.json") } // ConfigureTimezone sets the timezone data for the configuration if it is // currently missing. If a value has been set, this functionality will only run // to validate that the timezone being used is valid. // // This function IS NOT thread-safe. func ConfigureTimezone() error { tz := os.Getenv("TZ") if _config.System.Timezone == "" && tz != "" { _config.System.Timezone = tz } if _config.System.Timezone == "" { b, err := os.ReadFile("/etc/timezone") if err != nil { if !os.IsNotExist(err) { return errors.WithMessage(err, "config: failed to open timezone file") } _config.System.Timezone = "UTC" ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() // Okay, file isn't found on this OS, we will try using timedatectl to handle this. If this // command fails, exit, but if it returns a value use that. If no value is returned we will // fall through to UTC to get Wings booted at least. out, err := exec.CommandContext(ctx, "timedatectl").Output() if err != nil { log.WithField("error", err).Warn("failed to execute \"timedatectl\" to determine system timezone, falling back to UTC") return nil } r := regexp.MustCompile(`Time zone: ([\w/]+)`) matches := r.FindSubmatch(out) if len(matches) != 2 || string(matches[1]) == "" { log.Warn("failed to parse timezone from \"timedatectl\" output, falling back to UTC") return nil } _config.System.Timezone = string(matches[1]) } else { _config.System.Timezone = string(b) } } _config.System.Timezone = regexp.MustCompile(`(?i)[^a-z_/]+`).ReplaceAllString(_config.System.Timezone, "") _, err := time.LoadLocation(_config.System.Timezone) return errors.WithMessage(err, fmt.Sprintf("the supplied timezone %s is invalid", _config.System.Timezone)) } // Gets the system release name. func getSystemName() (string, error) { // use osrelease to get release version and ID release, err := osrelease.Read() if err != nil { return "", err } return release["ID"], nil } var ( openat2 atomic.Bool openat2Set atomic.Bool ) func UseOpenat2() bool { if openat2Set.Load() { return openat2.Load() } defer openat2Set.Store(true) c := Get() openatMode := c.System.OpenatMode switch openatMode { case "openat2": openat2.Store(true) return true case "openat": openat2.Store(false) return false default: fd, err := unix.Openat2(unix.AT_FDCWD, "/", &unix.OpenHow{}) if err != nil { log.WithError(err).Warn("error occurred while checking for openat2 support, falling back to openat") openat2.Store(false) return false } _ = unix.Close(fd) openat2.Store(true) return true } } \ No newline at end of file diff --git a/go.mod b/go.mod index 5dd1bf5a..54bad490 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,9 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/beevik/etree v1.3.0 github.com/buger/jsonparser v1.1.1 - github.com/cenkalti/backoff/v4 v4.2.1 + github.com/cenkalti/backoff/v4 v4.3.0 github.com/creasty/defaults v1.7.0 - github.com/docker/docker v25.0.4+incompatible + github.com/docker/docker v26.0.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fatih/color v1.16.0 github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf @@ -22,7 +22,7 @@ require ( github.com/gammazero/workerpool v1.1.3 github.com/gbrlsnchs/jwt/v3 v3.0.1 github.com/gin-gonic/gin v1.9.1 - github.com/glebarez/sqlite v1.10.0 + github.com/glebarez/sqlite v1.11.0 github.com/go-co-op/gocron v1.37.0 github.com/goccy/go-json v0.10.2 github.com/google/uuid v1.6.0 @@ -30,7 +30,7 @@ require ( github.com/iancoleman/strcase v0.3.0 github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 github.com/juju/ratelimit v1.0.2 - github.com/klauspost/compress v1.17.7 + github.com/klauspost/compress v1.17.8 github.com/klauspost/pgzip v1.2.6 github.com/magiconair/properties v1.8.7 github.com/mattn/go-colorable v0.1.13 @@ -41,28 +41,28 @@ require ( github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.9.0 - golang.org/x/crypto v0.21.0 - golang.org/x/sync v0.6.0 - golang.org/x/sys v0.18.0 + golang.org/x/crypto v0.22.0 + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.19.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - gorm.io/gorm v1.25.7 + gorm.io/gorm v1.25.9 ) require ( github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/Microsoft/hcsshim v0.12.0 // indirect + github.com/Microsoft/hcsshim v0.12.2 // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/bodgit/plumbing v1.3.0 // indirect - github.com/bodgit/sevenzip v1.5.0 // indirect + github.com/bodgit/sevenzip v1.5.1 // indirect github.com/bodgit/windows v1.0.1 // indirect github.com/bytedance/sonic v1.11.3 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/distribution/reference v0.5.0 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -91,6 +91,7 @@ require ( github.com/magefile/mage v1.15.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -99,7 +100,7 @@ require ( github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/pelletier/go-toml/v2 v2.1.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.1 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -110,31 +111,28 @@ require ( github.com/therootcompany/xz v1.0.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - github.com/ulikunitz/xz v0.5.11 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect + github.com/ulikunitz/xz v0.5.12 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect + go.opentelemetry.io/otel v1.25.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.25.0 // indirect go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.25.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/term v0.18.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect - golang.org/x/tools v0.19.0 // indirect + golang.org/x/tools v0.20.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/protobuf v1.33.0 // indirect gotest.tools/v3 v3.0.2 // indirect - modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect - modernc.org/libc v1.44.0 // indirect + modernc.org/libc v1.49.3 // indirect modernc.org/mathutil v1.6.0 // indirect - modernc.org/memory v1.7.2 // indirect - modernc.org/sqlite v1.29.5 // indirect - modernc.org/strutil v1.2.0 // indirect - modernc.org/token v1.1.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/sqlite v1.29.6 // indirect ) diff --git a/go.sum b/go.sum index 57c92445..21d93b85 100644 --- a/go.sum +++ b/go.sum @@ -19,7 +19,6 @@ emperror.dev/errors v0.8.1 h1:UavXZ5cSX/4u9iyvH6aDcuGkVjeexUGJ7Ij7G4VfQT0= emperror.dev/errors v0.8.1/go.mod h1:YcRvLPh626Ubn2xqtoprejnA5nFha+TJ+2vew48kWuE= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= -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/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -27,11 +26,10 @@ github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.12.0 h1:rbICA+XZFwrBef2Odk++0LjFvClNCJGRK+fsrP254Ts= -github.com/Microsoft/hcsshim v0.12.0/go.mod h1:RZV12pcHCXQ42XnlQ3pz6FZfmrC1C+R4gaOHhRNML1g= +github.com/Microsoft/hcsshim v0.12.2 h1:AcXy+yfRvrx20g9v7qYaJv5Rh+8GaHOS6b8G6Wx/nKs= +github.com/Microsoft/hcsshim v0.12.2/go.mod h1:RZV12pcHCXQ42XnlQ3pz6FZfmrC1C+R4gaOHhRNML1g= github.com/NYTimes/logrotate v1.0.0 h1:6jFGbon6jOtpy3t3kwZZKS4Gdmf1C/Wv5J4ll4Xn5yk= github.com/NYTimes/logrotate v1.0.0/go.mod h1:GxNz1cSw1c6t99PXoZlw+nm90H6cyQyrH66pjVv7x88= -github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE= github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY= @@ -50,8 +48,8 @@ github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU= github.com/beevik/etree v1.3.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc= github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= -github.com/bodgit/sevenzip v1.5.0 h1:QESwnPUnhqftOgbi6wIiWm1WEkrT4puHukt5a2psEcw= -github.com/bodgit/sevenzip v1.5.0/go.mod h1:+E74G6pfBX8IMaVybsKMgGTTTBcbHU8ssPTJ9mLUr38= +github.com/bodgit/sevenzip v1.5.1 h1:rVj0baZsooZFy64DJN0zQogPzhPrT8BQ8TTRd1H4WHw= +github.com/bodgit/sevenzip v1.5.1/go.mod h1:Q3YMySuVWq6pyGEolyIE98828lOfEoeWg5zeH6x22rc= github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= @@ -60,8 +58,8 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1 github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA= github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= @@ -79,17 +77,15 @@ github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3 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/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v25.0.4+incompatible h1:XITZTrq+52tZyZxUOtFIahUf3aH367FLxJzt9vZeAF8= -github.com/docker/docker v25.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v26.0.1+incompatible h1:t39Hm6lpXuXtgkF0dm1t9a5HkbUfdGy6XbWexmGr+hA= +github.com/docker/docker v26.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -106,7 +102,6 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf h1:NrF81UtW8gG2LBGkXFQFqlfNnvMt9WdB46sfdJY4oqc= github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= @@ -123,8 +118,8 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= -github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc= -github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -135,8 +130,6 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -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= @@ -159,8 +152,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y 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.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -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/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -170,15 +161,11 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -188,19 +175,15 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= @@ -227,8 +210,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C 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/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= @@ -242,11 +225,9 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 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= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= @@ -271,14 +252,14 @@ github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrS github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= 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= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= @@ -292,8 +273,9 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= -github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg= +github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -302,7 +284,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -312,7 +293,6 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= @@ -332,6 +312,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An 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/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -341,12 +322,10 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/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/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= -github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= @@ -357,8 +336,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2 github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= -github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -366,28 +345,20 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= +go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= +go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= +go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= +go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -405,8 +376,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -434,8 +405,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB 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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -456,8 +427,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -471,8 +442,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ 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.0.0-20220722155255-886fb9371eb4/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/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -498,14 +469,14 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/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/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -518,7 +489,6 @@ 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.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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= @@ -549,8 +519,8 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK 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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= 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= @@ -583,11 +553,6 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -595,14 +560,11 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -617,43 +579,22 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/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= -gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= -gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= +gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8= +gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -modernc.org/cc/v4 v4.19.3 h1:vE9kmJqUcyvNOf8F2Hn8od14SOMq34BiqcZ2tMzLk5c= -modernc.org/cc/v4 v4.19.3/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.10.1 h1:qi+3luLv0LR5UkLmZyKXZxIC4K/136vcAUoYYeGSS+g= -modernc.org/ccgo/v4 v4.10.1/go.mod h1:9YDnb1IIvHymh899K5a++jza0JIWygZPTc5dlh7xvhQ= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= -modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= -modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= -modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.44.0 h1:71bbnKgb0mCg7GOOI/PHlzz7Bv6obELGNKnIEeowX8c= -modernc.org/libc v1.44.0/go.mod h1:RRqfGVjvILF5AdNP3RPCiihj7+Dn2pIBrdlU60lA9vs= +modernc.org/libc v1.49.3 h1:j2MRCRdwJI2ls/sGbeSk0t2bypOG/uvPZUsGQFDulqg= +modernc.org/libc v1.49.3/go.mod h1:yMZuGkn7pXbKfoT/M35gFJOAEdSKdxL0q64sF7KqCDo= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= -modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= -modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.29.4 h1:mbvQTJ3Tl5Vz+wLA6z8hdBFSeNQ0XXQ+KVwn8NkUliw= -modernc.org/sqlite v1.29.4/go.mod h1:MjUIBKZ+tU/lqjNLbVAAMjsQPdWdA/ciwdhsT9kBwk8= -modernc.org/sqlite v1.29.5 h1:8l/SQKAjDtZFo9lkJLdk8g9JEOeYRG4/ghStDCCTiTE= -modernc.org/sqlite v1.29.5/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U= -modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= -modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/sqlite v1.29.6 h1:0lOXGrycJPptfHDuohfYgNqoe4hu+gYuN/pKgY5XjS4= +modernc.org/sqlite v1.29.6/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/router/downloader/downloader.go b/router/downloader/downloader.go index 541f29e8..b8fd660a 100644 --- a/router/downloader/downloader.go +++ b/router/downloader/downloader.go @@ -20,20 +20,58 @@ import ( "github.com/pelican-dev/wings/server" ) -var client = &http.Client{ - Timeout: time.Hour * 12, - // Disallow any redirect on an HTTP call. This is a security requirement: do not modify - // this logic without first ensuring that the new target location IS NOT within the current - // instance's local network. - // - // This specific error response just causes the client to not follow the redirect and - // returns the actual redirect response to the caller. Not perfect, but simple and most - // people won't be using URLs that redirect anyways hopefully? - // - // We'll re-evaluate this down the road if needed. - CheckRedirect: func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - }, +var client *http.Client + +func init() { + dialer := &net.Dialer{ + LocalAddr: nil, + } + + trnspt := http.DefaultTransport.(*http.Transport).Clone() + trnspt.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + c, err := dialer.DialContext(ctx, network, addr) + if err != nil { + return nil, errors.WithStack(err) + } + + ipStr, _, err := net.SplitHostPort(c.RemoteAddr().String()) + if err != nil { + return c, errors.WithStack(err) + } + ip := net.ParseIP(ipStr) + if ip == nil { + return c, errors.WithStack(ErrInvalidIPAddress) + } + if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast() { + return c, errors.WithStack(ErrInternalResolution) + } + for _, block := range internalRanges { + if !block.Contains(ip) { + continue + } + return c, errors.WithStack(ErrInternalResolution) + } + return c, nil + } + + client = &http.Client{ + Timeout: time.Hour * 12, + + Transport: trnspt, + + // Disallow any redirect on an HTTP call. This is a security requirement: do not modify + // this logic without first ensuring that the new target location IS NOT within the current + // instance's local network. + // + // This specific error response just causes the client to not follow the redirect and + // returns the actual redirect response to the caller. Not perfect, but simple and most + // people won't be using URLs that redirect anyways hopefully? + // + // We'll re-evaluate this down the road if needed. + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } } var instance = &Downloader{ @@ -143,12 +181,6 @@ func (dl *Download) Execute() error { dl.cancelFunc = &cancel defer dl.Cancel() - // Always ensure that we're checking the destination for the download to avoid a malicious - // user from accessing internal network resources. - if err := dl.isExternalNetwork(ctx); err != nil { - return err - } - // At this point we have verified the destination is not within the local network, so we can // now make a request to that URL and pull down the file, saving it to the server's data // directory. @@ -243,59 +275,6 @@ func (dl *Download) counter(contentLength int64) *Counter { } } -// Verifies that a given download resolves to a location not within the current local -// network for the machine. If the final destination of a resource is within the local -// network an ErrInternalResolution error is returned. -func (dl *Download) isExternalNetwork(ctx context.Context) error { - dialer := &net.Dialer{ - LocalAddr: nil, - } - - host := dl.req.URL.Host - - // This cluster-fuck of math and integer shit converts an integer IP into a proper IPv4. - // For example: 16843009 would become 1.1.1.1 - //if i, err := strconv.ParseInt(host, 10, 64); err == nil { - // host = strconv.FormatInt((i>>24)&0xFF, 10) + "." + strconv.FormatInt((i>>16)&0xFF, 10) + "." + strconv.FormatInt((i>>8)&0xFF, 10) + "." + strconv.FormatInt(i&0xFF, 10) - //} - - if _, _, err := net.SplitHostPort(host); err != nil { - if !strings.Contains(err.Error(), "missing port in address") { - return errors.WithStack(err) - } - switch dl.req.URL.Scheme { - case "http": - host += ":80" - case "https": - host += ":443" - } - } - - c, err := dialer.DialContext(ctx, "tcp", host) - if err != nil { - return errors.WithStack(err) - } - _ = c.Close() - - ipStr, _, err := net.SplitHostPort(c.RemoteAddr().String()) - if err != nil { - return errors.WithStack(err) - } - ip := net.ParseIP(ipStr) - if ip == nil { - return errors.WithStack(ErrInvalidIPAddress) - } - if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast() { - return errors.WithStack(ErrInternalResolution) - } - for _, block := range internalRanges { - if block.Contains(ip) { - return errors.WithStack(ErrInternalResolution) - } - } - return nil -} - // Downloader represents a global downloader that keeps track of all currently processing downloads // for the machine. type Downloader struct { diff --git a/router/router_download.go b/router/router_download.go index 0cdf3fde..17f674f6 100644 --- a/router/router_download.go +++ b/router/router_download.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/gin-gonic/gin" + "github.com/google/uuid" "github.com/pelican-dev/wings/router/middleware" "github.com/pelican-dev/wings/router/tokens" @@ -19,12 +20,14 @@ func getDownloadBackup(c *gin.Context) { client := middleware.ExtractApiClient(c) manager := middleware.ExtractManager(c) + // Get the payload from the token. token := tokens.BackupPayload{} if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil { middleware.CaptureAndAbort(c, err) return } + // Get the server using the UUID from the token. if _, ok := manager.Get(token.ServerUuid); !ok || !token.IsUniqueRequest() { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{ "error": "The requested resource was not found on this server.", @@ -32,6 +35,14 @@ func getDownloadBackup(c *gin.Context) { return } + // Validate that the BackupUuid field is actually a UUID and not some random characters or a + // file path. + if _, err := uuid.Parse(token.BackupUuid); err != nil { + middleware.CaptureAndAbort(c, err) + return + } + + // Locate the backup on the local disk. b, st, err := backup.LocateLocal(client, token.BackupUuid) if err != nil { if errors.Is(err, os.ErrNotExist) {