From 14c7f6e7b4b9c03dfab77564a17fde284a9ece2b Mon Sep 17 00:00:00 2001 From: Steve Tooke Date: Thu, 2 Apr 2026 08:29:14 +0100 Subject: [PATCH 1/7] green: Evaluate accepts params and passes them as data.params to OPA Extends the Evaluate function signature with variadic params. When provided, creates an inmem store so policies can read data.params. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/evaluate/rego.go | 32 +++++++++++++++++++++++++------- internal/evaluate/rego_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/internal/evaluate/rego.go b/internal/evaluate/rego.go index 6e89e43c6..33a31e232 100644 --- a/internal/evaluate/rego.go +++ b/internal/evaluate/rego.go @@ -6,6 +6,7 @@ import ( "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/rego" + "github.com/open-policy-agent/opa/v1/storage/inmem" ) // Result holds the outcome of a policy evaluation. @@ -16,18 +17,25 @@ type Result struct { // Evaluate evaluates a Rego policy against the given input. // The policy must use `package policy` and declare an `allow` rule. -func Evaluate(policySource string, input interface{}) (*Result, error) { +// An optional params map can be provided to populate data.params in the policy. +func Evaluate(policySource string, input interface{}, params ...map[string]interface{}) (*Result, error) { if err := validatePolicy(policySource); err != nil { return nil, err } ctx := context.Background() - r := rego.New( + opts := []func(*rego.Rego){ rego.Query("data.policy.allow"), rego.Module("policy.rego", policySource), rego.Input(input), - ) + } + if len(params) > 0 && params[0] != nil { + store := inmem.NewFromObject(map[string]interface{}{"params": params[0]}) + opts = append(opts, rego.Store(store)) + } + + r := rego.New(opts...) rs, err := r.Eval(ctx) if err != nil { @@ -46,7 +54,11 @@ func Evaluate(policySource string, input interface{}) (*Result, error) { result := &Result{Allow: allow} if !result.Allow { - violations, err := collectViolations(ctx, policySource, input) + var p map[string]interface{} + if len(params) > 0 { + p = params[0] + } + violations, err := collectViolations(ctx, policySource, input, p) if err != nil { return nil, err } @@ -81,12 +93,18 @@ func validatePolicy(policySource string) error { return nil } -func collectViolations(ctx context.Context, policySource string, input interface{}) ([]string, error) { - r := rego.New( +func collectViolations(ctx context.Context, policySource string, input interface{}, params map[string]interface{}) ([]string, error) { + opts := []func(*rego.Rego){ rego.Query("data.policy.violations"), rego.Module("policy.rego", policySource), rego.Input(input), - ) + } + if params != nil { + store := inmem.NewFromObject(map[string]interface{}{"params": params}) + opts = append(opts, rego.Store(store)) + } + + r := rego.New(opts...) rs, err := r.Eval(ctx) if err != nil { diff --git a/internal/evaluate/rego_test.go b/internal/evaluate/rego_test.go index c3953710d..b007108c8 100644 --- a/internal/evaluate/rego_test.go +++ b/internal/evaluate/rego_test.go @@ -106,3 +106,31 @@ allow = {{{ require.Error(t, err) require.Contains(t, err.Error(), "parse") } + +func TestEvaluate_ParamsProvided(t *testing.T) { + policy := `package policy + +import rego.v1 + +default threshold := 10 + +threshold := data.params.threshold if { data.params.threshold } + +allow if { input.score >= threshold } + +violations contains msg if { + input.score < threshold + msg := sprintf("score %d is below threshold %d", [input.score, threshold]) +} +` + input := map[string]interface{}{ + "score": 5, + } + params := map[string]interface{}{ + "threshold": 3, + } + + result, err := Evaluate(policy, input, params) + require.NoError(t, err) + require.True(t, result.Allow, "score 5 should pass threshold 3") +} From 088a01e6ca36ab9d2e70d8b85059a6ca0f0e2df2 Mon Sep 17 00:00:00 2001 From: Steve Tooke Date: Thu, 2 Apr 2026 08:30:05 +0100 Subject: [PATCH 2/7] green: params default fallback and ignored-by-policy tests Adds tests confirming that when no params are provided the policy's default value applies, and that supplying unused params has no effect. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/evaluate/rego_test.go | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/internal/evaluate/rego_test.go b/internal/evaluate/rego_test.go index b007108c8..cb449375c 100644 --- a/internal/evaluate/rego_test.go +++ b/internal/evaluate/rego_test.go @@ -112,6 +112,8 @@ func TestEvaluate_ParamsProvided(t *testing.T) { import rego.v1 +default allow := false + default threshold := 10 threshold := data.params.threshold if { data.params.threshold } @@ -134,3 +136,48 @@ violations contains msg if { require.NoError(t, err) require.True(t, result.Allow, "score 5 should pass threshold 3") } + +func TestEvaluate_ParamsDefault(t *testing.T) { + policy := `package policy + +import rego.v1 + +default allow := false + +default threshold := 10 + +threshold := data.params.threshold if { data.params.threshold } + +allow if { input.score >= threshold } + +violations contains msg if { + input.score < threshold + msg := sprintf("score %d is below threshold %d", [input.score, threshold]) +} +` + input := map[string]interface{}{ + "score": 5, + } + + // No params — policy uses default threshold of 10 + result, err := Evaluate(policy, input) + require.NoError(t, err) + require.False(t, result.Allow, "score 5 should fail default threshold 10") + require.Len(t, result.Violations, 1) + require.Contains(t, result.Violations[0], "below threshold 10") +} + +func TestEvaluate_ParamsIgnoredByPolicy(t *testing.T) { + policy := `package policy + +allow = true +` + input := map[string]interface{}{} + params := map[string]interface{}{ + "unused_key": "unused_value", + } + + result, err := Evaluate(policy, input, params) + require.NoError(t, err) + require.True(t, result.Allow, "params not referenced by policy should have no effect") +} From f3d28313e4db0260c032324700763eb6d8b7d06b Mon Sep 17 00:00:00 2001 From: Steve Tooke Date: Thu, 2 Apr 2026 08:33:27 +0100 Subject: [PATCH 3/7] green: add --params flag to all evaluate commands Adds --params flag to commonEvaluateOptions, accepting inline JSON or @file.json. Params are passed to OPA as data.params so policies can define configurable thresholds with defaults. Co-Authored-By: Claude Opus 4.6 (1M context) --- cmd/kosli/evaluateHelpers.go | 30 +++++++++++++++++-- cmd/kosli/evaluateInput.go | 7 ++++- cmd/kosli/evaluateInput_test.go | 16 ++++++++++ cmd/kosli/evaluateTrail.go | 7 ++++- cmd/kosli/evaluateTrails.go | 7 ++++- .../evaluate/params-low-threshold.json | 1 + cmd/kosli/testdata/evaluate/score-input.json | 1 + .../policies/check-params-threshold.rego | 16 ++++++++++ 8 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 cmd/kosli/testdata/evaluate/params-low-threshold.json create mode 100644 cmd/kosli/testdata/evaluate/score-input.json create mode 100644 cmd/kosli/testdata/policies/check-params-threshold.rego diff --git a/cmd/kosli/evaluateHelpers.go b/cmd/kosli/evaluateHelpers.go index b3de27ea9..8070d8b5f 100644 --- a/cmd/kosli/evaluateHelpers.go +++ b/cmd/kosli/evaluateHelpers.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "os" + "strings" "github.com/kosli-dev/cli/internal/evaluate" "github.com/kosli-dev/cli/internal/output" @@ -20,6 +21,7 @@ type commonEvaluateOptions struct { output string showInput bool attestations []string + params string } func (o *commonEvaluateOptions) addFlags(cmd *cobra.Command, policyDesc string) { @@ -28,6 +30,7 @@ func (o *commonEvaluateOptions) addFlags(cmd *cobra.Command, policyDesc string) cmd.Flags().StringVarP(&o.output, "output", "o", "table", outputFlag) cmd.Flags().BoolVar(&o.showInput, "show-input", false, "[optional] Include the policy input data in the output.") cmd.Flags().StringSliceVar(&o.attestations, "attestations", nil, "[optional] Limit which attestations are included. Plain name for trail-level, dot-qualified (artifact.name) for artifact-level.") + cmd.Flags().StringVar(&o.params, "params", "", "[optional] Policy parameters as inline JSON or @file.json. Available in policies as data.params.") } func fetchAndEnrichTrail(flowName, trailName string, attestations []string) (interface{}, error) { @@ -90,13 +93,36 @@ func fetchAndEnrichTrail(flowName, trailName string, attestations []string) (int return trailData, nil } -func evaluateAndPrintResult(out io.Writer, policyFile string, input map[string]interface{}, outputFormat string, showInput bool) error { +func parseParams(raw string) (map[string]interface{}, error) { + if raw == "" { + return nil, nil + } + + var jsonBytes []byte + if strings.HasPrefix(raw, "@") { + var err error + jsonBytes, err = os.ReadFile(raw[1:]) + if err != nil { + return nil, fmt.Errorf("failed to read --params file: %w", err) + } + } else { + jsonBytes = []byte(raw) + } + + var params map[string]interface{} + if err := json.Unmarshal(jsonBytes, ¶ms); err != nil { + return nil, fmt.Errorf("failed to parse --params: %w", err) + } + return params, nil +} + +func evaluateAndPrintResult(out io.Writer, policyFile string, input map[string]interface{}, outputFormat string, showInput bool, params map[string]interface{}) error { policySource, err := os.ReadFile(policyFile) if err != nil { return fmt.Errorf("failed to read policy file: %w", err) } - result, err := evaluate.Evaluate(string(policySource), input) + result, err := evaluate.Evaluate(string(policySource), input, params) if err != nil { return err } diff --git a/cmd/kosli/evaluateInput.go b/cmd/kosli/evaluateInput.go index 55f1e3ec7..abce0005d 100644 --- a/cmd/kosli/evaluateInput.go +++ b/cmd/kosli/evaluateInput.go @@ -94,7 +94,12 @@ func (o *evaluateInputOptions) run(out io.Writer, in io.Reader) error { return err } - return evaluateAndPrintResult(out, o.policyFile, input, o.output, o.showInput) + params, err := parseParams(o.params) + if err != nil { + return err + } + + return evaluateAndPrintResult(out, o.policyFile, input, o.output, o.showInput, params) } func loadInputFromFile(filePath string) (result map[string]interface{}, err error) { diff --git a/cmd/kosli/evaluateInput_test.go b/cmd/kosli/evaluateInput_test.go index edd64d131..df293333f 100644 --- a/cmd/kosli/evaluateInput_test.go +++ b/cmd/kosli/evaluateInput_test.go @@ -82,6 +82,22 @@ func (suite *EvaluateInputCommandTestSuite) TestEvaluateInputCmd() { {"input.trail.name", "test-trail"}, }, }, + { + name: "inline --params overrides policy default threshold", + cmd: `evaluate input --input-file testdata/evaluate/score-input.json --policy testdata/policies/check-params-threshold.rego --params '{"threshold":3}'`, + goldenRegex: `RESULT:\s+ALLOWED`, + }, + { + name: "--params from file overrides policy default threshold", + cmd: "evaluate input --input-file testdata/evaluate/score-input.json --policy testdata/policies/check-params-threshold.rego --params @testdata/evaluate/params-low-threshold.json", + goldenRegex: `RESULT:\s+ALLOWED`, + }, + { + wantError: true, + name: "--params with invalid JSON returns error", + cmd: "evaluate input --input-file testdata/evaluate/score-input.json --policy testdata/policies/allow-all.rego --params not-json", + goldenRegex: `failed to parse --params`, + }, } runTestCmd(suite.T(), tests) } diff --git a/cmd/kosli/evaluateTrail.go b/cmd/kosli/evaluateTrail.go index c2bd171d4..174ea7d75 100644 --- a/cmd/kosli/evaluateTrail.go +++ b/cmd/kosli/evaluateTrail.go @@ -81,9 +81,14 @@ func (o *evaluateTrailOptions) run(out io.Writer, args []string) error { return err } + params, err := parseParams(o.params) + if err != nil { + return err + } + input := map[string]interface{}{ "trail": trailData, } - return evaluateAndPrintResult(out, o.policyFile, input, o.output, o.showInput) + return evaluateAndPrintResult(out, o.policyFile, input, o.output, o.showInput, params) } diff --git a/cmd/kosli/evaluateTrails.go b/cmd/kosli/evaluateTrails.go index 11331b025..b42ec00fd 100644 --- a/cmd/kosli/evaluateTrails.go +++ b/cmd/kosli/evaluateTrails.go @@ -86,9 +86,14 @@ func (o *evaluateTrailsOptions) run(out io.Writer, args []string) error { trails = append(trails, trailData) } + params, err := parseParams(o.params) + if err != nil { + return err + } + input := map[string]interface{}{ "trails": trails, } - return evaluateAndPrintResult(out, o.policyFile, input, o.output, o.showInput) + return evaluateAndPrintResult(out, o.policyFile, input, o.output, o.showInput, params) } diff --git a/cmd/kosli/testdata/evaluate/params-low-threshold.json b/cmd/kosli/testdata/evaluate/params-low-threshold.json new file mode 100644 index 000000000..e08bb40eb --- /dev/null +++ b/cmd/kosli/testdata/evaluate/params-low-threshold.json @@ -0,0 +1 @@ +{"threshold": 3} diff --git a/cmd/kosli/testdata/evaluate/score-input.json b/cmd/kosli/testdata/evaluate/score-input.json new file mode 100644 index 000000000..2fa49cc3d --- /dev/null +++ b/cmd/kosli/testdata/evaluate/score-input.json @@ -0,0 +1 @@ +{"score": 5} diff --git a/cmd/kosli/testdata/policies/check-params-threshold.rego b/cmd/kosli/testdata/policies/check-params-threshold.rego new file mode 100644 index 000000000..58b8a1976 --- /dev/null +++ b/cmd/kosli/testdata/policies/check-params-threshold.rego @@ -0,0 +1,16 @@ +package policy + +import rego.v1 + +default allow := false + +default threshold := 10 + +threshold := data.params.threshold if { data.params.threshold } + +allow if { input.score >= threshold } + +violations contains msg if { + input.score < threshold + msg := sprintf("score %d is below threshold %d", [input.score, threshold]) +} From e42d39c87dfda6c97a23384bd54ae73360fcdaac Mon Sep 17 00:00:00 2001 From: Steve Tooke Date: Thu, 2 Apr 2026 08:34:21 +0100 Subject: [PATCH 4/7] green: show-input includes params in JSON output When --show-input is active and --params are provided, the params appear alongside input in the audit result output. Co-Authored-By: Claude Opus 4.6 (1M context) --- cmd/kosli/evaluateHelpers.go | 3 +++ cmd/kosli/evaluateInput_test.go | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/cmd/kosli/evaluateHelpers.go b/cmd/kosli/evaluateHelpers.go index 8070d8b5f..7a30f6228 100644 --- a/cmd/kosli/evaluateHelpers.go +++ b/cmd/kosli/evaluateHelpers.go @@ -134,6 +134,9 @@ func evaluateAndPrintResult(out io.Writer, policyFile string, input map[string]i if showInput { auditResult["input"] = input } + if showInput && params != nil { + auditResult["params"] = params + } raw, err := json.Marshal(auditResult) if err != nil { diff --git a/cmd/kosli/evaluateInput_test.go b/cmd/kosli/evaluateInput_test.go index df293333f..cdb651062 100644 --- a/cmd/kosli/evaluateInput_test.go +++ b/cmd/kosli/evaluateInput_test.go @@ -98,6 +98,15 @@ func (suite *EvaluateInputCommandTestSuite) TestEvaluateInputCmd() { cmd: "evaluate input --input-file testdata/evaluate/score-input.json --policy testdata/policies/allow-all.rego --params not-json", goldenRegex: `failed to parse --params`, }, + { + name: "show-input with params includes params in JSON output", + cmd: `evaluate input --input-file testdata/evaluate/score-input.json --policy testdata/policies/check-params-threshold.rego --params '{"threshold":3}' --output json --show-input`, + goldenJson: []jsonCheck{ + {"allow", true}, + {"input.score", float64(5)}, + {"params.threshold", float64(3)}, + }, + }, } runTestCmd(suite.T(), tests) } From 5604622f4c26a9cc3718a1f337edb9e640b6a133 Mon Sep 17 00:00:00 2001 From: Steve Tooke Date: Thu, 2 Apr 2026 08:35:52 +0100 Subject: [PATCH 5/7] docs: add --params examples and descriptions to evaluate commands Updates help text and examples for evaluate, evaluate trail, evaluate trails, and evaluate input to document the --params flag. Co-Authored-By: Claude Opus 4.6 (1M context) --- TODO.md | 7 +++++++ cmd/kosli/evaluate.go | 6 +++++- cmd/kosli/evaluateInput.go | 19 +++++++++++++++++-- cmd/kosli/evaluateTrail.go | 16 ++++++++++++++++ cmd/kosli/evaluateTrails.go | 8 ++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index fd7e269a9..7a1ff51d2 100644 --- a/TODO.md +++ b/TODO.md @@ -47,3 +47,10 @@ - [x] Refactor: use `cmd.InOrStdin()` for testable stdin - [x] Refactor: embed `commonEvaluateOptions` to remove flag duplication - [x] Slice 5: Detect terminal stdin and error when no input is piped + +## Add `--params` flag to `kosli evaluate` commands + +- [x] Slice 1: `evaluate.Evaluate()` accepts params, passes via OPA data store +- [x] Slice 2: Add `--params` flag across all three commands +- [x] Slice 3: Show params in `--show-input` output +- [ ] Slice 4: Update help text and examples ← active diff --git a/cmd/kosli/evaluate.go b/cmd/kosli/evaluate.go index da803937f..08f431ba7 100644 --- a/cmd/kosli/evaluate.go +++ b/cmd/kosli/evaluate.go @@ -18,7 +18,11 @@ Use ` + "`evaluate input`" + ` to evaluate a local JSON file or stdin without an The policy must use ` + "`package policy`" + ` and define an ` + "`allow`" + ` rule. An optional ` + "`violations`" + ` rule (a set of strings) can provide human-readable denial reasons. -The command exits with code 0 when allowed and code 1 when denied.` +The command exits with code 0 when allowed and code 1 when denied. + +Use ` + "`--params`" + ` to pass configuration data (thresholds, expected counts, etc.) +to your policy. Params are available as ` + "`data.params`" + ` in Rego, keeping policy +logic reusable across environments with different tolerances.` func newEvaluateCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ diff --git a/cmd/kosli/evaluateInput.go b/cmd/kosli/evaluateInput.go index abce0005d..1fa4b8de5 100644 --- a/cmd/kosli/evaluateInput.go +++ b/cmd/kosli/evaluateInput.go @@ -27,7 +27,10 @@ The policy must use ` + "`package policy`" + ` and define an ` + "`allow`" + ` r An optional ` + "`violations`" + ` rule (a set of strings) can provide human-readable denial reasons. The command exits with code 0 when allowed and code 1 when denied. -When ` + "`--input-file`" + ` is omitted, JSON is read from stdin.` +When ` + "`--input-file`" + ` is omitted, JSON is read from stdin. + +Use ` + "`--params`" + ` to pass configuration data to the policy as ` + "`data.params`" + `. +This accepts inline JSON or a file reference (` + "`@file.json`" + `).` const evaluateInputExample = ` # capture trail data for local policy iteration: @@ -49,7 +52,19 @@ kosli evaluate input \ # read input from stdin: cat trail-data.json | kosli evaluate input \ - --policy policy.rego` + --policy policy.rego + +# evaluate with policy parameters (inline JSON): +kosli evaluate input \ + --input-file trail-data.json \ + --policy policy.rego \ + --params '{"threshold": 3}' + +# evaluate with policy parameters from a file: +kosli evaluate input \ + --input-file trail-data.json \ + --policy policy.rego \ + --params @params.json` func newEvaluateInputCmd(out io.Writer) *cobra.Command { o := new(evaluateInputOptions) diff --git a/cmd/kosli/evaluateTrail.go b/cmd/kosli/evaluateTrail.go index 174ea7d75..5a7c0fddd 100644 --- a/cmd/kosli/evaluateTrail.go +++ b/cmd/kosli/evaluateTrail.go @@ -39,6 +39,22 @@ kosli evaluate trail yourTrailName \ --show-input \ --output json \ --api-token yourAPIToken \ + --org yourOrgName + +# evaluate a trail with policy parameters (inline JSON): +kosli evaluate trail yourTrailName \ + --policy yourPolicyFile.rego \ + --flow yourFlowName \ + --params '{"min_approvers": 2}' \ + --api-token yourAPIToken \ + --org yourOrgName + +# evaluate a trail with policy parameters from a file: +kosli evaluate trail yourTrailName \ + --policy yourPolicyFile.rego \ + --flow yourFlowName \ + --params @params.json \ + --api-token yourAPIToken \ --org yourOrgName` type evaluateTrailOptions struct { diff --git a/cmd/kosli/evaluateTrails.go b/cmd/kosli/evaluateTrails.go index b42ec00fd..cfafb9020 100644 --- a/cmd/kosli/evaluateTrails.go +++ b/cmd/kosli/evaluateTrails.go @@ -40,6 +40,14 @@ kosli evaluate trails yourTrailName1 yourTrailName2 \ --show-input \ --output json \ --api-token yourAPIToken \ + --org yourOrgName + +# evaluate trails with policy parameters: +kosli evaluate trails yourTrailName1 yourTrailName2 \ + --policy yourPolicyFile.rego \ + --flow yourFlowName \ + --params '{"min_approvers": 2}' \ + --api-token yourAPIToken \ --org yourOrgName` type evaluateTrailsOptions struct { From 837e2f82222cba7c4c203c67e1e2becdefef1b02 Mon Sep 17 00:00:00 2001 From: Steve Tooke Date: Thu, 2 Apr 2026 08:36:01 +0100 Subject: [PATCH 6/7] chore: mark --params slices complete in TODO.md Co-Authored-By: Claude Opus 4.6 (1M context) --- TODO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 7a1ff51d2..b8fd42d6f 100644 --- a/TODO.md +++ b/TODO.md @@ -53,4 +53,4 @@ - [x] Slice 1: `evaluate.Evaluate()` accepts params, passes via OPA data store - [x] Slice 2: Add `--params` flag across all three commands - [x] Slice 3: Show params in `--show-input` output -- [ ] Slice 4: Update help text and examples ← active +- [x] Slice 4: Update help text and examples From 83f92688bdbd3867e53dca73e17105c1aa50badd Mon Sep 17 00:00:00 2001 From: Steve Tooke Date: Thu, 2 Apr 2026 10:56:22 +0100 Subject: [PATCH 7/7] refactor: use plain params parameter instead of variadic Changes Evaluate signature from variadic params to an explicit map parameter. Callers pass nil when no params are needed, making the API unambiguous. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/evaluate/rego.go | 12 ++++-------- internal/evaluate/rego_test.go | 16 ++++++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/internal/evaluate/rego.go b/internal/evaluate/rego.go index 33a31e232..82d7f12c5 100644 --- a/internal/evaluate/rego.go +++ b/internal/evaluate/rego.go @@ -18,7 +18,7 @@ type Result struct { // Evaluate evaluates a Rego policy against the given input. // The policy must use `package policy` and declare an `allow` rule. // An optional params map can be provided to populate data.params in the policy. -func Evaluate(policySource string, input interface{}, params ...map[string]interface{}) (*Result, error) { +func Evaluate(policySource string, input interface{}, params map[string]interface{}) (*Result, error) { if err := validatePolicy(policySource); err != nil { return nil, err } @@ -30,8 +30,8 @@ func Evaluate(policySource string, input interface{}, params ...map[string]inter rego.Module("policy.rego", policySource), rego.Input(input), } - if len(params) > 0 && params[0] != nil { - store := inmem.NewFromObject(map[string]interface{}{"params": params[0]}) + if params != nil { + store := inmem.NewFromObject(map[string]interface{}{"params": params}) opts = append(opts, rego.Store(store)) } @@ -54,11 +54,7 @@ func Evaluate(policySource string, input interface{}, params ...map[string]inter result := &Result{Allow: allow} if !result.Allow { - var p map[string]interface{} - if len(params) > 0 { - p = params[0] - } - violations, err := collectViolations(ctx, policySource, input, p) + violations, err := collectViolations(ctx, policySource, input, params) if err != nil { return nil, err } diff --git a/internal/evaluate/rego_test.go b/internal/evaluate/rego_test.go index cb449375c..ec19ff196 100644 --- a/internal/evaluate/rego_test.go +++ b/internal/evaluate/rego_test.go @@ -17,7 +17,7 @@ allow = true }, } - result, err := Evaluate(policy, input) + result, err := Evaluate(policy, input, nil) require.NoError(t, err) require.True(t, result.Allow) require.Empty(t, result.Violations) @@ -38,7 +38,7 @@ violations contains msg if { }, } - result, err := Evaluate(policy, input) + result, err := Evaluate(policy, input, nil) require.NoError(t, err) require.False(t, result.Allow) require.Contains(t, result.Violations, "always denied") @@ -51,7 +51,7 @@ allow = true ` input := map[string]interface{}{} - _, err := Evaluate(policy, input) + _, err := Evaluate(policy, input, nil) require.Error(t, err) require.Contains(t, err.Error(), "package policy") } @@ -65,7 +65,7 @@ violations contains msg if { ` input := map[string]interface{}{} - _, err := Evaluate(policy, input) + _, err := Evaluate(policy, input, nil) require.Error(t, err) require.Contains(t, err.Error(), "allow") } @@ -77,7 +77,7 @@ allow = false ` input := map[string]interface{}{} - result, err := Evaluate(policy, input) + result, err := Evaluate(policy, input, nil) require.NoError(t, err) require.False(t, result.Allow) require.Empty(t, result.Violations) @@ -90,7 +90,7 @@ allow = "yes" ` input := map[string]interface{}{} - _, err := Evaluate(policy, input) + _, err := Evaluate(policy, input, nil) require.Error(t, err) require.Contains(t, err.Error(), "boolean") } @@ -102,7 +102,7 @@ allow = {{{ ` input := map[string]interface{}{} - _, err := Evaluate(policy, input) + _, err := Evaluate(policy, input, nil) require.Error(t, err) require.Contains(t, err.Error(), "parse") } @@ -160,7 +160,7 @@ violations contains msg if { } // No params — policy uses default threshold of 10 - result, err := Evaluate(policy, input) + result, err := Evaluate(policy, input, nil) require.NoError(t, err) require.False(t, result.Allow, "score 5 should fail default threshold 10") require.Len(t, result.Violations, 1)