Skip to content

Commit d47485e

Browse files
authored
feat(policy): change devel commands return to stdout (#2308)
Signed-off-by: Sylwester Piskozub <sylwesterpiskozub@gmail.com>
1 parent c9f809f commit d47485e

File tree

6 files changed

+76
-69
lines changed

6 files changed

+76
-69
lines changed

app/cli/cmd/output.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ type tabulatedData interface {
5454
*action.APITokenItem |
5555
[]*action.APITokenItem |
5656
*action.AttestationStatusMaterial |
57-
*action.ListMembershipResult
57+
*action.ListMembershipResult |
58+
*action.PolicyEvalResult
5859
}
5960

6061
var ErrOutputFormatNotImplemented = errors.New("format not implemented")

app/cli/cmd/policy_develop_eval.go

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,7 @@ evaluates the policy against the provided material or attestation.`,
6161
return newGracefulError(err)
6262
}
6363

64-
switch {
65-
case result.Skipped:
66-
logger.Info().Msg("policy evaluation skipped")
67-
for _, reason := range result.SkipReasons {
68-
logger.Info().Msgf("%s", reason)
69-
}
70-
71-
case len(result.Violations) > 0:
72-
for _, violation := range result.Violations {
73-
logger.Info().Msgf("- %s", violation)
74-
}
75-
logger.Info().Msg("policy evaluation failed")
76-
77-
default:
78-
if result.Ignored {
79-
logger.Info().Msg("policy was ignored")
80-
}
81-
logger.Info().Msg("policy evaluation passed")
82-
}
83-
84-
return nil
64+
return encodeJSON(result)
8565
},
8666
}
8767

app/cli/cmd/policy_develop_lint.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,7 @@ func newPolicyDevelopLintCmd() *cobra.Command {
5555
return nil
5656
}
5757

58-
// Print all validation errors
59-
for _, err := range result.Errors {
60-
logger.Error().Msg(err)
61-
}
62-
return fmt.Errorf("policy validation failed with %d issues", len(result.Errors))
58+
return encodeResult(result)
6359
},
6460
}
6561

@@ -68,3 +64,19 @@ func newPolicyDevelopLintCmd() *cobra.Command {
6864
cmd.Flags().StringVar(&regalConfig, "regal-config", "", "Path to custom regal config (Default: https://github.com/chainloop-dev/chainloop/tree/main/app/cli/internal/policydevel/.regal.yaml)")
6965
return cmd
7066
}
67+
68+
func encodeResult(result *action.PolicyLintResult) error {
69+
if result == nil {
70+
return nil
71+
}
72+
73+
output := fmt.Sprintf("Found %d issues:\n", len(result.Errors))
74+
75+
for i, err := range result.Errors {
76+
output += fmt.Sprintf(" %d. %s\n", i+1, err)
77+
}
78+
79+
fmt.Print(output)
80+
81+
return fmt.Errorf("policy validation failed with %d issues", len(result.Errors))
82+
}

app/cli/internal/action/policy_develop_eval.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ type PolicyEvalOpts struct {
3030
}
3131

3232
type PolicyEvalResult struct {
33-
Skipped bool
34-
SkipReasons []string
35-
Violations []string
36-
Ignored bool
33+
Violations []string `json:"violations"`
34+
SkipReasons []string `json:"skip_reasons"`
35+
Skipped bool `json:"skipped"`
36+
Ignored bool `json:"ignored,omitempty"`
3737
}
3838

3939
type PolicyEval struct {
@@ -48,7 +48,7 @@ func NewPolicyEval(opts *PolicyEvalOpts, actionOpts *ActionsOpts) (*PolicyEval,
4848
}, nil
4949
}
5050

51-
func (action *PolicyEval) Run() (*PolicyEvalResult, error) {
51+
func (action *PolicyEval) Run() ([]*PolicyEvalResult, error) {
5252
evalOpts := &policydevel.EvalOptions{
5353
PolicyPath: action.opts.PolicyPath,
5454
MaterialKind: action.opts.Kind,
@@ -58,15 +58,20 @@ func (action *PolicyEval) Run() (*PolicyEvalResult, error) {
5858
}
5959

6060
// Evaluate policy
61-
result, err := policydevel.Evaluate(evalOpts, action.Logger)
61+
resp, err := policydevel.Evaluate(evalOpts, action.Logger)
6262
if err != nil {
6363
return nil, fmt.Errorf("evaluating policy: %w", err)
6464
}
6565

66-
return &PolicyEvalResult{
67-
Ignored: result.Ignored,
68-
Skipped: result.Skipped,
69-
SkipReasons: result.SkipReasons,
70-
Violations: result.Violations,
71-
}, nil
66+
results := make([]*PolicyEvalResult, 0, len(resp))
67+
for _, r := range resp {
68+
results = append(results, &PolicyEvalResult{
69+
Violations: r.Violations,
70+
SkipReasons: r.SkipReasons,
71+
Skipped: r.Skipped,
72+
Ignored: r.Ignored,
73+
})
74+
}
75+
76+
return results, nil
7277
}

app/cli/internal/policydevel/eval.go

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type EvalResult struct {
4343
Ignored bool
4444
}
4545

46-
func Evaluate(opts *EvalOptions, logger zerolog.Logger) (*EvalResult, error) {
46+
func Evaluate(opts *EvalOptions, logger zerolog.Logger) ([]*EvalResult, error) {
4747
// 1. Create crafting schema
4848
schema, err := createCraftingSchema(opts.PolicyPath, opts.Inputs)
4949
if err != nil {
@@ -81,36 +81,44 @@ func createCraftingSchema(policyPath string, inputs map[string]string) (*v1.Craf
8181
}, nil
8282
}
8383

84-
func verifyMaterial(schema *v1.CraftingSchema, material *v12.Attestation_Material, materialPath string, logger *zerolog.Logger) (*EvalResult, error) {
84+
func verifyMaterial(schema *v1.CraftingSchema, material *v12.Attestation_Material, materialPath string, logger *zerolog.Logger) ([]*EvalResult, error) {
8585
v := policies.NewPolicyVerifier(schema, nil, logger)
86-
evs, err := v.VerifyMaterial(context.Background(), material, materialPath)
86+
policyEvs, err := v.VerifyMaterial(context.Background(), material, materialPath)
8787
if err != nil {
8888
return nil, err
8989
}
9090

91-
result := &EvalResult{
92-
Skipped: false,
93-
SkipReasons: []string{},
94-
Violations: []string{},
95-
Ignored: true,
96-
}
97-
98-
if len(evs) == 0 {
99-
return result, nil
91+
// no evaluations were returned
92+
if len(policyEvs) == 0 {
93+
return []*EvalResult{
94+
{
95+
Ignored: true,
96+
Skipped: false,
97+
SkipReasons: []string{},
98+
Violations: []string{},
99+
},
100+
}, nil
100101
}
101102

102-
result.Ignored = false
103-
result.Skipped = evs[0].GetSkipped()
104-
result.SkipReasons = evs[0].SkipReasons
105-
result.Violations = make([]string, 0, len(evs[0].Violations))
103+
results := make([]*EvalResult, 0, len(policyEvs))
104+
for _, policyEv := range policyEvs {
105+
result := &EvalResult{
106+
Skipped: policyEv.GetSkipped(),
107+
SkipReasons: policyEv.SkipReasons,
108+
Ignored: false,
109+
}
106110

107-
for _, e := range evs {
108-
for _, v := range e.Violations {
109-
result.Violations = append(result.Violations, fmt.Sprintf("%s: %s", v.Subject, v.Message))
111+
// Collect all violation messages
112+
violations := make([]string, 0, len(policyEv.Violations))
113+
for _, v := range policyEv.Violations {
114+
violations = append(violations, v.Message)
110115
}
116+
result.Violations = violations
117+
118+
results = append(results, result)
111119
}
112120

113-
return result, nil
121+
return results, nil
114122
}
115123

116124
func craftMaterial(materialPath, materialKind string, logger *zerolog.Logger) (*v12.Attestation_Material, error) {

app/cli/internal/policydevel/eval_test.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ func TestEvaluate(t *testing.T) {
4040
Annotations: map[string]string{"key": "value"},
4141
}
4242

43-
result, err := Evaluate(opts, logger)
43+
results, err := Evaluate(opts, logger)
4444
require.NoError(t, err)
45-
assert.NotNil(t, result)
45+
require.NotEmpty(t, results)
46+
assert.NotNil(t, results[0])
4647
})
4748

4849
t.Run("evaluation with auto-detected SBOM CYCLONEDX kind", func(t *testing.T) {
@@ -55,14 +56,14 @@ func TestEvaluate(t *testing.T) {
5556
Annotations: map[string]string{"key": "value"},
5657
}
5758

58-
result, err := Evaluate(opts, logger)
59+
results, err := Evaluate(opts, logger)
5960
require.NoError(t, err)
60-
assert.NotNil(t, result)
61+
require.NotEmpty(t, results)
6162

62-
if len(result.Violations) == 0 {
63+
if len(results[0].Violations) == 0 {
6364
t.Log("Policy evaluation passed (no violations)")
6465
} else {
65-
for _, violation := range result.Violations {
66+
for _, violation := range results[0].Violations {
6667
t.Logf("Violation: %s", violation)
6768
}
6869
}
@@ -78,14 +79,14 @@ func TestEvaluate(t *testing.T) {
7879
Annotations: map[string]string{"key": "value"},
7980
}
8081

81-
result, err := Evaluate(opts, logger)
82+
results, err := Evaluate(opts, logger)
8283
require.NoError(t, err)
83-
assert.NotNil(t, result)
84+
require.NotEmpty(t, results)
8485

85-
if len(result.Violations) == 0 {
86+
if len(results[0].Violations) == 0 {
8687
t.Log("Policy evaluation passed (no violations)")
8788
} else {
88-
for _, violation := range result.Violations {
89+
for _, violation := range results[0].Violations {
8990
t.Logf("Violation: %s", violation)
9091
}
9192
}

0 commit comments

Comments
 (0)