105 lines
2.8 KiB
Go
105 lines
2.8 KiB
Go
package builtin
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/drone/drone/engine/compiler/parse"
|
|
)
|
|
|
|
type validateOp struct {
|
|
visitor
|
|
plugins []string
|
|
trusted bool
|
|
}
|
|
|
|
// NewValidateOp returns a linter that checks container configuration.
|
|
func NewValidateOp(trusted bool, plugins []string) Visitor {
|
|
return &validateOp{
|
|
trusted: trusted,
|
|
plugins: plugins,
|
|
}
|
|
}
|
|
|
|
func (v *validateOp) VisitContainer(node *parse.ContainerNode) error {
|
|
switch node.NodeType {
|
|
case parse.NodePlugin, parse.NodeCache, parse.NodeClone:
|
|
if err := v.validatePlugins(node); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if node.NodeType == parse.NodePlugin {
|
|
if err := v.validatePluginConfig(node); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return v.validateConfig(node)
|
|
}
|
|
|
|
// validate the plugin image and return an error if the plugin
|
|
// image does not match the whitelist.
|
|
func (v *validateOp) validatePlugins(node *parse.ContainerNode) error {
|
|
match := false
|
|
for _, pattern := range v.plugins {
|
|
ok, err := filepath.Match(pattern, node.Container.Image)
|
|
if ok && err == nil {
|
|
match = true
|
|
break
|
|
}
|
|
}
|
|
if !match {
|
|
return fmt.Errorf(
|
|
"Plugin %s is not in the whitelist",
|
|
node.Container.Image,
|
|
)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// validate the plugin command and entrypoint and return an error
|
|
// the user attempts to set or override these values.
|
|
func (v *validateOp) validatePluginConfig(node *parse.ContainerNode) error {
|
|
if len(node.Container.Entrypoint) != 0 {
|
|
return fmt.Errorf("Cannot set plugin Entrypoint")
|
|
}
|
|
if len(node.Container.Command) != 0 {
|
|
return fmt.Errorf("Cannot set plugin Command")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// validate the container configuration and return an error if
|
|
// restricted configurations are used.
|
|
func (v *validateOp) validateConfig(node *parse.ContainerNode) error {
|
|
if v.trusted {
|
|
return nil
|
|
}
|
|
if node.Container.Privileged {
|
|
return fmt.Errorf("Insufficient privileges to use privileged mode")
|
|
}
|
|
if len(node.Container.DNS) != 0 {
|
|
return fmt.Errorf("Insufficient privileges to use custom dns")
|
|
}
|
|
if len(node.Container.DNSSearch) != 0 {
|
|
return fmt.Errorf("Insufficient privileges to use dns_search")
|
|
}
|
|
if len(node.Container.Devices) != 0 {
|
|
return fmt.Errorf("Insufficient privileges to use devices")
|
|
}
|
|
if len(node.Container.ExtraHosts) != 0 {
|
|
return fmt.Errorf("Insufficient privileges to use extra_hosts")
|
|
}
|
|
if len(node.Container.Network) != 0 {
|
|
return fmt.Errorf("Insufficient privileges to override the network")
|
|
}
|
|
if node.Container.OomKillDisable {
|
|
return fmt.Errorf("Insufficient privileges to disable oom_kill")
|
|
}
|
|
if len(node.Container.Volumes) != 0 && node.Type() != parse.NodeCache {
|
|
return fmt.Errorf("Insufficient privileges to use volumes")
|
|
}
|
|
if len(node.Container.VolumesFrom) != 0 {
|
|
return fmt.Errorf("Insufficient privileges to use volumes_from")
|
|
}
|
|
return nil
|
|
}
|