Skip to content

Commit

Permalink
Add a noop remediator
Browse files Browse the repository at this point in the history
  • Loading branch information
jhrozek committed Oct 2, 2023
1 parent 3c3c312 commit e07e800
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 10 deletions.
43 changes: 43 additions & 0 deletions internal/engine/remediate/noop/noop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2023 Stacklok, Inc.
//
// Licensed 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 noop provides a fallback remediation engine for cases where
// no remediation is set.
package noop

import (
"context"

"google.golang.org/protobuf/reflect/protoreflect"

"github.com/stacklok/mediator/internal/engine/interfaces"
)

// Remediator is the structure backing the noop remediator
type Remediator struct{}

// NewNoopRemediate creates a new noop remediation engine
func NewNoopRemediate() (*Remediator, error) {
return &Remediator{}, nil
}

// Remediate actually performs the remediation
func (_ *Remediator) Remediate(
_ context.Context,
_ interfaces.RemediateActionOpt,
_ protoreflect.ProtoMessage,
_ map[string]any,
) error {
return nil
}
8 changes: 3 additions & 5 deletions internal/engine/remediate/remediate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,17 @@ import (
"fmt"

engif "github.com/stacklok/mediator/internal/engine/interfaces"
"github.com/stacklok/mediator/internal/engine/remediate/noop"
"github.com/stacklok/mediator/internal/engine/remediate/rest"
"github.com/stacklok/mediator/internal/providers"
pb "github.com/stacklok/mediator/pkg/api/protobuf/go/mediator/v1"
)

// ErrNoRemediation is returned when no remediation is configured
var ErrNoRemediation = fmt.Errorf("no remediation configured")

// NewRuleRemediator creates a new rule remediator
func NewRuleRemediator(rt *pb.RuleType, pbuild *providers.ProviderBuilder) (engif.Remediator, error) {
rem := rt.Def.GetRemediate()
if rem == nil {
return nil, ErrNoRemediation
return noop.NewNoopRemediate()
}

// nolint:revive // let's keep the switch here, it would be nicer to extend a switch in the future
Expand All @@ -46,5 +44,5 @@ func NewRuleRemediator(rt *pb.RuleType, pbuild *providers.ProviderBuilder) (engi
return rest.NewRestRemediate(rem.GetRest(), pbuild)
}

return nil, nil
return nil, fmt.Errorf("unknown remediation type: %s", rem.GetType())
}
133 changes: 133 additions & 0 deletions internal/engine/remediate/remediate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright 2023 Stacklok, Inc.
//
// Licensed 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 rule provides the CLI subcommand for managing rules

// Package remediate_test provides tests for the remediate package.
package remediate_test

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/stacklok/mediator/internal/db"
engif "github.com/stacklok/mediator/internal/engine/interfaces"
"github.com/stacklok/mediator/internal/engine/remediate"
"github.com/stacklok/mediator/internal/engine/remediate/noop"
"github.com/stacklok/mediator/internal/engine/remediate/rest"
"github.com/stacklok/mediator/internal/providers"
pb "github.com/stacklok/mediator/pkg/api/protobuf/go/mediator/v1"
provifv1 "github.com/stacklok/mediator/pkg/providers/v1"
)

var (
simpleBodyTemplate = "{\"foo\": \"bar\"}"
validProviderBuilder = providers.NewProviderBuilder(
&db.Provider{
Name: "github",
Version: provifv1.V1,
Implements: []db.ProviderType{
db.ProviderTypeRest,
},
Definition: json.RawMessage(`{
"rest": {
"base_url": "https://api.github.com/"
}
}`),
},
db.ProviderAccessToken{},
"token",
)
)

func TestNewRuleRemediator(t *testing.T) {
t.Parallel()

tests := []struct {
name string
ruleType *pb.RuleType
wantError bool
wantType engif.Remediator
provBuilder *providers.ProviderBuilder
}{
{
name: "Test Noop Remediate",
ruleType: &pb.RuleType{
Def: &pb.RuleType_Definition{}, // No remediate field set
},
wantError: false, // Expecting a NoopRemediate instance (or whichever condition you check for)
wantType: &noop.Remediator{},
},
{
name: "Test REST Remediate",
ruleType: &pb.RuleType{
Def: &pb.RuleType_Definition{
Remediate: &pb.RuleType_Definition_Remediate{
Type: rest.RemediateType,
Rest: &pb.RestType{
Method: "POST",
Endpoint: "{{.Policy.endpoint}}",
Body: &simpleBodyTemplate,
},
},
},
},
provBuilder: validProviderBuilder,
wantError: false, // Expecting a NoopRemediate instance (or whichever condition you check for)
wantType: &rest.Remediator{},
},
{
name: "Test Rest Remediate Without Config",
ruleType: &pb.RuleType{
Def: &pb.RuleType_Definition{
Remediate: &pb.RuleType_Definition_Remediate{
Type: rest.RemediateType,
},
},
},
wantError: true,
},
{
name: "Test made up remediator",
ruleType: &pb.RuleType{
Def: &pb.RuleType_Definition{
Remediate: &pb.RuleType_Definition_Remediate{
Type: "madeup",
},
},
},
wantError: true,
},
// ... Add more test cases as needed
}

for _, tt := range tests {
tt := tt

t.Run(tt.name, func(t *testing.T) {
t.Parallel()

result, err := remediate.NewRuleRemediator(tt.ruleType, tt.provBuilder)
if tt.wantError {
require.Error(t, err)
return
}

require.NoError(t, err)
assert.IsType(t, tt.wantType, result) // Or whichever condition you check for
})
}
}
6 changes: 1 addition & 5 deletions internal/engine/rule_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,7 @@ func NewRuleTypeEngine(rt *mediatorv1.RuleType, cli *providers.ProviderBuilder)
}

rrem, err := remediate.NewRuleRemediator(rt, cli)
if errors.Is(err, remediate.ErrNoRemediation) {
// we should be graceful about not having a remediator
// TODO: return a noop remediator instead that would log that there's nothing configured?
rrem = nil
} else if err != nil {
if err != nil {
return nil, fmt.Errorf("cannot create rule remediator: %w", err)
}

Expand Down

0 comments on commit e07e800

Please sign in to comment.