Allow to disable deployments (#3570)

…but if they're enabled, allow for all events. Also add warning that you
should only enable it if you trust the users with push access.

closes #3559

---------

Co-authored-by: Robert Kaussow <xoxys@rknet.org>
This commit is contained in:
qwerty287 2024-04-02 22:03:37 +02:00 committed by GitHub
parent a6e054f9fe
commit eaf10611eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 42 additions and 12 deletions

View file

@ -4048,6 +4048,9 @@ const docTemplate = `{
"active": {
"type": "boolean"
},
"allow_deploy": {
"type": "boolean"
},
"allow_pr": {
"type": "boolean"
},
@ -4123,6 +4126,9 @@ const docTemplate = `{
"RepoPatch": {
"type": "object",
"properties": {
"allow_deploy": {
"type": "boolean"
},
"allow_pr": {
"type": "boolean"
},

View file

@ -16,6 +16,15 @@ Your Version-Control-System will notify Woodpecker about events via webhooks. If
Enables handling webhook's pull request event. If disabled, then pipeline won't run for pull requests.
## Allow deployments
Enables a pipeline to be started with the `deploy` event from a successful pipeline.
:::danger
Only activate this option if you trust all users who have push access to your repository.
Otherwise, these users will be able to steal secrets that are only available for `deploy` events.
:::
## Protected
Every pipeline initiated by an webhook event needs to be approved by a project members with push permissions before being executed.

View file

@ -407,23 +407,22 @@ func PostPipeline(c *gin.Context) {
refreshUserToken(c, user)
// make Deploy overridable
pl.Deploy = c.DefaultQuery("deploy_to", pl.Deploy)
// make Event overridable to deploy
// TODO refactor to use own proper API for deploy
if event, ok := c.GetQuery("event"); ok {
// only allow deploy from push, tag and release
if pl.Event != model.EventPush && pl.Event != model.EventTag && pl.Event != model.EventRelease {
_ = c.AbortWithError(http.StatusBadRequest, fmt.Errorf("can only deploy push, tag and release pipelines"))
return
}
pl.Event = model.WebhookEvent(event)
if pl.Event != model.EventDeploy {
_ = c.AbortWithError(http.StatusBadRequest, model.ErrInvalidWebhookEvent)
return
}
if !repo.AllowDeploy {
_ = c.AbortWithError(http.StatusForbidden, fmt.Errorf("repo does not allow deployments"))
return
}
pl.Deploy = c.DefaultQuery("deploy_to", pl.Deploy)
}
// Read query string parameters into pipelineParams, exclude reserved params

View file

@ -86,6 +86,7 @@ func PostRepo(c *gin.Context) {
} else {
repo = from
repo.AllowPull = true
repo.AllowDeploy = false
repo.NetrcOnlyTrusted = true
repo.CancelPreviousPipelineEvents = server.Config.Pipeline.DefaultCancelPreviousPipelineEvents
}
@ -223,6 +224,9 @@ func PatchRepo(c *gin.Context) {
if in.AllowPull != nil {
repo.AllowPull = *in.AllowPull
}
if in.AllowDeploy != nil {
repo.AllowDeploy = *in.AllowDeploy
}
if in.IsGated != nil {
repo.IsGated = *in.IsGated
}

View file

@ -44,6 +44,7 @@ type Repo struct {
IsGated bool `json:"gated" xorm:"repo_gated"`
IsActive bool `json:"active" xorm:"repo_active"`
AllowPull bool `json:"allow_pr" xorm:"repo_allow_pr"`
AllowDeploy bool `json:"allow_deploy" xorm:"repo_allow_deploy"`
Config string `json:"config_file" xorm:"varchar(500) 'repo_config_path'"`
Hash string `json:"-" xorm:"varchar(500) 'repo_hash'"`
Perm *Perm `json:"-" xorm:"-"`
@ -112,6 +113,7 @@ type RepoPatch struct {
Timeout *int64 `json:"timeout,omitempty"`
Visibility *string `json:"visibility,omitempty"`
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"`
} // @name RepoPatch

View file

@ -90,6 +90,10 @@
"allow": "Allow Pull Requests",
"desc": "Pipelines can run on pull requests."
},
"allow_deploy": {
"allow": "Allow deployments",
"desc": "Allow deployments from successful pipelines. Only use if you trust all users with push access."
},
"protected": {
"protected": "Protected",
"desc": "Every pipeline needs to be approved before being executed."

View file

@ -29,6 +29,11 @@
:label="$t('repo.settings.general.allow_pr.allow')"
:description="$t('repo.settings.general.allow_pr.desc')"
/>
<Checkbox
v-model="repoSettings.allow_deploy"
:label="$t('repo.settings.general.allow_deploy.allow')"
:description="$t('repo.settings.general.allow_deploy.desc')"
/>
<Checkbox
v-model="repoSettings.gated"
:label="$t('repo.settings.general.protected.protected')"
@ -132,6 +137,7 @@ function loadRepoSettings() {
gated: repo.value.gated,
trusted: repo.value.trusted,
allow_pr: repo.value.allow_pr,
allow_deploy: repo.value.allow_deploy,
cancel_previous_pipeline_events: repo.value.cancel_previous_pipeline_events || [],
netrc_only_trusted: repo.value.netrc_only_trusted,
};

View file

@ -56,6 +56,8 @@ export type Repo = {
// Whether pull requests should trigger a pipeline.
allow_pr: boolean;
allow_deploy: boolean;
config_file: string;
visibility: RepoVisibility;
@ -84,6 +86,7 @@ export type RepoSettings = Pick<
| 'trusted'
| 'gated'
| 'allow_pr'
| 'allow_deploy'
| 'cancel_previous_pipeline_events'
| 'netrc_only_trusted'
>;

View file

@ -45,10 +45,7 @@
@click="restartPipeline"
/>
<Button
v-if="
pipeline.status === 'success' &&
(pipeline.event === 'push' || pipeline.event === 'tag' || pipeline.event === 'release')
"
v-if="pipeline.status === 'success' && repo.allow_deploy"
class="flex-shrink-0"
:text="$t('repo.pipeline.actions.deploy')"
@click="showDeployPipelinePopup = true"