Skip to content

Commit

Permalink
persist and compare yaml for gating
Browse files Browse the repository at this point in the history
  • Loading branch information
bradrydzewski committed May 5, 2017
1 parent 1866ab3 commit 4569b60
Show file tree
Hide file tree
Showing 21 changed files with 394 additions and 35 deletions.
1 change: 1 addition & 0 deletions drone/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ func setupEvilGlobals(c *cli.Context, v store.Store) {

// storage
droneserver.Config.Storage.Files = v
droneserver.Config.Storage.Config = v

// services
droneserver.Config.Services.Queue = setupQueue(c, v)
Expand Down
1 change: 1 addition & 0 deletions model/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package model
type Build struct {
ID int64 `json:"id" meddler:"build_id,pk"`
RepoID int64 `json:"-" meddler:"build_repo_id"`
ConfigID int64 `json:"-" meddler:"build_config_id"`
Number int `json:"number" meddler:"build_number"`
Parent int `json:"parent" meddler:"build_parent"`
Event string `json:"event" meddler:"build_event"`
Expand Down
32 changes: 13 additions & 19 deletions model/config.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
package model

// Config defines system configuration parameters.
type Config struct {
Open bool // Enables open registration
Secret string // Secret token used to authenticate agents
Admins map[string]bool // Administrative users
Orgs map[string]bool // Organization whitelist
}

// IsAdmin returns true if the user is a member of the administrator list.
func (c *Config) IsAdmin(user *User) bool {
return c.Admins[user.Login]
// ConfigStore persists pipeline configuration to storage.
type ConfigStore interface {
ConfigLoad(int64) (*Config, error)
ConfigFind(*Repo, string) (*Config, error)
ConfigUpdate(*Config) error
ConfigInsert(*Config) error
}

// IsMember returns true if the user is a member of the whitelisted teams.
func (c *Config) IsMember(teams []*Team) bool {
for _, team := range teams {
if c.Orgs[team.Login] {
return true
}
}
return false
// Config represents a pipeline configuration.
type Config struct {
ID int64 `json:"-" meddler:"config_id,pk"`
RepoID int64 `json:"-" meddler:"config_repo_id"`
Data string `json:"data" meddler:"config_data"`
Hash string `json:"hash" meddler:"config_hash"`
Approved bool `json:"approved" meddler:"config_approved"`
}
1 change: 1 addition & 0 deletions model/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Repo struct {
IsTrusted bool `json:"trusted" meddler:"repo_trusted"`
IsStarred bool `json:"starred,omitempty" meddler:"-"`
IsGated bool `json:"gated" meddler:"repo_gated"`
IsGatedConf bool `json:"gated_conf" meddler:"repo_gated_conf"`
AllowPull bool `json:"allow_pr" meddler:"repo_allow_pr"`
AllowPush bool `json:"allow_push" meddler:"repo_allow_push"`
AllowDeploy bool `json:"allow_deploys" meddler:"repo_allow_deploys"`
Expand Down
24 changes: 24 additions & 0 deletions model/settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package model

// Settings defines system configuration parameters.
type Settings struct {
Open bool // Enables open registration
Secret string // Secret token used to authenticate agents
Admins map[string]bool // Administrative users
Orgs map[string]bool // Organization whitelist
}

// IsAdmin returns true if the user is a member of the administrator list.
func (c *Settings) IsAdmin(user *User) bool {
return c.Admins[user.Login]
}

// IsMember returns true if the user is a member of the whitelisted teams.
func (c *Settings) IsMember(teams []*Team) bool {
for _, team := range teams {
if c.Orgs[team.Login] {
return true
}
}
return false
}
4 changes: 2 additions & 2 deletions router/middleware/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ func Config(cli *cli.Context) gin.HandlerFunc {
}

// helper function to create the configuration from the CLI context.
func setupConfig(c *cli.Context) *model.Config {
return &model.Config{
func setupConfig(c *cli.Context) *model.Settings {
return &model.Settings{
Open: c.Bool("open"),
Secret: c.String("agent-secret"),
Admins: sliceToMap2(c.StringSlice("admin")),
Expand Down
2 changes: 1 addition & 1 deletion router/middleware/session/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func SetUser() gin.HandlerFunc {
})
if err == nil {
confv := c.MustGet("config")
if conf, ok := confv.(*model.Config); ok {
if conf, ok := confv.(*model.Settings); ok {
user.Admin = conf.IsAdmin(user)
}
c.Set("user", user)
Expand Down
16 changes: 12 additions & 4 deletions server/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,16 @@ func PostApproval(c *gin.Context) {
//

// fetch the build file from the database
raw, err := remote_.File(user, repo, build, repo.Config)
conf, err := Config.Storage.Config.ConfigLoad(build.ConfigID)
if err != nil {
logrus.Errorf("failure to get build config for %s. %s", repo.FullName, err)
c.AbortWithError(404, err)
return
}
if !conf.Approved {
conf.Approved = true
Config.Storage.Config.ConfigUpdate(conf)
}

netrc, err := remote_.Netrc(user, repo)
if err != nil {
Expand Down Expand Up @@ -222,7 +226,7 @@ func PostApproval(c *gin.Context) {
Secs: secs,
Regs: regs,
Link: httputil.GetURL(c.Request),
Yaml: string(raw),
Yaml: conf.Data,
}
items, err := b.Build()
if err != nil {
Expand Down Expand Up @@ -394,12 +398,16 @@ func PostBuild(c *gin.Context) {
}

// fetch the .drone.yml file from the database
raw, err := remote_.File(user, repo, build, repo.Config)
conf, err := Config.Storage.Config.ConfigLoad(build.ConfigID)
if err != nil {
logrus.Errorf("failure to get build config for %s. %s", repo.FullName, err)
c.AbortWithError(404, err)
return
}
if !conf.Approved {
conf.Approved = true
Config.Storage.Config.ConfigUpdate(conf)
}

netrc, err := remote_.Netrc(user, repo)
if err != nil {
Expand Down Expand Up @@ -493,7 +501,7 @@ func PostBuild(c *gin.Context) {
Secs: secs,
Regs: regs,
Link: httputil.GetURL(c.Request),
Yaml: string(raw),
Yaml: conf.Data,
}
// TODO inject environment varibles !!!!!! buildParams
items, err := b.Build()
Expand Down
42 changes: 37 additions & 5 deletions server/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package server

import (
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"regexp"
Expand Down Expand Up @@ -131,12 +132,38 @@ func PostHook(c *gin.Context) {
}

// fetch the build file from the database
raw, err := remote_.File(user, repo, build, repo.Config)
confb, err := remote_.File(user, repo, build, repo.Config)
if err != nil {
logrus.Errorf("failure to get build config for %s. %s", repo.FullName, err)
c.AbortWithError(404, err)
return
}
sha := shasum(confb)
conf, err := Config.Storage.Config.ConfigFind(repo, sha)
if err != nil {
conf = &model.Config{
RepoID: repo.ID,
Data: string(confb),
Hash: sha,
Approved: false,
}
if user.Login == repo.Owner || build.Event != model.EventPull {
conf.Approved = true
}
err = Config.Storage.Config.ConfigInsert(conf)
if err != nil {
logrus.Errorf("failure to persist config for %s. %s", repo.FullName, err)
c.AbortWithError(500, err)
return
}
}
if !conf.Approved {
if user.Login == repo.Owner || build.Event != model.EventPull || !repo.IsGatedConf {
conf.Approved = true
Config.Storage.Config.ConfigUpdate(conf)
}
}
build.ConfigID = conf.ID

netrc, err := remote_.Netrc(user, repo)
if err != nil {
Expand All @@ -145,7 +172,7 @@ func PostHook(c *gin.Context) {
}

// verify the branches can be built vs skipped
branches, err := yaml.ParseBytes(raw)
branches, err := yaml.ParseString(conf.Data)
if err == nil {
if !branches.Branches.Match(build.Branch) && build.Event != model.EventTag && build.Event != model.EventDeploy {
c.String(200, "Branch does not match restrictions defined in yaml")
Expand All @@ -168,7 +195,7 @@ func PostHook(c *gin.Context) {
build.Verified = true
build.Status = model.StatusPending

if repo.IsGated {
if repo.IsGated || repo.IsGatedConf {
allowed, _ := Config.Services.Senders.SenderAllowed(user, repo, build)
if !allowed {
build.Status = model.StatusBlocked
Expand Down Expand Up @@ -212,7 +239,7 @@ func PostHook(c *gin.Context) {
Secs: secs,
Regs: regs,
Link: httputil.GetURL(c.Request),
Yaml: string(raw),
Yaml: conf.Data,
}
items, err := b.Build()
if err != nil {
Expand Down Expand Up @@ -442,7 +469,7 @@ func (b *builder) Build() ([]*buildItem, error) {
linter.WithTrusted(b.Repo.IsTrusted),
).Lint(parsed)
if lerr != nil {
return nil, err
return nil, lerr
}

var registries []compiler.Registry
Expand Down Expand Up @@ -511,3 +538,8 @@ func (b *builder) Build() ([]*buildItem, error) {

return items, nil
}

func shasum(raw []byte) string {
sum := sha256.Sum256(raw)
return fmt.Sprintf("%x", sum)
}
4 changes: 2 additions & 2 deletions server/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ type tokenPayload struct {
}

// ToConfig returns the config from the Context
func ToConfig(c *gin.Context) *model.Config {
func ToConfig(c *gin.Context) *model.Settings {
v := c.MustGet("config")
return v.(*model.Config)
return v.(*model.Settings)
}
5 changes: 3 additions & 2 deletions server/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ var Config = struct {
// Repos model.RepoStore
// Builds model.BuildStore
// Logs model.LogStore
Files model.FileStore
Procs model.ProcStore
Config model.ConfigStore
Files model.FileStore
Procs model.ProcStore
// Registries model.RegistryStore
// Secrets model.SecretStore
}
Expand Down
29 changes: 29 additions & 0 deletions store/datastore/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package datastore

import (
"github.com/drone/drone/model"
"github.com/drone/drone/store/datastore/sql"
"github.com/russross/meddler"
)

func (db *datastore) ConfigLoad(id int64) (*model.Config, error) {
stmt := sql.Lookup(db.driver, "config-find-repo-id")
conf := new(model.Config)
err := meddler.QueryRow(db, conf, stmt, id)
return conf, err
}

func (db *datastore) ConfigFind(repo *model.Repo, hash string) (*model.Config, error) {
stmt := sql.Lookup(db.driver, "config-find-repo-hash")
conf := new(model.Config)
err := meddler.QueryRow(db, conf, stmt, repo.ID, hash)
return conf, err
}

func (db *datastore) ConfigUpdate(config *model.Config) error {
return meddler.Update(db, "config", config)
}

func (db *datastore) ConfigInsert(config *model.Config) error {
return meddler.Insert(db, "config", config)
}
Loading

0 comments on commit 4569b60

Please sign in to comment.