Skip to content

Commit 3462b1a

Browse files
authoredMay 4, 2022
Cherry pick empty data cache fix into release 0.5 (#224)
* Make sure that the Rego hook is well-behaved with no data cache (#222) Fixes open-policy-agent/gatekeeper#2026 Signed-off-by: Max Smythe <[email protected]> * Upgrade linter Signed-off-by: Max Smythe <[email protected]> * Upgrade workflows Signed-off-by: Max Smythe <[email protected]>
1 parent 8066162 commit 3462b1a

File tree

7 files changed

+121
-30
lines changed

7 files changed

+121
-30
lines changed
 

‎.github/workflows/gatekeeper.yml

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@ jobs:
55
lint:
66
name: "Gatekeeper Test"
77
runs-on: ubuntu-latest
8-
timeout-minutes: 5
8+
timeout-minutes: 10
99
steps:
10-
- name: Set up Go 1.17
11-
uses: actions/setup-go@v2
10+
- name: Set up Go 1.18
11+
uses: actions/setup-go@v3
1212
with:
13-
go-version: 1.17
13+
go-version: 1.18
1414

1515
- name: Check out code into the Go module directory
16-
uses: actions/checkout@v2
16+
uses: actions/checkout@v3
1717
with:
1818
path: go/src/github.com/open-policy-agent/frameworks
1919

2020
- name: Check out Gatekeeper default branch
21-
uses: actions/checkout@v2
21+
uses: actions/checkout@v3
2222
with:
2323
repository: open-policy-agent/gatekeeper
2424
path: go/src/github.com/open-policy-agent/gatekeeper

‎.github/workflows/workflow.yml

+12-9
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,30 @@ jobs:
77
runs-on: ubuntu-latest
88
timeout-minutes: 5
99
steps:
10-
- uses: actions/checkout@v2
11-
# source: https://github.com/golangci/golangci-lint-action
10+
- uses: actions/checkout@v3
11+
- name: Set up Go 1.18
12+
uses: actions/setup-go@v3
13+
with:
14+
go-version: 1.18
1215
- name: golangci-lint
13-
uses: golangci/golangci-lint-action@v2
16+
uses: golangci/golangci-lint-action@v3
1417
with:
1518
# version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
16-
version: v1.42.1
19+
version: v1.45.2
1720
working-directory: constraint
1821

1922
test:
2023
name: "Unit test"
2124
runs-on: ubuntu-latest
2225
timeout-minutes: 5
2326
steps:
24-
- name: Set up Go 1.17
25-
uses: actions/setup-go@v2
27+
- name: Set up Go 1.18
28+
uses: actions/setup-go@v3
2629
with:
27-
go-version: 1.17
30+
go-version: 1.18
2831

2932
- name: Check out code into the Go module directory
30-
uses: actions/checkout@v2
33+
uses: actions/checkout@v3
3134
with:
3235
path: go/src/github.com/open-policy-agent/frameworks
3336

@@ -49,7 +52,7 @@ jobs:
4952
GOBIN: ${{ github.workspace }}/go/bin
5053

5154
- name: Codecov Upload
52-
uses: codecov/codecov-action@v1
55+
uses: codecov/codecov-action@v3
5356
with:
5457
flags: unittests
5558
file: go/src/github.com/open-policy-agent/frameworks/constraint/cover.out

‎constraint/Makefile

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# When updating this, make sure to update the corresponding action in
2+
# workflow.yaml
3+
GOLANGCI_LINT_VERSION := v1.45.2
4+
5+
# Detects the location of the user golangci-lint cache.
6+
GOLANGCI_LINT_CACHE := $(shell pwd)/.tmp/golangci-lint
7+
18
all: test
29

310
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
@@ -47,8 +54,14 @@ manifests:
4754
sed -i '/- externaldata.gatekeeper.sh_providers.yaml/d' .staging/templatecrd/kustomization.yaml
4855
kustomize build .staging/templatecrd --output=.staging/templatecrd/crd.yaml
4956

57+
# lint runs a dockerized golangci-lint, and should give consistent results
58+
# across systems.
59+
# Source: https://golangci-lint.run/usage/install/#docker
5060
lint:
51-
golangci-lint -v run ./... --timeout 5m
61+
docker run --rm -v $(shell pwd):/app \
62+
-v ${GOLANGCI_LINT_CACHE}:/root/.cache/golangci-lint \
63+
-w /app golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine \
64+
golangci-lint run -v
5265

5366
# Generate code
5467
# Not working? Try running `make gen-dependencies`

‎constraint/pkg/client/client_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ func TestClient_RemoveTemplate_CascadingDelete(t *testing.T) {
821821

822822
sLower := strings.ToLower(s)
823823
if strings.Contains(sLower, "cascadingdelete") {
824-
t.Errorf("Template not removed from cache: %s", s)
824+
t.Errorf("Constraint not removed from cache: %s", s)
825825
}
826826

827827
finalPreserved := strings.Count(sLower, "stillpersists")

‎constraint/pkg/client/drivers/local/driver.go

+22-12
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func (d *Driver) AddTemplate(ctx context.Context, templ *templates.ConstraintTem
9090
func (d *Driver) RemoveTemplate(ctx context.Context, templ *templates.ConstraintTemplate) error {
9191
kind := templ.Spec.CRD.Spec.Names.Kind
9292

93-
constraintParent := storage.Path{"constraint", kind}
93+
constraintParent := storage.Path{"constraints", kind}
9494

9595
d.mtx.Lock()
9696
defer d.mtx.Unlock()
@@ -281,28 +281,38 @@ func (d *Driver) Query(ctx context.Context, target string, constraints []*unstru
281281
}
282282

283283
func (d *Driver) Dump(ctx context.Context) (string, error) {
284-
dt := make(map[string]map[string]rego.ResultSet)
284+
// we want to create:
285+
// targetName.modules.kind.moduleName = contents
286+
// targetName.data = data
287+
dt := make(map[string]map[string]interface{})
285288

286289
compilers := d.compilers.list()
287290
for targetName, targetCompilers := range compilers {
288-
targetData := make(map[string]rego.ResultSet)
291+
targetModules := make(map[string]map[string]string)
289292

290293
for kind, compiler := range targetCompilers {
291-
rs, _, err := d.eval(ctx, compiler, targetName, []string{"data"}, nil)
292-
if err != nil {
293-
return "", err
294+
kindModules := make(map[string]string)
295+
for modname, contents := range compiler.Modules {
296+
kindModules[modname] = contents.String()
294297
}
295-
targetData[kind] = rs
298+
targetModules[kind] = kindModules
296299
}
300+
dt[targetName] = map[string]interface{}{}
301+
dt[targetName]["modules"] = targetModules
297302

298-
dt[targetName] = targetData
299-
}
303+
emptyCompiler := ast.NewCompiler().WithCapabilities(d.compilers.capabilities)
300304

301-
resp := map[string]interface{}{
302-
"data": dt,
305+
rs, _, err := d.eval(ctx, emptyCompiler, targetName, []string{}, nil)
306+
if err != nil {
307+
return "", err
308+
}
309+
310+
if len(rs) != 0 && len(rs[0].Expressions) != 0 {
311+
dt[targetName]["data"] = rs[0].Expressions[0].Value
312+
}
303313
}
304314

305-
b, err := json.MarshalIndent(resp, "", " ")
315+
b, err := json.MarshalIndent(dt, "", " ")
306316
if err != nil {
307317
return "", err
308318
}

‎constraint/pkg/client/drivers/local/driver_unit_test.go

+58
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,67 @@ fooisbar[msg] {
2727
input.foo == "bar"
2828
msg := "input.foo is bar"
2929
}
30+
`
31+
32+
AlwaysViolate string = `
33+
package foobar
34+
35+
violation[{"msg": "always violate"}] {
36+
true
37+
}
3038
`
3139
)
3240

41+
func TestDriver_Query(t *testing.T) {
42+
d, err := New()
43+
if err != nil {
44+
t.Fatal(err)
45+
}
46+
47+
tmpl := cts.New(cts.OptTargets(cts.Target(cts.MockTargetHandler, AlwaysViolate)))
48+
ctx := context.Background()
49+
50+
if err := d.AddTemplate(ctx, tmpl); err != nil {
51+
t.Fatalf("got AddTemplate() error = %v, want %v", err, nil)
52+
}
53+
54+
if err := d.AddConstraint(ctx, cts.MakeConstraint(t, "Fakes", "foo-1")); err != nil {
55+
t.Fatalf("got AddConstraint() error = %v, want %v", err, nil)
56+
}
57+
58+
res, _, err := d.Query(
59+
ctx,
60+
cts.MockTargetHandler,
61+
[]*unstructured.Unstructured{cts.MakeConstraint(t, "Fakes", "foo-1")},
62+
map[string]interface{}{"hi": "there"},
63+
)
64+
if err != nil {
65+
t.Fatalf("got Query() error = %v, want %v", err, nil)
66+
}
67+
if len(res) == 0 {
68+
t.Fatalf("got 0 errors on normal query; want 1")
69+
}
70+
71+
// Remove data to make sure our rego hook is well-behaved when
72+
// there is no external data root
73+
if err := d.RemoveData(ctx, cts.MockTargetHandler, nil); err != nil {
74+
t.Fatalf("got RemoveData() error = %v, want %v", err, nil)
75+
}
76+
77+
res, _, err = d.Query(
78+
ctx,
79+
cts.MockTargetHandler,
80+
[]*unstructured.Unstructured{cts.MakeConstraint(t, "Fakes", "foo-1")},
81+
map[string]interface{}{"hi": "there"},
82+
)
83+
if err != nil {
84+
t.Fatalf("got Query() (#2) error = %v, want %v", err, nil)
85+
}
86+
if len(res) == 0 {
87+
t.Fatalf("got 0 errors on data-less query; want 1")
88+
}
89+
}
90+
3391
func TestDriver_AddTemplate(t *testing.T) {
3492
testCases := []struct {
3593
name string

‎constraint/pkg/client/drivers/local/rego.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ violation[response] {
3434
}
3535
3636
# Run the Template with Constraint.
37-
data.template.violation[r] with input as inp with data.inventory as data.external
37+
inventory[inv]
38+
data.template.violation[r] with input as inp with data.inventory as inv
3839
3940
# Construct the response, defaulting "details" to empty object if it is not
4041
# specified.
@@ -45,6 +46,12 @@ violation[response] {
4546
}
4647
}
4748
49+
inventory[inv] {
50+
inv = data.external
51+
}
52+
inventory[{}] {
53+
not data.external
54+
}
4855
`
4956
)
5057

0 commit comments

Comments
 (0)
Please sign in to comment.