mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-19 00:11:16 +00:00
Merge pull request #2054 from bradrydzewski/feature/visibility
Add visibility field for access control
This commit is contained in:
commit
2341e09def
11 changed files with 135 additions and 71 deletions
|
@ -25,3 +25,9 @@ const (
|
||||||
RepoFossil = "fossil"
|
RepoFossil = "fossil"
|
||||||
RepoPerforce = "perforce"
|
RepoPerforce = "perforce"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
VisibilityPublic = "public"
|
||||||
|
VisibilityPrivate = "private"
|
||||||
|
VisibilityInternal = "internal"
|
||||||
|
)
|
||||||
|
|
|
@ -22,6 +22,7 @@ type Repo struct {
|
||||||
Clone string `json:"clone_url,omitempty" meddler:"repo_clone"`
|
Clone string `json:"clone_url,omitempty" meddler:"repo_clone"`
|
||||||
Branch string `json:"default_branch,omitempty" meddler:"repo_branch"`
|
Branch string `json:"default_branch,omitempty" meddler:"repo_branch"`
|
||||||
Timeout int64 `json:"timeout,omitempty" meddler:"repo_timeout"`
|
Timeout int64 `json:"timeout,omitempty" meddler:"repo_timeout"`
|
||||||
|
Visibility string `json:"visibility" meddler:"repo_visibility"`
|
||||||
IsPrivate bool `json:"private,omitempty" meddler:"repo_private"`
|
IsPrivate bool `json:"private,omitempty" meddler:"repo_private"`
|
||||||
IsTrusted bool `json:"trusted" meddler:"repo_trusted"`
|
IsTrusted bool `json:"trusted" meddler:"repo_trusted"`
|
||||||
IsStarred bool `json:"starred,omitempty" meddler:"-"`
|
IsStarred bool `json:"starred,omitempty" meddler:"-"`
|
||||||
|
@ -40,6 +41,7 @@ type RepoPatch struct {
|
||||||
IsTrusted *bool `json:"trusted,omitempty"`
|
IsTrusted *bool `json:"trusted,omitempty"`
|
||||||
IsGated *bool `json:"gated,omitempty"`
|
IsGated *bool `json:"gated,omitempty"`
|
||||||
Timeout *int64 `json:"timeout,omitempty"`
|
Timeout *int64 `json:"timeout,omitempty"`
|
||||||
|
Visibility *string `json:"visibility,omitempty"`
|
||||||
AllowPull *bool `json:"allow_pr,omitempty"`
|
AllowPull *bool `json:"allow_pr,omitempty"`
|
||||||
AllowPush *bool `json:"allow_push,omitempty"`
|
AllowPush *bool `json:"allow_push,omitempty"`
|
||||||
AllowDeploy *bool `json:"allow_deploy,omitempty"`
|
AllowDeploy *bool `json:"allow_deploy,omitempty"`
|
||||||
|
|
|
@ -2,7 +2,6 @@ package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/drone/drone/cache"
|
"github.com/drone/drone/cache"
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
|
@ -79,7 +78,6 @@ func Perm(c *gin.Context) *model.Perm {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetPerm() gin.HandlerFunc {
|
func SetPerm() gin.HandlerFunc {
|
||||||
PUBLIC_MODE := os.Getenv("PUBLIC_MODE")
|
|
||||||
|
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
user := User(c)
|
user := User(c)
|
||||||
|
@ -87,49 +85,24 @@ func SetPerm() gin.HandlerFunc {
|
||||||
perm := &model.Perm{}
|
perm := &model.Perm{}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// if the user is not authenticated, and the
|
case user != nil && user.Admin:
|
||||||
// repository is private, the user has NO permission
|
|
||||||
// to view the repository.
|
|
||||||
case user == nil && repo.IsPrivate == true:
|
|
||||||
perm.Pull = false
|
|
||||||
perm.Push = false
|
|
||||||
perm.Admin = false
|
|
||||||
|
|
||||||
// if the user is not authenticated, but the repository
|
|
||||||
// is public, the user has pull-rights only.
|
|
||||||
case user == nil && repo.IsPrivate == false:
|
|
||||||
perm.Pull = true
|
|
||||||
perm.Push = false
|
|
||||||
perm.Admin = false
|
|
||||||
|
|
||||||
case user.Admin:
|
|
||||||
perm.Pull = true
|
perm.Pull = true
|
||||||
perm.Push = true
|
perm.Push = true
|
||||||
perm.Admin = true
|
perm.Admin = true
|
||||||
|
|
||||||
// otherwise if the user is authenticated we should
|
case user != nil:
|
||||||
// check the remote system to get the users permissiosn.
|
|
||||||
default:
|
|
||||||
var err error
|
var err error
|
||||||
perm, err = cache.GetPerms(c, user, repo.Owner, repo.Name)
|
perm, err = cache.GetPerms(c, user, repo.Owner, repo.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
perm.Pull = false
|
|
||||||
perm.Push = false
|
|
||||||
perm.Admin = false
|
|
||||||
|
|
||||||
// debug
|
|
||||||
log.Errorf("Error fetching permission for %s %s",
|
log.Errorf("Error fetching permission for %s %s",
|
||||||
user.Login, repo.FullName)
|
user.Login, repo.FullName)
|
||||||
}
|
}
|
||||||
// if we couldn't fetch permissions, but the repository
|
|
||||||
// is public, we should grant the user pull access.
|
|
||||||
if err != nil && repo.IsPrivate == false {
|
|
||||||
perm.Pull = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// all build logs are visible in public mode
|
switch {
|
||||||
if PUBLIC_MODE != "" {
|
case repo.Visibility == model.VisibilityPublic:
|
||||||
|
perm.Pull = true
|
||||||
|
case repo.Visibility == model.VisibilityInternal && user != nil:
|
||||||
perm.Pull = true
|
perm.Pull = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,9 @@
|
||||||
package session
|
package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
|
||||||
"github.com/franela/goblin"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetPerm(t *testing.T) {
|
func TestSetPerm(t *testing.T) {
|
||||||
g := goblin.Goblin(t)
|
|
||||||
g.Describe("SetPerm", func() {
|
|
||||||
g.BeforeEach(func() {
|
|
||||||
os.Unsetenv("PUBLIC_MODE")
|
|
||||||
})
|
|
||||||
g.It("Should set pull to false (private repo, user not logged in)", func() {
|
|
||||||
c := gin.Context{}
|
|
||||||
c.Set("repo", &model.Repo{
|
|
||||||
IsPrivate: true,
|
|
||||||
})
|
|
||||||
SetPerm()(&c)
|
|
||||||
v, ok := c.Get("perm")
|
|
||||||
g.Assert(ok).IsTrue("perm was not set")
|
|
||||||
p, ok := v.(*model.Perm)
|
|
||||||
g.Assert(ok).IsTrue("perm was the wrong type")
|
|
||||||
g.Assert(p.Pull).IsFalse("pull should be false")
|
|
||||||
})
|
|
||||||
g.It("Should set pull to true (private repo, user not logged in, public mode)", func() {
|
|
||||||
os.Setenv("PUBLIC_MODE", "true")
|
|
||||||
c := gin.Context{}
|
|
||||||
c.Set("repo", &model.Repo{
|
|
||||||
IsPrivate: true,
|
|
||||||
})
|
|
||||||
SetPerm()(&c)
|
|
||||||
v, ok := c.Get("perm")
|
|
||||||
g.Assert(ok).IsTrue("perm was not set")
|
|
||||||
p, ok := v.(*model.Perm)
|
|
||||||
g.Assert(ok).IsTrue("perm was the wrong type")
|
|
||||||
g.Assert(p.Pull).IsTrue("pull should be true")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,11 +55,15 @@ func PostRepo(c *gin.Context) {
|
||||||
r.UserID = user.ID
|
r.UserID = user.ID
|
||||||
r.AllowPush = true
|
r.AllowPush = true
|
||||||
r.AllowPull = true
|
r.AllowPull = true
|
||||||
|
r.Visibility = model.VisibilityPublic
|
||||||
r.Config = ".drone.yml"
|
r.Config = ".drone.yml"
|
||||||
r.Timeout = 60 // 1 hour default build time
|
r.Timeout = 60 // 1 hour default build time
|
||||||
r.Hash = base32.StdEncoding.EncodeToString(
|
r.Hash = base32.StdEncoding.EncodeToString(
|
||||||
securecookie.GenerateRandomKey(32),
|
securecookie.GenerateRandomKey(32),
|
||||||
)
|
)
|
||||||
|
if r.IsPrivate {
|
||||||
|
r.Visibility = model.VisibilityPrivate
|
||||||
|
}
|
||||||
|
|
||||||
// crates the jwt token used to verify the repository
|
// crates the jwt token used to verify the repository
|
||||||
t := token.New(token.HookToken, r.FullName)
|
t := token.New(token.HookToken, r.FullName)
|
||||||
|
@ -132,6 +136,15 @@ func PatchRepo(c *gin.Context) {
|
||||||
if in.Config != nil {
|
if in.Config != nil {
|
||||||
repo.Config = *in.Config
|
repo.Config = *in.Config
|
||||||
}
|
}
|
||||||
|
if in.Visibility != nil {
|
||||||
|
switch *in.Visibility {
|
||||||
|
case model.VisibilityInternal, model.VisibilityPrivate, model.VisibilityPublic:
|
||||||
|
repo.Visibility = *in.Visibility
|
||||||
|
default:
|
||||||
|
c.String(400, "Invalid visibility type")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := store.UpdateRepo(c, repo)
|
err := store.UpdateRepo(c, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -88,6 +88,14 @@ var migrations = []struct {
|
||||||
name: "create-index-sender-repos",
|
name: "create-index-sender-repos",
|
||||||
stmt: createIndexSenderRepos,
|
stmt: createIndexSenderRepos,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "alter-table-add-repo-visibility",
|
||||||
|
stmt: alterTableAddRepoVisibility,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update-table-set-repo-visibility",
|
||||||
|
stmt: updateTableSetRepoVisibility,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate performs the database migration. If the migration fails
|
// Migrate performs the database migration. If the migration fails
|
||||||
|
@ -442,3 +450,19 @@ CREATE TABLE IF NOT EXISTS senders (
|
||||||
var createIndexSenderRepos = `
|
var createIndexSenderRepos = `
|
||||||
CREATE INDEX sender_repo_ix ON senders (sender_repo_id);
|
CREATE INDEX sender_repo_ix ON senders (sender_repo_id);
|
||||||
`
|
`
|
||||||
|
|
||||||
|
//
|
||||||
|
// 013_add_column_repo_visibility.sql
|
||||||
|
//
|
||||||
|
|
||||||
|
var alterTableAddRepoVisibility = `
|
||||||
|
ALTER TABLE repos ADD COLUMN repo_visibility VARCHAR(50)
|
||||||
|
`
|
||||||
|
|
||||||
|
var updateTableSetRepoVisibility = `
|
||||||
|
UPDATE repos
|
||||||
|
SET repo_visibility = CASE
|
||||||
|
WHEN repo_private = 0 THEN 'public'
|
||||||
|
ELSE 'private'
|
||||||
|
END
|
||||||
|
`
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
-- name: alter-table-add-repo-visibility
|
||||||
|
|
||||||
|
ALTER TABLE repos ADD COLUMN repo_visibility VARCHAR(50)
|
||||||
|
|
||||||
|
-- name: update-table-set-repo-visibility
|
||||||
|
|
||||||
|
UPDATE repos
|
||||||
|
SET repo_visibility = CASE
|
||||||
|
WHEN repo_private = 0 THEN 'public'
|
||||||
|
ELSE 'private'
|
||||||
|
END
|
|
@ -88,6 +88,14 @@ var migrations = []struct {
|
||||||
name: "create-index-sender-repos",
|
name: "create-index-sender-repos",
|
||||||
stmt: createIndexSenderRepos,
|
stmt: createIndexSenderRepos,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "alter-table-add-repo-visibility",
|
||||||
|
stmt: alterTableAddRepoVisibility,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update-table-set-repo-visibility",
|
||||||
|
stmt: updateTableSetRepoVisibility,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate performs the database migration. If the migration fails
|
// Migrate performs the database migration. If the migration fails
|
||||||
|
@ -150,7 +158,7 @@ func selectCompleted(db *sql.DB) (map[string]struct{}, error) {
|
||||||
|
|
||||||
var migrationTableCreate = `
|
var migrationTableCreate = `
|
||||||
CREATE TABLE IF NOT EXISTS migrations (
|
CREATE TABLE IF NOT EXISTS migrations (
|
||||||
name VARCHAR(512)
|
name VARCHAR(255)
|
||||||
,UNIQUE(name)
|
,UNIQUE(name)
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
@ -442,3 +450,19 @@ CREATE TABLE IF NOT EXISTS senders (
|
||||||
var createIndexSenderRepos = `
|
var createIndexSenderRepos = `
|
||||||
CREATE INDEX IF NOT EXISTS sender_repo_ix ON senders (sender_repo_id);
|
CREATE INDEX IF NOT EXISTS sender_repo_ix ON senders (sender_repo_id);
|
||||||
`
|
`
|
||||||
|
|
||||||
|
//
|
||||||
|
// 013_add_column_repo_visibility.sql
|
||||||
|
//
|
||||||
|
|
||||||
|
var alterTableAddRepoVisibility = `
|
||||||
|
ALTER TABLE repos ADD COLUMN repo_visibility VARCHAR(50)
|
||||||
|
`
|
||||||
|
|
||||||
|
var updateTableSetRepoVisibility = `
|
||||||
|
UPDATE repos
|
||||||
|
SET repo_visibility = (CASE
|
||||||
|
WHEN repo_private = true THEN 'public'
|
||||||
|
ELSE 'private'
|
||||||
|
END)
|
||||||
|
`
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
-- name: alter-table-add-repo-visibility
|
||||||
|
|
||||||
|
ALTER TABLE repos ADD COLUMN repo_visibility VARCHAR(50)
|
||||||
|
|
||||||
|
-- name: update-table-set-repo-visibility
|
||||||
|
|
||||||
|
UPDATE repos
|
||||||
|
SET repo_visibility = (CASE
|
||||||
|
WHEN repo_private = true THEN 'public'
|
||||||
|
ELSE 'private'
|
||||||
|
END)
|
|
@ -92,6 +92,14 @@ var migrations = []struct {
|
||||||
name: "create-index-sender-repos",
|
name: "create-index-sender-repos",
|
||||||
stmt: createIndexSenderRepos,
|
stmt: createIndexSenderRepos,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "alter-table-add-repo-visibility",
|
||||||
|
stmt: alterTableAddRepoVisibility,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update-table-set-repo-visibility",
|
||||||
|
stmt: updateTableSetRepoVisibility,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate performs the database migration. If the migration fails
|
// Migrate performs the database migration. If the migration fails
|
||||||
|
@ -154,7 +162,7 @@ func selectCompleted(db *sql.DB) (map[string]struct{}, error) {
|
||||||
|
|
||||||
var migrationTableCreate = `
|
var migrationTableCreate = `
|
||||||
CREATE TABLE IF NOT EXISTS migrations (
|
CREATE TABLE IF NOT EXISTS migrations (
|
||||||
name VARCHAR(512)
|
name VARCHAR(255)
|
||||||
,UNIQUE(name)
|
,UNIQUE(name)
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
@ -443,3 +451,19 @@ CREATE TABLE IF NOT EXISTS senders (
|
||||||
var createIndexSenderRepos = `
|
var createIndexSenderRepos = `
|
||||||
CREATE INDEX IF NOT EXISTS sender_repo_ix ON senders (sender_repo_id);
|
CREATE INDEX IF NOT EXISTS sender_repo_ix ON senders (sender_repo_id);
|
||||||
`
|
`
|
||||||
|
|
||||||
|
//
|
||||||
|
// 013_add_column_repo_visibility.sql
|
||||||
|
//
|
||||||
|
|
||||||
|
var alterTableAddRepoVisibility = `
|
||||||
|
ALTER TABLE repos ADD COLUMN repo_visibility TEXT
|
||||||
|
`
|
||||||
|
|
||||||
|
var updateTableSetRepoVisibility = `
|
||||||
|
UPDATE repos
|
||||||
|
SET repo_visibility = CASE
|
||||||
|
WHEN repo_private = 0 THEN 'public'
|
||||||
|
ELSE 'private'
|
||||||
|
END
|
||||||
|
`
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
-- name: alter-table-add-repo-visibility
|
||||||
|
|
||||||
|
ALTER TABLE repos ADD COLUMN repo_visibility TEXT
|
||||||
|
|
||||||
|
-- name: update-table-set-repo-visibility
|
||||||
|
|
||||||
|
UPDATE repos
|
||||||
|
SET repo_visibility = CASE
|
||||||
|
WHEN repo_private = 0 THEN 'public'
|
||||||
|
ELSE 'private'
|
||||||
|
END
|
Loading…
Reference in a new issue