Skip to content

Commit

Permalink
Merge pull request #717 from stacklok/rule-params
Browse files Browse the repository at this point in the history
rules: Use JSON schema for parameter validations
  • Loading branch information
JAORMX authored Aug 23, 2023
2 parents 0b0f717 + 0397b98 commit 3f64ae7
Show file tree
Hide file tree
Showing 16 changed files with 1,105 additions and 1,339 deletions.
52 changes: 12 additions & 40 deletions cmd/cli/app/rule_type/rtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func testCmdRun(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("error reading fragment from file: %w", err)
}

rules, err := getRelevantRules(rt, p)
rules, err := engine.GetRulesFromPolicyOfType(p, rt)
if err != nil {
return fmt.Errorf("error getting relevant fragment: %w", err)
}
Expand All @@ -116,16 +116,22 @@ func runEvaluationForRules(eng *engine.RuleTypeEngine, ent protoreflect.ProtoMes
for idx := range frags {
frag := frags[idx]

// We already do validation of the rule definition when parsing.
// It's safe to simply
def := frag.Def.AsMap()
err := eng.ValidateAgainstSchema(def)
val := eng.GetRuleInstanceValidator()
err := val.ValidateRuleDefAgainstSchema(def)
if err != nil {
return fmt.Errorf("error validating rule against schema: %w", err)
}
fmt.Printf("Policy valid according to the JSON schema!\n")

params := frag.GetParams().AsMap()
var params map[string]any
if err := val.ValidateParamsAgainstSchema(frag.GetParams()); err != nil {
return fmt.Errorf("error validating params against schema: %w", err)
}

if frag.GetParams() != nil {
params = frag.GetParams().AsMap()
}

if err := eng.Eval(context.Background(), ent, def, params); err != nil {
return fmt.Errorf("error evaluating rule type: %w", err)
Expand All @@ -143,18 +149,7 @@ func readRuleTypeFromFile(fpath string) (*pb.RuleType, error) {
return nil, fmt.Errorf("error opening file: %w", err)
}

// We transcode to JSON so we can decode it straight to the protobuf structure
w := &bytes.Buffer{}
if err := util.TranscodeYAMLToJSON(f, w); err != nil {
return nil, fmt.Errorf("error converting yaml to json: %w", err)
}

r := &pb.RuleType{}
if err := json.NewDecoder(w).Decode(r); err != nil {
return nil, fmt.Errorf("error decoding json: %w", err)
}

return r, nil
return engine.ParseRuleType(f)
}

// readEntityFromFile reads an entity from a file and returns it as a protobuf
Expand Down Expand Up @@ -189,29 +184,6 @@ func readEntityFromFile(fpath string, entType pb.Entity) (protoreflect.ProtoMess
return out, nil
}

// getRelevantRules returns the relevant rules for the rule type
func getRelevantRules(rt *pb.RuleType, p *pb.PipelinePolicy) ([]*pb.PipelinePolicy_Rule, error) {
contextualRules, err := engine.GetRulesForEntity(p, entities.FromString(rt.Def.InEntity))
if err != nil {
return nil, fmt.Errorf("error getting rules for entity: %w", err)
}

rules := []*pb.PipelinePolicy_Rule{}
err = engine.TraverseRules(contextualRules, func(r *pb.PipelinePolicy_Rule) error {
if r.Type == rt.Name {
rules = append(rules, r)
}
return nil
})

// This shouldn't happen
if err != nil {
return nil, fmt.Errorf("error traversing rules: %w", err)
}

return rules, nil
}

// getProviderClient returns a client for the provider specified in the rule type
// definition.
// TODO: This should be moved to a provider package and we should have some
Expand Down
15 changes: 4 additions & 11 deletions cmd/cli/app/rule_type/rule_type_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
package rule_type

import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -26,6 +24,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/stacklok/mediator/internal/engine"
"github.com/stacklok/mediator/internal/util"
pb "github.com/stacklok/mediator/pkg/generated/protobuf/go/mediator/v1"
)
Expand Down Expand Up @@ -77,15 +76,9 @@ within a mediator control plane.`,
ctx, cancel := util.GetAppContext()
defer cancel()

// We transcode to JSON so we can decode it straight to the protobuf structure
w := &bytes.Buffer{}
if err := util.TranscodeYAMLToJSON(preader, w); err != nil {
return fmt.Errorf("error converting yaml to json: %w", err)
}

r := &pb.RuleType{}
if err := json.NewDecoder(w).Decode(r); err != nil {
return fmt.Errorf("error decoding json: %w", err)
r, err := engine.ParseRuleType(preader)
if err != nil {
return fmt.Errorf("error parsing rule type: %w", err)
}

// create a policy
Expand Down
1 change: 0 additions & 1 deletion database/migrations/000001_init.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ CREATE TABLE rule_type (
provider TEXT NOT NULL,
group_id INTEGER NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
definition JSONB NOT NULL,
params JSONB NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
Expand Down
5 changes: 2 additions & 3 deletions database/query/rule_types.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ INSERT INTO rule_type (
name,
provider,
group_id,
definition,
params) VALUES ($1, $2, $3, sqlc.arg(definition)::jsonb, sqlc.arg(params)::jsonb) RETURNING *;
definition) VALUES ($1, $2, $3, sqlc.arg(definition)::jsonb) RETURNING *;

-- name: ListRuleTypesByProviderAndGroup :many
SELECT * FROM rule_type WHERE provider = $1 AND group_id = $2;
Expand All @@ -19,4 +18,4 @@ SELECT * FROM rule_type WHERE provider = $1 AND group_id = $2 AND name = $3;
DELETE FROM rule_type WHERE id = $1;

-- name: UpdateRuleType :exec
UPDATE rule_type SET definition = sqlc.arg(definition)::jsonb, params = sqlc.arg(params)::jsonb WHERE id = $1;
UPDATE rule_type SET definition = sqlc.arg(definition)::jsonb WHERE id = $1;
55 changes: 2 additions & 53 deletions docs/docs/protodocs/proto.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 12 additions & 8 deletions examples/github/rule-types/artifact_signature.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@ name: artifact_signature
context:
provider: github
group: Root Group
params:
entries:
- name: artifactName
type: string
description: "The name of the artifact to check."
- name: tag
type: string
description: "The tag of the artifact to check."
def:
# Defines the section of the pipeline the rule will appear in.
# This will affect the template that is used to render multiple parts
# of the rule.
in_entity: artifact
# Defines the schema for parameters that will be passed to the rule
param_schema:
properties:
artifactName:
type: string
description: "The name of the artifact to check."
tag:
type: string
description: "The tag of the artifact to check."
required:
- artifactName
- tag
# Defines the schema for writing a rule with this rule being checked
rule_schema:
properties:
Expand Down
13 changes: 8 additions & 5 deletions examples/github/rule-types/branch_protection.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ name: branch_protection
context:
provider: github
group: Root Group
params:
entries:
- name: branch
type: string
description: "The name of the branch to check."
def:
# Defines the section of the pipeline the rule will appear in.
# This will affect the template that is used to render multiple parts
# of the rule.
in_entity: repository
# Defines the schema for parameters that will be passed to the rule
param_schema:
properties:
branch:
type: string
description: "The name of the branch to check."
required:
- branch
# Defines the schema for writing a rule with this rule being checked
rule_schema:
properties:
Expand Down
Loading

0 comments on commit 3f64ae7

Please sign in to comment.