implement compose secret syntax

This commit is contained in:
Brad Rydzewski 2017-04-10 12:39:50 +02:00
parent 4502e5a256
commit b10a074b57
13 changed files with 132 additions and 76 deletions

View file

@ -115,9 +115,6 @@ type Client interface {
// target environment. // target environment.
Deploy(string, string, int, string, map[string]string) (*model.Build, error) Deploy(string, string, int, string, map[string]string) (*model.Build, error)
// AgentList returns a list of build agents.
AgentList() ([]*model.Agent, error)
// Registry returns a registry by hostname. // Registry returns a registry by hostname.
Registry(owner, name, hostname string) (*model.Registry, error) Registry(owner, name, hostname string) (*model.Registry, error)

View file

@ -53,7 +53,6 @@ const (
pathUsers = "%s/api/users" pathUsers = "%s/api/users"
pathUser = "%s/api/users/%s" pathUser = "%s/api/users/%s"
pathBuildQueue = "%s/api/builds" pathBuildQueue = "%s/api/builds"
pathAgent = "%s/api/agents"
) )
type client struct { type client struct {
@ -367,14 +366,6 @@ func (c *client) Sign(owner, name string, in []byte) ([]byte, error) {
return ioutil.ReadAll(rc) return ioutil.ReadAll(rc)
} }
// AgentList returns a list of build agents.
func (c *client) AgentList() ([]*model.Agent, error) {
var out []*model.Agent
uri := fmt.Sprintf(pathAgent, c.base)
err := c.get(uri, &out)
return out, err
}
// Registry returns a registry by hostname. // Registry returns a registry by hostname.
func (c *client) Registry(owner, name, hostname string) (*model.Registry, error) { func (c *client) Registry(owner, name, hostname string) (*model.Registry, error) {
out := new(model.Registry) out := new(model.Registry)

View file

@ -1,10 +0,0 @@
package model
type Agent struct {
ID int64 `json:"id" meddler:"agent_id,pk"`
Address string `json:"address" meddler:"agent_addr"`
Platform string `json:"platform" meddler:"agent_platform"`
Capacity int `json:"capacity" meddler:"agent_capacity"`
Created int64 `json:"created_at" meddler:"agent_created"`
Updated int64 `json:"updated_at" meddler:"agent_updated"`
}

17
model/approval.go Normal file
View file

@ -0,0 +1,17 @@
package model
type (
// ApprovalStore persists approved committers to storage.
ApprovalStore interface {
Approve(*Repo) error
}
// Approval represents an approved committer.
Approval struct {
Username string `json:"username" meddler:"approval_username"`
Approved bool `json:"approved" meddler:"approval_approved"`
Comments string `json:"comments" meddler:"approval_comments"`
CreatedBy string `json:"created_by" meddler:"approval_created_by"`
CreatedAt int64 `json:"created_at" meddler:"approval_created_at"`
}
)

23
model/gate.go Normal file
View file

@ -0,0 +1,23 @@
package model
// Gated indicates a build is gated and requires approval to proceed. It also
// includes the reason the build was gated.
type Gated struct {
Gated bool `json:"gated"`
Reason string `json:"reason"`
}
// GateService defines a service for gating builds.
type GateService interface {
Gated(*User, *Repo, *Build) (*Gated, error)
}
type gateService struct{}
func (s *gateService) Gated(owner *User, repo *Repo, build *Build) (*Gated, error) {
g := new(Gated)
if repo.IsPrivate && build.Event == EventPull && build.Sender != owner.Login {
g.Gated = true
}
return g, nil
}

View file

@ -1,17 +0,0 @@
package model
// // swagger:model job
// type Job struct {
// ID int64 `json:"id" meddler:"job_id,pk"`
// BuildID int64 `json:"-" meddler:"job_build_id"`
// NodeID int64 `json:"-" meddler:"job_node_id"`
// Number int `json:"number" meddler:"job_number"`
// Error string `json:"error" meddler:"job_error"`
// Status string `json:"status" meddler:"job_status"`
// ExitCode int `json:"exit_code" meddler:"job_exit_code"`
// Enqueued int64 `json:"enqueued_at" meddler:"job_enqueued"`
// Started int64 `json:"started_at" meddler:"job_started"`
// Finished int64 `json:"finished_at" meddler:"job_finished"`
//
// Environment map[string]string `json:"environment" meddler:"job_environment,json"`
// }

View file

@ -460,12 +460,18 @@ func (b *builder) Build() ([]*buildItem, error) {
} }
secrets := map[string]string{} secrets := map[string]string{}
var csecrets []compiler.Secret
for _, sec := range b.Secs { for _, sec := range b.Secs {
if !sec.MatchEvent(b.Curr.Event) { if !sec.MatchEvent(b.Curr.Event) {
continue continue
} }
if b.Curr.Verified || sec.SkipVerify { if b.Curr.Verified || sec.SkipVerify {
secrets[sec.Name] = sec.Value secrets[sec.Name] = sec.Value
csecrets = append(csecrets, compiler.Secret{
Name: sec.Name,
Value: sec.Value,
Match: sec.Images,
})
} }
} }
sub := func(name string) string { sub := func(name string) string {
@ -521,6 +527,7 @@ func (b *builder) Build() ([]*buildItem, error) {
b.Repo.IsPrivate, b.Repo.IsPrivate,
), ),
compiler.WithRegistry(registries...), compiler.WithRegistry(registries...),
compiler.WithSecrets(csecrets...),
compiler.WithPrefix( compiler.WithPrefix(
fmt.Sprintf( fmt.Sprintf(
"%d_%d", "%d_%d",

View file

@ -20,6 +20,12 @@ type Registry struct {
Token string Token string
} }
type Secret struct {
Name string
Value string
Match []string
}
// Compiler compiles the yaml // Compiler compiles the yaml
type Compiler struct { type Compiler struct {
local bool local bool
@ -31,13 +37,16 @@ type Compiler struct {
path string path string
metadata frontend.Metadata metadata frontend.Metadata
registries []Registry registries []Registry
secrets map[string]Secret
aliases []string aliases []string
} }
// New creates a new Compiler with options. // New creates a new Compiler with options.
func New(opts ...Option) *Compiler { func New(opts ...Option) *Compiler {
compiler := new(Compiler) compiler := &Compiler{
compiler.env = map[string]string{} env: map[string]string{},
secrets: map[string]Secret{},
}
for _, opt := range opts { for _, opt := range opts {
opt(compiler) opt(compiler)
} }

View file

@ -3,6 +3,7 @@ package compiler
import ( import (
"fmt" "fmt"
"path" "path"
"strings"
"github.com/cncd/pipeline/pipeline/backend" "github.com/cncd/pipeline/pipeline/backend"
"github.com/cncd/pipeline/pipeline/frontend/yaml" "github.com/cncd/pipeline/pipeline/frontend/yaml"
@ -73,7 +74,7 @@ func (c *Compiler) createProcess(name string, container *yaml.Container) *backen
if isPlugin(container) { if isPlugin(container) {
paramsToEnv(container.Vargs, environment) paramsToEnv(container.Vargs, environment)
if imageMatches(container.Image, c.escalated) { if matchImage(container.Image, c.escalated...) {
privileged = true privileged = true
entrypoint = []string{} entrypoint = []string{}
command = []string{} command = []string{}
@ -102,6 +103,13 @@ func (c *Compiler) createProcess(name string, container *yaml.Container) *backen
} }
} }
for _, requested := range container.Secrets.Secrets {
secret, ok := c.secrets[strings.ToLower(requested.Source)]
if ok && (len(secret.Match) == 0 || matchImage(image, secret.Match...)) {
environment[strings.ToUpper(requested.Target)] = secret.Value
}
}
return &backend.Step{ return &backend.Step{
Name: name, Name: name,
Alias: container.Name, Alias: container.Name,
@ -134,16 +142,6 @@ func (c *Compiler) createProcess(name string, container *yaml.Container) *backen
} }
} }
func imageMatches(image string, to []string) bool {
image = trimImage(image)
for _, i := range to {
if image == i {
return true
}
}
return false
}
func isPlugin(c *yaml.Container) bool { func isPlugin(c *yaml.Container) bool {
return len(c.Vargs) != 0 return len(c.Vargs) != 0
} }

View file

@ -39,6 +39,16 @@ func WithRegistry(registries ...Registry) Option {
} }
} }
// WithSecret configures the compiler with external secrets
// to be injected into the container at runtime.
func WithSecret(secrets ...Secret) Option {
return func(compiler *Compiler) {
for _, secret := range secrets {
compiler.secrets[strings.ToLower(secret.Name)] = secret
}
}
}
// WithMetadata configutes the compiler with the repostiory, build // WithMetadata configutes the compiler with the repostiory, build
// and system metadata. The metadata is used to remove steps from // and system metadata. The metadata is used to remove steps from
// the compiled pipeline configuration that should be skipped. The // the compiled pipeline configuration that should be skipped. The

View file

@ -52,6 +52,7 @@ type (
ShmSize libcompose.MemStringorInt `yaml:"shm_size,omitempty"` ShmSize libcompose.MemStringorInt `yaml:"shm_size,omitempty"`
Ulimits libcompose.Ulimits `yaml:"ulimits,omitempty"` Ulimits libcompose.Ulimits `yaml:"ulimits,omitempty"`
Volumes libcompose.Volumes `yaml:"volumes,omitempty"` Volumes libcompose.Volumes `yaml:"volumes,omitempty"`
Secrets Secrets `yaml:"secrets,omitempty"`
Constraints Constraints `yaml:"when,omitempty"` Constraints Constraints `yaml:"when,omitempty"`
Vargs map[string]interface{} `yaml:",inline"` Vargs map[string]interface{} `yaml:",inline"`
} }

View file

@ -0,0 +1,30 @@
package yaml
type (
// Secrets defines a collection of secrets.
Secrets struct {
Secrets []*Secret
}
// Secret defines a container secret.
Secret struct {
Source string `yaml:"source"`
Target string `yaml:"target"`
}
)
// UnmarshalYAML implements the Unmarshaller interface.
func (s *Secrets) UnmarshalYAML(unmarshal func(interface{}) error) error {
var strslice []string
err := unmarshal(&strslice)
if err == nil {
for _, str := range strslice {
s.Secrets = append(s.Secrets, &Secret{
Source: str,
Target: str,
})
}
return nil
}
return unmarshal(&s.Secrets)
}

48
vendor/vendor.json vendored
View file

@ -28,68 +28,68 @@
{ {
"checksumSHA1": "W3AuK8ocqHwlUajGmQLFvnRhTZE=", "checksumSHA1": "W3AuK8ocqHwlUajGmQLFvnRhTZE=",
"path": "github.com/cncd/pipeline/pipeline", "path": "github.com/cncd/pipeline/pipeline",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "Qu2FreqaMr8Yx2bW9O0cxAGgjr0=", "checksumSHA1": "Qu2FreqaMr8Yx2bW9O0cxAGgjr0=",
"path": "github.com/cncd/pipeline/pipeline/backend", "path": "github.com/cncd/pipeline/pipeline/backend",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "0CGXRaYwZhJxGIrGhn8WGpkFqPo=", "checksumSHA1": "0CGXRaYwZhJxGIrGhn8WGpkFqPo=",
"path": "github.com/cncd/pipeline/pipeline/backend/docker", "path": "github.com/cncd/pipeline/pipeline/backend/docker",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "/8wE+cVb7T4PQZgpLNu0DHzKGuE=", "checksumSHA1": "/8wE+cVb7T4PQZgpLNu0DHzKGuE=",
"path": "github.com/cncd/pipeline/pipeline/frontend", "path": "github.com/cncd/pipeline/pipeline/frontend",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "O0sulBQAHJeNLg3lO38Cq5uf/eg=", "checksumSHA1": "QWs+L3emrt5DDTWvqD6rbMtLKMw=",
"path": "github.com/cncd/pipeline/pipeline/frontend/yaml", "path": "github.com/cncd/pipeline/pipeline/frontend/yaml",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "4gmWpW2MkXgWGSSvSoRFu1YjGbQ=", "checksumSHA1": "Bsp5Fq7oc6ZDDX5COo//pajb0kk=",
"path": "github.com/cncd/pipeline/pipeline/frontend/yaml/compiler", "path": "github.com/cncd/pipeline/pipeline/frontend/yaml/compiler",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "Q0GkNUFamVYIA1Fd8r0A5M6Gx54=", "checksumSHA1": "Q0GkNUFamVYIA1Fd8r0A5M6Gx54=",
"path": "github.com/cncd/pipeline/pipeline/frontend/yaml/linter", "path": "github.com/cncd/pipeline/pipeline/frontend/yaml/linter",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "kx2sPUIMozPC/g6E4w48h3FfH3k=", "checksumSHA1": "kx2sPUIMozPC/g6E4w48h3FfH3k=",
"path": "github.com/cncd/pipeline/pipeline/frontend/yaml/matrix", "path": "github.com/cncd/pipeline/pipeline/frontend/yaml/matrix",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "2/3f3oNmxXy5kcrRLCFa24Oc9O4=", "checksumSHA1": "2/3f3oNmxXy5kcrRLCFa24Oc9O4=",
"path": "github.com/cncd/pipeline/pipeline/interrupt", "path": "github.com/cncd/pipeline/pipeline/interrupt",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "uOjTfke7Qxosrivgz/nVTHeIP5g=", "checksumSHA1": "uOjTfke7Qxosrivgz/nVTHeIP5g=",
"path": "github.com/cncd/pipeline/pipeline/multipart", "path": "github.com/cncd/pipeline/pipeline/multipart",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "TP5lK1T8cOKv5QjZ2nqdlYczSTo=", "checksumSHA1": "TP5lK1T8cOKv5QjZ2nqdlYczSTo=",
"path": "github.com/cncd/pipeline/pipeline/rpc", "path": "github.com/cncd/pipeline/pipeline/rpc",
"revision": "087d10834b19bbb8d1665152696ca63883610021", "revision": "94d637b94d0439ed4853e8089d8a1b1820b67c65",
"revisionTime": "2017-04-06T15:46:03Z" "revisionTime": "2017-04-09T09:45:58Z"
}, },
{ {
"checksumSHA1": "7Qj1DK0ceAXkYztW0l3+L6sn+V8=", "checksumSHA1": "7Qj1DK0ceAXkYztW0l3+L6sn+V8=",