From e6768088b67bc55efa85083ec09683f026e0a88e Mon Sep 17 00:00:00 2001 From: Tore Martin Hagen Date: Fri, 30 Oct 2026 11:06:08 +0100 Subject: [PATCH 1/2] feat: unhide server-side evaluation commands and --server-side flag kosli evaluate policy, publish/list/get rego-policy and --server-side on evaluate trail/trails are now public as beta, now that the server gates them on the controls feature flag. See kosli-dev/server#7658 Co-Authored-By: Claude Opus 5.5 --- cmd/kosli/evaluateHelpers.go | 10 ++-------- cmd/kosli/evaluatePolicy.go | 3 --- cmd/kosli/evaluatePolicy_test.go | 13 ++----------- cmd/kosli/evaluateServerSide_test.go | 7 ++----- cmd/kosli/getRegoPolicy.go | 12 +++++------- cmd/kosli/getRegoPolicy_test.go | 4 ++-- cmd/kosli/lifecycle_test.go | 11 +++++------ cmd/kosli/listRegoPolicies.go | 12 +++++------- cmd/kosli/listRegoPolicies_test.go | 4 ++-- cmd/kosli/publishRegoPolicy.go | 12 +++++------- cmd/kosli/publishRegoPolicy_test.go | 6 ++---- cmd/kosli/root.go | 2 +- 12 files changed, 33 insertions(+), 63 deletions(-) diff --git a/cmd/kosli/evaluateHelpers.go b/cmd/kosli/evaluateHelpers.go index afc4b9b16..259723ec4 100644 --- a/cmd/kosli/evaluateHelpers.go +++ b/cmd/kosli/evaluateHelpers.go @@ -82,16 +82,10 @@ func (o *commonEvaluateOptions) addFlags(cmd *cobra.Command, policyDesc string) } // addServerSideFlag offers the evaluation to the Kosli server instead of -// running it here. It is hidden, and stays hidden: it exists to run the two -// evaluation paths against each other while neither is a contract anyone can -// rely on, and the two do not yet agree on what a policy may contain or on -// what a policy sees. Only the trail commands have it, because an evaluation -// is created from trail references and `evaluate input` has none to send. +// running it here. Only the trail commands have it, because an evaluation is +// created from trail references and `evaluate input` has none to send. func (o *commonEvaluateOptions) addServerSideFlag(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.serverSide, "server-side", false, serverSideFlag) - if err := cmd.Flags().MarkHidden("server-side"); err != nil { - logger.Error("failed to hide the server-side flag: %v", err) - } } // assertOnDeny resolves the --assert / --no-assert pair into a single bool. diff --git a/cmd/kosli/evaluatePolicy.go b/cmd/kosli/evaluatePolicy.go index ef5e50bd2..db927b46c 100644 --- a/cmd/kosli/evaluatePolicy.go +++ b/cmd/kosli/evaluatePolicy.go @@ -170,9 +170,6 @@ func newEvaluatePolicyCmd(out io.Writer) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return o.run(out) }, - // Hidden while the command is proved out against a server that can run - // it. Unhiding it is this line, and it also restores its docs page. - Hidden: true, } cmd.Flags().StringArrayVar(&o.contexts, "context", []string{}, policyContextFlag) diff --git a/cmd/kosli/evaluatePolicy_test.go b/cmd/kosli/evaluatePolicy_test.go index 9d7352855..3f70f0ed3 100644 --- a/cmd/kosli/evaluatePolicy_test.go +++ b/cmd/kosli/evaluatePolicy_test.go @@ -27,20 +27,11 @@ func (suite *EvaluatePolicyCommandTestSuite) cmd(host, extra string) string { host, extra) } -// Hidden while the command is proved out against a server that can run it. -func (suite *EvaluatePolicyCommandTestSuite) TestTheCommandIsHiddenForNow() { +func (suite *EvaluatePolicyCommandTestSuite) TestTheCommandIsListed() { _, listed, _, _, err := executeCommandC("evaluate --help") require.NoError(suite.T(), err) - require.NotContains(suite.T(), listed, evaluatePolicyShortDesc) - for _, sibling := range []string{"trail", "trails", "input"} { - require.Contains(suite.T(), listed, sibling, "the rest of the listing still renders") - } - - // Its own help still renders, for anyone told to try it. - _, help, _, _, err := executeCommandC("evaluate policy --help") - require.NoError(suite.T(), err) - require.Contains(suite.T(), help, "--context") + require.Contains(suite.T(), listed, evaluatePolicyShortDesc) } // The flags that only make sense on this machine are absent rather than diff --git a/cmd/kosli/evaluateServerSide_test.go b/cmd/kosli/evaluateServerSide_test.go index c0f81f752..c5c4878df 100644 --- a/cmd/kosli/evaluateServerSide_test.go +++ b/cmd/kosli/evaluateServerSide_test.go @@ -126,16 +126,13 @@ func (suite *EvaluateServerSideTestSuite) serverSideCmd(host, extra string) stri host, extra) } -// The flag is deliberately undocumented: it exists to run the two evaluation -// paths against each other while neither is a contract anyone can rely on. -func (suite *EvaluateServerSideTestSuite) TestTheFlagIsHiddenFromHelp() { +func (suite *EvaluateServerSideTestSuite) TestTheFlagIsInHelp() { for _, command := range []string{"trail", "trails"} { suite.Run(command, func() { _, combined, _, _, err := executeCommandC("evaluate " + command + " --help") require.NoError(suite.T(), err) - require.NotContains(suite.T(), combined, "--server-side") - require.Contains(suite.T(), combined, "--policy", "the rest of the help still renders") + require.Contains(suite.T(), combined, "--server-side") }) } } diff --git a/cmd/kosli/getRegoPolicy.go b/cmd/kosli/getRegoPolicy.go index 16ba8bd1f..364b752e2 100644 --- a/cmd/kosli/getRegoPolicy.go +++ b/cmd/kosli/getRegoPolicy.go @@ -66,13 +66,11 @@ type getRegoPolicyOptions struct { func newGetRegoPolicyCmd(out io.Writer) *cobra.Command { o := new(getRegoPolicyOptions) cmd := &cobra.Command{ - Use: "rego-policy IDENTIFIER", - Short: getRegoPolicyShortDesc, - Long: getRegoPolicyLongDesc, - Example: getRegoPolicyExample, - Args: cobra.ExactArgs(1), - // Hidden while the server gates the endpoint behind is-server-side-evaluation-enabled. - Hidden: true, + Use: "rego-policy IDENTIFIER", + Short: getRegoPolicyShortDesc, + Long: getRegoPolicyLongDesc, + Example: getRegoPolicyExample, + Args: cobra.ExactArgs(1), Annotations: map[string]string{betaCLIAnnotation: ""}, PreRunE: func(cmd *cobra.Command, args []string) error { err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) diff --git a/cmd/kosli/getRegoPolicy_test.go b/cmd/kosli/getRegoPolicy_test.go index c87ae3928..b31899d86 100644 --- a/cmd/kosli/getRegoPolicy_test.go +++ b/cmd/kosli/getRegoPolicy_test.go @@ -40,14 +40,14 @@ func (suite *GetRegoPolicyCommandTestSuite) getCmd(host, args string) string { args, host) } -func (suite *GetRegoPolicyCommandTestSuite) TestItIsHiddenAndBeta() { +func (suite *GetRegoPolicyCommandTestSuite) TestItIsVisibleAndBeta() { root, err := newRootCmd(io.Discard, io.Discard, nil) require.NoError(suite.T(), err) cmd, _, err := root.Find([]string{"get", "rego-policy"}) require.NoError(suite.T(), err) require.Equal(suite.T(), "rego-policy", cmd.Name()) - require.True(suite.T(), cmd.Hidden) + require.False(suite.T(), cmd.Hidden) require.Contains(suite.T(), cmd.Annotations, betaCLIAnnotation) } diff --git a/cmd/kosli/lifecycle_test.go b/cmd/kosli/lifecycle_test.go index 7f938fa9e..922010066 100644 --- a/cmd/kosli/lifecycle_test.go +++ b/cmd/kosli/lifecycle_test.go @@ -51,12 +51,11 @@ func TestLifecycleAttestDecisionIsBetaAndVisible(t *testing.T) { } } -// Hidden while the server gates the endpoint behind is-server-side-evaluation-enabled. -func TestLifecyclePublishRegoPolicyIsBetaAndHidden(t *testing.T) { +func TestLifecyclePublishRegoPolicyIsBetaAndVisible(t *testing.T) { global = &GlobalOpts{} cmd := newPublishRegoPolicyCmd(io.Discard) - if !cmd.Hidden { - t.Error("expected publish rego-policy to be Hidden") + if cmd.Hidden { + t.Error("expected publish rego-policy to be visible (not Hidden)") } if !isBeta(cmd) { t.Error("expected publish rego-policy to be beta") @@ -70,8 +69,8 @@ func TestLifecyclePublishRegoPolicyIsBetaAndHidden(t *testing.T) { if err != nil { t.Fatal(err) } - if len(pages) > 0 { - t.Errorf("expected no docs page for a hidden rego-policy command, got %v", pages) + if len(pages) == 0 { + t.Error("expected a docs page for the rego-policy commands") } } diff --git a/cmd/kosli/listRegoPolicies.go b/cmd/kosli/listRegoPolicies.go index bfc567c76..48386082a 100644 --- a/cmd/kosli/listRegoPolicies.go +++ b/cmd/kosli/listRegoPolicies.go @@ -65,13 +65,11 @@ type listRegoPoliciesResponse struct { func newListRegoPoliciesCmd(out io.Writer) *cobra.Command { o := new(listRegoPoliciesOptions) cmd := &cobra.Command{ - Use: "rego-policies", - Short: listRegoPoliciesShortDesc, - Long: listRegoPoliciesLongDesc, - Example: listRegoPoliciesExample, - Args: cobra.NoArgs, - // Hidden while the server gates the endpoint behind is-server-side-evaluation-enabled. - Hidden: true, + Use: "rego-policies", + Short: listRegoPoliciesShortDesc, + Long: listRegoPoliciesLongDesc, + Example: listRegoPoliciesExample, + Args: cobra.NoArgs, Annotations: map[string]string{betaCLIAnnotation: ""}, PreRunE: func(cmd *cobra.Command, args []string) error { err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) diff --git a/cmd/kosli/listRegoPolicies_test.go b/cmd/kosli/listRegoPolicies_test.go index 342d669c8..05a3414b7 100644 --- a/cmd/kosli/listRegoPolicies_test.go +++ b/cmd/kosli/listRegoPolicies_test.go @@ -34,14 +34,14 @@ func (suite *ListRegoPoliciesCommandTestSuite) listCmd(host, args string) string args, host) } -func (suite *ListRegoPoliciesCommandTestSuite) TestItIsHiddenAndBeta() { +func (suite *ListRegoPoliciesCommandTestSuite) TestItIsVisibleAndBeta() { root, err := newRootCmd(io.Discard, io.Discard, nil) require.NoError(suite.T(), err) cmd, _, err := root.Find([]string{"list", "rego-policies"}) require.NoError(suite.T(), err) require.Equal(suite.T(), "rego-policies", cmd.Name()) - require.True(suite.T(), cmd.Hidden) + require.False(suite.T(), cmd.Hidden) require.Contains(suite.T(), cmd.Annotations, betaCLIAnnotation) } diff --git a/cmd/kosli/publishRegoPolicy.go b/cmd/kosli/publishRegoPolicy.go index ce9e34d60..e8447700b 100644 --- a/cmd/kosli/publishRegoPolicy.go +++ b/cmd/kosli/publishRegoPolicy.go @@ -108,13 +108,11 @@ type publishRegoPolicyOptions struct { func newPublishRegoPolicyCmd(out io.Writer) *cobra.Command { o := new(publishRegoPolicyOptions) cmd := &cobra.Command{ - Use: "rego-policy IDENTIFIER", - Short: publishRegoPolicyShortDesc, - Long: publishRegoPolicyLongDesc, - Example: publishRegoPolicyExample, - Args: cobra.ExactArgs(1), - // Hidden while the server gates the endpoint behind is-server-side-evaluation-enabled. - Hidden: true, + Use: "rego-policy IDENTIFIER", + Short: publishRegoPolicyShortDesc, + Long: publishRegoPolicyLongDesc, + Example: publishRegoPolicyExample, + Args: cobra.ExactArgs(1), Annotations: map[string]string{betaCLIAnnotation: ""}, PreRunE: func(cmd *cobra.Command, args []string) error { err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) diff --git a/cmd/kosli/publishRegoPolicy_test.go b/cmd/kosli/publishRegoPolicy_test.go index 73140baa6..cc7fcf2d1 100644 --- a/cmd/kosli/publishRegoPolicy_test.go +++ b/cmd/kosli/publishRegoPolicy_test.go @@ -111,13 +111,11 @@ func (suite *PublishRegoPolicyCommandTestSuite) publishCmd(host, args string) st args, host) } -// The publish verb has no visible subcommand, so it is hidden as well. -func (suite *PublishRegoPolicyCommandTestSuite) TestItIsHiddenFromHelp() { +func (suite *PublishRegoPolicyCommandTestSuite) TestItIsListedInHelp() { _, combined, _, _, err := executeCommandC("--help") require.NoError(suite.T(), err) - require.NotContains(suite.T(), combined, "publish") - require.Contains(suite.T(), combined, "create", "the rest of the help still renders") + require.Contains(suite.T(), combined, "publish") } func (suite *PublishRegoPolicyCommandTestSuite) TestItIsNoLongerACreateCommand() { diff --git a/cmd/kosli/root.go b/cmd/kosli/root.go index 074431e5a..574e85e1d 100644 --- a/cmd/kosli/root.go +++ b/cmd/kosli/root.go @@ -148,7 +148,7 @@ Paths the list already matches stay excluded whatever is later added there, so k templateArtifactName = "The name of the artifact in the yml template file." flowNamesFlag = "[defaulted] The comma separated list of Kosli flows. Defaults to all flows of the org." outputFlag = "[defaulted] The format of the output. Valid formats are: [table, json]." - serverSideFlag = "[hidden] Evaluate the policy on the Kosli server rather than on this machine. Unsupported and subject to change." + serverSideFlag = "[optional] Evaluate the policy on the Kosli server rather than on this machine." policyParamsFlag = "[optional] Policy parameters as inline JSON or @file.json. Available in policies as data.params." policyOutputRuleFlag = "[optional] [experimental] Name of a policy rule to add to the JSON output, next to allow and violations. Can be repeated, or given as a comma-separated list. Subject to change." policyAssertFlag = "[optional] Exit with a non-zero status when the policy denies. Without it the verdict is printed and the command exits 0." From 524a6b111899428129a1d090388d9408725d1e10 Mon Sep 17 00:00:00 2001 From: Tore Martin Hagen Date: Fri, 30 Oct 2026 12:01:59 +0100 Subject: [PATCH 2/2] fix: name the options --server-side cannot combine with, tighten publish help test Co-Authored-By: Claude Opus 5.5 --- cmd/kosli/publishRegoPolicy_test.go | 2 +- cmd/kosli/root.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/kosli/publishRegoPolicy_test.go b/cmd/kosli/publishRegoPolicy_test.go index cc7fcf2d1..e46edb680 100644 --- a/cmd/kosli/publishRegoPolicy_test.go +++ b/cmd/kosli/publishRegoPolicy_test.go @@ -115,7 +115,7 @@ func (suite *PublishRegoPolicyCommandTestSuite) TestItIsListedInHelp() { _, combined, _, _, err := executeCommandC("--help") require.NoError(suite.T(), err) - require.Contains(suite.T(), combined, "publish") + require.Contains(suite.T(), combined, publishDesc) } func (suite *PublishRegoPolicyCommandTestSuite) TestItIsNoLongerACreateCommand() { diff --git a/cmd/kosli/root.go b/cmd/kosli/root.go index 574e85e1d..d8218cf06 100644 --- a/cmd/kosli/root.go +++ b/cmd/kosli/root.go @@ -148,7 +148,7 @@ Paths the list already matches stay excluded whatever is later added there, so k templateArtifactName = "The name of the artifact in the yml template file." flowNamesFlag = "[defaulted] The comma separated list of Kosli flows. Defaults to all flows of the org." outputFlag = "[defaulted] The format of the output. Valid formats are: [table, json]." - serverSideFlag = "[optional] Evaluate the policy on the Kosli server rather than on this machine." + serverSideFlag = "[optional] Evaluate the policy on the Kosli server rather than on this machine. Cannot be combined with --attestations, --show-input or --output-rule." policyParamsFlag = "[optional] Policy parameters as inline JSON or @file.json. Available in policies as data.params." policyOutputRuleFlag = "[optional] [experimental] Name of a policy rule to add to the JSON output, next to allow and violations. Can be repeated, or given as a comma-separated list. Subject to change." policyAssertFlag = "[optional] Exit with a non-zero status when the policy denies. Without it the verdict is printed and the command exits 0."