summaryrefslogtreecommitdiff
path: root/pkg/hooks/1.0.0/when.go
blob: c23223ec0ce3f290cd1c2c6f29aec104c5978078 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package hook

import (
	"regexp"

	rspec "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
)

// When holds hook-injection conditions.
type When struct {
	Always        *bool             `json:"always,omitempty"`
	Annotations   map[string]string `json:"annotation,omitempty"`
	Commands      []string          `json:"commands,omitempty"`
	HasBindMounts *bool             `json:"hasBindMounts,omitempty"`

	// Or enables any-of matching.
	//
	// Deprecated: this property is for is backwards-compatibility with
	// 0.1.0 hooks.  It will be removed when we drop support for them.
	Or bool `json:"-"`
}

// Match returns true if the given conditions match the configuration.
func (when *When) Match(config *rspec.Spec, annotations map[string]string, hasBindMounts bool) (match bool, err error) {
	matches := 0

	if when.Always != nil {
		if *when.Always {
			if when.Or {
				return true, nil
			}
			matches++
		} else if !when.Or {
			return false, nil
		}
	}

	if when.HasBindMounts != nil {
		if *when.HasBindMounts && hasBindMounts {
			if when.Or {
				return true, nil
			}
			matches++
		} else if !when.Or {
			return false, nil
		}
	}

	for keyPattern, valuePattern := range when.Annotations {
		match := false
		for key, value := range annotations {
			match, err = regexp.MatchString(keyPattern, key)
			if err != nil {
				return false, errors.Wrap(err, "annotation key")
			}
			if match {
				match, err = regexp.MatchString(valuePattern, value)
				if err != nil {
					return false, errors.Wrap(err, "annotation value")
				}
				if match {
					break
				}
			}
		}
		if match {
			if when.Or {
				return true, nil
			}
			matches++
		} else if !when.Or {
			return false, nil
		}
	}

	if config.Process != nil {
		if len(config.Process.Args) == 0 {
			return false, errors.New("process.args must have at least one entry")
		}
		command := config.Process.Args[0]
		for _, cmdPattern := range when.Commands {
			match, err := regexp.MatchString(cmdPattern, command)
			if err != nil {
				return false, errors.Wrap(err, "command")
			}
			if match {
				return true, nil
			}
		}
		return false, nil
	}

	return matches > 0, nil
}