diff --git a/pkg/bundle/ruleset/bundle.go b/pkg/bundle/ruleset/bundle.go index 4b2f26a2..33443153 100644 --- a/pkg/bundle/ruleset/bundle.go +++ b/pkg/bundle/ruleset/bundle.go @@ -73,6 +73,16 @@ func FromBundle(b *bundlev1.Bundle) (*bundlev1.RuleSet, error) { Constraints: []string{}, } + // Process the labels for each secret + for label := range p.Labels { + r.Constraints = append(r.Constraints, fmt.Sprintf(`p.match_label(%q)`, label)) + } + + // Process the annotations for each secret + for annotation := range p.Annotations { + r.Constraints = append(r.Constraints, fmt.Sprintf(`p.match_annotation(%q)`, annotation)) + } + // Process each secret for _, s := range p.Secrets.Data { r.Constraints = append(r.Constraints, fmt.Sprintf(`p.has_secret(%q)`, s.Key)) diff --git a/pkg/bundle/ruleset/bundle_test.go b/pkg/bundle/ruleset/bundle_test.go new file mode 100644 index 00000000..50a160d9 --- /dev/null +++ b/pkg/bundle/ruleset/bundle_test.go @@ -0,0 +1,226 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package ruleset + +import ( + "testing" + + bundlev1 "github.com/elastic/harp/api/gen/go/harp/bundle/v1" + "github.com/golang/protobuf/proto" +) + +func TestFromBundle(t *testing.T) { + type args struct { + b *bundlev1.Bundle + } + tests := []struct { + name string + args args + want *bundlev1.RuleSet + wantErr bool + }{ + { + name: "nil", + args: args{ + b: nil, + }, + want: nil, + wantErr: true, + }, + { + name: "packages are nil", + args: args{ + b: &bundlev1.Bundle{ + Labels: map[string]string{ + "test": "true", + }, + Annotations: map[string]string{ + "harp.elastic.co/v1/testing#bundlePurpose": "test", + }, + Packages: nil, + }, + }, + want: nil, + wantErr: true, + }, + { + name: "secrets are nil", + args: args{ + b: &bundlev1.Bundle{ + Labels: map[string]string{ + "test": "true", + }, + Annotations: map[string]string{ + "harp.elastic.co/v1/testing#bundlePurpose": "test", + }, + Packages: []*bundlev1.Package{ + { + Labels: map[string]string{ + "external": "true", + }, + Annotations: map[string]string{ + "infosec.elastic.co/v1/SecretPolicy#rotationMethod": "ci", + "infosec.elastic.co/v1/SecretPolicy#rotationPeriod": "90d", + "infosec.elastic.co/v1/SecretPolicy#serviceType": "authentication", + "infosec.elastic.co/v1/SecretPolicy#severity": "high", + "infra.elastic.co/v1/CI#jobName": "rotate-external-api-key", + "harp.elastic.co/v1/package#encryptionKeyAlias": "test", + }, + Name: "app/production/testAccount/testService/v1.0.0/internalTestComponent/authentication/api_key", + Secrets: nil, + }, + }, + }, + }, + want: &bundlev1.RuleSet{ + ApiVersion: "harp.elastic.co/v1", + Kind: "RuleSet", + Meta: &bundlev1.RuleSetMeta{ + Description: "Generated from bundle content", + }, + Spec: &bundlev1.RuleSetSpec{ + Rules: []*bundlev1.Rule{}, + }, + }, + wantErr: false, + }, + { + name: "secret data is nil", + args: args{ + b: &bundlev1.Bundle{ + Labels: map[string]string{ + "test": "true", + }, + Annotations: map[string]string{ + "harp.elastic.co/v1/testing#bundlePurpose": "test", + }, + Packages: []*bundlev1.Package{ + { + Labels: map[string]string{ + "external": "true", + }, + Annotations: map[string]string{ + "infosec.elastic.co/v1/SecretPolicy#rotationMethod": "ci", + "infosec.elastic.co/v1/SecretPolicy#rotationPeriod": "90d", + "infosec.elastic.co/v1/SecretPolicy#serviceType": "authentication", + "infosec.elastic.co/v1/SecretPolicy#severity": "high", + "infra.elastic.co/v1/CI#jobName": "rotate-external-api-key", + "harp.elastic.co/v1/package#encryptionKeyAlias": "test", + }, + Name: "app/production/testAccount/testService/v1.0.0/internalTestComponent/authentication/api_key", + Secrets: &bundlev1.SecretChain{ + Data: nil, + }, + }, + }, + }, + }, + want: &bundlev1.RuleSet{ + ApiVersion: "harp.elastic.co/v1", + Kind: "RuleSet", + Meta: &bundlev1.RuleSetMeta{ + Description: "Generated from bundle content", + }, + Spec: &bundlev1.RuleSetSpec{ + Rules: []*bundlev1.Rule{}, + }, + }, + wantErr: false, + }, + { + name: "package and secrets define with annotations and labels", + args: args{ + b: &bundlev1.Bundle{ + Labels: map[string]string{ + "test": "true", + }, + Annotations: map[string]string{ + "harp.elastic.co/v1/testing#bundlePurpose": "test", + }, + Packages: []*bundlev1.Package{ + { + Labels: map[string]string{ + "external": "true", + }, + Annotations: map[string]string{ + "harp.elastic.co/v1/package#encryptionKeyAlias": "test", + "infra.elastic.co/v1/CI#jobName": "rotate-external-api-key", + "infosec.elastic.co/v1/SecretPolicy#rotationMethod": "ci", + "infosec.elastic.co/v1/SecretPolicy#rotationPeriod": "90d", + "infosec.elastic.co/v1/SecretPolicy#serviceType": "authentication", + "infosec.elastic.co/v1/SecretPolicy#severity": "high", + }, + Name: "app/production/testAccount/testService/v1.0.0/internalTestComponent/authentication/api_key", + Secrets: &bundlev1.SecretChain{ + Labels: map[string]string{ + "vendor": "true", + }, + Data: []*bundlev1.KV{ + { + Key: "API_KEY", + Type: "string", + Value: []byte("3YGVuHwUqYVkjk-c6lQgfVQwFHawPG36TgAm72sPZGE="), + }, + }, + }, + }, + }, + }, + }, + want: &bundlev1.RuleSet{ + ApiVersion: "harp.elastic.co/v1", + Kind: "RuleSet", + Meta: &bundlev1.RuleSetMeta{ + Description: "Generated from bundle content", + Name: "D0QMaOw378tey2m_TvEuhBPkHOZQAgG88MUV4g6XiLk616urhu5an_hUf_N-k_-PF0TqslvGPFSpUUgZcxRhpg", + }, + Spec: &bundlev1.RuleSetSpec{ + Rules: []*bundlev1.Rule{ + &bundlev1.Rule{ + Name: "LINT-D0QMaO-1", + Path: "app/production/testAccount/testService/v1.0.0/internalTestComponent/authentication/api_key", + Constraints: []string{ + "p.match_label(\"external\")", + "p.match_annotation(\"harp.elastic.co/v1/package#encryptionKeyAlias\")", + "p.match_annotation(\"infra.elastic.co/v1/CI#jobName\")", + "p.match_annotation(\"infosec.elastic.co/v1/SecretPolicy#rotationMethod\")", + "p.match_annotation(\"infosec.elastic.co/v1/SecretPolicy#rotationPeriod\")", + "p.match_annotation(\"infosec.elastic.co/v1/SecretPolicy#serviceType\")", + "p.match_annotation(\"infosec.elastic.co/v1/SecretPolicy#severity\")", + "p.has_secret(\"API_KEY\")", + }, + }, + }, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := FromBundle(tt.args.b) + if (err != nil) != tt.wantErr { + t.Errorf("error = %v, wantErr %v", err, tt.wantErr) + } + + if !proto.Equal(got, tt.want) { + t.Errorf("Ruleset not equal = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/bundle/ruleset/package.go b/pkg/bundle/ruleset/package.go index a83dd6df..349e21ff 100644 --- a/pkg/bundle/ruleset/package.go +++ b/pkg/bundle/ruleset/package.go @@ -51,7 +51,7 @@ func Evaluate(ctx context.Context, b *bundlev1.Bundle, spec *bundlev1.RuleSet) e // Process each rule for _, r := range spec.Spec.Rules { - // Complie path matcher + // Compile path matcher pathMatcher, err := glob.Compile(r.Path) if err != nil { return fmt.Errorf("unable to compile path matcher: %w", err) diff --git a/pkg/sdk/value/encryption/transformer_test.go b/pkg/sdk/value/encryption/transformer_test.go index ae63ab2e..854fb618 100644 --- a/pkg/sdk/value/encryption/transformer_test.go +++ b/pkg/sdk/value/encryption/transformer_test.go @@ -27,6 +27,7 @@ import ( "github.com/elastic/harp/pkg/sdk/value" "github.com/elastic/harp/pkg/sdk/value/encryption" + // Register encryption transformers _ "github.com/elastic/harp/pkg/sdk/value/encryption/aead" _ "github.com/elastic/harp/pkg/sdk/value/encryption/age" diff --git a/pkg/tasks/bundle/decrypt_test.go b/pkg/tasks/bundle/decrypt_test.go index 1f3f6e7f..e688971c 100644 --- a/pkg/tasks/bundle/decrypt_test.go +++ b/pkg/tasks/bundle/decrypt_test.go @@ -26,6 +26,7 @@ import ( "github.com/elastic/harp/pkg/sdk/cmdutil" "github.com/elastic/harp/pkg/sdk/value" "github.com/elastic/harp/pkg/sdk/value/encryption" + // Import for tests _ "github.com/elastic/harp/pkg/sdk/value/encryption/aead" "github.com/elastic/harp/pkg/sdk/value/identity" diff --git a/pkg/tasks/container/recover_test.go b/pkg/tasks/container/recover_test.go index 24b9a42d..9a9862c6 100644 --- a/pkg/tasks/container/recover_test.go +++ b/pkg/tasks/container/recover_test.go @@ -26,6 +26,7 @@ import ( "github.com/elastic/harp/pkg/sdk/cmdutil" "github.com/elastic/harp/pkg/sdk/value" "github.com/elastic/harp/pkg/sdk/value/encryption" + // Imported for tests _ "github.com/elastic/harp/pkg/sdk/value/encryption/jwe" "github.com/elastic/harp/pkg/sdk/value/identity"