From e4f954ef9495419918aeacf405ac975c55e1db57 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 31 Aug 2024 19:04:47 +0200 Subject: [PATCH] Remove all default 3rd party privileged plugins (#3918) --- cmd/server/flags.go | 2 +- cmd/server/setup.go | 7 +++++- docs/docs/91-migrations.md | 1 + pipeline/frontend/yaml/linter/linter.go | 25 ++++++++++++++++++-- pipeline/frontend/yaml/linter/linter_test.go | 8 +++++-- pipeline/frontend/yaml/linter/option.go | 7 ++++++ pipeline/frontend/yaml/utils/image_test.go | 5 ++++ server/config.go | 2 +- server/pipeline/stepbuilder/stepBuilder.go | 3 ++- shared/constant/constant.go | 5 +--- 10 files changed, 53 insertions(+), 12 deletions(-) diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 45c905a4f..1f2400aca 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -161,7 +161,7 @@ var flags = append([]cli.Flag{ &cli.StringSliceFlag{ Sources: cli.EnvVars("WOODPECKER_ESCALATE"), Name: "escalate", - Usage: "images to run in privileged mode", + Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none", Value: constant.PrivilegedPlugins, }, &cli.StringSliceFlag{ diff --git a/cmd/server/setup.go b/cmd/server/setup.go index f394c0777..375df7a90 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -222,10 +222,15 @@ func setupEvilGlobals(ctx context.Context, c *cli.Command, s store.Store) error server.Config.Server.CustomJsFile = strings.TrimSpace(c.String("custom-js-file")) server.Config.Pipeline.Networks = c.StringSlice("network") server.Config.Pipeline.Volumes = c.StringSlice("volume") - server.Config.Pipeline.Privileged = c.StringSlice("escalate") server.Config.WebUI.EnableSwagger = c.Bool("enable-swagger") server.Config.WebUI.SkipVersionCheck = c.Bool("skip-version-check") + // list has default value but should be able to be set to zero + server.Config.Pipeline.PrivilegedPlugins = c.StringSlice("escalate") + if val, set := os.LookupEnv("WOODPECKER_ESCALATE"); set && val == "" { + server.Config.Pipeline.PrivilegedPlugins = []string{} + } + // prometheus server.Config.Prometheus.AuthToken = c.String("prometheus-auth-token") diff --git a/docs/docs/91-migrations.md b/docs/docs/91-migrations.md index 53c1c5814..645fbc405 100644 --- a/docs/docs/91-migrations.md +++ b/docs/docs/91-migrations.md @@ -4,6 +4,7 @@ Some versions need some changes to the server configuration or the pipeline conf ## `next` +- Remove `plugins/docker`, `plugins/gcr` and `plugins/ecr` from the default list of privileged plugins ([modify the list via config if needed](./30-administration/10-server-config.md#woodpecker_escalate)). - Secret filters for plugins now check against tag if specified - Removed `WOODPECKER_DEV_OAUTH_HOST` and `WOODPECKER_DEV_GITEA_OAUTH_URL` use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST` - Compatibility mode of deprecated `pipeline:`, `platform:` and `branches:` pipeline config options are now removed and pipeline will now fail if still in use. diff --git a/pipeline/frontend/yaml/linter/linter.go b/pipeline/frontend/yaml/linter/linter.go index 6b4a51fc7..c1bc349be 100644 --- a/pipeline/frontend/yaml/linter/linter.go +++ b/pipeline/frontend/yaml/linter/linter.go @@ -24,11 +24,13 @@ import ( errorTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter/schema" "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/types" + "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/utils" ) // A Linter lints a pipeline configuration. type Linter struct { - trusted bool + trusted bool + privilegedPlugins *[]string } // New creates a new Linter with options. @@ -120,6 +122,9 @@ func (l *Linter) lintContainers(config *WorkflowConfig, area string) error { if err := l.lintSettings(config, container, area); err != nil { linterErr = multierr.Append(linterErr, err) } + if err := l.lintPrivilegedPlugins(config, container, area); err != nil { + linterErr = multierr.Append(linterErr, err) + } } return linterErr @@ -132,6 +137,22 @@ func (l *Linter) lintImage(config *WorkflowConfig, c *types.Container, area stri return nil } +func (l *Linter) lintPrivilegedPlugins(config *WorkflowConfig, c *types.Container, area string) error { + // lint for conflicts of https://github.com/woodpecker-ci/woodpecker/pull/3918 + if utils.MatchImage(c.Image, "plugins/docker", "plugins/gcr", "plugins/ecr") { + msg := "Cannot use once privileged plugins removed from WOODPECKER_ESCALATE, use 'woodpeckerci/plugin-docker-buildx' instead" + // check first if user did not add them back + if l.privilegedPlugins != nil && !utils.MatchImage(c.Image, *l.privilegedPlugins...) { + return newLinterError(msg, config.File, fmt.Sprintf("%s.%s", area, c.Name), false) + } else if l.privilegedPlugins == nil { + // if linter has no info of current privileged plugins, it's just a warning + return newLinterError(msg, config.File, fmt.Sprintf("%s.%s", area, c.Name), true) + } + } + + return nil +} + func (l *Linter) lintSettings(config *WorkflowConfig, c *types.Container, field string) error { if len(c.Settings) == 0 { return nil @@ -218,7 +239,7 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { return err } - return err + return nil } func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) { diff --git a/pipeline/frontend/yaml/linter/linter_test.go b/pipeline/frontend/yaml/linter/linter_test.go index 19bc5ae43..deff4ca44 100644 --- a/pipeline/frontend/yaml/linter/linter_test.go +++ b/pipeline/frontend/yaml/linter/linter_test.go @@ -39,7 +39,7 @@ steps: - go build - go test publish: - image: plugins/docker + image: woodpeckerci/plugin-docker-buildx settings: repo: foo/bar foo: bar @@ -61,7 +61,7 @@ steps: - go build - go test - name: publish - image: plugins/docker + image: woodpeckerci/plugin-docker-buildx settings: repo: foo/bar foo: bar @@ -169,6 +169,10 @@ func TestLintErrors(t *testing.T) { from: "{pipeline: { build: { image: golang, settings: { test: 'true' } } }, when: { branch: main, event: push } }", want: "Additional property pipeline is not allowed", }, + { + from: "{steps: { build: { image: plugins/docker, settings: { test: 'true' } } }, when: { branch: main, event: push } } }", + want: "Cannot use once privileged plugins removed from WOODPECKER_ESCALATE, use 'woodpeckerci/plugin-docker-buildx' instead", + }, } for _, test := range testdata { diff --git a/pipeline/frontend/yaml/linter/option.go b/pipeline/frontend/yaml/linter/option.go index 0fe2af76f..3a3cbba44 100644 --- a/pipeline/frontend/yaml/linter/option.go +++ b/pipeline/frontend/yaml/linter/option.go @@ -23,3 +23,10 @@ func WithTrusted(trusted bool) Option { linter.trusted = trusted } } + +// PrivilegedPlugins adds the list of privileged plugins. +func PrivilegedPlugins(plugins []string) Option { + return func(linter *Linter) { + linter.privilegedPlugins = &plugins + } +} diff --git a/pipeline/frontend/yaml/utils/image_test.go b/pipeline/frontend/yaml/utils/image_test.go index 1d3a6de90..7b79f669b 100644 --- a/pipeline/frontend/yaml/utils/image_test.go +++ b/pipeline/frontend/yaml/utils/image_test.go @@ -254,6 +254,11 @@ func Test_matchImage(t *testing.T) { to: "gcr.io/golang", want: false, }, + { + from: "woodpeckerci/plugin-docker-buildx", + to: "docker.io/woodpeckerci/plugin-docker-buildx", + want: true, + }, } for _, test := range testdata { assert.Equal(t, test.want, MatchImage(test.from, test.to)) diff --git a/server/config.go b/server/config.go index bb5ba721e..80e367a51 100644 --- a/server/config.go +++ b/server/config.go @@ -68,7 +68,7 @@ var Config = struct { Limits model.ResourceLimit Volumes []string Networks []string - Privileged []string + PrivilegedPlugins []string DefaultTimeout int64 MaxTimeout int64 Proxy struct { diff --git a/server/pipeline/stepbuilder/stepBuilder.go b/server/pipeline/stepbuilder/stepBuilder.go index 593ff0fc1..eafb58a55 100644 --- a/server/pipeline/stepbuilder/stepBuilder.go +++ b/server/pipeline/stepbuilder/stepBuilder.go @@ -142,6 +142,7 @@ func (b *StepBuilder) genItemForWorkflow(workflow *model.Workflow, axis matrix.A // lint pipeline errorsAndWarnings = multierr.Append(errorsAndWarnings, linter.New( linter.WithTrusted(b.Repo.IsTrusted), + linter.PrivilegedPlugins(server.Config.Pipeline.PrivilegedPlugins), ).Lint([]*linter.WorkflowConfig{{ Workflow: parsed, File: workflow.Name, @@ -267,7 +268,7 @@ func (b *StepBuilder) toInternalRepresentation(parsed *yaml_types.Workflow, envi compiler.WithEnviron(environ), compiler.WithEnviron(b.Envs), // TODO: server deps should be moved into StepBuilder fields and set on StepBuilder creation - compiler.WithEscalated(server.Config.Pipeline.Privileged...), + compiler.WithEscalated(server.Config.Pipeline.PrivilegedPlugins...), compiler.WithResourceLimit(server.Config.Pipeline.Limits.MemSwapLimit, server.Config.Pipeline.Limits.MemLimit, server.Config.Pipeline.Limits.ShmSize, server.Config.Pipeline.Limits.CPUQuota, server.Config.Pipeline.Limits.CPUShares, server.Config.Pipeline.Limits.CPUSet), compiler.WithVolumes(server.Config.Pipeline.Volumes...), compiler.WithNetworks(server.Config.Pipeline.Networks...), diff --git a/shared/constant/constant.go b/shared/constant/constant.go index d4984725a..fc6bb40ee 100644 --- a/shared/constant/constant.go +++ b/shared/constant/constant.go @@ -16,10 +16,7 @@ package constant // PrivilegedPlugins can be changed by 'WOODPECKER_ESCALATE' at runtime. var PrivilegedPlugins = []string{ - "plugins/docker", - "plugins/gcr", - "plugins/ecr", - "woodpeckerci/plugin-docker-buildx", + "docker.io/woodpeckerci/plugin-docker-buildx", "codeberg.org/woodpecker-plugins/docker-buildx", }