Merge tag 'docker-v29.5.1' into docker-29.x

docker-v29.5.1
This commit is contained in:
Paweł Gronowski
2026-06-18 22:13:01 +02:00
18 changed files with 264 additions and 66 deletions

View File

@@ -24,14 +24,19 @@ jobs:
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
});
core.info(`Modified files: ${files.map(f => f.filename).join(', ')}`);
const touchesVersions = files.some(f => f.filename === 'releases/versions.yaml');
core.info(`Touches version: ${touchesVersions}`);
// Use the PR's version when it bumps the file, base branch otherwise.
// It's fine to trust the author in this case, it's not meant to be
// a security gate, just a helpful check for maintainers.
const ref = touchesVersions
? context.payload.pull_request.head.sha
: context.payload.pull_request.base.sha;
: context.payload.pull_request.base.ref;
core.info(`Base ref: ${ref}`);
const resp = await github.rest.repos.getContent({
owner: context.repo.owner,

View File

@@ -9,6 +9,7 @@ import (
"path/filepath"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
containertypes "github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/v2/daemon/container"
@@ -101,6 +102,15 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
container.Lock()
defer container.Unlock()
// Decompress the archive before switching into the container's
// filesystem to avoid executing decompression binaries (xz, unpigz)
// that may have been placed inside the container image.
decompressed, err := compression.DecompressStream(content)
if err != nil {
return err
}
defer decompressed.Close()
cfs, err := daemon.openContainerFS(container)
if err != nil {
return err
@@ -143,7 +153,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
}
}
return archive.Untar(content, absPath, options)
return archive.UntarUncompressed(decompressed, absPath, options)
})
if err != nil {
return err

View File

@@ -7,7 +7,7 @@ import (
"os"
"path/filepath"
"runtime"
"strings"
"strconv"
"github.com/containerd/log"
"github.com/moby/sys/mount"
@@ -91,10 +91,21 @@ func (daemon *Daemon) openContainerFS(ctr *container.Container) (_ *containerFSV
if err := mount.MakeRSlave("/"); err != nil {
return err
}
root, err := os.OpenRoot(ctr.BaseFS)
if err != nil {
return fmt.Errorf("open container root: %w", err)
}
defer root.Close()
// TODO(vvoland): Refactor this after security release.
for _, m := range mounts {
dest, err := ctr.GetResourcePath(m.Destination)
// Destination is an absolute path within container
// filesystem. For the os.Root to work, we need to convert it
// to a path relative to root fs /
relDest, err := filepath.Rel("/", m.Destination)
if err != nil {
return err
return fmt.Errorf("make destination relative: %w", err)
}
var stat os.FileInfo
@@ -102,7 +113,7 @@ func (daemon *Daemon) openContainerFS(ctr *container.Container) (_ *containerFSV
if err != nil {
return err
}
if err := createIfNotExists(dest, stat.IsDir()); err != nil {
if err := createIfNotExists(root, relDest, stat.IsDir()); err != nil {
return err
}
@@ -110,9 +121,7 @@ func (daemon *Daemon) openContainerFS(ctr *container.Container) (_ *containerFSV
if m.NonRecursive {
bindMode = "bind"
}
writeMode := "ro"
if m.Writable {
writeMode = "rw"
if m.ReadOnlyNonRecursive {
return errors.New("options conflict: Writable && ReadOnlyNonRecursive")
}
@@ -124,6 +133,37 @@ func (daemon *Daemon) openContainerFS(ctr *container.Container) (_ *containerFSV
return errors.New("options conflict: ReadOnlyNonRecursive && ReadOnlyForceRecursive")
}
// Open the mount target through os.Root so we have a
// file descriptor pinning the resolved inode. Using
// /proc/self/fd/<fd> as the mount target prevents any
// subsequent symlink swap from redirecting the mount.
targetFile, err := root.Open(relDest)
if err != nil {
return fmt.Errorf("open mount target %q: %w", m.Destination, err)
}
targetPath := "/proc/self/fd/" + strconv.FormatUint(uint64(targetFile.Fd()), 10)
// The kernel rejects remount and propagation-change syscalls
// when the target is a /proc/self/fd path. Only the initial
// bind mount works on such paths, so we perform that via the
// fd path for TOCTOU safety and then resolve the real path for
// the read-only remount and propagation change.
if err := mount.Mount(m.Source, targetPath, "", bindMode); err != nil {
targetFile.Close()
return err
}
realPath, err := os.Readlink(targetPath)
if err != nil {
targetFile.Close()
return fmt.Errorf("readlink %s: %w", targetPath, err)
}
if !m.Writable {
if err := mount.Mount("", realPath, "", "ro,remount,bind"); err != nil {
targetFile.Close()
return err
}
}
// openContainerFS() is called for temporary mounts
// outside the container. Soon these will be unmounted
// with lazy unmount option and given we have mounted
@@ -134,20 +174,21 @@ func (daemon *Daemon) openContainerFS(ctr *container.Container) (_ *containerFSV
// all these mounts rprivate. Do not use propagation
// property of volume as that should apply only when
// mounting happens inside the container.
opts := strings.Join([]string{bindMode, writeMode, "rprivate"}, ",")
if err := mount.Mount(m.Source, dest, "", opts); err != nil {
if err := mount.MakeRPrivate(realPath); err != nil {
targetFile.Close()
return err
}
if !m.Writable && !m.ReadOnlyNonRecursive {
if err := makeMountRRO(dest); err != nil {
if err := makeMountRRO(realPath); err != nil {
targetFile.Close()
if m.ReadOnlyForceRecursive {
return err
} else {
log.G(context.TODO()).WithError(err).Debugf("Failed to make %q recursively read-only", dest)
}
log.G(context.TODO()).WithError(err).Debugf("Failed to make %q recursively read-only", m.Destination)
}
}
targetFile.Close()
}
return mounttree.SwitchRoot(ctr.BaseFS)
@@ -254,24 +295,24 @@ func (vw *containerFSView) Stat(ctx context.Context, path string) (*containertyp
}
// createIfNotExists creates a file or a directory only if it does not already exist.
func createIfNotExists(dest string, isDir bool) error {
if _, err := os.Stat(dest); err != nil {
// FIXME(thaJeztah): this ignores any other error (which may include "dest" is of the wrong type, or permission errors).
if os.IsNotExist(err) {
if isDir {
return os.MkdirAll(dest, 0o755)
}
if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {
return err
}
f, err := os.OpenFile(dest, os.O_CREATE, 0o755)
if err != nil {
return err
}
_ = f.Close()
// The path is scoped to root using [os.Root] to prevent symlink escape attacks.
func createIfNotExists(root *os.Root, unsafePath string, isDir bool) error {
if isDir {
return root.MkdirAll(unsafePath, 0o755)
}
parent := filepath.Dir(unsafePath)
if parent != "." && parent != "/" {
if err := root.MkdirAll(parent, 0o755); err != nil {
return err
}
}
return nil
f, err := root.OpenFile(unsafePath, os.O_CREATE|os.O_WRONLY, 0o755)
if err != nil {
return err
}
return f.Close()
}
// makeMountRRO makes the mount recursively read-only.

View File

@@ -10,30 +10,36 @@ import (
func TestCreateIfNotExists(t *testing.T) {
t.Run("directory", func(t *testing.T) {
toCreate := filepath.Join(t.TempDir(), "tocreate")
dir := t.TempDir()
root, err := os.OpenRoot(dir)
assert.NilError(t, err)
defer root.Close()
err := createIfNotExists(toCreate, true)
err = createIfNotExists(root, "tocreate", true)
assert.NilError(t, err)
fileinfo, err := os.Stat(toCreate)
fileinfo, err := os.Stat(filepath.Join(dir, "tocreate"))
assert.NilError(t, err, "Did not create destination")
assert.Assert(t, fileinfo.IsDir(), "Should have been a dir, seems it's not")
err = createIfNotExists(toCreate, true)
err = createIfNotExists(root, "tocreate", true)
assert.NilError(t, err, "Should not fail if already exists")
})
t.Run("file", func(t *testing.T) {
toCreate := filepath.Join(t.TempDir(), "file/to/create")
dir := t.TempDir()
root, err := os.OpenRoot(dir)
assert.NilError(t, err)
defer root.Close()
err := createIfNotExists(toCreate, false)
err = createIfNotExists(root, "file/to/create", false)
assert.NilError(t, err)
fileinfo, err := os.Stat(toCreate)
fileinfo, err := os.Stat(filepath.Join(dir, "file/to/create"))
assert.NilError(t, err, "Did not create destination")
assert.Assert(t, !fileinfo.IsDir(), "Should have been a file, but created a directory")
err = createIfNotExists(toCreate, true)
err = createIfNotExists(root, "file/to/create", false)
assert.NilError(t, err, "Should not fail if already exists")
})
}

View File

@@ -98,14 +98,20 @@ func DeleteConntrackEntriesByPort(nlh nlwrap.Handle, proto types.Protocol, ports
}).Warn("Failed to delete conntrack state for port")
continue
}
if err := filter.AddIP(netlink.ConntrackOrigDstIP, port.HostIP); err != nil {
log.G(context.TODO()).WithFields(log.Fields{
"error": err,
"hostIP": port.HostIP.String(),
"proto": port.Proto.String(),
"port": port.Port,
}).Warn("Failed to delete conntrack state for port")
continue
// Only filter by destination IP when the host IP is specified. When
// HostIP is 0.0.0.0 or ::, the binding applies to all interfaces, but
// conntrack entries record the actual interface IP, so filtering by the
// unspecified address would never match.
if !port.HostIP.IsUnspecified() {
if err := filter.AddIP(netlink.ConntrackOrigDstIP, port.HostIP); err != nil {
log.G(context.TODO()).WithFields(log.Fields{
"error": err,
"hostIP": port.HostIP.String(),
"proto": port.Proto.String(),
"port": port.Port,
}).Warn("Failed to delete conntrack state for port")
continue
}
}
v4FlowPurged, err := nlh.ConntrackDeleteFilters(netlink.ConntrackTable, syscall.AF_INET, filter)

View File

@@ -41,7 +41,7 @@ func getCgroupFromBuildOutput(buildOutput io.Reader) (string, error) {
// Returns the container cgroup and daemon cgroup.
func testBuildWithCgroupNs(ctx context.Context, t *testing.T, daemonNsMode string) (string, string) {
d := daemon.New(t, daemon.WithDefaultCgroupNamespaceMode(daemonNsMode))
d.StartWithBusybox(ctx, t)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
dockerfile := `
@@ -72,6 +72,8 @@ func TestCgroupNamespacesBuild(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// When the daemon defaults to private cgroup namespaces, containers launched
@@ -85,6 +87,8 @@ func TestCgroupNamespacesBuildDaemonHostMode(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// When the daemon defaults to host cgroup namespaces, containers

View File

@@ -26,13 +26,15 @@ func TestCreateWithCDIDevices(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux", "CDI devices are only supported on Linux")
skip.If(t, testEnv.IsRemoteDaemon, "cannot run cdi tests with a remote daemon")
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
cwd, err := os.Getwd()
assert.NilError(t, err)
d := daemon.New(t)
d.StartWithBusybox(ctx, t, "--cdi-spec-dir="+filepath.Join(cwd, "testdata", "cdi"))
d.StartWithBusybox(ctx, t, "--cdi-spec-dir="+filepath.Join(cwd, "testdata", "cdi"), "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
apiClient := d.NewClientT(t)
@@ -74,6 +76,8 @@ func TestCDISpecDirsAreInSystemInfo(t *testing.T) {
// TODO: This restriction can be relaxed with https://github.com/moby/moby/pull/46158
skip.If(t, testEnv.IsRootless, "the t.TempDir test creates a folder with incorrect permissions for rootless")
t.Parallel()
testCases := []struct {
description string
config string
@@ -146,6 +150,7 @@ func TestCDISpecDirsAreInSystemInfo(t *testing.T) {
args = append(args, "--config-file="+configPath)
}
args = append(args, "--iptables=false", "--ip6tables=false")
d.Start(t, args...)
defer d.Stop(t)
@@ -160,6 +165,8 @@ func TestCDIInfoDiscoveredDevices(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "CDI not supported on Windows")
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// Create a sample CDI spec file
@@ -185,7 +192,7 @@ func TestCDIInfoDiscoveredDevices(t *testing.T) {
assert.NilError(t, err, "Failed to write sample CDI spec file")
d := daemon.New(t)
d.Start(t, "--feature", "cdi", "--cdi-spec-dir="+cdiDir)
d.Start(t, "--feature", "cdi", "--cdi-spec-dir="+cdiDir, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
c := d.NewClientT(t)

View File

@@ -14,11 +14,13 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/go-archive"
"github.com/moby/moby/api/types/build"
buildtypes "github.com/moby/moby/api/types/build"
"github.com/moby/moby/api/types/jsonstream"
"github.com/moby/moby/client"
"github.com/moby/moby/client/pkg/jsonmessage"
"github.com/moby/moby/v2/integration/internal/build"
"github.com/moby/moby/v2/integration/internal/container"
"github.com/moby/moby/v2/internal/testutil/daemon"
"github.com/moby/moby/v2/internal/testutil/fakecontext"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -216,7 +218,7 @@ func makeTestImage(ctx context.Context, t *testing.T) (imageID string) {
defer resp.Body.Close()
err = jsonmessage.DisplayStream(resp.Body, io.Discard, jsonmessage.WithAuxCallback(func(msg jsonstream.Message) {
var r build.Result
var r buildtypes.Result
assert.NilError(t, json.Unmarshal(*msg.Aux, &r))
imageID = r.ID
}))
@@ -291,7 +293,7 @@ func TestCopyFromContainer(t *testing.T) {
var imageID string
err = jsonmessage.DisplayStream(resp.Body, io.Discard, jsonmessage.WithAuxCallback(func(msg jsonstream.Message) {
var r build.Result
var r buildtypes.Result
assert.NilError(t, json.Unmarshal(*msg.Aux, &r))
imageID = r.ID
}))
@@ -362,3 +364,76 @@ func TestCopyFromContainer(t *testing.T) {
})
}
}
// TestCopyToContainerXZBinaryNotExecutedOnDaemon tests that when
// uploading an xz-compressed archive to a container via the
// PUT /containers/{id}/archive API, the daemon does NOT execute the xz
// binary found inside the container's filesystem.
// This is a regression test for
// https://github.com/moby/moby/security/advisories/GHSA-x86f-5xw2-fm2r
func TestCopyToContainerXZBinaryNotExecutedOnDaemon(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
ctx := setupTest(t)
const tokenEnv = "MOBY_EXPLOIT_TEST_TOKEN"
const tokenVal = "host-boundary-crossed"
d := daemon.New(t)
defer d.Cleanup(t)
d.SetEnvVar(tokenEnv, tokenVal)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
apiClient := d.NewClientT(t)
dir := t.TempDir()
buildCtx := fakecontext.New(t, dir,
// The fake xz writes the daemon's secret env var to a marker file.
// A process inside the container would not have this env var.
fakecontext.WithFile("fake-xz", "#!/bin/sh\necho $"+tokenEnv+" > /xz-was-executed\n"),
fakecontext.WithDockerfile(`FROM busybox
COPY fake-xz /usr/bin/xz
RUN chmod +x /usr/bin/xz`),
)
defer buildCtx.Close()
imageID := build.Do(ctx, t, apiClient, buildCtx, client.ImageBuildOptions{})
cID := container.Run(ctx, t, apiClient, container.WithImage(imageID))
defer container.Remove(ctx, t, apiClient, cID, client.ContainerRemoveOptions{Force: true})
// Craft a payload that starts with xz magic bytes so the daemon's
// DecompressStream identifies it as xz-compressed. The payload is
// deliberately invalid xz data; we only care whether the daemon
// attempts to run the container's /usr/bin/xz to decompress it.
xzMagic := []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}
payload := append(xzMagic, []byte("not-real-xz-data")...)
// CopyToContainer is expected to fail because the payload is not a
// valid xz archive. We don't care about the error; we care about
// whether the container's xz binary was invoked.
_, _ = apiClient.CopyToContainer(ctx, cID, client.CopyToContainerOptions{
DestinationPath: "/tmp",
Content: bytes.NewReader(payload),
})
t.Run("binary not executed", func(t *testing.T) {
// If the container's /usr/bin/xz was executed, the marker file
// will exist, and this assertion will fail.
res, err := container.Exec(ctx, apiClient, cID, []string{"test", "-f", "/xz-was-executed"})
assert.NilError(t, err)
assert.Check(t, is.Equal(res.ExitCode, 1),
"container's xz binary was executed by the daemon during archive extraction; marker file /xz-was-executed was created")
})
t.Run("runs container", func(t *testing.T) {
// If the binary ran, check that it ran in the daemon's process
// context by looking for the daemon's secret env var in the
// marker file. A container process would not have this env var.
res, err := container.Exec(ctx, apiClient, cID, []string{"cat", "/xz-was-executed"})
assert.NilError(t, err)
assert.Check(t, !strings.Contains(res.Stdout(), tokenVal),
"container's xz binary was executed in the daemon's process context: marker file contains the daemon's secret env var")
})
}

View File

@@ -59,17 +59,19 @@ func TestExportContainerAfterDaemonRestart(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
skip.If(t, testEnv.IsRemoteDaemon)
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t)
c := d.NewClientT(t)
d.StartWithBusybox(ctx, t)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
ctrID := container.Create(ctx, t, c)
d.Restart(t)
d.Restart(t, "--iptables=false", "--ip6tables=false")
res, err := c.ContainerExport(ctx, ctrID, client.ContainerExportOptions{})
assert.NilError(t, err)

View File

@@ -18,7 +18,7 @@ func testRunWithCgroupNs(ctx context.Context, t *testing.T, daemonNsMode string,
d := daemon.New(t, daemon.WithDefaultCgroupNamespaceMode(daemonNsMode))
apiClient := d.NewClientT(t)
d.StartWithBusybox(ctx, t)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
cID := container.Run(ctx, t, apiClient, containerOpts...)
@@ -34,7 +34,7 @@ func testCreateFailureWithCgroupNs(ctx context.Context, t *testing.T, daemonNsMo
d := daemon.New(t, daemon.WithDefaultCgroupNamespaceMode(daemonNsMode))
apiClient := d.NewClientT(t)
d.StartWithBusybox(ctx, t)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
_, err := container.CreateFromConfig(ctx, apiClient, container.NewTestConfig(containerOpts...))
assert.ErrorContains(t, err, errStr)
@@ -45,6 +45,8 @@ func TestCgroupNamespacesRun(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// When the daemon defaults to private cgroup namespaces, containers launched
@@ -59,6 +61,8 @@ func TestCgroupNamespacesRunPrivileged(t *testing.T) {
skip.If(t, !requirement.CgroupNamespacesEnabled())
skip.If(t, testEnv.DaemonInfo.CgroupVersion == "2", "on cgroup v2, privileged containers use private cgroupns")
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// When the daemon defaults to private cgroup namespaces, privileged containers
@@ -72,6 +76,8 @@ func TestCgroupNamespacesRunDaemonHostMode(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// When the daemon defaults to host cgroup namespaces, containers
@@ -85,6 +91,8 @@ func TestCgroupNamespacesRunHostMode(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// When the daemon defaults to private cgroup namespaces, containers launched
@@ -98,6 +106,8 @@ func TestCgroupNamespacesRunPrivateMode(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// When the daemon defaults to private cgroup namespaces, containers launched
@@ -111,6 +121,8 @@ func TestCgroupNamespacesRunPrivilegedAndPrivate(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
containerCgroup, daemonCgroup := testRunWithCgroupNs(ctx, t, "private", container.WithPrivileged(true), container.WithCgroupnsMode("private"))
@@ -122,6 +134,8 @@ func TestCgroupNamespacesRunInvalidMode(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
// An invalid cgroup namespace mode should return an error on container creation
@@ -136,12 +150,14 @@ func TestCgroupNamespacesRunOlderClient(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
skip.If(t, !requirement.CgroupNamespacesEnabled())
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t, daemon.WithEnvVars("DOCKER_MIN_API_VERSION=1.39"), daemon.WithDefaultCgroupNamespaceMode("private"))
apiClient := d.NewClientT(t, client.WithAPIVersion("1.39"))
d.StartWithBusybox(ctx, t)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
cID := container.Run(ctx, t, apiClient)

View File

@@ -23,6 +23,8 @@ func TestNRIContainerCreateEnvVarMod(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "cannot start a separate daemon with NRI enabled on Windows")
skip.If(t, testEnv.IsRootless)
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
sockPath := filepath.Join(t.TempDir(), "nri.sock")
@@ -78,6 +80,8 @@ func TestNRIContainerCreateUnsupportedAdj(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "cannot start a separate daemon with NRI enabled on Windows")
skip.If(t, testEnv.IsRootless)
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
sockPath := filepath.Join(t.TempDir(), "nri.sock")
@@ -138,6 +142,8 @@ func TestNRIContainerCreateAddMount(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "cannot start a separate daemon with NRI enabled on Windows")
skip.If(t, testEnv.IsRootless)
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
sockPath := filepath.Join(t.TempDir(), "nri.sock")
@@ -258,6 +264,8 @@ func TestNRIReload(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "cannot start a separate daemon with NRI enabled on Windows")
skip.If(t, testEnv.IsRootless)
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
const pluginName = "00-nri-test-plugin"

View File

@@ -56,9 +56,11 @@ func TestUsernsCommit(t *testing.T) {
skip.If(t, !testEnv.IsUserNamespaceInKernel())
skip.If(t, testEnv.IsRootless())
t.Parallel()
ctx := context.Background()
dUserRemap := daemon.New(t, daemon.WithUserNsRemap("default"))
dUserRemap.StartWithBusybox(ctx, t)
dUserRemap.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false")
clientUserRemap := dUserRemap.NewClientT(t)
defer clientUserRemap.Close()

View File

@@ -24,6 +24,8 @@ func TestDiskUsageConcurrentPrune(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
skip.If(t, !testEnv.UsingSnapshotter(), "only happens with containerd image store")
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t)

View File

@@ -18,6 +18,8 @@ import (
func TestDiskUsage(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows") // d.Start fails on Windows with `protocol not available`
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t)

View File

@@ -45,12 +45,14 @@ func TestInfoAPIWarnings(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t)
c := d.NewClientT(t)
d.Start(t, "-H=0.0.0.0:23756", "-H="+d.Sock())
d.Start(t, "-H=0.0.0.0:23756", "-H="+d.Sock(), "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
result, err := c.Info(ctx, client.InfoOptions{})
@@ -73,10 +75,12 @@ func TestInfoDebug(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME: test starts daemon with -H unix://.....")
t.Parallel()
_ = testutil.StartSpan(baseContext, t)
d := daemon.New(t)
d.Start(t, "--debug")
d.Start(t, "--debug", "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
info := d.Info(t)
@@ -95,13 +99,15 @@ func TestInfoInsecureRegistries(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME: test starts daemon with -H unix://.....")
t.Parallel()
const (
registryCIDR = "192.168.1.0/24"
registryHost = "insecurehost.com:5000"
)
d := daemon.New(t)
d.Start(t, "--insecure-registry="+registryCIDR, "--insecure-registry="+registryHost)
d.Start(t, "--insecure-registry="+registryCIDR, "--insecure-registry="+registryHost, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
info := d.Info(t)
@@ -122,13 +128,15 @@ func TestInfoRegistryMirrors(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME: test starts daemon with -H unix://.....")
t.Parallel()
const (
registryMirror1 = "https://192.168.1.2"
registryMirror2 = "http://registry-mirror.example.com:5000"
)
d := daemon.New(t)
d.Start(t, "--registry-mirror="+registryMirror1, "--registry-mirror="+registryMirror2)
d.Start(t, "--registry-mirror="+registryMirror1, "--registry-mirror="+registryMirror2, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
info := d.Info(t)

View File

@@ -101,14 +101,16 @@ func TestPingBuilderHeader(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon)
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "cannot spin up additional daemons on windows")
ctx := setupTest(t)
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t)
apiClient := d.NewClientT(t)
defer apiClient.Close()
t.Run("default config", func(t *testing.T) {
testutil.StartSpan(ctx, t)
d.Start(t)
d.Start(t, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
expected := build.BuilderBuildKit
@@ -126,7 +128,7 @@ func TestPingBuilderHeader(t *testing.T) {
cfg := filepath.Join(d.RootDir(), "daemon.json")
err := os.WriteFile(cfg, []byte(`{"features": { "buildkit": false }}`), 0o644)
assert.NilError(t, err)
d.Start(t, "--config-file", cfg)
d.Start(t, "--config-file", cfg, "--iptables=false", "--ip6tables=false")
defer d.Stop(t)
expected := build.BuilderV1

View File

@@ -436,6 +436,8 @@ func TestRunMountImageSubpathDaemonRestart(t *testing.T) {
skip.If(t, testEnv.IsRootless, "FIXME: https://github.com/moby/moby/issues/50999")
skip.If(t, !testEnv.UsingSnapshotter(), "FIXME: https://github.com/moby/moby/issues/50999")
t.Parallel()
ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t)

View File

@@ -1,4 +1,4 @@
---
docker:
current: "29.4.1"
next: "29.5.0"
current: "29.5.1"
next: "29.5.2"