Skip to content

Commit 5db31fc

Browse files
committed
Create result summary for task validation
The assert step in the validate vsa task reads the output from a task result which has to be under 4k. This step determines whether the task fails or not. This is similar to the appstudio output for validate image. example {"result": "FAILURE"}
1 parent 59be019 commit 5db31fc

File tree

5 files changed

+155
-25
lines changed

5 files changed

+155
-25
lines changed

cmd/validate/vsa.go

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ func addVSAFlags(cmd *cobra.Command, data *validateVSAData) {
216216
cmd.Flags().BoolVar(&data.noFallback, "no-fallback", false, "Disable fallback to image validation when VSA validation fails (fallback is enabled by default)")
217217
cmd.Flags().StringVar(&data.fallbackPublicKey, "fallback-public-key", "", "Public key to use for fallback image validation (different from VSA verification key)")
218218
// Output options
219-
validOutputFormats := []string{"json", "yaml", "text"}
219+
validOutputFormats := []string{"json", "yaml", "text", "status"}
220220
cmd.Flags().StringSliceVar(&data.output, "output", []string{}, hd.Doc(`
221221
write output to a file in a specific format. Use empty string path for stdout.
222222
May be used multiple times. Possible formats are:
@@ -1206,8 +1206,21 @@ func (d ComponentResultsDisplay) toFormat(format string) ([]byte, error) {
12061206
return data, nil
12071207
case "text":
12081208
return d.toText(), nil
1209+
case "status":
1210+
// Status format: simple JSON with overall result as SUCCESS or FAILURE
1211+
// Determine result from Overall field (contains "PASSED" or "FAILED")
1212+
resultStr := "FAILURE"
1213+
if strings.Contains(d.Result.Overall, "PASSED") {
1214+
resultStr = "SUCCESS"
1215+
}
1216+
statusReport := map[string]string{"result": resultStr}
1217+
data, err := json.Marshal(statusReport)
1218+
if err != nil {
1219+
return nil, err
1220+
}
1221+
return data, nil
12091222
default:
1210-
return nil, fmt.Errorf("unsupported format: %s (supported: json, yaml, text)", format)
1223+
return nil, fmt.Errorf("unsupported format: %s (supported: json, yaml, text, status)", format)
12111224
}
12121225
}
12131226

@@ -1313,8 +1326,25 @@ func writeVSAReport(report VSAReport, display ComponentResultsDisplay, outputFor
13131326
b.WriteString(fallbackBuf.String())
13141327
}
13151328
data = []byte(b.String())
1329+
case "status":
1330+
// Status format: simple JSON with overall result as SUCCESS or FAILURE
1331+
// If fallback was used, use fallback result; otherwise use VSA result
1332+
resultStr := "FAILURE"
1333+
if report.Fallback != nil {
1334+
// Fallback was used, use its success status as the overall result
1335+
if report.Fallback.Success {
1336+
resultStr = "SUCCESS"
1337+
}
1338+
} else if strings.Contains(display.Result.Overall, "PASSED") {
1339+
resultStr = "SUCCESS"
1340+
}
1341+
statusReport := map[string]string{"result": resultStr}
1342+
data, err = json.Marshal(statusReport)
1343+
if err != nil {
1344+
return fmt.Errorf("failed to marshal status report: %w", err)
1345+
}
13161346
default:
1317-
return fmt.Errorf("unsupported format: %s (supported: json, yaml, text)", formatName)
1347+
return fmt.Errorf("unsupported format: %s (supported: json, yaml, text, status)", formatName)
13181348
}
13191349

13201350
// Use shared file writing logic
@@ -1381,34 +1411,37 @@ func displayComponentResults(allResults []vsa.ComponentResult, data *validateVSA
13811411
// Filter output formats to only json, yaml, text (exclude other formats like appstudio, etc.)
13821412
vsaOutputFormats := filterVSAOutputFormats(data.output)
13831413

1384-
// Check if we need combined output (file output specified AND fallback will be used)
1414+
// Check if file output is specified
13851415
hasFileOutput := hasFileOutputInFormats(vsaOutputFormats)
13861416

1387-
// If file output is specified and fallback will be used, combine them
1388-
if hasFileOutput && allData.FallbackUsed {
1389-
// Create fallback report without writing
1390-
fallbackReport, err := createFallbackReport(allData, data)
1391-
if err != nil {
1392-
return fmt.Errorf("failed to create fallback report: %w", err)
1393-
}
1394-
1395-
// Build combined VSAReport (call toVSASectionsReport once and reuse)
1417+
// If file output is specified, write to file (with or without fallback)
1418+
if hasFileOutput {
1419+
// Build VSAReport (call toVSASectionsReport once and reuse)
13961420
vsaSections := display.toVSASectionsReport()
13971421
vsaReport := VSAReport{
13981422
Header: vsaSections.Header,
13991423
Result: vsaSections.Result,
14001424
VSASummary: vsaSections.VSASummary,
14011425
PolicyDiff: vsaSections.PolicyDiff,
1402-
Fallback: fallbackReport,
1426+
Fallback: nil, // Will be set if fallback is used
1427+
}
1428+
1429+
// Add fallback report if fallback was used
1430+
if allData.FallbackUsed {
1431+
fallbackReport, err := createFallbackReport(allData, data)
1432+
if err != nil {
1433+
return fmt.Errorf("failed to create fallback report: %w", err)
1434+
}
1435+
vsaReport.Fallback = fallbackReport
14031436
}
14041437

1405-
// Write combined report to file(s)
1438+
// Write report to file(s)
14061439
fs := utils.FS(cmd.Context())
14071440
if err := writeVSAReport(vsaReport, display, vsaOutputFormats, fs, cmd); err != nil {
1408-
return fmt.Errorf("failed to write combined VSA report: %w", err)
1441+
return fmt.Errorf("failed to write VSA report: %w", err)
14091442
}
14101443
} else {
1411-
// Use separate output (current behavior)
1444+
// Use separate output to stdout (current behavior)
14121445
if len(vsaOutputFormats) > 0 {
14131446
// Use format system for structured output (json/yaml/text)
14141447
fs := utils.FS(cmd.Context())
@@ -1445,14 +1478,13 @@ func displayComponentResults(allResults []vsa.ComponentResult, data *validateVSA
14451478
return nil
14461479
}
14471480

1448-
// filterVSAOutputFormats filters output formats to only include json, yaml, and text
1449-
// Other formats (like appstudio, summary, etc.) are handled by handleSnapshotOutput
1481+
// filterVSAOutputFormats filters output formats to only include json, yaml, text, and status
14501482
func filterVSAOutputFormats(outputFormats []string) []string {
14511483
var filtered []string
14521484
for _, format := range outputFormats {
14531485
parts := strings.SplitN(format, "=", 2)
14541486
formatName := parts[0]
1455-
if formatName == "json" || formatName == "yaml" || formatName == "text" {
1487+
if formatName == "json" || formatName == "yaml" || formatName == "text" || formatName == "status" {
14561488
filtered = append(filtered, format)
14571489
}
14581490
}

docs/modules/ROOT/pages/ec_validate_vsa.adoc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ ec validate vsa <vsa-identifier> [flags]
3535
--images:: Application snapshot file
3636
--no-color:: Disable color when using text output even when the current terminal supports it (Default: false)
3737
--no-fallback:: Disable fallback to image validation when VSA validation fails (fallback is enabled by default) (Default: false)
38-
--output:: Output formats (e.g., json, yaml, text) (Default: [])
38+
--output:: write output to a file in a specific format. Use empty string path for stdout.
39+
May be used multiple times. Possible formats are:
40+
json, yaml, text, status. In following format and file path
41+
additional options can be provided in key=value form following the question
42+
mark (?) sign, for example: --output text=output.txt?show-successes=false
43+
(Default: [])
3944
-p, --policy:: Policy configuration
4045
--strict:: Exit with non-zero code if validation fails (Default: true)
4146
-v, --vsa:: VSA identifier (image digest, file path)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
= verify-conforma-vsa-release-ta
2+
3+
Version: 0.1
4+
5+
== Synopsis
6+
7+
Validates a Snapshot using Conforma in two phases: 1) `ec validate vsa` (CLI will fall back to `validate image` if VSA missing/expired) 2) `ec validate image` with release-time rules only (pipeline_intention=release)
8+
9+
10+
== Params
11+
[horizontal]
12+
13+
*SNAPSHOT_FILENAME* (`string`):: The filename of the Snapshot located within the trusted artifact
14+
*SOURCE_DATA_ARTIFACT* (`string`):: Trusted Artifact to use to obtain the Snapshot to validate.
15+
*POLICY_CONFIGURATION* (`string`):: Name of the policy configuration (EnterpriseContractPolicy
16+
resource) to use. `namespace/name` or just `name`. Can also be a
17+
Git URL, e.g. `github.com/conforma/config//slsa3`.
18+
19+
+
20+
*Default*: `enterprise-contract-service/default`
21+
*PUBLIC_KEY* (`string`):: Public key used to verify signatures. Must be a valid k8s cosign reference (e.g. k8s://my-ns/my-secret) where the secret contains `cosign.pub`.
22+
23+
*VSA_PUBLIC_KEY* (`string`):: Public key used to verify signatures. Must be a valid k8s cosign reference (e.g. k8s://my-ns/my-secret) where the secret contains `cosign.pub`.
24+
25+
*REKOR_HOST* (`string`):: Rekor host for transparency log lookups
26+
*IGNORE_REKOR* (`string`):: Skip Rekor transparency log checks during validation.
27+
+
28+
*Default*: `true`
29+
*TUF_MIRROR* (`string`):: TUF mirror URL. Provide a value when NOT using public sigstore deployment.
30+
*SSL_CERT_DIR* (`string`):: Extra certs path(s) for external services. Useful with local
31+
registries/Rekor. Multiple paths can be provided using `:`.
32+
33+
*CA_TRUST_CONFIGMAP_NAME* (`string`):: Name of the ConfigMap to read CA bundle data from.
34+
+
35+
*Default*: `trusted-ca`
36+
*CA_TRUST_CONFIG_MAP_KEY* (`string`):: Key in the ConfigMap that contains the CA bundle data.
37+
+
38+
*Default*: `ca-bundle.crt`
39+
*INFO* (`string`):: Include rule titles/descriptions in output. Set to "false" to disable.
40+
+
41+
*Default*: `true`
42+
*STRICT* (`string`):: Fail the task if policy fails. Set to "false" to disable.
43+
+
44+
*Default*: `true`
45+
*HOMEDIR* (`string`):: Value for the HOME environment variable.
46+
+
47+
*Default*: `/tekton/home`
48+
*EFFECTIVE_TIME* (`string`):: Run policy checks with the provided time.
49+
+
50+
*Default*: `now`
51+
*EXTRA_RULE_DATA* (`string`):: Merge additional Rego variables into the policy data. Syntax: key=val,key2=val2
52+
53+
*TIMEOUT* (`string`):: Deprecated; ignored by the task. EC is run without a timeout (use Tekton timeouts).
54+
55+
*WORKERS* (`string`):: Number of parallel workers to use for policy evaluation.
56+
+
57+
*Default*: `4`
58+
*SINGLE_COMPONENT* (`string`):: Reduce Snapshot to only the component whose build created the Snapshot
59+
+
60+
*Default*: `false`
61+
*SINGLE_COMPONENT_CUSTOM_RESOURCE* (`string`):: Kind/name of the Kubernetes resource to query labels when single component mode is enabled, e.g. pr/somepipeline.
62+
63+
+
64+
*Default*: `unknown`
65+
*SINGLE_COMPONENT_CUSTOM_RESOURCE_NS* (`string`):: Namespace where SINGLE_COMPONENT_CUSTOM_RESOURCE is found (for single component mode).
66+
*ORAS_OPTIONS* (`string`):: ORAS options to pass to Trusted Artifacts calls
67+
*TRUSTED_ARTIFACTS_DEBUG* (`string`):: Enable debug logging in trusted artifacts when non-empty.
68+
*TRUSTED_ARTIFACTS_EXTRACT_DIR* (`string`):: Directory to extract the trusted artifact archive into.
69+
+
70+
*Default*: `/var/workdir/conforma`
71+
*RETRY_DURATION* (`string`):: Base duration for exponential backoff (e.g., "1s", "500ms")
72+
+
73+
*Default*: `1s`
74+
*RETRY_FACTOR* (`string`):: Exponential backoff multiplier (e.g., "2.0", "1.5")
75+
+
76+
*Default*: `2.0`
77+
*RETRY_JITTER* (`string`):: Randomness factor for backoff (0.0-1.0, e.g., "0.1", "0.2")
78+
+
79+
*Default*: `0.1`
80+
*RETRY_MAX_RETRY* (`string`):: Maximum number of retry attempts
81+
+
82+
*Default*: `3`
83+
*RETRY_MAX_WAIT* (`string`):: Maximum wait time between retries (e.g., "3s", "10s")
84+
+
85+
*Default*: `3s`
86+
87+
== Results
88+
89+
[horizontal]
90+
*VSA_TEST_OUTPUT*:: Short summary of the VSA validation result
91+
*IMAGE_RELEASE_TEST_OUTPUT*:: Short summary of the release-time image validation result
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
* xref:tasks.adoc[Tekton Tasks]
22
** xref:verify-conforma-konflux-ta.adoc[verify-conforma-konflux-ta]
3+
** xref:verify-conforma-vsa-release-ta.adoc[verify-conforma-vsa-release-ta]
34
** xref:verify-enterprise-contract.adoc[verify-enterprise-contract]

tasks/verify-conforma-konflux-vsa-ta/0.1/verify-conforma-konflux-vsa-ta.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,12 @@ spec:
287287
- "--workers"
288288
- "$(params.WORKERS)"
289289
- "--strict=false"
290-
- "--debug"
291290
- "--fallback-public-key"
292291
- "$(params.PUBLIC_KEY)"
292+
- "--output"
293+
- "status=$(results.VSA_TEST_OUTPUT.path)"
294+
- "--output"
295+
- "text"
293296
env:
294297
- name: SSL_CERT_DIR
295298
value: >-
@@ -356,8 +359,6 @@ spec:
356359
- "--output"
357360
- "text"
358361
- "--output"
359-
- "text=$(params.HOMEDIR)/text-report.txt?show-successes=false"
360-
- "--output"
361362
- "appstudio=$(results.IMAGE_RELEASE_TEST_OUTPUT.path)"
362363
- "--output"
363364
- "json=$(params.HOMEDIR)/report-json.json"
@@ -421,7 +422,7 @@ spec:
421422
- |
422423
set -euo pipefail
423424
strict='$(params.STRICT)'
424-
vsa_ok=$(jq -r '.result=="SUCCESS" or .result=="WARNING"' \
425+
vsa_ok=$(jq -r '.result=="SUCCESS"' \
425426
"$(results.VSA_TEST_OUTPUT.path)" || echo false)
426427
rel_ok=$(jq -r '.result=="SUCCESS" or .result=="WARNING"' \
427428
"$(results.IMAGE_RELEASE_TEST_OUTPUT.path)" || echo false)

0 commit comments

Comments
 (0)