Add support for glob syntax when checking volumes (#64)
Follow #60 Reviewed-on: https://gitea.com/gitea/act/pulls/64 Reviewed-by: Jason Song <i@wolfogre.com> Co-authored-by: Zettat123 <zettat123@gmail.com> Co-committed-by: Zettat123 <zettat123@gmail.com>
This commit is contained in:
parent
56e103b4ba
commit
a165e17878
4 changed files with 104 additions and 6 deletions
1
go.mod
1
go.mod
|
@ -14,6 +14,7 @@ require (
|
|||
github.com/docker/go-connections v0.4.0
|
||||
github.com/go-git/go-billy/v5 v5.4.1
|
||||
github.com/go-git/go-git/v5 v5.7.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/imdario/mergo v0.3.15
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -68,6 +68,8 @@ github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw4
|
|||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
|
||||
github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE=
|
||||
github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/types/network"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
"github.com/gobwas/glob"
|
||||
|
||||
"github.com/go-git/go-billy/v5/helper/polyfill"
|
||||
"github.com/go-git/go-billy/v5/osfs"
|
||||
|
@ -883,13 +884,27 @@ func (cr *containerReference) wait() common.Executor {
|
|||
}
|
||||
}
|
||||
|
||||
// For Gitea
|
||||
// sanitizeConfig remove the invalid configurations from `config` and `hostConfig`
|
||||
func (cr *containerReference) sanitizeConfig(ctx context.Context, config *container.Config, hostConfig *container.HostConfig) (*container.Config, *container.HostConfig) {
|
||||
logger := common.Logger(ctx)
|
||||
|
||||
if len(cr.input.ValidVolumes) > 0 {
|
||||
vv := make(map[string]struct{}, len(cr.input.ValidVolumes))
|
||||
for _, volume := range cr.input.ValidVolumes {
|
||||
vv[volume] = struct{}{}
|
||||
globs := make([]glob.Glob, 0, len(cr.input.ValidVolumes))
|
||||
for _, v := range cr.input.ValidVolumes {
|
||||
if g, err := glob.Compile(v); err != nil {
|
||||
logger.Errorf("create glob from %s error: %v", v, err)
|
||||
} else {
|
||||
globs = append(globs, g)
|
||||
}
|
||||
}
|
||||
isValid := func(v string) bool {
|
||||
for _, g := range globs {
|
||||
if g.Match(v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// sanitize binds
|
||||
sanitizedBinds := make([]string, 0, len(hostConfig.Binds))
|
||||
|
@ -904,23 +919,26 @@ func (cr *containerReference) sanitizeConfig(ctx context.Context, config *contai
|
|||
sanitizedBinds = append(sanitizedBinds, bind)
|
||||
continue
|
||||
}
|
||||
if _, ok := vv[parsed.Source]; ok {
|
||||
if isValid(parsed.Source) {
|
||||
sanitizedBinds = append(sanitizedBinds, bind)
|
||||
} else {
|
||||
logger.Warnf("[%s] is not a valid volume, will be ignored", bind)
|
||||
logger.Warnf("[%s] is not a valid volume, will be ignored", parsed.Source)
|
||||
}
|
||||
}
|
||||
hostConfig.Binds = sanitizedBinds
|
||||
// sanitize mounts
|
||||
sanitizedMounts := make([]mount.Mount, 0, len(hostConfig.Mounts))
|
||||
for _, mt := range hostConfig.Mounts {
|
||||
if _, ok := vv[mt.Source]; ok {
|
||||
if isValid(mt.Source) {
|
||||
sanitizedMounts = append(sanitizedMounts, mt)
|
||||
} else {
|
||||
logger.Warnf("[%s] is not a valid volume, will be ignored", mt.Source)
|
||||
}
|
||||
}
|
||||
hostConfig.Mounts = sanitizedMounts
|
||||
} else {
|
||||
hostConfig.Binds = []string{}
|
||||
hostConfig.Mounts = []mount.Mount{}
|
||||
}
|
||||
|
||||
return config, hostConfig
|
||||
|
|
|
@ -9,8 +9,12 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nektos/act/pkg/common"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
@ -166,3 +170,76 @@ func TestDockerExecFailure(t *testing.T) {
|
|||
|
||||
// Type assert containerReference implements ExecutionsEnvironment
|
||||
var _ ExecutionsEnvironment = &containerReference{}
|
||||
|
||||
func TestCheckVolumes(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
validVolumes []string
|
||||
binds []string
|
||||
expectedBinds []string
|
||||
}{
|
||||
{
|
||||
desc: "match all volumes",
|
||||
validVolumes: []string{"**"},
|
||||
binds: []string{
|
||||
"shared_volume:/shared_volume",
|
||||
"/home/test/data:/test_data",
|
||||
"/etc/conf.d/base.json:/config/base.json",
|
||||
"sql_data:/sql_data",
|
||||
"/secrets/keys:/keys",
|
||||
},
|
||||
expectedBinds: []string{
|
||||
"shared_volume:/shared_volume",
|
||||
"/home/test/data:/test_data",
|
||||
"/etc/conf.d/base.json:/config/base.json",
|
||||
"sql_data:/sql_data",
|
||||
"/secrets/keys:/keys",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "no volumes can be matched",
|
||||
validVolumes: []string{},
|
||||
binds: []string{
|
||||
"shared_volume:/shared_volume",
|
||||
"/home/test/data:/test_data",
|
||||
"/etc/conf.d/base.json:/config/base.json",
|
||||
"sql_data:/sql_data",
|
||||
"/secrets/keys:/keys",
|
||||
},
|
||||
expectedBinds: []string{},
|
||||
},
|
||||
{
|
||||
desc: "only allowed volumes can be matched",
|
||||
validVolumes: []string{
|
||||
"shared_volume",
|
||||
"/home/test/data",
|
||||
"/etc/conf.d/*.json",
|
||||
},
|
||||
binds: []string{
|
||||
"shared_volume:/shared_volume",
|
||||
"/home/test/data:/test_data",
|
||||
"/etc/conf.d/base.json:/config/base.json",
|
||||
"sql_data:/sql_data",
|
||||
"/secrets/keys:/keys",
|
||||
},
|
||||
expectedBinds: []string{
|
||||
"shared_volume:/shared_volume",
|
||||
"/home/test/data:/test_data",
|
||||
"/etc/conf.d/base.json:/config/base.json",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
logger, _ := test.NewNullLogger()
|
||||
ctx := common.WithLogger(context.Background(), logger)
|
||||
cr := &containerReference{
|
||||
input: &NewContainerInput{
|
||||
ValidVolumes: tc.validVolumes,
|
||||
},
|
||||
}
|
||||
_, hostConf := cr.sanitizeConfig(ctx, &container.Config{}, &container.HostConfig{Binds: tc.binds})
|
||||
assert.Equal(t, tc.expectedBinds, hostConf.Binds)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue