Skip to content

Commit 186f399

Browse files
authored
[RuleSet] add support for annotations and labels (#271)
fix: add support to process annotations for the ruleset fix: add support to process labels test: add test for ruleset generation from bundle test: add bundle with labels and annotations test: update test to match expected values fix: update ruleset FromBundle to use Labels and Annotations test: update use to proto.Equal versus reflect.DeepEqual Signed-off-by: Ben Stickel <[email protected]>
1 parent 9c6967f commit 186f399

File tree

6 files changed

+240
-1
lines changed

6 files changed

+240
-1
lines changed

pkg/bundle/ruleset/bundle.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ func FromBundle(b *bundlev1.Bundle) (*bundlev1.RuleSet, error) {
7373
Constraints: []string{},
7474
}
7575

76+
// Process the labels for each secret
77+
for label := range p.Labels {
78+
r.Constraints = append(r.Constraints, fmt.Sprintf(`p.match_label(%q)`, label))
79+
}
80+
81+
// Process the annotations for each secret
82+
for annotation := range p.Annotations {
83+
r.Constraints = append(r.Constraints, fmt.Sprintf(`p.match_annotation(%q)`, annotation))
84+
}
85+
7686
// Process each secret
7787
for _, s := range p.Secrets.Data {
7888
r.Constraints = append(r.Constraints, fmt.Sprintf(`p.has_secret(%q)`, s.Key))

pkg/bundle/ruleset/bundle_test.go

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package ruleset
19+
20+
import (
21+
"testing"
22+
23+
bundlev1 "github.com/elastic/harp/api/gen/go/harp/bundle/v1"
24+
"github.com/golang/protobuf/proto"
25+
)
26+
27+
func TestFromBundle(t *testing.T) {
28+
type args struct {
29+
b *bundlev1.Bundle
30+
}
31+
tests := []struct {
32+
name string
33+
args args
34+
want *bundlev1.RuleSet
35+
wantErr bool
36+
}{
37+
{
38+
name: "nil",
39+
args: args{
40+
b: nil,
41+
},
42+
want: nil,
43+
wantErr: true,
44+
},
45+
{
46+
name: "packages are nil",
47+
args: args{
48+
b: &bundlev1.Bundle{
49+
Labels: map[string]string{
50+
"test": "true",
51+
},
52+
Annotations: map[string]string{
53+
"harp.elastic.co/v1/testing#bundlePurpose": "test",
54+
},
55+
Packages: nil,
56+
},
57+
},
58+
want: nil,
59+
wantErr: true,
60+
},
61+
{
62+
name: "secrets are nil",
63+
args: args{
64+
b: &bundlev1.Bundle{
65+
Labels: map[string]string{
66+
"test": "true",
67+
},
68+
Annotations: map[string]string{
69+
"harp.elastic.co/v1/testing#bundlePurpose": "test",
70+
},
71+
Packages: []*bundlev1.Package{
72+
{
73+
Labels: map[string]string{
74+
"external": "true",
75+
},
76+
Annotations: map[string]string{
77+
"infosec.elastic.co/v1/SecretPolicy#rotationMethod": "ci",
78+
"infosec.elastic.co/v1/SecretPolicy#rotationPeriod": "90d",
79+
"infosec.elastic.co/v1/SecretPolicy#serviceType": "authentication",
80+
"infosec.elastic.co/v1/SecretPolicy#severity": "high",
81+
"infra.elastic.co/v1/CI#jobName": "rotate-external-api-key",
82+
"harp.elastic.co/v1/package#encryptionKeyAlias": "test",
83+
},
84+
Name: "app/production/testAccount/testService/v1.0.0/internalTestComponent/authentication/api_key",
85+
Secrets: nil,
86+
},
87+
},
88+
},
89+
},
90+
want: &bundlev1.RuleSet{
91+
ApiVersion: "harp.elastic.co/v1",
92+
Kind: "RuleSet",
93+
Meta: &bundlev1.RuleSetMeta{
94+
Description: "Generated from bundle content",
95+
},
96+
Spec: &bundlev1.RuleSetSpec{
97+
Rules: []*bundlev1.Rule{},
98+
},
99+
},
100+
wantErr: false,
101+
},
102+
{
103+
name: "secret data is nil",
104+
args: args{
105+
b: &bundlev1.Bundle{
106+
Labels: map[string]string{
107+
"test": "true",
108+
},
109+
Annotations: map[string]string{
110+
"harp.elastic.co/v1/testing#bundlePurpose": "test",
111+
},
112+
Packages: []*bundlev1.Package{
113+
{
114+
Labels: map[string]string{
115+
"external": "true",
116+
},
117+
Annotations: map[string]string{
118+
"infosec.elastic.co/v1/SecretPolicy#rotationMethod": "ci",
119+
"infosec.elastic.co/v1/SecretPolicy#rotationPeriod": "90d",
120+
"infosec.elastic.co/v1/SecretPolicy#serviceType": "authentication",
121+
"infosec.elastic.co/v1/SecretPolicy#severity": "high",
122+
"infra.elastic.co/v1/CI#jobName": "rotate-external-api-key",
123+
"harp.elastic.co/v1/package#encryptionKeyAlias": "test",
124+
},
125+
Name: "app/production/testAccount/testService/v1.0.0/internalTestComponent/authentication/api_key",
126+
Secrets: &bundlev1.SecretChain{
127+
Data: nil,
128+
},
129+
},
130+
},
131+
},
132+
},
133+
want: &bundlev1.RuleSet{
134+
ApiVersion: "harp.elastic.co/v1",
135+
Kind: "RuleSet",
136+
Meta: &bundlev1.RuleSetMeta{
137+
Description: "Generated from bundle content",
138+
},
139+
Spec: &bundlev1.RuleSetSpec{
140+
Rules: []*bundlev1.Rule{},
141+
},
142+
},
143+
wantErr: false,
144+
},
145+
{
146+
name: "package and secrets define with annotations and labels",
147+
args: args{
148+
b: &bundlev1.Bundle{
149+
Labels: map[string]string{
150+
"test": "true",
151+
},
152+
Annotations: map[string]string{
153+
"harp.elastic.co/v1/testing#bundlePurpose": "test",
154+
},
155+
Packages: []*bundlev1.Package{
156+
{
157+
Labels: map[string]string{
158+
"external": "true",
159+
},
160+
Annotations: map[string]string{
161+
"harp.elastic.co/v1/package#encryptionKeyAlias": "test",
162+
"infra.elastic.co/v1/CI#jobName": "rotate-external-api-key",
163+
"infosec.elastic.co/v1/SecretPolicy#rotationMethod": "ci",
164+
"infosec.elastic.co/v1/SecretPolicy#rotationPeriod": "90d",
165+
"infosec.elastic.co/v1/SecretPolicy#serviceType": "authentication",
166+
"infosec.elastic.co/v1/SecretPolicy#severity": "high",
167+
},
168+
Name: "app/production/testAccount/testService/v1.0.0/internalTestComponent/authentication/api_key",
169+
Secrets: &bundlev1.SecretChain{
170+
Labels: map[string]string{
171+
"vendor": "true",
172+
},
173+
Data: []*bundlev1.KV{
174+
{
175+
Key: "API_KEY",
176+
Type: "string",
177+
Value: []byte("3YGVuHwUqYVkjk-c6lQgfVQwFHawPG36TgAm72sPZGE="),
178+
},
179+
},
180+
},
181+
},
182+
},
183+
},
184+
},
185+
want: &bundlev1.RuleSet{
186+
ApiVersion: "harp.elastic.co/v1",
187+
Kind: "RuleSet",
188+
Meta: &bundlev1.RuleSetMeta{
189+
Description: "Generated from bundle content",
190+
Name: "D0QMaOw378tey2m_TvEuhBPkHOZQAgG88MUV4g6XiLk616urhu5an_hUf_N-k_-PF0TqslvGPFSpUUgZcxRhpg",
191+
},
192+
Spec: &bundlev1.RuleSetSpec{
193+
Rules: []*bundlev1.Rule{
194+
&bundlev1.Rule{
195+
Name: "LINT-D0QMaO-1",
196+
Path: "app/production/testAccount/testService/v1.0.0/internalTestComponent/authentication/api_key",
197+
Constraints: []string{
198+
"p.match_label(\"external\")",
199+
"p.match_annotation(\"harp.elastic.co/v1/package#encryptionKeyAlias\")",
200+
"p.match_annotation(\"infra.elastic.co/v1/CI#jobName\")",
201+
"p.match_annotation(\"infosec.elastic.co/v1/SecretPolicy#rotationMethod\")",
202+
"p.match_annotation(\"infosec.elastic.co/v1/SecretPolicy#rotationPeriod\")",
203+
"p.match_annotation(\"infosec.elastic.co/v1/SecretPolicy#serviceType\")",
204+
"p.match_annotation(\"infosec.elastic.co/v1/SecretPolicy#severity\")",
205+
"p.has_secret(\"API_KEY\")",
206+
},
207+
},
208+
},
209+
},
210+
},
211+
wantErr: false,
212+
},
213+
}
214+
for _, tt := range tests {
215+
t.Run(tt.name, func(t *testing.T) {
216+
got, err := FromBundle(tt.args.b)
217+
if (err != nil) != tt.wantErr {
218+
t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
219+
}
220+
221+
if !proto.Equal(got, tt.want) {
222+
t.Errorf("Ruleset not equal = %v, want %v", got, tt.want)
223+
}
224+
})
225+
}
226+
}

pkg/bundle/ruleset/package.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func Evaluate(ctx context.Context, b *bundlev1.Bundle, spec *bundlev1.RuleSet) e
5151

5252
// Process each rule
5353
for _, r := range spec.Spec.Rules {
54-
// Complie path matcher
54+
// Compile path matcher
5555
pathMatcher, err := glob.Compile(r.Path)
5656
if err != nil {
5757
return fmt.Errorf("unable to compile path matcher: %w", err)

pkg/sdk/value/encryption/transformer_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
"github.com/elastic/harp/pkg/sdk/value"
2929
"github.com/elastic/harp/pkg/sdk/value/encryption"
30+
3031
// Register encryption transformers
3132
_ "github.com/elastic/harp/pkg/sdk/value/encryption/aead"
3233
_ "github.com/elastic/harp/pkg/sdk/value/encryption/age"

pkg/tasks/bundle/decrypt_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/elastic/harp/pkg/sdk/cmdutil"
2727
"github.com/elastic/harp/pkg/sdk/value"
2828
"github.com/elastic/harp/pkg/sdk/value/encryption"
29+
2930
// Import for tests
3031
_ "github.com/elastic/harp/pkg/sdk/value/encryption/aead"
3132
"github.com/elastic/harp/pkg/sdk/value/identity"

pkg/tasks/container/recover_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/elastic/harp/pkg/sdk/cmdutil"
2727
"github.com/elastic/harp/pkg/sdk/value"
2828
"github.com/elastic/harp/pkg/sdk/value/encryption"
29+
2930
// Imported for tests
3031
_ "github.com/elastic/harp/pkg/sdk/value/encryption/jwe"
3132
"github.com/elastic/harp/pkg/sdk/value/identity"

0 commit comments

Comments
 (0)