Skip to content

Commit e01d3c4

Browse files
authored
Add template for imagePullPolicy checks (#202)
1 parent 6c2c830 commit e01d3c4

File tree

7 files changed

+246
-1
lines changed

7 files changed

+246
-1
lines changed

docs/generated/templates.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,30 @@ KubeLinter supports the following templates:
318318
[]
319319
```
320320

321+
## Image Pull Policy
322+
323+
**Key**: `image-pull-policy`
324+
325+
**Description**: Flag containers with forbidden image pull policy
326+
327+
**Supported Objects**: DeploymentLike
328+
329+
**Parameters**:
330+
331+
```json
332+
[
333+
{
334+
"name": "forbiddenPolicies",
335+
"type": "array",
336+
"description": "list of forbidden image pull policy",
337+
"required": false,
338+
"regexAllowed": false,
339+
"negationAllowed": false,
340+
"arrayElemType": "string"
341+
}
342+
]
343+
```
344+
321345
## Latest Tag
322346

323347
**Key**: `latest-tag`

pkg/templates/all/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
_ "golang.stackrox.io/kube-linter/pkg/templates/hostmounts"
1616
_ "golang.stackrox.io/kube-linter/pkg/templates/hostnetwork"
1717
_ "golang.stackrox.io/kube-linter/pkg/templates/hostpid"
18+
_ "golang.stackrox.io/kube-linter/pkg/templates/imagepullpolicy"
1819
_ "golang.stackrox.io/kube-linter/pkg/templates/latesttag"
1920
_ "golang.stackrox.io/kube-linter/pkg/templates/livenessprobe"
2021
_ "golang.stackrox.io/kube-linter/pkg/templates/memoryrequirements"

pkg/templates/codegen/main.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ var (
7373
func (p *Params) Validate() error {
7474
var validationErrors []string
7575
{{- range . }}
76-
{{- if eq .ParamDesc.Type "object" }}
76+
{{- if eq .ParamDesc.Type "object" }}
7777
return errors.Errorf("parameter validation not yet supported for object type \"{{ .ParamDesc.Key }}\"")
7878
{{- end }}
7979
{{- if .ParamDesc.Required }}
@@ -85,6 +85,24 @@ func (p *Params) Validate() error {
8585
}
8686
{{- end }}
8787
{{- if .ParamDesc.Enum }}
88+
{{- if eq .ParamDesc.Type "array" }}
89+
for _, value := range p.{{ .ParamDesc.XXXStructFieldName }} {
90+
var found bool
91+
for _, allowedValue := range []string{
92+
{{- range .ParamDesc.Enum }}
93+
"{{ . }}",
94+
{{- end }}
95+
}{
96+
if value == allowedValue {
97+
found = true
98+
break
99+
}
100+
}
101+
if !found {
102+
validationErrors = append(validationErrors, fmt.Sprintf("param {{ .ParamDesc.Name }} has invalid value %q, must be one of {{ .ParamDesc.Enum }}", p.{{ .ParamDesc.XXXStructFieldName }}))
103+
}
104+
}
105+
{{- else }}
88106
var found bool
89107
for _, allowedValue := range []string{
90108
{{- range .ParamDesc.Enum }}
@@ -101,6 +119,7 @@ func (p *Params) Validate() error {
101119
}
102120
{{- end }}
103121
{{- end }}
122+
{{- end }}
104123
if len(validationErrors) > 0 {
105124
return errors.Errorf("invalid parameters: %s", strings.Join(validationErrors, ", "))
106125
}

pkg/templates/imagepullpolicy/internal/params/gen-params.go

Lines changed: 89 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package params
2+
3+
// Params represents the params accepted by this template.
4+
type Params struct {
5+
// list of forbidden image pull policy
6+
// +noregex
7+
// +notnegatable
8+
// +enum=Always
9+
// +enum=IfNotPresent
10+
// +enum=Never
11+
ForbiddenPolicies []string
12+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package imagepullpolicy
2+
3+
import (
4+
"fmt"
5+
6+
"golang.stackrox.io/kube-linter/internal/set"
7+
"golang.stackrox.io/kube-linter/pkg/check"
8+
"golang.stackrox.io/kube-linter/pkg/config"
9+
"golang.stackrox.io/kube-linter/pkg/diagnostic"
10+
"golang.stackrox.io/kube-linter/pkg/objectkinds"
11+
"golang.stackrox.io/kube-linter/pkg/templates"
12+
"golang.stackrox.io/kube-linter/pkg/templates/imagepullpolicy/internal/params"
13+
"golang.stackrox.io/kube-linter/pkg/templates/util"
14+
v1 "k8s.io/api/core/v1"
15+
)
16+
17+
const (
18+
templateKey = "image-pull-policy"
19+
)
20+
21+
func init() {
22+
templates.Register(check.Template{
23+
HumanName: "Image Pull Policy",
24+
Key: templateKey,
25+
Description: "Flag containers with forbidden image pull policy",
26+
SupportedObjectKinds: config.ObjectKindsDesc{
27+
ObjectKinds: []string{objectkinds.DeploymentLike},
28+
},
29+
Parameters: params.ParamDescs,
30+
ParseAndValidateParams: params.ParseAndValidate,
31+
Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
32+
forbiddenPolicies := set.NewStringSet(p.ForbiddenPolicies...)
33+
return util.PerContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
34+
if forbiddenPolicies.Contains(string(container.ImagePullPolicy)) {
35+
return []diagnostic.Diagnostic{{Message: fmt.Sprintf("container %q has imagePullPolicy set to %s", container.Name, container.ImagePullPolicy)}}
36+
}
37+
return nil
38+
}), nil
39+
}),
40+
})
41+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package imagepullpolicy
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/suite"
7+
8+
"golang.stackrox.io/kube-linter/pkg/diagnostic"
9+
"golang.stackrox.io/kube-linter/pkg/lintcontext/mocks"
10+
"golang.stackrox.io/kube-linter/pkg/templates"
11+
"golang.stackrox.io/kube-linter/pkg/templates/imagepullpolicy/internal/params"
12+
13+
v1 "k8s.io/api/core/v1"
14+
)
15+
16+
func TestContainerImage(t *testing.T) {
17+
suite.Run(t, new(ContainerImageTestSuite))
18+
}
19+
20+
type ContainerImageTestSuite struct {
21+
templates.TemplateTestSuite
22+
ctx *mocks.MockLintContext
23+
}
24+
25+
func (s *ContainerImageTestSuite) SetupTest() {
26+
s.Init(templateKey)
27+
s.ctx = mocks.NewMockContext()
28+
}
29+
30+
func (s *ContainerImageTestSuite) addDeploymentWithContainerImage(name string, pullPolicy v1.PullPolicy) {
31+
s.ctx.AddMockDeployment(s.T(), name)
32+
s.ctx.AddContainerToDeployment(s.T(), name, v1.Container{Name: "test-container", ImagePullPolicy: pullPolicy})
33+
}
34+
35+
func (s *ContainerImageTestSuite) TestImaPolicy() {
36+
const (
37+
alwaysDep = "deployment-with-always-pull-policy"
38+
ifNotPresentDep = "deployment-with-if-not-present-pull-policy"
39+
neverDep = "deployment-with-never-pull-policy"
40+
)
41+
42+
s.addDeploymentWithContainerImage(alwaysDep, v1.PullAlways)
43+
s.addDeploymentWithContainerImage(ifNotPresentDep, v1.PullIfNotPresent)
44+
s.addDeploymentWithContainerImage(neverDep, v1.PullNever)
45+
46+
s.Validate(s.ctx, []templates.TestCase{
47+
{
48+
Param: params.Params{
49+
ForbiddenPolicies: []string{"Always"},
50+
},
51+
Diagnostics: map[string][]diagnostic.Diagnostic{
52+
alwaysDep: {
53+
{Message: "container \"test-container\" has imagePullPolicy set to Always"},
54+
},
55+
},
56+
ExpectInstantiationError: false,
57+
},
58+
})
59+
}

0 commit comments

Comments
 (0)