|
7 | 7 | "net/http" |
8 | 8 | "net/url" |
9 | 9 |
|
| 10 | + "github.com/kosli-dev/cli/internal/output" |
10 | 11 | "github.com/kosli-dev/cli/internal/requests" |
11 | 12 | "github.com/spf13/cobra" |
12 | 13 | ) |
@@ -45,6 +46,7 @@ type assertArtifactOptions struct { |
45 | 46 | fingerprint string // This is calculated or provided by the user |
46 | 47 | flowName string |
47 | 48 | envName string |
| 49 | + output string |
48 | 50 | } |
49 | 51 |
|
50 | 52 | func newAssertArtifactCmd(out io.Writer) *cobra.Command { |
@@ -75,6 +77,8 @@ func newAssertArtifactCmd(out io.Writer) *cobra.Command { |
75 | 77 | cmd.Flags().StringVarP(&o.fingerprint, "fingerprint", "F", "", fingerprintFlag) |
76 | 78 | cmd.Flags().StringVarP(&o.flowName, "flow", "f", "", flowNameFlag) |
77 | 79 | cmd.Flags().StringVar(&o.envName, "environment", "", envNameFlag) |
| 80 | + cmd.Flags().StringVarP(&o.output, "output", "o", "table", outputFlag) |
| 81 | + |
78 | 82 | addFingerprintFlags(cmd, o.fingerprintOptions) |
79 | 83 | addDryRunFlag(cmd) |
80 | 84 |
|
@@ -116,31 +120,92 @@ func (o *assertArtifactOptions) run(out io.Writer, args []string) error { |
116 | 120 | return err |
117 | 121 | } |
118 | 122 |
|
| 123 | + return output.FormattedPrint(response.Body, o.output, out, 0, |
| 124 | + map[string]output.FormatOutputFunc{ |
| 125 | + "table": printAssertAsTable, |
| 126 | + "json": output.PrintJson, |
| 127 | + }) |
| 128 | +} |
| 129 | + |
| 130 | +func printAssertAsTable(raw string, out io.Writer, page int) error { |
119 | 131 | var evaluationResult map[string]interface{} |
120 | | - err = json.Unmarshal([]byte(response.Body), &evaluationResult) |
| 132 | + err := json.Unmarshal([]byte(raw), &evaluationResult) |
121 | 133 | if err != nil { |
122 | 134 | return err |
123 | 135 | } |
124 | 136 |
|
| 137 | + flow, _ := evaluationResult["flow"].(string) |
| 138 | + trail, _ := evaluationResult["trail"].(string) |
125 | 139 | scope := evaluationResult["scope"].(string) |
| 140 | + complianceStatus, _ := evaluationResult["compliance_status"].(map[string]interface{}) |
| 141 | + attestationsStatuses, _ := complianceStatus["attestations_statuses"].([]interface{}) |
126 | 142 |
|
127 | 143 | if evaluationResult["compliant"].(bool) { |
128 | 144 | logger.Info("COMPLIANT") |
129 | | - if scope == "flow" { |
130 | | - logger.Info("See more details at %s", evaluationResult["html_url"].(string)) |
131 | | - } |
132 | 145 | } else { |
133 | | - if scope == "flow" { |
134 | | - return fmt.Errorf("not compliant\nSee more details at %s", evaluationResult["html_url"].(string)) |
135 | | - } else { |
136 | | - jsonData, err := json.MarshalIndent(evaluationResult["policy_evaluations"], "", " ") |
137 | | - if err != nil { |
138 | | - return fmt.Errorf("error marshalling evaluation result: %v", err) |
| 146 | + logger.Info("Error: NON-COMPLIANT") |
| 147 | + } |
| 148 | + logger.Info("Flow: %v\nTrail %v", flow, trail) |
| 149 | + logger.Info("%-32v %-30v %-15v %-10v", "Attestation-name", "type", "status", "compliant") |
| 150 | + |
| 151 | + for _, item := range attestationsStatuses { |
| 152 | + attestation := item.(map[string]interface{}) |
| 153 | + name := attestation["attestation_name"] |
| 154 | + attType := attestation["attestation_type"] |
| 155 | + status := attestation["status"] |
| 156 | + isCompliant, _ := attestation["is_compliant"].(bool) |
| 157 | + unexpected, _ := attestation["unexpected"].(bool) |
| 158 | + unexpectedStr := "" |
| 159 | + if unexpected { |
| 160 | + unexpectedStr = "unexpected" |
| 161 | + } |
| 162 | + |
| 163 | + logger.Info(" %-32v %-30v %-15v %-10v %-10v", name, attType, status, isCompliant, unexpectedStr) |
| 164 | + } |
| 165 | + if scope == "environment" { |
| 166 | + logger.Info("%-32v %-30v", "Policy-name", "status") |
| 167 | + policyEvaluations := evaluationResult["policy_evaluations"].([]interface{}) |
| 168 | + for _, item := range policyEvaluations { |
| 169 | + policyEvaluation := item.(map[string]interface{}) |
| 170 | + policyName := policyEvaluation["policy_name"] |
| 171 | + policyStatus := policyEvaluation["status"] |
| 172 | + logger.Info(" %-32v %-30v", policyName, policyStatus) |
| 173 | + if policyStatus != "COMPLIANT" { |
| 174 | + ruleEvaluations := policyEvaluation["rule_evaluations"].([]interface{}) |
| 175 | + var failures []string |
| 176 | + for _, item2 := range ruleEvaluations { |
| 177 | + ruleEvaluation := item2.(map[string]interface{}) |
| 178 | + ignored := ruleEvaluation["ignored"].(bool) |
| 179 | + satisfied, _ := ruleEvaluation["satisfied"].(bool) |
| 180 | + if !ignored && !satisfied { |
| 181 | + rule := ruleEvaluation["rule"].(map[string]interface{}) |
| 182 | + resolutions := ruleEvaluation["resolutions"].([]interface{}) |
| 183 | + for _, item3 := range resolutions { |
| 184 | + resolution := item3.(map[string]interface{}) |
| 185 | + resolutionType := resolution["type"].(string) |
| 186 | + ruleDefinition := rule["definition"].(map[string]interface{}) |
| 187 | + attestationName := ruleDefinition["name"] |
| 188 | + attestationType := ruleDefinition["type"] |
| 189 | + switch resolutionType { |
| 190 | + case "legacy_flow": |
| 191 | + failures = append(failures, "artifact comes from a legacy flow and does not have the new attestations") |
| 192 | + case "missing_attestation": |
| 193 | + failures = append(failures, fmt.Sprintf("artifact is missing required '%v' (type: %v) attestation in trail", attestationName, attestationType)) |
| 194 | + case "non_compliant_attestation": |
| 195 | + failures = append(failures, fmt.Sprintf("attestation '%v' is non-compliant in trail", attestationName)) |
| 196 | + case "non_compliant_in_trail": |
| 197 | + failures = append(failures, "artifact is not compliant in trail") |
| 198 | + } |
| 199 | + } |
| 200 | + } |
| 201 | + } |
| 202 | + for _, fail := range failures { |
| 203 | + logger.Info(" %v", fail) |
| 204 | + } |
139 | 205 | } |
140 | | - return fmt.Errorf("not compliant for env [%s]: \n %v", o.envName, |
141 | | - string(jsonData)) |
142 | 206 | } |
143 | 207 | } |
| 208 | + logger.Info("\nSee more details at %s", evaluationResult["html_url"].(string)) |
144 | 209 |
|
145 | 210 | return nil |
146 | 211 | } |
0 commit comments