-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Add tag protection #15629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Add tag protection #15629
Changes from 26 commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
98c8760
Added tag protection in hook.
KN4CK3R 4718c2a
Prevent UI tag creation if protected.
KN4CK3R 911fec6
Added settings page.
KN4CK3R e20ddac
Added tests.
KN4CK3R 751c13b
Added suggestions.
KN4CK3R 932a677
Renamed file.
KN4CK3R 922cab1
Added suggestions.
KN4CK3R 15ac4b4
Moved tests.
KN4CK3R 2943590
Merge branch 'master' of https://github.com/go-gitea/gitea into featu…
KN4CK3R afc7673
Use individual errors.
KN4CK3R 3ee5427
Removed unneeded methods.
KN4CK3R dfbff8c
Switched delete selector.
KN4CK3R 46d4e29
Changed method names.
KN4CK3R 784b16b
Changed url.
KN4CK3R 2324fa8
Removed fix.
KN4CK3R 3c4d57c
No reason to be unique.
KN4CK3R 739939b
Allow editing of protected tags.
KN4CK3R a4d0953
Merge branch 'master' of https://github.com/go-gitea/gitea into featu…
KN4CK3R e5a6804
lint
KN4CK3R 0540877
Merge branch 'master' into feature-tag-protection
zeripath f3a4d02
Removed unique key from migration.
KN4CK3R 7080e28
Apply suggestion.
KN4CK3R 970a19b
Fixed comment.
KN4CK3R 9120297
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R 7466925
Get tag by id.
KN4CK3R a5ecd2c
Added docs page.
KN4CK3R d814f02
Changed date.
KN4CK3R 7cbbe4e
Respond with 404 to not found tags.
KN4CK3R deebd92
Handle id = 0.
KN4CK3R 4b94720
Lint
KN4CK3R ddf3ece
Replaced glob with regex pattern.
KN4CK3R 6c4be57
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R 3063811
Added support for glob and regex pattern.
KN4CK3R b707196
Updated documentation.
KN4CK3R 6c1c35f
Added suggestions.
KN4CK3R 16a360e
Fixed tests.
KN4CK3R b59f11b
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R b8441e7
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R 46eb17e
Changed white* to allow*.
KN4CK3R 5e0b73e
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R b584cd9
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R b70268f
Fixed edit button link.
KN4CK3R bdabf96
Added cancel button.
KN4CK3R 54917a2
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R 34280e8
Merge branch 'main' into feature-tag-protection
zeripath 2b42948
Merge branch 'main' into feature-tag-protection
lunny 6e768b0
Merge branch 'main' into feature-tag-protection
6543 384f27f
Merge branch 'main' into feature-tag-protection
zeripath 1e413e5
Fixed binding name.
KN4CK3R 9694fca
Merge branch 'main' into feature-tag-protection
6543 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
--- | ||
date: "2019-09-06T01:35:00-03:00" | ||
title: "Protected tags" | ||
slug: "protected-tags" | ||
weight: 45 | ||
toc: false | ||
draft: false | ||
menu: | ||
sidebar: | ||
parent: "advanced" | ||
name: "Protected tags" | ||
weight: 45 | ||
identifier: "protected-tags" | ||
--- | ||
|
||
# Protected tags | ||
|
||
Protected tags allow control over who has permission to create or update git tags. Each rule allows you to match either an individual tag name, or use wildcards to control multiple tags at once. | ||
|
||
**Table of Contents** | ||
|
||
{{< toc >}} | ||
|
||
## Setting up protected tags | ||
|
||
To protect a tag, you need to follow these steps: | ||
|
||
1. Go to the repository’s **Settings** > **Tags** page. | ||
2. Type the name of specific tag or use a pattern to match multiple tags at once. | ||
3. Choose the allowed users and/or teams. If you leave these fields empty noone is allowed to create or modify this tag. | ||
4. Select **Save** to save the configuration. | ||
|
||
## Wildcard protected tags | ||
|
||
You can specify a wildcard protected tag, which protects all tags matching the wildcard. For example: | ||
|
||
| Wildcard Protected Tag | Matching Tags | | ||
| ---------------------- | --------------------------------------- | | ||
| `v*` | `v`, `v-1`, `version2` | | ||
| `v[0-9]` | `v0`, `v1` up to `v9` | | ||
| `*-release` | `2.1-release`, `final-release` | | ||
| `*gitea*` | `gitea`, `2.1-gitea`, `1_gitea-release` | | ||
| `{v,rel}-*` | `v-`, `v-1`, `v-final`, `rel-`, `rel-x` | | ||
| `*` | matches all possible tag names | | ||
|
||
See [github.com/gobwas/glob](https://pkg.go.dev/github.com/gobwas/glob#Compile) documentation for syntax. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright 2021 The Gitea Authors. All rights reserved. | ||
// Use of this source code is governed by a MIT-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package integrations | ||
|
||
import ( | ||
"io/ioutil" | ||
"net/url" | ||
"testing" | ||
|
||
"code.gitea.io/gitea/models" | ||
"code.gitea.io/gitea/modules/git" | ||
"code.gitea.io/gitea/modules/util" | ||
"code.gitea.io/gitea/services/release" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestCreateNewTagProtected(t *testing.T) { | ||
defer prepareTestEnv(t)() | ||
|
||
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) | ||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User) | ||
|
||
t.Run("API", func(t *testing.T) { | ||
defer PrintCurrentTest(t)() | ||
|
||
err := release.CreateNewTag(owner, repo, "master", "v-1", "first tag") | ||
assert.NoError(t, err) | ||
|
||
err = models.InsertProtectedTag(&models.ProtectedTag{ | ||
RepoID: repo.ID, | ||
NamePattern: "v-*", | ||
}) | ||
assert.NoError(t, err) | ||
err = models.InsertProtectedTag(&models.ProtectedTag{ | ||
RepoID: repo.ID, | ||
NamePattern: "v-1.1", | ||
WhitelistUserIDs: []int64{repo.OwnerID}, | ||
}) | ||
assert.NoError(t, err) | ||
|
||
err = release.CreateNewTag(owner, repo, "master", "v-2", "second tag") | ||
assert.Error(t, err) | ||
assert.True(t, models.IsErrProtectedTagName(err)) | ||
|
||
err = release.CreateNewTag(owner, repo, "master", "v-1.1", "third tag") | ||
assert.NoError(t, err) | ||
}) | ||
|
||
t.Run("Git", func(t *testing.T) { | ||
onGiteaRun(t, func(t *testing.T, u *url.URL) { | ||
username := "user2" | ||
httpContext := NewAPITestContext(t, username, "repo1") | ||
|
||
dstPath, err := ioutil.TempDir("", httpContext.Reponame) | ||
assert.NoError(t, err) | ||
defer util.RemoveAll(dstPath) | ||
|
||
u.Path = httpContext.GitPath() | ||
u.User = url.UserPassword(username, userPassword) | ||
|
||
doGitClone(dstPath, u)(t) | ||
|
||
_, err = git.NewCommand("tag", "v-2").RunInDir(dstPath) | ||
assert.NoError(t, err) | ||
|
||
_, err = git.NewCommand("push", "--tags").RunInDir(dstPath) | ||
assert.Error(t, err) | ||
assert.Contains(t, err.Error(), "Tag v-2 is protected") | ||
}) | ||
}) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright 2021 The Gitea Authors. All rights reserved. | ||
// Use of this source code is governed by a MIT-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package migrations | ||
|
||
import ( | ||
"code.gitea.io/gitea/modules/timeutil" | ||
|
||
"xorm.io/xorm" | ||
) | ||
|
||
func createProtectedTagTable(x *xorm.Engine) error { | ||
type ProtectedTag struct { | ||
ID int64 `xorm:"pk autoincr"` | ||
RepoID int64 | ||
NamePattern string | ||
WhitelistUserIDs []int64 `xorm:"JSON TEXT"` | ||
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | ||
|
||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | ||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | ||
} | ||
|
||
return x.Sync2(new(ProtectedTag)) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright 2021 The Gitea Authors. All rights reserved. | ||
// Use of this source code is governed by a MIT-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package models | ||
|
||
import ( | ||
"strings" | ||
|
||
"code.gitea.io/gitea/modules/base" | ||
"code.gitea.io/gitea/modules/timeutil" | ||
|
||
"github.com/gobwas/glob" | ||
) | ||
|
||
// ProtectedTag struct | ||
type ProtectedTag struct { | ||
ID int64 `xorm:"pk autoincr"` | ||
RepoID int64 | ||
NamePattern string | ||
KN4CK3R marked this conversation as resolved.
Show resolved
Hide resolved
|
||
NameGlob glob.Glob `xorm:"-"` | ||
WhitelistUserIDs []int64 `xorm:"JSON TEXT"` | ||
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | ||
|
||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | ||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | ||
} | ||
|
||
// InsertProtectedTag inserts a protected tag to database | ||
func InsertProtectedTag(pt *ProtectedTag) error { | ||
_, err := x.Insert(pt) | ||
return err | ||
} | ||
|
||
// UpdateProtectedTag updates the protected tag | ||
func UpdateProtectedTag(pt *ProtectedTag) error { | ||
_, err := x.ID(pt.ID).AllCols().Update(pt) | ||
return err | ||
} | ||
|
||
// DeleteProtectedTag deletes a protected tag by ID | ||
func DeleteProtectedTag(pt *ProtectedTag) error { | ||
_, err := x.ID(pt.ID).Delete(&ProtectedTag{}) | ||
return err | ||
} | ||
|
||
// EnsureCompiledPattern ensures the glob pattern is compiled | ||
func (pt *ProtectedTag) EnsureCompiledPattern() error { | ||
if pt.NameGlob != nil { | ||
return nil | ||
} | ||
|
||
var err error | ||
pt.NameGlob, err = glob.Compile(strings.TrimSpace(pt.NamePattern)) | ||
return err | ||
} | ||
|
||
// IsUserAllowed returns true if the user is allowed to modify the tag | ||
func (pt *ProtectedTag) IsUserAllowed(userID int64) (bool, error) { | ||
if base.Int64sContains(pt.WhitelistUserIDs, userID) { | ||
return true, nil | ||
} | ||
|
||
if len(pt.WhitelistTeamIDs) == 0 { | ||
return false, nil | ||
} | ||
|
||
in, err := IsUserInTeams(userID, pt.WhitelistTeamIDs) | ||
if err != nil { | ||
return false, err | ||
} | ||
return in, nil | ||
} | ||
|
||
// GetProtectedTags gets all protected tags of the repository | ||
func (repo *Repository) GetProtectedTags() ([]*ProtectedTag, error) { | ||
tags := make([]*ProtectedTag, 0) | ||
return tags, x.Find(&tags, &ProtectedTag{RepoID: repo.ID}) | ||
} | ||
|
||
// GetProtectedTagByID gets the protected tag with the specific id | ||
func GetProtectedTagByID(id int64) (*ProtectedTag, error) { | ||
tag := &ProtectedTag{ID: id} | ||
KN4CK3R marked this conversation as resolved.
Show resolved
Hide resolved
|
||
has, err := x.Get(tag) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if !has { | ||
return nil, nil | ||
} | ||
return tag, nil | ||
} | ||
|
||
// IsUserAllowedToControlTag checks if a user can control the specific tag. | ||
// It returns true if the tag name is not protected or the user is allowed to control it. | ||
func IsUserAllowedToControlTag(tags []*ProtectedTag, tagName string, userID int64) (bool, error) { | ||
isAllowed := true | ||
for _, tag := range tags { | ||
err := tag.EnsureCompiledPattern() | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
if !tag.NameGlob.Match(tagName) { | ||
continue | ||
} | ||
|
||
isAllowed, err = tag.IsUserAllowed(userID) | ||
if err != nil { | ||
return false, err | ||
} | ||
if isAllowed { | ||
break | ||
} | ||
} | ||
|
||
return isAllowed, nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.