From a83d91f427fe8d1815db6d1cb25e47e103efaa8d Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 15 Sep 2025 14:56:51 +0200 Subject: [PATCH] API: /info: remove `SecurityOptions` re-formatting for API < 1.25 On docker 1.12 (API v1.24) and older, the `SecurityOptions` field of the `/info` response would only list names of the security options that are enabled in the daemon. API v1.25 added additional information to this information. Initially, this included a change to return the information in structured format (b237189e6c8a4f97be59f08c63cdcb1f2f4680a8), which was a backward-incompatible change, so an alternative format was introduced in 514ca09426e5d023753101ffa6ac3a21b0e0efb5 to used a string-slice, but prefixing options with `name=`, followed by the name of the security-options and any config options related to it as `key[=]` pairs. On current API versions: curl -s --unix-socket /var/run/docker.sock 'http://localhost/v1.51/info' | jq .SecurityOptions [ "name=seccomp,profile=builtin", "name=cgroupns" ] On API version v1.24: curl -s --unix-socket /var/run/docker.sock 'http://localhost/v1.24/info' | jq .SecurityOptions [ "seccomp", "cgroupns" ] The Docker CLI unconditionally handles either format when presenting the information; for backward-compatibility, it contains fallback code to handle cases where no `name=` prefix is present, but this logic is not based on API version. Given that any current version of the CLI is handling either format, and versions of the CLI that did not have this handling are at least 9 Years old (and long EOL), removing the old format is unlikely to be causing issues and we can remove this special handling, and return the information in the current format. If we consider this information to be relevant for clients, we should ultimately consider making it available in a more structured format as was the original intent of b237189e6c8a4f97be59f08c63cdcb1f2f4680a8. Signed-off-by: Sebastiaan van Stijn --- daemon/info.go | 4 ++ daemon/server/router/system/system_routes.go | 44 -------------------- daemon/server/systembackend/security_opts.go | 12 ------ 3 files changed, 4 insertions(+), 56 deletions(-) delete mode 100644 daemon/server/systembackend/security_opts.go diff --git a/daemon/info.go b/daemon/info.go index 624deba00c..4d143f98de 100644 --- a/daemon/info.go +++ b/daemon/info.go @@ -175,6 +175,10 @@ func (daemon *Daemon) fillPluginsInfo(ctx context.Context, v *system.Info, cfg * } } +// fillSecurityOptions fills the [system.Info.SecurityOptions] field based +// on the daemon configuration. +// +// TODO(thaJeztah): consider making [system.Info.SecurityOptions] a structured response as originally intended in https://github.com/moby/moby/pull/26276 func (daemon *Daemon) fillSecurityOptions(v *system.Info, sysInfo *sysinfo.SysInfo, cfg *config.Config) { var securityOptions []string if sysInfo.AppArmor { diff --git a/daemon/server/router/system/system_routes.go b/daemon/server/router/system/system_routes.go index 719e1651f1..34b6e9c075 100644 --- a/daemon/server/router/system/system_routes.go +++ b/daemon/server/router/system/system_routes.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "net/http" - "strings" "time" "github.com/containerd/log" @@ -22,7 +21,6 @@ import ( "github.com/moby/moby/v2/daemon/server/backend" "github.com/moby/moby/v2/daemon/server/httputils" "github.com/moby/moby/v2/daemon/server/router/build" - "github.com/moby/moby/v2/daemon/server/systembackend" "github.com/moby/moby/v2/pkg/ioutils" "github.com/pkg/errors" "golang.org/x/sync/errgroup" @@ -75,18 +73,6 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht info.Warnings = append(info.Warnings, info.Swarm.Warnings...) } - if versions.LessThan(version, "1.25") { - // TODO: handle this conversion in engine-api - kvSecOpts, err := decodeSecurityOptions(info.SecurityOptions) - if err != nil { - info.Warnings = append(info.Warnings, err.Error()) - } - var nameOnly []string - for _, so := range kvSecOpts { - nameOnly = append(nameOnly, so.Name) - } - info.SecurityOptions = nameOnly - } if versions.LessThan(version, "1.44") { for k, rt := range info.Runtimes { // Status field introduced in API v1.44. @@ -137,36 +123,6 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht return httputils.WriteJSON(w, http.StatusOK, info) } -// decodeSecurityOptions decodes a security options string slice to a -// type-safe [systembackend.SecurityOption]. -func decodeSecurityOptions(opts []string) ([]systembackend.SecurityOption, error) { - so := []systembackend.SecurityOption{} - for _, opt := range opts { - // support output from a < 1.13 docker daemon - if !strings.Contains(opt, "=") { - so = append(so, systembackend.SecurityOption{Name: opt}) - continue - } - secopt := systembackend.SecurityOption{} - for _, s := range strings.Split(opt, ",") { - k, v, ok := strings.Cut(s, "=") - if !ok { - return nil, fmt.Errorf("invalid security option %q", s) - } - if k == "" || v == "" { - return nil, errors.New("invalid empty security option") - } - if k == "name" { - secopt.Name = v - continue - } - secopt.Options = append(secopt.Options, systembackend.KeyValue{Key: k, Value: v}) - } - so = append(so, secopt) - } - return so, nil -} - func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { info, err := s.backend.SystemVersion(ctx) if err != nil { diff --git a/daemon/server/systembackend/security_opts.go b/daemon/server/systembackend/security_opts.go deleted file mode 100644 index 173a78b3c1..0000000000 --- a/daemon/server/systembackend/security_opts.go +++ /dev/null @@ -1,12 +0,0 @@ -package systembackend - -// SecurityOption contains the name and options of a security option -type SecurityOption struct { - Name string - Options []KeyValue -} - -// KeyValue holds a key/value pair. -type KeyValue struct { - Key, Value string -}