summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopherHX <christopher.homberger@web.de>2022-06-21 00:47:39 +0200
committerGitHub <noreply@github.com>2022-06-21 00:47:39 +0200
commitb59e6dee6d01253cb96505f8effc0516c2a390d9 (patch)
tree11dcc0b78aa43d1584eb22fc91788fcdaeaf14a7
parentfix: processing of strategy.matrix.include (#1200) (diff)
downloadforgejo-act-b59e6dee6d01253cb96505f8effc0516c2a390d9.tar.xz
forgejo-act-b59e6dee6d01253cb96505f8effc0516c2a390d9.zip
feat: non root user container (#1202)
* feat: non root user container * Also chown WorkingDir * . * . * Update docker_run.go * Add Test * Update runner_test.go * Update docker_run.go * Apply suggestions from code review Co-authored-by: R <me@hackerc.at> * remove cruft from master merge Co-authored-by: R <me@hackerc.at> Co-authored-by: Casey Lee <cplee@nektos.com> Co-authored-by: Casey Lee <caseypl@amazon.com>
-rw-r--r--pkg/container/docker_run.go64
-rw-r--r--pkg/container/file_collector.go11
-rw-r--r--pkg/runner/run_context.go1
-rw-r--r--pkg/runner/runner_test.go1
4 files changed, 71 insertions, 6 deletions
diff --git a/pkg/container/docker_run.go b/pkg/container/docker_run.go
index 22c2008..7f0a577 100644
--- a/pkg/container/docker_run.go
+++ b/pkg/container/docker_run.go
@@ -12,6 +12,7 @@ import (
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"github.com/go-git/go-billy/v5/helper/polyfill"
@@ -125,6 +126,13 @@ func (cr *containerReference) Start(attach bool) common.Executor {
cr.attach().IfBool(attach),
cr.start(),
cr.wait().IfBool(attach),
+ cr.tryReadUID(),
+ cr.tryReadGID(),
+ func(ctx context.Context) error {
+ // If this fails, then folders have wrong permissions on non root container
+ _ = cr.Exec([]string{"chown", "-R", fmt.Sprintf("%d:%d", cr.UID, cr.GID), cr.input.WorkingDir}, nil, "0", "")(ctx)
+ return nil
+ },
).IfNot(common.Dryrun),
)
}
@@ -154,8 +162,12 @@ func (cr *containerReference) Copy(destPath string, files ...*FileEntry) common.
func (cr *containerReference) CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor {
return common.NewPipelineExecutor(
common.NewInfoExecutor("%sdocker cp src=%s dst=%s", logPrefix, srcPath, destPath),
- cr.Exec([]string{"mkdir", "-p", destPath}, nil, "", ""),
cr.copyDir(destPath, srcPath, useGitIgnore),
+ func(ctx context.Context) error {
+ // If this fails, then folders have wrong permissions on non root container
+ _ = cr.Exec([]string{"chown", "-R", fmt.Sprintf("%d:%d", cr.UID, cr.GID), destPath}, nil, "0", "")(ctx)
+ return nil
+ },
).IfNot(common.Dryrun)
}
@@ -211,6 +223,8 @@ type containerReference struct {
cli client.APIClient
id string
input *NewContainerInput
+ UID int
+ GID int
}
func GetDockerClient(ctx context.Context) (cli client.APIClient, err error) {
@@ -581,6 +595,47 @@ func (cr *containerReference) exec(cmd []string, env map[string]string, user, wo
}
}
+func (cr *containerReference) tryReadID(opt string, cbk func(id int)) common.Executor {
+ return func(ctx context.Context) error {
+ idResp, err := cr.cli.ContainerExecCreate(ctx, cr.id, types.ExecConfig{
+ Cmd: []string{"id", opt},
+ AttachStdout: true,
+ AttachStderr: true,
+ })
+ if err != nil {
+ return nil
+ }
+
+ resp, err := cr.cli.ContainerExecAttach(ctx, idResp.ID, types.ExecStartCheck{})
+ if err != nil {
+ return nil
+ }
+ defer resp.Close()
+
+ sid, err := resp.Reader.ReadString('\n')
+ if err != nil {
+ return nil
+ }
+ exp := regexp.MustCompile(`\d+\n`)
+ found := exp.FindString(sid)
+ id, err := strconv.ParseInt(found[:len(found)-1], 10, 32)
+ if err != nil {
+ return nil
+ }
+ cbk(int(id))
+
+ return nil
+ }
+}
+
+func (cr *containerReference) tryReadUID() common.Executor {
+ return cr.tryReadID("-u", func(id int) { cr.UID = id })
+}
+
+func (cr *containerReference) tryReadGID() common.Executor {
+ return cr.tryReadID("-g", func(id int) { cr.GID = id })
+}
+
func (cr *containerReference) waitForCommand(ctx context.Context, isTerminal bool, resp types.HijackedResponse, idResp types.IDResponse, user string, workdir string) error {
logger := common.Logger(ctx)
@@ -670,6 +725,9 @@ func (cr *containerReference) copyDir(dstPath string, srcPath string, useGitIgno
SrcPrefix: srcPrefix,
Handler: &tarCollector{
TarWriter: tw,
+ UID: cr.UID,
+ GID: cr.GID,
+ DstDir: dstPath[1:],
},
}
@@ -686,7 +744,7 @@ func (cr *containerReference) copyDir(dstPath string, srcPath string, useGitIgno
if err != nil {
return fmt.Errorf("failed to seek tar archive: %w", err)
}
- err = cr.cli.CopyToContainer(ctx, cr.id, dstPath, tarFile, types.CopyToContainerOptions{})
+ err = cr.cli.CopyToContainer(ctx, cr.id, "/", tarFile, types.CopyToContainerOptions{})
if err != nil {
return fmt.Errorf("failed to copy content to container: %w", err)
}
@@ -705,6 +763,8 @@ func (cr *containerReference) copyContent(dstPath string, files ...*FileEntry) c
Name: file.Name,
Mode: file.Mode,
Size: int64(len(file.Body)),
+ Uid: cr.UID,
+ Gid: cr.GID,
}
if err := tw.WriteHeader(hdr); err != nil {
return err
diff --git a/pkg/container/file_collector.go b/pkg/container/file_collector.go
index 84821aa..8c8c62b 100644
--- a/pkg/container/file_collector.go
+++ b/pkg/container/file_collector.go
@@ -23,9 +23,12 @@ type fileCollectorHandler interface {
type tarCollector struct {
TarWriter *tar.Writer
+ UID int
+ GID int
+ DstDir string
}
-func (tc tarCollector) WriteFile(path string, fi fs.FileInfo, linkName string, f io.Reader) error {
+func (tc tarCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error {
// create a new dir/file header
header, err := tar.FileInfoHeader(fi, linkName)
if err != nil {
@@ -33,9 +36,11 @@ func (tc tarCollector) WriteFile(path string, fi fs.FileInfo, linkName string, f
}
// update the name to correctly reflect the desired destination when untaring
- header.Name = path
+ header.Name = path.Join(tc.DstDir, fpath)
header.Mode = int64(fi.Mode())
header.ModTime = fi.ModTime()
+ header.Uid = tc.UID
+ header.Gid = tc.GID
// write the header
if err := tc.TarWriter.WriteHeader(header); err != nil {
@@ -138,7 +143,7 @@ func (fc *fileCollector) collectFiles(ctx context.Context, submodulePath []strin
}
}
if err == nil && entry.Mode == filemode.Submodule {
- err = filepath.Walk(fi.Name(), fc.collectFiles(ctx, split))
+ err = fc.Fs.Walk(fi.Name(), fc.collectFiles(ctx, split))
if err != nil {
return err
}
diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go
index 3afc364..acbff9b 100644
--- a/pkg/runner/run_context.go
+++ b/pkg/runner/run_context.go
@@ -180,7 +180,6 @@ func (rc *RunContext) startJobContainer() common.Executor {
rc.JobContainer.Start(false),
rc.JobContainer.UpdateFromImageEnv(&rc.Env),
rc.JobContainer.UpdateFromEnv("/etc/environment", &rc.Env),
- rc.JobContainer.Exec([]string{"mkdir", "-m", "0777", "-p", ActPath}, rc.Env, "root", ""),
rc.JobContainer.Copy(ActPath+"/", &container.FileEntry{
Name: "workflow/event.json",
Mode: 0644,
diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go
index 2129c43..c116bc5 100644
--- a/pkg/runner/runner_test.go
+++ b/pkg/runner/runner_test.go
@@ -158,6 +158,7 @@ func TestRunEvent(t *testing.T) {
{workdir, "container-hostname", "push", "", platforms},
{workdir, "remote-action-docker", "push", "", platforms},
{workdir, "remote-action-js", "push", "", platforms},
+ {workdir, "remote-action-js", "push", "", map[string]string{"ubuntu-latest": "ghcr.io/catthehacker/ubuntu:runner-latest"}}, // Test if this works with non root container
{workdir, "matrix", "push", "", platforms},
{workdir, "matrix-include-exclude", "push", "", platforms},
{workdir, "commands", "push", "", platforms},