From 5bb7cef08b47352bf245e950d0a6bca3cd5d4ee2 Mon Sep 17 00:00:00 2001 From: qwerty287 <80460567+qwerty287@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:27:05 +0200 Subject: [PATCH] Allow to set custom trusted clone plugins (#4352) Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: Thomas Anderson <127358482+zc-devs@users.noreply.github.com> Co-authored-by: Anbraten <6918444+anbraten@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- cmd/server/openapi/docs.go | 14 +++++-- docs/docs/20-usage/75-project-settings.md | 9 ++-- pipeline/frontend/yaml/compiler/compiler.go | 5 +-- pipeline/frontend/yaml/compiler/option.go | 7 ---- server/api/repo.go | 5 +-- server/model/repo.go | 4 +- server/pipeline/stepbuilder/stepBuilder.go | 3 +- .../020_remove_repo_netrc_only_trusted.go | 36 ++++++++++++++++ server/store/datastore/migration/migration.go | 1 + web/src/assets/locales/en.json | 4 +- web/src/lib/api/types/repo.ts | 4 +- web/src/views/repo/settings/General.vue | 42 ++++++++++++++++--- 12 files changed, 97 insertions(+), 37 deletions(-) create mode 100644 server/store/datastore/migration/020_remove_repo_netrc_only_trusted.go diff --git a/cmd/server/openapi/docs.go b/cmd/server/openapi/docs.go index 645933163..ba2940d67 100644 --- a/cmd/server/openapi/docs.go +++ b/cmd/server/openapi/docs.go @@ -5070,8 +5070,11 @@ const docTemplate = `{ "name": { "type": "string" }, - "netrc_only_trusted": { - "type": "boolean" + "netrc_trusted": { + "type": "array", + "items": { + "type": "string" + } }, "org_id": { "type": "integer" @@ -5124,8 +5127,11 @@ const docTemplate = `{ "description": "TODO: deprecated in favor of RequireApproval =\u003e Remove in next major release", "type": "boolean" }, - "netrc_only_trusted": { - "type": "boolean" + "netrc_trusted": { + "type": "array", + "items": { + "type": "string" + } }, "require_approval": { "type": "string" diff --git a/docs/docs/20-usage/75-project-settings.md b/docs/docs/20-usage/75-project-settings.md index c15bba2ec..b87b3011d 100644 --- a/docs/docs/20-usage/75-project-settings.md +++ b/docs/docs/20-usage/75-project-settings.md @@ -39,16 +39,13 @@ Only server admins can set this option. If you are not a server admin this optio ::: -## Only inject Git credentials into trusted clone plugins +## Custom trusted clone plugins The clone step may require Git credentials (e.g. for private repos) which are injected via `netrc`. -By default, they are only injected into trusted clone plugins listed in the env var `WOODPECKER_PLUGINS_TRUSTED_CLONE`. -If this option is disabled, the Git credentials are injected into every clone plugin, regardless of whether it is trusted or not. +They are only injected into trusted plugins listed in the env var `WOODPECKER_PLUGINS_TRUSTED_CLONE` or in this repo setting. -:::note -This option has no effect on steps other than the clone step. -::: +This allows you to use a trusted plugin for in the clone section or as a step to pull or push using your git credentials. ## Project visibility diff --git a/pipeline/frontend/yaml/compiler/compiler.go b/pipeline/frontend/yaml/compiler/compiler.go index be2b59cbc..a4c394e92 100644 --- a/pipeline/frontend/yaml/compiler/compiler.go +++ b/pipeline/frontend/yaml/compiler/compiler.go @@ -98,7 +98,6 @@ type Compiler struct { defaultClonePlugin string trustedClonePlugins []string securityTrustedPipeline bool - netrcOnlyTrusted bool } // New creates a new Compiler with options. @@ -196,7 +195,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er } // only inject netrc if it's a trusted repo or a trusted plugin - if !c.netrcOnlyTrusted || c.securityTrustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) { + if c.securityTrustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) { for k, v := range c.cloneEnv { step.Environment[k] = v } @@ -252,7 +251,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er return nil, err } - // inject netrc if it's a trusted repo or a trusted clone-plugin + // only inject netrc if it's a trusted repo or a trusted plugin if c.securityTrustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) { for k, v := range c.cloneEnv { step.Environment[k] = v diff --git a/pipeline/frontend/yaml/compiler/option.go b/pipeline/frontend/yaml/compiler/option.go index 3787bbd82..77e24c4ce 100644 --- a/pipeline/frontend/yaml/compiler/option.go +++ b/pipeline/frontend/yaml/compiler/option.go @@ -176,13 +176,6 @@ func WithTrustedSecurity(trusted bool) Option { } } -// WithNetrcOnlyTrusted configures the compiler with the netrcOnlyTrusted repo option. -func WithNetrcOnlyTrusted(only bool) Option { - return func(compiler *Compiler) { - compiler.netrcOnlyTrusted = only - } -} - type ProxyOptions struct { NoProxy string HTTPProxy string diff --git a/server/api/repo.go b/server/api/repo.go index 10388edc4..4072dcb45 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -94,7 +94,6 @@ func PostRepo(c *gin.Context) { repo.RequireApproval = model.RequireApprovalForks repo.AllowPull = true repo.AllowDeploy = false - repo.NetrcOnlyTrusted = true repo.CancelPreviousPipelineEvents = server.Config.Pipeline.DefaultCancelPreviousPipelineEvents } repo.IsActive = true @@ -275,8 +274,8 @@ func PatchRepo(c *gin.Context) { if in.CancelPreviousPipelineEvents != nil { repo.CancelPreviousPipelineEvents = *in.CancelPreviousPipelineEvents } - if in.NetrcOnlyTrusted != nil { - repo.NetrcOnlyTrusted = *in.NetrcOnlyTrusted + if in.NetrcTrusted != nil { + repo.NetrcTrustedPlugins = *in.NetrcTrusted } if in.Visibility != nil { switch *in.Visibility { diff --git a/server/model/repo.go b/server/model/repo.go index d12966679..b833ce407 100644 --- a/server/model/repo.go +++ b/server/model/repo.go @@ -71,7 +71,7 @@ type Repo struct { Hash string `json:"-" xorm:"varchar(500) 'hash'"` Perm *Perm `json:"-" xorm:"-"` CancelPreviousPipelineEvents []WebhookEvent `json:"cancel_previous_pipeline_events" xorm:"json 'cancel_previous_pipeline_events'"` - NetrcOnlyTrusted bool `json:"netrc_only_trusted" xorm:"NOT NULL DEFAULT true 'netrc_only_trusted'"` + NetrcTrustedPlugins []string `json:"netrc_trusted" xorm:"json 'netrc_trusted'"` } // @name Repo // TableName return database table name for xorm. @@ -137,7 +137,7 @@ type RepoPatch struct { AllowPull *bool `json:"allow_pr,omitempty"` AllowDeploy *bool `json:"allow_deploy,omitempty"` CancelPreviousPipelineEvents *[]WebhookEvent `json:"cancel_previous_pipeline_events"` - NetrcOnlyTrusted *bool `json:"netrc_only_trusted"` + NetrcTrusted *[]string `json:"netrc_trusted"` Trusted *TrustedConfigurationPatch `json:"trusted"` } // @name RepoPatch diff --git a/server/pipeline/stepbuilder/stepBuilder.go b/server/pipeline/stepbuilder/stepBuilder.go index c628fe83c..8145bf9e4 100644 --- a/server/pipeline/stepbuilder/stepBuilder.go +++ b/server/pipeline/stepbuilder/stepBuilder.go @@ -290,7 +290,7 @@ func (b *StepBuilder) toInternalRepresentation(parsed *yaml_types.Workflow, envi b.Repo.IsSCMPrivate || server.Config.Pipeline.AuthenticatePublicRepos, ), compiler.WithDefaultClonePlugin(server.Config.Pipeline.DefaultClonePlugin), - compiler.WithTrustedClonePlugins(server.Config.Pipeline.TrustedClonePlugins), + compiler.WithTrustedClonePlugins(append(b.Repo.NetrcTrustedPlugins, server.Config.Pipeline.TrustedClonePlugins...)), compiler.WithRegistry(registries...), compiler.WithSecret(secrets...), compiler.WithPrefix( @@ -304,7 +304,6 @@ func (b *StepBuilder) toInternalRepresentation(parsed *yaml_types.Workflow, envi compiler.WithWorkspaceFromURL(compiler.DefaultWorkspaceBase, b.Repo.ForgeURL), compiler.WithMetadata(metadata), compiler.WithTrustedSecurity(b.Repo.Trusted.Security), - compiler.WithNetrcOnlyTrusted(b.Repo.NetrcOnlyTrusted), ).Compile(parsed) } diff --git a/server/store/datastore/migration/020_remove_repo_netrc_only_trusted.go b/server/store/datastore/migration/020_remove_repo_netrc_only_trusted.go new file mode 100644 index 000000000..f93c61bc5 --- /dev/null +++ b/server/store/datastore/migration/020_remove_repo_netrc_only_trusted.go @@ -0,0 +1,36 @@ +// Copyright 2024 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migration + +import ( + "src.techknowlogick.com/xormigrate" + "xorm.io/xorm" +) + +var removeRepoNetrcOnlyTrusted = xormigrate.Migration{ + ID: "remove-repo-netrc-only-trusted", + MigrateSession: func(sess *xorm.Session) (err error) { + type repos struct { + NetrcOnlyTrusted string `xorm:"netrc_only_trusted"` + } + + // ensure columns to drop exist + if err := sess.Sync(new(repos)); err != nil { + return err + } + + return dropTableColumns(sess, "repos", "netrc_only_trusted") + }, +} diff --git a/server/store/datastore/migration/migration.go b/server/store/datastore/migration/migration.go index 611beb30e..9fde10f54 100644 --- a/server/store/datastore/migration/migration.go +++ b/server/store/datastore/migration/migration.go @@ -48,6 +48,7 @@ var migrationTasks = []*xormigrate.Migration{ &splitTrusted, &correctPotentialCorruptOrgsUsersRelation, &gatedToRequireApproval, + &removeRepoNetrcOnlyTrusted, } var allBeans = []any{ diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json index 8b4624e97..cba931e00 100644 --- a/web/src/assets/locales/en.json +++ b/web/src/assets/locales/en.json @@ -104,8 +104,8 @@ "desc": "Permit 'deployment' runs for successful pipelines. All users with with push permissions can trigger these, so use with caution." }, "netrc_only_trusted": { - "netrc_only_trusted": "Only inject git credentials into trusted clone plugins", - "desc": "When enabled, git credentials are accessible only to trusted clone plugins specified in WOODPECKER_PLUGINS_TRUSTED_CLONE. Otherwise, custom clone plugins can use git credentials. This setting has no affect on non-clone steps." + "netrc_only_trusted": "Custom trusted clone plugins", + "desc": "Plugins listed here will get access to netrc credentials that can be used to clone repositories from the forge or push to it." }, "trusted": { "trusted": "Trusted", diff --git a/web/src/lib/api/types/repo.ts b/web/src/lib/api/types/repo.ts index 3062279c0..18698aaae 100644 --- a/web/src/lib/api/types/repo.ts +++ b/web/src/lib/api/types/repo.ts @@ -76,7 +76,7 @@ export interface Repo { // Events that will cancel running pipelines before starting a new one cancel_previous_pipeline_events: string[]; - netrc_only_trusted: boolean; + netrc_trusted: string[]; } /* eslint-disable no-unused-vars */ @@ -104,7 +104,7 @@ export type RepoSettings = Pick< | 'allow_pr' | 'allow_deploy' | 'cancel_previous_pipeline_events' - | 'netrc_only_trusted' + | 'netrc_trusted' >; export interface RepoPermissions { diff --git a/web/src/views/repo/settings/General.vue b/web/src/views/repo/settings/General.vue index a03cf0050..1430028d0 100644 --- a/web/src/views/repo/settings/General.vue +++ b/web/src/views/repo/settings/General.vue @@ -15,11 +15,25 @@ :label="$t('repo.settings.general.allow_deploy.allow')" :description="$t('repo.settings.general.allow_deploy.desc')" /> - + + + + {{ $t('repo.settings.general.netrc_only_trusted.desc') }} + +
+
+ +
+
+ +
+
i !== image); +}