mirror of
https://gitea.com/gitea/act_runner
synced 2026-09-21 19:37:07 +02:00
Containers a job starts through its Docker socket, for example `docker run -v "$PWD:/src"`, `./data:/data` in docker compose, or actions like dockerfile-roast, can now bind-mount the workspace and other paths the job sees, as on a host, without `bind_workdir`. The per-job Docker proxy rewrites container and volume create requests. A bind source, or the device of a `local` volume with `o: bind`, that lies under one of the job container's mounts is pointed at that mount's path on the daemon, read from inspecting the job container. Paths that already name a daemon path, like `GITEA_DOCKER_WORKSPACE`, and paths outside the job's mounts pass through unchanged. The proxy now also starts when the runner runs in a container given the host's Docker socket, by placing its socket in the runner's working directory, and in rootless dind, by granting the daemon socket's group through an ACL. Fixes https://gitea.com/gitea/runner/issues/1219 Fixes https://gitea.com/gitea/runner/issues/1193 Reviewed-on: https://gitea.com/gitea/runner/pulls/1226 Reviewed-by: bircni <bircni@icloud.com> Co-authored-by: silverwind <2021+silverwind@noreply.gitea.com>
49 lines
1.6 KiB
Go
49 lines
1.6 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//go:build !WITHOUT_DOCKER && (linux || darwin || netbsd)
|
|
|
|
package container
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"io/fs"
|
|
"math"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func copyDockerSocketPermissions(daemonSocket, socket string, info os.FileInfo) error {
|
|
stat, ok := info.Sys().(*syscall.Stat_t)
|
|
if !ok {
|
|
return errors.New("docker socket ownership is unavailable")
|
|
}
|
|
groupErr := os.Chown(socket, int(stat.Uid), int(stat.Gid))
|
|
if groupErr != nil && (!errors.Is(groupErr, fs.ErrPermission) || int(stat.Uid) != os.Geteuid()) {
|
|
return groupErr
|
|
}
|
|
if err := os.Chown(filepath.Dir(socket), int(stat.Uid), -1); err != nil {
|
|
return err
|
|
}
|
|
mode := uint16(info.Mode().Perm())
|
|
if err := os.Chmod(socket, fs.FileMode(mode)); err != nil || groupErr == nil {
|
|
return err
|
|
}
|
|
if size, err := unix.Getxattr(daemonSocket, "system.posix_acl_access", nil); err == nil && size > 0 {
|
|
return groupErr
|
|
}
|
|
owner, group, other := mode>>6, mode>>3&7, mode&7
|
|
acl := binary.LittleEndian.AppendUint32(nil, 2)
|
|
for _, entry := range []struct {
|
|
tag, perm uint16
|
|
id uint32
|
|
}{{1, owner, math.MaxUint32}, {4, other, math.MaxUint32}, {8, group, stat.Gid}, {16, group | other, math.MaxUint32}, {32, other, math.MaxUint32}} {
|
|
acl = binary.LittleEndian.AppendUint32(binary.LittleEndian.AppendUint16(binary.LittleEndian.AppendUint16(acl, entry.tag), entry.perm), entry.id)
|
|
}
|
|
return unix.Setxattr(socket, "system.posix_acl_access", acl, 0) // names the group a rootless runner cannot chown to, its own group keeps what others had
|
|
}
|