woodpecker/pipeline/frontend/yaml/linter/linter.go
6543 b15ca52a63
Move constrain to only have a single command in backend to run to dedicated backends (#1032)
at the moment we compile a script that we can pipe in as single command
this is because of the constrains the docker backend gives us.

so we move it into the docker backend and eventually get rid of it altogether
2022-10-31 00:26:49 +01:00

123 lines
2.9 KiB
Go

package linter
import (
"fmt"
"github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml"
)
const (
blockClone uint8 = iota
blockPipeline
blockServices
)
// A Linter lints a pipeline configuration.
type Linter struct {
trusted bool
}
// New creates a new Linter with options.
func New(opts ...Option) *Linter {
linter := new(Linter)
for _, opt := range opts {
opt(linter)
}
return linter
}
// Lint lints the configuration.
func (l *Linter) Lint(c *yaml.Config) error {
if len(c.Pipeline.Containers) == 0 {
return fmt.Errorf("Invalid or missing pipeline section")
}
if err := l.lint(c.Clone.Containers, blockClone); err != nil {
return err
}
if err := l.lint(c.Pipeline.Containers, blockPipeline); err != nil {
return err
}
if err := l.lint(c.Services.Containers, blockServices); err != nil {
return err
}
return nil
}
func (l *Linter) lint(containers []*yaml.Container, block uint8) error {
for _, container := range containers {
if err := l.lintImage(container); err != nil {
return err
}
if !l.trusted {
if err := l.lintTrusted(container); err != nil {
return err
}
}
if err := l.lintCommands(container); err != nil {
return err
}
}
return nil
}
func (l *Linter) lintImage(c *yaml.Container) error {
if len(c.Image) == 0 {
return fmt.Errorf("Invalid or missing image")
}
return nil
}
func (l *Linter) lintCommands(c *yaml.Container) error {
if len(c.Commands) == 0 {
return nil
}
if len(c.Settings) != 0 {
var keys []string
for key := range c.Settings {
keys = append(keys, key)
}
return fmt.Errorf("Cannot configure both commands and custom attributes %v", keys)
}
return nil
}
func (l *Linter) lintTrusted(c *yaml.Container) error {
if c.Privileged {
return fmt.Errorf("Insufficient privileges to use privileged mode")
}
if c.ShmSize != 0 {
return fmt.Errorf("Insufficient privileges to override shm_size")
}
if len(c.DNS) != 0 {
return fmt.Errorf("Insufficient privileges to use custom dns")
}
if len(c.DNSSearch) != 0 {
return fmt.Errorf("Insufficient privileges to use dns_search")
}
if len(c.Devices) != 0 {
return fmt.Errorf("Insufficient privileges to use devices")
}
if len(c.ExtraHosts) != 0 {
return fmt.Errorf("Insufficient privileges to use extra_hosts")
}
if len(c.NetworkMode) != 0 {
return fmt.Errorf("Insufficient privileges to use network_mode")
}
if len(c.IpcMode) != 0 {
return fmt.Errorf("Insufficient privileges to use ipc_mode")
}
if len(c.Sysctls) != 0 {
return fmt.Errorf("Insufficient privileges to use sysctls")
}
if c.Networks.Networks != nil && len(c.Networks.Networks) != 0 {
return fmt.Errorf("Insufficient privileges to use networks")
}
if c.Volumes.Volumes != nil && len(c.Volumes.Volumes) != 0 {
return fmt.Errorf("Insufficient privileges to use volumes")
}
if len(c.Tmpfs) != 0 {
return fmt.Errorf("Insufficient privileges to use tmpfs")
}
return nil
}