From 2997b87d9e05ac460fcc177407f4d431e3607c94 Mon Sep 17 00:00:00 2001 From: Dheeraj Date: Mon, 16 Mar 2026 18:41:41 +0530 Subject: [PATCH] feat: Add --show-policy-docs-link flag for validation output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Give users control over policy documentation links in validation reports. Defaults to false to keep demo output clean—production CI can opt in with --show-policy-docs-link=true when they want the help link. Why default to false? Your colleague nailed it: "for demos it's better if the default is false, otherwise every example needs to include the flag." Nobody wants documentation URLs cluttering their quick validation examples. Implementation: - Added persistent flag on parent validate command (all subcommands inherit) - Flag controls display of https://conforma.dev/docs/policy/ link - Link only appears when violations/warnings exist - Updated tests to properly initialize flags - Updated snapshots for new default behavior Usage: # Default - clean output for demos ec validate image --image --policy # Opt-in for production/CI ec validate image --image --policy --show-policy-docs-link=true resolves: EC-1603 Co-Authored-By: Claude Sonnet 4.5 --- cmd/validate/image.go | 16 +- cmd/validate/input.go | 3 +- cmd/validate/validate.go | 1 + cmd/validate/vsa.go | 24 +- cmd/validate/vsa_test.go | 4 + docs/modules/ROOT/pages/ec_validate.adoc | 1 + .../modules/ROOT/pages/ec_validate_image.adoc | 1 + .../modules/ROOT/pages/ec_validate_input.adoc | 1 + .../ROOT/pages/ec_validate_policy.adoc | 1 + docs/modules/ROOT/pages/ec_validate_vsa.adoc | 1 + features/__snapshots__/conftest_test.snap | 162 +++---- features/__snapshots__/initialize.snap | 28 +- features/__snapshots__/inspect_policy.snap | 62 +-- .../__snapshots__/ta_task_validate_image.snap | 162 ------- .../__snapshots__/task_validate_image.snap | 455 ------------------ features/__snapshots__/track_bundle.snap | 86 ++-- features/__snapshots__/validate_image.snap | 2 - features/__snapshots__/validate_input.snap | 89 ++-- features/__snapshots__/vsa.snap | 120 ++--- internal/applicationsnapshot/report.go | 54 ++- internal/applicationsnapshot/report_test.go | 33 +- .../templates/text_report.tmpl | 2 +- internal/input/report.go | 42 +- internal/input/report_test.go | 12 +- internal/input/templates/text_report.tmpl | 2 +- internal/validate/report.go | 16 +- 26 files changed, 396 insertions(+), 984 deletions(-) delete mode 100755 features/__snapshots__/ta_task_validate_image.snap delete mode 100755 features/__snapshots__/task_validate_image.snap diff --git a/cmd/validate/image.go b/cmd/validate/image.go index 4410fb29e..336f1080d 100644 --- a/cmd/validate/image.go +++ b/cmd/validate/image.go @@ -338,6 +338,7 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command { showSuccesses, _ := cmd.Flags().GetBool("show-successes") showWarnings, _ := cmd.Flags().GetBool("show-warnings") + showPolicyDocsLink, _ := cmd.Flags().GetBool("show-policy-docs-link") // worker is responsible for processing one component at a time from the jobs channel, // and for emitting a corresponding result for the component on the results channel. @@ -429,13 +430,14 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command { } reportData := validate_utils.ReportData{ - Snapshot: data.snapshot, - Components: components, - Policy: data.policy, - PolicyInputs: manyPolicyInput, - Expansion: data.expansion, - ShowSuccesses: showSuccesses, - ShowWarnings: showWarnings, + Snapshot: data.snapshot, + Components: components, + Policy: data.policy, + PolicyInputs: manyPolicyInput, + Expansion: data.expansion, + ShowSuccesses: showSuccesses, + ShowWarnings: showWarnings, + ShowPolicyDocsLink: showPolicyDocsLink, } outputOpts := validate_utils.ReportOutputOptions{ Output: data.output, diff --git a/cmd/validate/input.go b/cmd/validate/input.go index 9d4f5808a..698bd9930 100644 --- a/cmd/validate/input.go +++ b/cmd/validate/input.go @@ -121,6 +121,7 @@ func validateInputCmd(validate InputValidationFunc) *cobra.Command { showSuccesses, _ := cmd.Flags().GetBool("show-successes") showWarnings, _ := cmd.Flags().GetBool("show-warnings") + showPolicyDocsLink, _ := cmd.Flags().GetBool("show-policy-docs-link") // Set numWorkers to the value from our flag. The default is 5. numWorkers := data.workers @@ -210,7 +211,7 @@ func validateInputCmd(validate InputValidationFunc) *cobra.Command { return inputs[i].FilePath > inputs[j].FilePath }) - report, err := input.NewReport(inputs, data.policy, manyPolicyInput, showSuccesses, showWarnings) + report, err := input.NewReport(inputs, data.policy, manyPolicyInput, showSuccesses, showWarnings, showPolicyDocsLink) if err != nil { return err } diff --git a/cmd/validate/validate.go b/cmd/validate/validate.go index b4d73dc4b..81a618a33 100644 --- a/cmd/validate/validate.go +++ b/cmd/validate/validate.go @@ -45,5 +45,6 @@ func NewValidateCmd() *cobra.Command { } validateCmd.PersistentFlags().Bool("show-successes", false, "") validateCmd.PersistentFlags().Bool("show-warnings", true, "") + validateCmd.PersistentFlags().Bool("show-policy-docs-link", false, "Show link to policy documentation in output when there are violations or warnings") return validateCmd } diff --git a/cmd/validate/vsa.go b/cmd/validate/vsa.go index 66a37faca..a98fc729a 100644 --- a/cmd/validate/vsa.go +++ b/cmd/validate/vsa.go @@ -126,8 +126,9 @@ type validateVSAData struct { workers int // Number of worker threads for parallel processing // Output formatting options - noColor bool // Disable color output - forceColor bool // Force color output + noColor bool // Disable color output + forceColor bool // Force color output + showPolicyDocsLink bool // Show policy docs link in output // Internal state policySpec ecapi.EnterpriseContractPolicySpec @@ -266,6 +267,9 @@ func runValidateVSA(cmd *cobra.Command, data *validateVSAData, args []string) er // Set color support based on flags utils.SetColorEnabled(data.noColor, data.forceColor) + // Get show-policy-docs-link flag value + data.showPolicyDocsLink, _ = cmd.Flags().GetBool("show-policy-docs-link") + // Parse VSA expiration if err := parseVSAExpiration(data); err != nil { return err @@ -1095,13 +1099,14 @@ func buildFallbackReportData(fallbackResults []validate_utils.Result, vsaData *v } return validate_utils.ReportData{ - Snapshot: vsaData.images, - Components: components, - Policy: vsaData.fallbackContext.FallbackPolicy, - PolicyInputs: manyPolicyInput, - Expansion: nil, - ShowSuccesses: false, - ShowWarnings: true, + Snapshot: vsaData.images, + Components: components, + Policy: vsaData.fallbackContext.FallbackPolicy, + PolicyInputs: manyPolicyInput, + Expansion: nil, + ShowSuccesses: false, + ShowWarnings: true, + ShowPolicyDocsLink: vsaData.showPolicyDocsLink, }, nil } @@ -1121,6 +1126,7 @@ func createFallbackReport(allData AllSectionsData, vsaData *validateVSAData) (*a reportData.PolicyInputs, reportData.ShowSuccesses, reportData.ShowWarnings, + reportData.ShowPolicyDocsLink, reportData.Expansion, ) if err != nil { diff --git a/cmd/validate/vsa_test.go b/cmd/validate/vsa_test.go index af6f746f4..e8c820e58 100644 --- a/cmd/validate/vsa_test.go +++ b/cmd/validate/vsa_test.go @@ -1034,6 +1034,8 @@ func TestValidateSingleVSA(t *testing.T) { ctx := context.Background() cmd := &cobra.Command{} cmd.SetContext(ctx) + // Add the persistent flag that runValidateVSA expects + cmd.Flags().Bool("show-policy-docs-link", false, "") // Use the unified runValidateVSA function which handles both single and snapshot cases err := runValidateVSA(cmd, tt.data, tt.args) @@ -1132,6 +1134,8 @@ func TestValidateSnapshotVSAs(t *testing.T) { ctx := context.Background() cmd := &cobra.Command{} cmd.SetContext(ctx) + // Add the persistent flag that runValidateVSA expects + cmd.Flags().Bool("show-policy-docs-link", false, "") // Use the unified runValidateVSA function which handles both single and snapshot cases err := runValidateVSA(cmd, tt.data, []string{}) diff --git a/docs/modules/ROOT/pages/ec_validate.adoc b/docs/modules/ROOT/pages/ec_validate.adoc index 4ac8b07a8..689206794 100644 --- a/docs/modules/ROOT/pages/ec_validate.adoc +++ b/docs/modules/ROOT/pages/ec_validate.adoc @@ -5,6 +5,7 @@ Validate conformance with the provided policies == Options -h, --help:: help for validate (Default: false) +--show-policy-docs-link:: Show link to policy documentation in output when there are violations or warnings (Default: false) --show-successes:: (Default: false) --show-warnings:: (Default: true) diff --git a/docs/modules/ROOT/pages/ec_validate_image.adoc b/docs/modules/ROOT/pages/ec_validate_image.adoc index f84b30804..d2d67263f 100644 --- a/docs/modules/ROOT/pages/ec_validate_image.adoc +++ b/docs/modules/ROOT/pages/ec_validate_image.adoc @@ -172,6 +172,7 @@ JSON of the "spec" or a reference to a Kubernetes object [/] --retry-jitter:: randomness factor for backoff calculation (0.0-1.0) (Default: 0.1) --retry-max-retry:: maximum number of retry attempts (Default: 3) --retry-max-wait:: maximum wait time between retries (Default: 3s) +--show-policy-docs-link:: Show link to policy documentation in output when there are violations or warnings (Default: false) --show-successes:: (Default: false) --show-warnings:: (Default: true) --timeout:: max overall execution duration (Default: 5m0s) diff --git a/docs/modules/ROOT/pages/ec_validate_input.adoc b/docs/modules/ROOT/pages/ec_validate_input.adoc index 111fdaea3..8445f6041 100644 --- a/docs/modules/ROOT/pages/ec_validate_input.adoc +++ b/docs/modules/ROOT/pages/ec_validate_input.adoc @@ -76,6 +76,7 @@ mark (?) sign, for example: --output text=output.txt?show-successes=false --retry-jitter:: randomness factor for backoff calculation (0.0-1.0) (Default: 0.1) --retry-max-retry:: maximum number of retry attempts (Default: 3) --retry-max-wait:: maximum wait time between retries (Default: 3s) +--show-policy-docs-link:: Show link to policy documentation in output when there are violations or warnings (Default: false) --show-successes:: (Default: false) --show-warnings:: (Default: true) --timeout:: max overall execution duration (Default: 5m0s) diff --git a/docs/modules/ROOT/pages/ec_validate_policy.adoc b/docs/modules/ROOT/pages/ec_validate_policy.adoc index 96e270838..41cc9a79a 100644 --- a/docs/modules/ROOT/pages/ec_validate_policy.adoc +++ b/docs/modules/ROOT/pages/ec_validate_policy.adoc @@ -37,6 +37,7 @@ ec validate policy --policy-configuration github.com/org/repo/policy.yaml --retry-jitter:: randomness factor for backoff calculation (0.0-1.0) (Default: 0.1) --retry-max-retry:: maximum number of retry attempts (Default: 3) --retry-max-wait:: maximum wait time between retries (Default: 3s) +--show-policy-docs-link:: Show link to policy documentation in output when there are violations or warnings (Default: false) --show-successes:: (Default: false) --show-warnings:: (Default: true) --timeout:: max overall execution duration (Default: 5m0s) diff --git a/docs/modules/ROOT/pages/ec_validate_vsa.adoc b/docs/modules/ROOT/pages/ec_validate_vsa.adoc index 284d99b0b..30e8729be 100644 --- a/docs/modules/ROOT/pages/ec_validate_vsa.adoc +++ b/docs/modules/ROOT/pages/ec_validate_vsa.adoc @@ -60,6 +60,7 @@ mark (?) sign, for example: --output text=output.txt?show-successes=false --retry-jitter:: randomness factor for backoff calculation (0.0-1.0) (Default: 0.1) --retry-max-retry:: maximum number of retry attempts (Default: 3) --retry-max-wait:: maximum wait time between retries (Default: 3s) +--show-policy-docs-link:: Show link to policy documentation in output when there are violations or warnings (Default: false) --show-successes:: (Default: false) --show-warnings:: (Default: true) --timeout:: max overall execution duration (Default: 5m0s) diff --git a/features/__snapshots__/conftest_test.snap b/features/__snapshots__/conftest_test.snap index 357d1981e..4c32ee026 100755 --- a/features/__snapshots__/conftest_test.snap +++ b/features/__snapshots__/conftest_test.snap @@ -1,18 +1,23 @@ -[appstudio error nofail:stdout - 1] -{ - "timestamp": "${TIMESTAMP}", - "namespace": "", - "successes": 0, - "failures": 0, - "warnings": 0, - "result": "ERROR", - "note": "Error: running test: load: loading policies: load: 1 error occurred during loading: stat file/not/exist.rego: no such file or directory" -} +[a warning with fail-on-warn:stdout - 1] +[ + { + "filename": "acceptance/examples/empty_input.json", + "namespace": "main", + "successes": 0, + "warnings": [ + { + "msg": "Has a warning", + "metadata": { + "query": "data.main.warn" + } + } + ] + } +] --- -[appstudio error nofail:stderr - 1] -Error: running test: load: loading policies: load: 1 error occurred during loading: stat file/not/exist.rego: no such file or directory +[a warning with fail-on-warn:stderr - 1] --- @@ -32,25 +37,23 @@ Error: running test: load: loading policies: load: 1 error occurred during loadi --- -[a warning:stdout - 1] -[ - { - "filename": "acceptance/examples/empty_input.json", - "namespace": "main", - "successes": 0, - "warnings": [ - { - "msg": "Has a warning", - "metadata": { - "query": "data.main.warn" - } - } - ] - } -] +[normal error:stdout - 1] + --- -[a warning:stderr - 1] +[normal error:stderr - 1] +Error: running test: load: loading policies: load: 1 error occurred during loading: stat file/not/exist.rego: no such file or directory + +--- + +[plain text deny:stdout - 1] +FAIL - acceptance/examples/empty_input.json - main - Failure due to overripeness + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +--- + +[plain text deny:stderr - 1] --- @@ -71,19 +74,7 @@ Error: running test: parse configurations: parser unmarshal: unmarshal json: inv --- -[appstudio success:stdout - 1] -{ - "timestamp": "${TIMESTAMP}", - "namespace": "main", - "successes": 1, - "failures": 0, - "warnings": 0, - "result": "SUCCESS", - "note": "All checks passed successfully" -} ---- - -[a deny with no-fail:stdout - 1] +[a deny:stdout - 1] [ { "filename": "acceptance/examples/empty_input.json", @@ -101,11 +92,7 @@ Error: running test: parse configurations: parser unmarshal: unmarshal json: inv ] --- -[appstudio success:stderr - 1] - ---- - -[a deny with no-fail:stderr - 1] +[a deny:stderr - 1] --- @@ -121,7 +108,27 @@ Error: running test: parse configurations: parser unmarshal: unmarshal json: inv } --- -[a deny:stdout - 1] +[appstudio deny:stderr - 1] + +--- + +[appstudio success:stdout - 1] +{ + "timestamp": "${TIMESTAMP}", + "namespace": "main", + "successes": 1, + "failures": 0, + "warnings": 0, + "result": "SUCCESS", + "note": "All checks passed successfully" +} +--- + +[appstudio success:stderr - 1] + +--- + +[a deny with no-fail:stdout - 1] [ { "filename": "acceptance/examples/empty_input.json", @@ -139,15 +146,28 @@ Error: running test: parse configurations: parser unmarshal: unmarshal json: inv ] --- -[appstudio deny:stderr - 1] +[a deny with no-fail:stderr - 1] --- -[a deny:stderr - 1] +[appstudio error nofail:stdout - 1] +{ + "timestamp": "${TIMESTAMP}", + "namespace": "", + "successes": 0, + "failures": 0, + "warnings": 0, + "result": "ERROR", + "note": "Error: running test: load: loading policies: load: 1 error occurred during loading: stat file/not/exist.rego: no such file or directory" +} +--- + +[appstudio error nofail:stderr - 1] +Error: running test: load: loading policies: load: 1 error occurred during loading: stat file/not/exist.rego: no such file or directory --- -[a warning with fail-on-warn:stdout - 1] +[a warning:stdout - 1] [ { "filename": "acceptance/examples/empty_input.json", @@ -165,50 +185,35 @@ Error: running test: parse configurations: parser unmarshal: unmarshal json: inv ] --- -[a warning with fail-on-warn:stderr - 1] +[a warning:stderr - 1] --- -[appstudio skipped:stdout - 1] +[appstudio error:stdout - 1] { "timestamp": "${TIMESTAMP}", - "namespace": "main", + "namespace": "", "successes": 0, "failures": 0, "warnings": 0, - "result": "SKIPPED", - "note": "All checks were skipped" + "result": "ERROR", + "note": "Error: running test: load: loading policies: load: 1 error occurred during loading: stat file/not/exist.rego: no such file or directory" } --- -[appstudio skipped:stderr - 1] - ---- - -[plain text deny:stdout - 1] -FAIL - acceptance/examples/empty_input.json - main - Failure due to overripeness - -1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions - ---- - -[plain text deny:stderr - 1] - ---- - -[appstudio error:stdout - 1] +[appstudio skipped:stdout - 1] { "timestamp": "${TIMESTAMP}", - "namespace": "", + "namespace": "main", "successes": 0, "failures": 0, "warnings": 0, - "result": "ERROR", - "note": "Error: running test: load: loading policies: load: 1 error occurred during loading: stat file/not/exist.rego: no such file or directory" + "result": "SKIPPED", + "note": "All checks were skipped" } --- -[normal error:stdout - 1] +[appstudio skipped:stderr - 1] --- @@ -217,11 +222,6 @@ Error: running test: load: loading policies: load: 1 error occurred during loadi --- -[normal error:stderr - 1] -Error: running test: load: loading policies: load: 1 error occurred during loading: stat file/not/exist.rego: no such file or directory - ---- - [success:stdout - 1] [ { diff --git a/features/__snapshots__/initialize.snap b/features/__snapshots__/initialize.snap index c3f1cb37f..d6f590234 100755 --- a/features/__snapshots__/initialize.snap +++ b/features/__snapshots__/initialize.snap @@ -1,18 +1,4 @@ -[success:stdout - 1] -[ - { - "filename": "acceptance/examples/empty_input.json", - "namespace": "main", - "successes": 1 - } -] ---- - -[success:stderr - 1] - ---- - [appstudio success:stdout - 1] { "timestamp": "${TIMESTAMP}", @@ -28,3 +14,17 @@ [appstudio success:stderr - 1] --- + +[success:stdout - 1] +[ + { + "filename": "acceptance/examples/empty_input.json", + "namespace": "main", + "successes": 1 + } +] +--- + +[success:stderr - 1] + +--- diff --git a/features/__snapshots__/inspect_policy.snap b/features/__snapshots__/inspect_policy.snap index 78b93f8d8..eb291cb3a 100755 --- a/features/__snapshots__/inspect_policy.snap +++ b/features/__snapshots__/inspect_policy.snap @@ -1,35 +1,4 @@ -[inspecting a data source:stdout - 1] -{ - "rule_data": { - "banana_fail_reason": "spider attack" - }, - "spam_count": 42 -} ---- - -[inspecting a data source:stderr - 1] - ---- - -[short names output:stdout - 1] -kitty.purr - ---- - -[short names output:stderr - 1] - ---- - -[inspecting a data source with a merge error:stdout - 1] - ---- - -[inspecting a data source with a merge error:stderr - 1] -Error: Merge error. The 'rule_data' key was found more than once! - ---- - [json output:stdout - 1] { "git::${GITHOST}/git/policy.git?ref=${LATEST_COMMIT}": [ @@ -85,6 +54,37 @@ Fluffy --- +[short names output:stdout - 1] +kitty.purr + +--- + +[short names output:stderr - 1] + +--- + +[inspecting a data source:stdout - 1] +{ + "rule_data": { + "banana_fail_reason": "spider attack" + }, + "spam_count": 42 +} +--- + +[inspecting a data source:stderr - 1] + +--- + +[inspecting a data source with a merge error:stdout - 1] + +--- + +[inspecting a data source with a merge error:stderr - 1] +Error: Merge error. The 'rule_data' key was found more than once! + +--- + [sources from ECP:stdout - 1] # Source: git::${GITHOST}/git/policy1.git?ref=f81eaf65be8da58460ff920408ba1313051184a1 diff --git a/features/__snapshots__/ta_task_validate_image.snap b/features/__snapshots__/ta_task_validate_image.snap deleted file mode 100755 index 45b2ae93a..000000000 --- a/features/__snapshots__/ta_task_validate_image.snap +++ /dev/null @@ -1,162 +0,0 @@ - -[Golden container image with trusted artifacts:report-json - 1] -{ - "success": true, - "components": [ - { - "name": "", - "containerImage": "quay.io/hacbs-contract-demo/golden-container@sha256:e76a4ae9dd8a52a0d191fd34ca133af5b4f2609536d32200a4a40a09fdc93a0d", - "source": {}, - "successes": [ - { - "msg": "Pass", - "metadata": { - "code": "builtin.attestation.signature_check", - "description": "The attestation signature matches available signing materials.", - "title": "Attestation signature check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "builtin.attestation.syntax_check", - "description": "The attestation has correct syntax.", - "title": "Attestation syntax check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "builtin.image.signature_check", - "description": "The image signature matches available signing materials.", - "title": "Image signature check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "slsa_provenance_available.allowed_predicate_types_provided", - "collections": [ - "minimal", - "slsa3", - "redhat", - "redhat_rpms", - "policy_data" - ], - "description": "Confirm the `allowed_predicate_types` rule data was provided, since it is required by the policy rules in this package.", - "title": "Allowed predicate types provided" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "slsa_provenance_available.attestation_predicate_type_accepted", - "collections": [ - "minimal", - "slsa3", - "redhat", - "redhat_rpms" - ], - "depends_on": [ - "attestation_type.known_attestation_type" - ], - "description": "Verify that the predicateType field of the attestation indicates the in-toto SLSA Provenance format was used to attest the PipelineRun.", - "title": "Expected attestation predicate type found" - } - } - ], - "success": true, - "signatures": [ - { - "keyid": "", - "sig": "MEUCIFPod1d9HhGt+TEQPG4j+LINjkifCFFOFrE4jbkvexGGAiEAqSp3ROZUsIOwWro6Tv+lRiR7sdMR0U6Crs1ISuQhHtA=" - } - ], - "attestations": [ - { - "type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v0.2", - "predicateBuildType": "tekton.dev/v1beta1/TaskRun", - "signatures": [ - { - "keyid": "SHA256:RHajkr+wMEtGfT2CRFrQEhg/8MY2bDLXVg3F8IuI5nE", - "sig": "MEUCIHFVZeVR59n9UvN1dwF9Lh3Gv8XWLPDPIIJcnQ8e3TtvAiEA0z/5v6ggvmQyQ1EnYTJo9rwxOYuve4th4P/0639orLg=" - } - ] - }, - { - "type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v0.2", - "predicateBuildType": "tekton.dev/v1beta1/PipelineRun", - "signatures": [ - { - "keyid": "SHA256:RHajkr+wMEtGfT2CRFrQEhg/8MY2bDLXVg3F8IuI5nE", - "sig": "MEUCIQClx1zvZGvyRu5gCHiC+oWVZTmWJGQlocSZMnzx/5omZAIgUiLQuMm+USYE+H0PDn/xPSVVQjkhWjDc3fulkxVzlC0=" - } - ] - }, - { - "type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v0.2", - "predicateBuildType": "tekton.dev/v1beta1/PipelineRun", - "signatures": [ - { - "keyid": "SHA256:RHajkr+wMEtGfT2CRFrQEhg/8MY2bDLXVg3F8IuI5nE", - "sig": "MEUCIGS176zN5aoorLQMukjoCkHm7ocu7UhnKXLhzEdsgp4BAiEAviub3Lf4thLmSTU6ZqnEjw02kkrb9LKBBa1t8hVgAM4=" - } - ] - } - ] - } - ], - "key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\n-----END PUBLIC KEY-----\n", - "policy": { - "sources": [ - { - "policy": [ - "git::github.com/conforma/policy//policy/release?ref=d34eab36b23d43748e451004177ca144296bf323", - "git::github.com/conforma/policy//policy/lib?ref=d34eab36b23d43748e451004177ca144296bf323" - ], - "config": { - "include": [ - "slsa_provenance_available" - ] - } - } - ], - "publicKey": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\n-----END PUBLIC KEY-----" - }, - "ec-version": "${EC_VERSION}", - "effective-time": "${TIMESTAMP}" -} ---- - -[Golden container image with trusted artifacts:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n", - "VSA_GENERATED": "false" -} ---- - -[Golden container image with trusted artifacts:show-config - 1] -{ - "policy": { - "sources": [ - { - "policy": [ - "git::github.com/conforma/policy//policy/release?ref=d34eab36b23d43748e451004177ca144296bf323", - "git::github.com/conforma/policy//policy/lib?ref=d34eab36b23d43748e451004177ca144296bf323" - ], - "config": { - "include": [ - "slsa_provenance_available" - ] - } - } - ], - "publicKey": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\n-----END PUBLIC KEY-----" - }, - "key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\n-----END PUBLIC KEY-----\n", - "effective-time": "${TIMESTAMP}" -} ---- diff --git a/features/__snapshots__/task_validate_image.snap b/features/__snapshots__/task_validate_image.snap deleted file mode 100755 index 91a7a9e69..000000000 --- a/features/__snapshots__/task_validate_image.snap +++ /dev/null @@ -1,455 +0,0 @@ - -[Non strict with warnings:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":3,\"failures\":0,\"warnings\":1,\"result\":\"WARNING\"}\n" -} ---- - -[Outputs are there:initialize-tuf - 1] -${TIMESTAMP} INFO Step was skipped due to when expressions were evaluated to false. - ---- - -[Golden container image:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" -} ---- - -[Initialize TUF fails:initialize-tuf - 1] -Error: Get "http://tuf.invalid/root.json": dial tcp: lookup tuf.invalid on 10.96.0.10:53: no such host - ---- - -[Titles and descriptions can be excluded:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":3,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" -} ---- - -[Strict with failures:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":0,\"failures\":1,\"warnings\":0,\"result\":\"FAILURE\"}\n" -} ---- - -[Golden container image:show-config - 1] -{ - "policy": { - "sources": [ - { - "policy": [ - "git::github.com/conforma/policy//policy/release?ref=0de5461c14413484575e63e96ddb514d8ab954b5", - "git::github.com/conforma/policy//policy/lib?ref=0de5461c14413484575e63e96ddb514d8ab954b5" - ], - "config": { - "include": [ - "slsa_provenance_available" - ] - } - } - ], - "publicKey": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\n-----END PUBLIC KEY-----" - }, - "key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\n-----END PUBLIC KEY-----\n", - "effective-time": "${TIMESTAMP}" -} ---- - -[Extra rule data provided to task:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" -} ---- - -[Initialize TUF succeeds:initialize-tuf - 1] -${TIMESTAMP} INFO Step was skipped due to when expressions were evaluated to false. - ---- - -[Strict with warnings:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":3,\"failures\":0,\"warnings\":1,\"result\":\"WARNING\"}\n" -} ---- - -[Non strict with failures:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":0,\"failures\":1,\"warnings\":0,\"result\":\"FAILURE\"}\n" -} ---- - -[PUBLIC_KEY param overwrites key from policy:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":3,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" -} ---- - -[Outputs are there:summary - 1] -{ - "timestamp": "${TIMESTAMP}", - "namespace": "", - "successes": 3, - "failures": 0, - "warnings": 0, - "result": "SUCCESS" -} ---- - -[Initialize TUF fails:results - 1] -{} ---- - -[Initialize TUF succeeds:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" -} ---- - -[Outputs are there:assert - 1] -true ---- - -[Outputs are there:report-json - 1] -{ - "success": true, - "components": [ - { - "name": "", - "containerImage": "${REGISTRY}/acceptance/okayish@sha256:${REGISTRY_acceptance/okayish:latest_DIGEST}", - "source": {}, - "successes": [ - { - "msg": "Pass", - "metadata": { - "code": "builtin.attestation.signature_check", - "description": "The attestation signature matches available signing materials.", - "title": "Attestation signature check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "builtin.attestation.syntax_check", - "description": "The attestation has correct syntax.", - "title": "Attestation syntax check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "builtin.image.signature_check", - "description": "The image signature matches available signing materials.", - "title": "Image signature check passed" - } - } - ], - "success": true, - "signatures": [ - { - "keyid": "", - "sig": "${IMAGE_SIGNATURE_acceptance/okayish}" - } - ], - "attestations": [ - { - "type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v0.2", - "predicateBuildType": "https://tekton.dev/attestations/chains/pipelinerun@v2", - "signatures": [ - { - "keyid": "", - "sig": "${ATTESTATION_SIGNATURE_acceptance/okayish}" - } - ] - } - ] - } - ], - "key": "${known_PUBLIC_KEY}", - "policy": { - "publicKey": "${known_PUBLIC_KEY}" - }, - "ec-version": "${EC_VERSION}", - "effective-time": "${TIMESTAMP}" -} ---- - -[Outputs are there:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":3,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" -} ---- - -[Keyless signing verification cosign v3 style:report-json - 1] -{ - "success": true, - "components": [ - { - "name": "", - "containerImage": "quay.io/conforma/test@sha256:712ca3a7fcd41fe6b3e6f434a31f738743b6c31f1d81ad458502d6b0239a8903", - "source": {}, - "successes": [ - { - "msg": "Pass", - "metadata": { - "code": "builtin.attestation.signature_check", - "description": "The attestation signature matches available signing materials.", - "title": "Attestation signature check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "builtin.attestation.syntax_check", - "description": "The attestation has correct syntax.", - "title": "Attestation syntax check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "builtin.image.signature_check", - "description": "The image signature matches available signing materials.", - "title": "Image signature check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "slsa_provenance_available.allowed_predicate_types_provided", - "collections": [ - "minimal", - "slsa3", - "redhat", - "redhat_rpms", - "policy_data" - ], - "description": "Confirm the `allowed_predicate_types` rule data was provided, since it is required by the policy rules in this package.", - "title": "Allowed predicate types provided" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "slsa_provenance_available.attestation_predicate_type_accepted", - "collections": [ - "minimal", - "slsa3", - "redhat", - "redhat_rpms" - ], - "depends_on": [ - "attestation_type.known_attestation_type" - ], - "description": "Verify that the predicateType field of the attestation indicates the in-toto SLSA Provenance format was used to attest the PipelineRun.", - "title": "Expected attestation predicate type found" - } - } - ], - "success": true, - "signatures": [ - { - "keyid": "", - "sig": "" - }, - { - "keyid": "", - "sig": "" - } - ], - "attestations": [ - { - "type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v1", - "signatures": [ - { - "keyid": "", - "sig": "MEUCIQC5bGm4zzbExXBMrZCmqZ98iqUhi8TV/maq/8dJ/c3POAIgCNw+RkeO7PAkT6JDWIvISZ2AjILu9YuPQ0qqfNwCqug=" - } - ] - }, - { - "type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://sigstore.dev/cosign/sign/v1", - "signatures": [ - { - "keyid": "", - "sig": "MEUCID1cJkxyk1oGvXcoAVkDST9A1vfX2gxPEz+LUzN10nDmAiEAxh9rp79yr4fZmAWWOit0dZ5QWK+uYIU8fQVb0/rLIyM=" - } - ] - } - ] - } - ], - "key": "", - "policy": { - "sources": [ - { - "policy": [ - "git::github.com/conforma/policy//policy/release?ref=0de5461c14413484575e63e96ddb514d8ab954b5", - "git::github.com/conforma/policy//policy/lib?ref=0de5461c14413484575e63e96ddb514d8ab954b5" - ], - "config": { - "include": [ - "slsa_provenance_available" - ] - } - } - ], - "rekorUrl": "https://rekor.sigstore.dev" - }, - "ec-version": "${EC_VERSION}", - "effective-time": "${TIMESTAMP}" -} ---- - -[Keyless signing verification cosign v3 style:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" -} ---- - -[Keyless signing verification cosign v2 style:report-json - 1] -{ - "success": true, - "components": [ - { - "name": "", - "containerImage": "quay.io/conforma/test@sha256:03a10dff06ae364ef9727d562e7077b135b00c7a978e571c4354519e6d0f23b8", - "source": {}, - "successes": [ - { - "msg": "Pass", - "metadata": { - "code": "builtin.attestation.signature_check", - "description": "The attestation signature matches available signing materials.", - "title": "Attestation signature check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "builtin.attestation.syntax_check", - "description": "The attestation has correct syntax.", - "title": "Attestation syntax check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "builtin.image.signature_check", - "description": "The image signature matches available signing materials.", - "title": "Image signature check passed" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "slsa_provenance_available.allowed_predicate_types_provided", - "collections": [ - "minimal", - "slsa3", - "redhat", - "redhat_rpms", - "policy_data" - ], - "description": "Confirm the `allowed_predicate_types` rule data was provided, since it is required by the policy rules in this package.", - "title": "Allowed predicate types provided" - } - }, - { - "msg": "Pass", - "metadata": { - "code": "slsa_provenance_available.attestation_predicate_type_accepted", - "collections": [ - "minimal", - "slsa3", - "redhat", - "redhat_rpms" - ], - "depends_on": [ - "attestation_type.known_attestation_type" - ], - "description": "Verify that the predicateType field of the attestation indicates the in-toto SLSA Provenance format was used to attest the PipelineRun.", - "title": "Expected attestation predicate type found" - } - } - ], - "success": true, - "signatures": [ - { - "keyid": "dc5f3121f1f76f0d687877532ce44ff55aab2050", - "sig": "MEUCIQDV4du9T+vV6dtN1LsCrZgByokRslw43oxscniN3wbaigIgMV+NFgix7ZjqhIpXFIMVFl1CQuya8JQsYP96ByA5iAc=", - "certificate": "-----BEGIN CERTIFICATE-----\nMIIC0zCCAlqgAwIBAgIUfPJP4pJfIr6Pgt2Q2J9hu4DqoJcwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjYwMzAzMTkxNjUyWhcNMjYwMzAzMTkyNjUyWjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEGMk9duvfPU07wcRpBWKXUi8bmr833N3pKhP2\nGCVBlFxZIRcD01FKT4TEMvlRIq8gZJO4eQ/WvEL/NpNmkk+PzaOCAXkwggF1MA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU3F8x\nIfH3bw1oeHdTLORP9VqrIFAwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wKQYDVR0RAQH/BB8wHYEbY29uZm9ybWFjb21tdW5pdHlAZ21haWwuY29tMCkG\nCisGAQQBg78wAQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTArBgorBgEE\nAYO/MAEIBB0MG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBigYKKwYBBAHW\neQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAAB\nnLUhueMAAAQDAEcwRQIgARu6tEmE0vUHU+MhCQB6tzwROaEn4VdlfGBFWQxxcygC\nIQCHm2/lgszmmt2gC6Pl2bfvCRDKewUQDvWjzNqq8WtPczAKBggqhkjOPQQDAwNn\nADBkAjAMnyVwJVMQflB7Iwfte7cuOYYN2uvmEibKwjmmPgZOq43vSH9Y9gtUvyJk\nZ23vTpwCMHKChuWjhTQgxczH7MhKUO2IphbaHeJYmeFa4rrswhv6h9z6v5IIPovF\nsdbKg+sEHw==\n-----END CERTIFICATE-----\n", - "chain": [ - "-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7\n7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS\n0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB\nBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp\nKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI\nzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR\nnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP\nmygUY7Ii2zbdCdliiow=\n-----END CERTIFICATE-----\n", - "-----BEGIN CERTIFICATE-----\nMIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7\nXeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex\nX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j\nYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY\nwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ\nKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM\nWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9\nTNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\n-----END CERTIFICATE-----\n" - ], - "metadata": { - "Fulcio Issuer": "https://accounts.google.com", - "Fulcio Issuer (V2)": "https://accounts.google.com", - "Issuer": "CN=sigstore-intermediate,O=sigstore.dev", - "Not After": "${TIMESTAMP}", - "Not Before": "${TIMESTAMP}", - "Serial Number": "7cf24fe2925f22be8f82dd90d89f61bb80eaa097", - "Subject Alternative Name": "Email Addresses:conformacommunity@gmail.com" - } - } - ], - "attestations": [ - { - "type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v1", - "predicateBuildType": "https://example.com/build-type/v1", - "signatures": [ - { - "keyid": "17d7418e0517e21e30f4fe144128b7ca1d1bb2ac", - "sig": "MEUCIBvsTgzJ5DOVIEAH/u5eav7C3QXx6ttR0tZxFQlJe6c4AiEAtIid+gk+EqgxSYNBLquaq2dfdWBL28yR1EOjn/Fi1T8=", - "certificate": "-----BEGIN CERTIFICATE-----\nMIIC1TCCAlqgAwIBAgIUPUQSAPNDQoKF8C3ufUx0Jta8GvEwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjYwMzAzMTkxNzA1WhcNMjYwMzAzMTkyNzA1WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE81mfg8hXUQRHdZpbbST2ckHT4YrcRPRvM+tc\nRmcvvexGuwm0yIOBZqIqXeyd/YrJn9MjBdHrmyKIztdR9mdpUaOCAXkwggF1MA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUF9dB\njgUX4h4w9P4UQSi3yh0bsqwwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wKQYDVR0RAQH/BB8wHYEbY29uZm9ybWFjb21tdW5pdHlAZ21haWwuY29tMCkG\nCisGAQQBg78wAQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTArBgorBgEE\nAYO/MAEIBB0MG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBigYKKwYBBAHW\neQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAAB\nnLUh7ZUAAAQDAEcwRQIgY5+UpYgU0LsrAiTQSoeLquv9EVJ8lH4rtxQupmSWDWwC\nIQC6zpOJpx/ryldrjdpfycB9wBWIexg+/XC8Avdv9W2D3jAKBggqhkjOPQQDAwNp\nADBmAjEA/LIHzfKog0PwRohtlpLV32CpVyWrTt9jK84quvooFP5dgeegze/A4mrk\n0bO73KdEAjEA94BFoAYPJw1RTmIw5VnZXbYKqhlt0hm4nTx9pVoGQMFEtnIguX7f\nNnaoX2+paxVF\n-----END CERTIFICATE-----\n", - "chain": [ - "-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7\n7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS\n0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB\nBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp\nKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI\nzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR\nnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP\nmygUY7Ii2zbdCdliiow=\n-----END CERTIFICATE-----\n", - "-----BEGIN CERTIFICATE-----\nMIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7\nXeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex\nX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j\nYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY\nwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ\nKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM\nWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9\nTNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\n-----END CERTIFICATE-----\n" - ], - "metadata": { - "Fulcio Issuer": "https://accounts.google.com", - "Fulcio Issuer (V2)": "https://accounts.google.com", - "Issuer": "CN=sigstore-intermediate,O=sigstore.dev", - "Not After": "${TIMESTAMP}", - "Not Before": "${TIMESTAMP}", - "Serial Number": "3d441200f343428285f02dee7d4c7426d6bc1af1", - "Subject Alternative Name": "Email Addresses:conformacommunity@gmail.com" - } - } - ] - } - ] - } - ], - "key": "", - "policy": { - "sources": [ - { - "policy": [ - "git::github.com/conforma/policy//policy/release?ref=0de5461c14413484575e63e96ddb514d8ab954b5", - "git::github.com/conforma/policy//policy/lib?ref=0de5461c14413484575e63e96ddb514d8ab954b5" - ], - "config": { - "include": [ - "slsa_provenance_available" - ] - } - } - ], - "rekorUrl": "https://rekor.sigstore.dev" - }, - "ec-version": "${EC_VERSION}", - "effective-time": "${TIMESTAMP}" -} ---- - -[Keyless signing verification cosign v2 style:results - 1] -{ - "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" -} ---- diff --git a/features/__snapshots__/track_bundle.snap b/features/__snapshots__/track_bundle.snap index 1a38b3a95..fae7f6325 100755 --- a/features/__snapshots__/track_bundle.snap +++ b/features/__snapshots__/track_bundle.snap @@ -1,110 +1,110 @@ -[Fresh tags:stdout - 1] +[Track git references, append to existing:stdout - 1] /-/-/-/ trusted_tasks: - oci://${REGISTRY}/acceptance/bundle:tag: - - ref: sha256:${REGISTRY_acceptance/bundle:tag_DIGEST} + git+https://forge.io/organization/repository.git//task/0.1/task.yaml: + - ref: f0cacc1af00d - expires_on: "${TIMESTAMP}" - ref: sha256:0af8c4f92f4b252b3ef0cbd712e7352196bc33a96c58b6e1d891b26e171deae8 + ref: f0cacc1a --- -[Fresh tags:stderr - 1] +[Track git references, append to existing:stderr - 1] --- -[Track git references, without git id:stdout - 1] +[Track git references:stdout - 1] +/-/-/-/ +trusted_tasks: + git+https://github.com/konflux-ci/build-definitions.git//task/buildah/0.1/buildah.yaml: + - ref: 3672a457e3e89c0591369f609eba727b8e84108f --- -[Track git references, without git id:stderr - 1] -Error: expected "git+https://${GITHOST}/git/tasks.git//task.yaml" to contain the revision information following the `@`, e.g. git+https://github.com/org/repository//task/0.1/task.yaml@f0cacc1a, to fetch the latest revision from a remote URL provide the --freshen parameter +[Track git references:stderr - 1] --- -[Pipeline definition is ignored on its own:stdout - 1] +[Pipeline definition is ignored from mixed bundle:stdout - 1] /-/-/-/ -{} +trusted_tasks: + oci://${REGISTRY}/acceptance/bundle:tag: + - ref: sha256:${REGISTRY_acceptance/bundle:tag_DIGEST} --- -[Pipeline definition is ignored on its own:stderr - 1] +[Track git references, with prune:stdout - 1] +/-/-/-/ +trusted_tasks: + git+https://forge.io/organization/repository.git//task/0.1/task.yaml: + - ref: f0cacc1a --- -[Track tekton-task alias:stdout - 1] -/-/-/-/ -trusted_tasks: - git+https://github.com/konflux-ci/build-definitions.git//task/buildah/0.1/buildah.yaml: - - ref: 3672a457e3e89c0591369f609eba727b8e84108f - oci://${REGISTRY}/acceptance/bundle:tag: - - ref: sha256:${REGISTRY_acceptance/bundle:tag_DIGEST} +[Track git references, with prune:stderr - 1] --- -[Track tekton-task alias:stderr - 1] +[Pipeline definition is ignored from mixed bundle:stderr - 1] --- -[Track git references, with freshen:stdout - 1] +[Track tekton-task alias:stdout - 1] /-/-/-/ trusted_tasks: - git+https://${GITHOST}/git/tasks.git//task.yaml: - - ref: ${LATEST_COMMIT} + git+https://github.com/konflux-ci/build-definitions.git//task/buildah/0.1/buildah.yaml: + - ref: 3672a457e3e89c0591369f609eba727b8e84108f + oci://${REGISTRY}/acceptance/bundle:tag: + - ref: sha256:${REGISTRY_acceptance/bundle:tag_DIGEST} --- -[Track git references, with freshen:stderr - 1] +[Track tekton-task alias:stderr - 1] --- -[Track git references, with prune:stdout - 1] -/-/-/-/ -trusted_tasks: - git+https://forge.io/organization/repository.git//task/0.1/task.yaml: - - ref: f0cacc1a +[Track git references, without git id:stdout - 1] --- -[Track git references, with prune:stderr - 1] +[Track git references, without git id:stderr - 1] +Error: expected "git+https://${GITHOST}/git/tasks.git//task.yaml" to contain the revision information following the `@`, e.g. git+https://github.com/org/repository//task/0.1/task.yaml@f0cacc1a, to fetch the latest revision from a remote URL provide the --freshen parameter --- -[Track git references, append to existing:stdout - 1] +[Fresh tags:stdout - 1] /-/-/-/ trusted_tasks: - git+https://forge.io/organization/repository.git//task/0.1/task.yaml: - - ref: f0cacc1af00d + oci://${REGISTRY}/acceptance/bundle:tag: + - ref: sha256:${REGISTRY_acceptance/bundle:tag_DIGEST} - expires_on: "${TIMESTAMP}" - ref: f0cacc1a + ref: sha256:0af8c4f92f4b252b3ef0cbd712e7352196bc33a96c58b6e1d891b26e171deae8 --- -[Track git references, append to existing:stderr - 1] +[Fresh tags:stderr - 1] --- -[Pipeline definition is ignored from mixed bundle:stdout - 1] +[Track git references, with freshen:stdout - 1] /-/-/-/ trusted_tasks: - oci://${REGISTRY}/acceptance/bundle:tag: - - ref: sha256:${REGISTRY_acceptance/bundle:tag_DIGEST} + git+https://${GITHOST}/git/tasks.git//task.yaml: + - ref: ${LATEST_COMMIT} --- -[Pipeline definition is ignored from mixed bundle:stderr - 1] +[Track git references, with freshen:stderr - 1] --- -[Track git references:stdout - 1] +[Pipeline definition is ignored on its own:stdout - 1] /-/-/-/ -trusted_tasks: - git+https://github.com/konflux-ci/build-definitions.git//task/buildah/0.1/buildah.yaml: - - ref: 3672a457e3e89c0591369f609eba727b8e84108f +{} --- -[Track git references:stderr - 1] +[Pipeline definition is ignored on its own:stderr - 1] --- diff --git a/features/__snapshots__/validate_image.snap b/features/__snapshots__/validate_image.snap index 10af79f2b..a4d79fedb 100755 --- a/features/__snapshots__/validate_image.snap +++ b/features/__snapshots__/validate_image.snap @@ -1991,7 +1991,6 @@ Results: Title: Allow rule Description: This rule will never fail -For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/ --- [future failure is a deny when using effective-date flag:stdout - 1] @@ -4858,7 +4857,6 @@ Results: ImageRef: ${REGISTRY}/acceptance/image@sha256:${REGISTRY_acceptance/image:latest_DIGEST} Reason: Fails always -For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/ --- diff --git a/features/__snapshots__/validate_input.snap b/features/__snapshots__/validate_input.snap index 149c21ded..4fce88211 100755 --- a/features/__snapshots__/validate_input.snap +++ b/features/__snapshots__/validate_input.snap @@ -1,48 +1,10 @@ -[valid policy URL:stdout - 1] -{ - "success": true, - "filepaths": [ - { - "filepath": "pipeline_definition.yaml", - "violations": [], - "warnings": [], - "successes": null, - "success": true, - "success-count": 1 - } - ], - "policy": { - "sources": [ - { - "policy": [ - "git::https://${GITHOST}/git/happy-day-policy.git" - ] - } - ] - }, - "ec-version": "${EC_VERSION}", - "effective-time": "${TIMESTAMP}" -} ---- - -[valid policy URL:stderr - 1] - ---- -[valid policy URL with text output:stdout - 1] -Success: true -Result: SUCCESS -Violations: 0, Warnings: 0, Successes: 1 -Input File: pipeline_definition.yaml - -Results: -✓ [Success] main.acceptor - FilePath: pipeline_definition.yaml - +[policy URL with no rego files:stdout - 1] --- -[valid policy URL with text output:stderr - 1] +[policy URL with no rego files:stderr - 1] +Error: error validating file pipeline_definition.yaml: evaluating policy: no rego files found in policy subdirectory --- @@ -105,12 +67,20 @@ Error: error validating file input.json: evaluating policy: load: load documents --- -[policy URL with no rego files:stdout - 1] +[valid policy URL with text output:stdout - 1] +Success: true +Result: SUCCESS +Violations: 0, Warnings: 0, Successes: 1 +Input File: pipeline_definition.yaml + +Results: +✓ [Success] main.acceptor + FilePath: pipeline_definition.yaml + --- -[policy URL with no rego files:stderr - 1] -Error: error validating file pipeline_definition.yaml: evaluating policy: no rego files found in policy subdirectory +[valid policy URL with text output:stderr - 1] --- @@ -171,3 +141,34 @@ success: true [valid policy URL with publicKey in policy config:stderr - 1] --- + +[valid policy URL:stdout - 1] +{ + "success": true, + "filepaths": [ + { + "filepath": "pipeline_definition.yaml", + "violations": [], + "warnings": [], + "successes": null, + "success": true, + "success-count": 1 + } + ], + "policy": { + "sources": [ + { + "policy": [ + "git::https://${GITHOST}/git/happy-day-policy.git" + ] + } + ] + }, + "ec-version": "${EC_VERSION}", + "effective-time": "${TIMESTAMP}" +} +--- + +[valid policy URL:stderr - 1] + +--- diff --git a/features/__snapshots__/vsa.snap b/features/__snapshots__/vsa.snap index e6da80a3d..2f50c4da8 100755 --- a/features/__snapshots__/vsa.snap +++ b/features/__snapshots__/vsa.snap @@ -1,17 +1,17 @@ -[VSA expiration flag functionality:stdout - 1] +[VSA generation with invalid storage backend configuration:stdout - 1] { "success": true, "components": [ { "name": "Unnamed", - "containerImage": "${REGISTRY}/acceptance/vsa-expiration-image@sha256:${REGISTRY_acceptance/vsa-expiration-image:latest_DIGEST}", + "containerImage": "${REGISTRY}/acceptance/vsa-invalid-image@sha256:${REGISTRY_acceptance/vsa-invalid-image:latest_DIGEST}", "source": {}, "success": true, "signatures": [ { "keyid": "", - "sig": "${IMAGE_SIGNATURE_acceptance/vsa-expiration-image}" + "sig": "${IMAGE_SIGNATURE_acceptance/vsa-invalid-image}" } ], "attestations": [ @@ -22,48 +22,49 @@ "signatures": [ { "keyid": "", - "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-expiration-image}" + "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-invalid-image}" } ] } ] } ], - "key": "${vsa-expiration_PUBLIC_KEY_JSON}", + "key": "${vsa-invalid_PUBLIC_KEY_JSON}", "policy": { "sources": [ { "policy": [ - "git::${GITHOST}/git/vsa-expiration-policy.git?ref=${LATEST_COMMIT}" + "git::${GITHOST}/git/vsa-invalid-policy.git?ref=${LATEST_COMMIT}" ] } ], "rekorUrl": "${REKOR}", - "publicKey": "${vsa-expiration_PUBLIC_KEY}" + "publicKey": "${vsa-invalid_PUBLIC_KEY}" }, "ec-version": "${EC_VERSION}", "effective-time": "${TIMESTAMP}" } --- -[VSA expiration flag functionality:stderr - 1] -time="${TIMESTAMP}" level=warning msg="Failed to check for existing VSA for image ${REGISTRY}/acceptance/vsa-expiration-image@sha256:${REGISTRY_acceptance/vsa-expiration-image:latest_DIGEST}: failed to retrieve VSA envelope: no entries found in Rekor for image digest: sha256:${REGISTRY_acceptance/vsa-expiration-image:latest_DIGEST}" +[VSA generation with invalid storage backend configuration:stderr - 1] +time="${TIMESTAMP}" level=warning msg="invalid storage config 'invalid-backend@somewhere': unsupported backend 'invalid-backend'. Supported backends: rekor, local" +time="${TIMESTAMP}" level=warning msg="invalid storage config 'invalid-backend@somewhere': unsupported backend 'invalid-backend'. Supported backends: rekor, local" --- -[VSA generation with local storage backend:stdout - 1] +[VSA expiration flag functionality:stdout - 1] { "success": true, "components": [ { "name": "Unnamed", - "containerImage": "${REGISTRY}/acceptance/vsa-test-image@sha256:${REGISTRY_acceptance/vsa-test-image:latest_DIGEST}", + "containerImage": "${REGISTRY}/acceptance/vsa-expiration-image@sha256:${REGISTRY_acceptance/vsa-expiration-image:latest_DIGEST}", "source": {}, "success": true, "signatures": [ { "keyid": "", - "sig": "${IMAGE_SIGNATURE_acceptance/vsa-test-image}" + "sig": "${IMAGE_SIGNATURE_acceptance/vsa-expiration-image}" } ], "attestations": [ @@ -74,47 +75,48 @@ time="${TIMESTAMP}" level=warning msg="Failed to check for existing VSA for imag "signatures": [ { "keyid": "", - "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-test-image}" + "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-expiration-image}" } ] } ] } ], - "key": "${vsa-test_PUBLIC_KEY_JSON}", + "key": "${vsa-expiration_PUBLIC_KEY_JSON}", "policy": { "sources": [ { "policy": [ - "git::${GITHOST}/git/vsa-policy.git?ref=${LATEST_COMMIT}" + "git::${GITHOST}/git/vsa-expiration-policy.git?ref=${LATEST_COMMIT}" ] } ], "rekorUrl": "${REKOR}", - "publicKey": "${vsa-test_PUBLIC_KEY}" + "publicKey": "${vsa-expiration_PUBLIC_KEY}" }, "ec-version": "${EC_VERSION}", "effective-time": "${TIMESTAMP}" } --- -[VSA generation with local storage backend:stderr - 1] +[VSA expiration flag functionality:stderr - 1] +time="${TIMESTAMP}" level=warning msg="Failed to check for existing VSA for image ${REGISTRY}/acceptance/vsa-expiration-image@sha256:${REGISTRY_acceptance/vsa-expiration-image:latest_DIGEST}: failed to retrieve VSA envelope: no entries found in Rekor for image digest: sha256:${REGISTRY_acceptance/vsa-expiration-image:latest_DIGEST}" --- -[VSA expiration with existing valid VSA:stdout - 1] +[VSA generation without upload backends shows warning:stdout - 1] { "success": true, "components": [ { "name": "Unnamed", - "containerImage": "${REGISTRY}/acceptance/vsa-existing-image@sha256:${REGISTRY_acceptance/vsa-existing-image:latest_DIGEST}", + "containerImage": "${REGISTRY}/acceptance/vsa-no-upload-image@sha256:${REGISTRY_acceptance/vsa-no-upload-image:latest_DIGEST}", "source": {}, "success": true, "signatures": [ { "keyid": "", - "sig": "${IMAGE_SIGNATURE_acceptance/vsa-existing-image}" + "sig": "${IMAGE_SIGNATURE_acceptance/vsa-no-upload-image}" } ], "attestations": [ @@ -125,47 +127,48 @@ time="${TIMESTAMP}" level=warning msg="Failed to check for existing VSA for imag "signatures": [ { "keyid": "", - "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-existing-image}" + "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-no-upload-image}" } ] } ] } ], - "key": "${vsa-existing_PUBLIC_KEY_JSON}", + "key": "${vsa-no-upload_PUBLIC_KEY_JSON}", "policy": { "sources": [ { "policy": [ - "git::${GITHOST}/git/vsa-existing-policy.git?ref=${LATEST_COMMIT}" + "git::${GITHOST}/git/vsa-no-upload-policy.git?ref=${LATEST_COMMIT}" ] } ], "rekorUrl": "${REKOR}", - "publicKey": "${vsa-existing_PUBLIC_KEY}" + "publicKey": "${vsa-no-upload_PUBLIC_KEY}" }, "ec-version": "${EC_VERSION}", "effective-time": "${TIMESTAMP}" } --- -[VSA expiration with existing valid VSA:stderr - 1] +[VSA generation without upload backends shows warning:stderr - 1] +time="${TIMESTAMP}" level=error msg="[VSA] VSA files generated but not uploaded (no --vsa-upload backends specified)" --- -[VSA generation with Rekor storage backend:stdout - 1] +[VSA generation with multiple storage backends:stdout - 1] { "success": true, "components": [ { "name": "Unnamed", - "containerImage": "${REGISTRY}/acceptance/vsa-rekor-image@sha256:${REGISTRY_acceptance/vsa-rekor-image:latest_DIGEST}", + "containerImage": "${REGISTRY}/acceptance/vsa-multi-image@sha256:${REGISTRY_acceptance/vsa-multi-image:latest_DIGEST}", "source": {}, "success": true, "signatures": [ { "keyid": "", - "sig": "${IMAGE_SIGNATURE_acceptance/vsa-rekor-image}" + "sig": "${IMAGE_SIGNATURE_acceptance/vsa-multi-image}" } ], "attestations": [ @@ -176,47 +179,47 @@ time="${TIMESTAMP}" level=warning msg="Failed to check for existing VSA for imag "signatures": [ { "keyid": "", - "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-rekor-image}" + "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-multi-image}" } ] } ] } ], - "key": "${vsa-rekor_PUBLIC_KEY_JSON}", + "key": "${vsa-multi_PUBLIC_KEY_JSON}", "policy": { "sources": [ { "policy": [ - "git::${GITHOST}/git/vsa-rekor-policy.git?ref=${LATEST_COMMIT}" + "git::${GITHOST}/git/vsa-multi-policy.git?ref=${LATEST_COMMIT}" ] } ], "rekorUrl": "${REKOR}", - "publicKey": "${vsa-rekor_PUBLIC_KEY}" + "publicKey": "${vsa-multi_PUBLIC_KEY}" }, "ec-version": "${EC_VERSION}", "effective-time": "${TIMESTAMP}" } --- -[VSA generation with Rekor storage backend:stderr - 1] +[VSA generation with multiple storage backends:stderr - 1] --- -[VSA generation with invalid storage backend configuration:stdout - 1] +[VSA generation with Rekor storage backend:stdout - 1] { "success": true, "components": [ { "name": "Unnamed", - "containerImage": "${REGISTRY}/acceptance/vsa-invalid-image@sha256:${REGISTRY_acceptance/vsa-invalid-image:latest_DIGEST}", + "containerImage": "${REGISTRY}/acceptance/vsa-rekor-image@sha256:${REGISTRY_acceptance/vsa-rekor-image:latest_DIGEST}", "source": {}, "success": true, "signatures": [ { "keyid": "", - "sig": "${IMAGE_SIGNATURE_acceptance/vsa-invalid-image}" + "sig": "${IMAGE_SIGNATURE_acceptance/vsa-rekor-image}" } ], "attestations": [ @@ -227,49 +230,47 @@ time="${TIMESTAMP}" level=warning msg="Failed to check for existing VSA for imag "signatures": [ { "keyid": "", - "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-invalid-image}" + "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-rekor-image}" } ] } ] } ], - "key": "${vsa-invalid_PUBLIC_KEY_JSON}", + "key": "${vsa-rekor_PUBLIC_KEY_JSON}", "policy": { "sources": [ { "policy": [ - "git::${GITHOST}/git/vsa-invalid-policy.git?ref=${LATEST_COMMIT}" + "git::${GITHOST}/git/vsa-rekor-policy.git?ref=${LATEST_COMMIT}" ] } ], "rekorUrl": "${REKOR}", - "publicKey": "${vsa-invalid_PUBLIC_KEY}" + "publicKey": "${vsa-rekor_PUBLIC_KEY}" }, "ec-version": "${EC_VERSION}", "effective-time": "${TIMESTAMP}" } --- -[VSA generation with invalid storage backend configuration:stderr - 1] -time="${TIMESTAMP}" level=warning msg="invalid storage config 'invalid-backend@somewhere': unsupported backend 'invalid-backend'. Supported backends: rekor, local" -time="${TIMESTAMP}" level=warning msg="invalid storage config 'invalid-backend@somewhere': unsupported backend 'invalid-backend'. Supported backends: rekor, local" +[VSA generation with Rekor storage backend:stderr - 1] --- -[VSA generation with multiple storage backends:stdout - 1] +[VSA expiration with existing valid VSA:stdout - 1] { "success": true, "components": [ { "name": "Unnamed", - "containerImage": "${REGISTRY}/acceptance/vsa-multi-image@sha256:${REGISTRY_acceptance/vsa-multi-image:latest_DIGEST}", + "containerImage": "${REGISTRY}/acceptance/vsa-existing-image@sha256:${REGISTRY_acceptance/vsa-existing-image:latest_DIGEST}", "source": {}, "success": true, "signatures": [ { "keyid": "", - "sig": "${IMAGE_SIGNATURE_acceptance/vsa-multi-image}" + "sig": "${IMAGE_SIGNATURE_acceptance/vsa-existing-image}" } ], "attestations": [ @@ -280,47 +281,47 @@ time="${TIMESTAMP}" level=warning msg="invalid storage config 'invalid-backend@s "signatures": [ { "keyid": "", - "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-multi-image}" + "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-existing-image}" } ] } ] } ], - "key": "${vsa-multi_PUBLIC_KEY_JSON}", + "key": "${vsa-existing_PUBLIC_KEY_JSON}", "policy": { "sources": [ { "policy": [ - "git::${GITHOST}/git/vsa-multi-policy.git?ref=${LATEST_COMMIT}" + "git::${GITHOST}/git/vsa-existing-policy.git?ref=${LATEST_COMMIT}" ] } ], "rekorUrl": "${REKOR}", - "publicKey": "${vsa-multi_PUBLIC_KEY}" + "publicKey": "${vsa-existing_PUBLIC_KEY}" }, "ec-version": "${EC_VERSION}", "effective-time": "${TIMESTAMP}" } --- -[VSA generation with multiple storage backends:stderr - 1] +[VSA expiration with existing valid VSA:stderr - 1] --- -[VSA generation without upload backends shows warning:stdout - 1] +[VSA generation with local storage backend:stdout - 1] { "success": true, "components": [ { "name": "Unnamed", - "containerImage": "${REGISTRY}/acceptance/vsa-no-upload-image@sha256:${REGISTRY_acceptance/vsa-no-upload-image:latest_DIGEST}", + "containerImage": "${REGISTRY}/acceptance/vsa-test-image@sha256:${REGISTRY_acceptance/vsa-test-image:latest_DIGEST}", "source": {}, "success": true, "signatures": [ { "keyid": "", - "sig": "${IMAGE_SIGNATURE_acceptance/vsa-no-upload-image}" + "sig": "${IMAGE_SIGNATURE_acceptance/vsa-test-image}" } ], "attestations": [ @@ -331,31 +332,30 @@ time="${TIMESTAMP}" level=warning msg="invalid storage config 'invalid-backend@s "signatures": [ { "keyid": "", - "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-no-upload-image}" + "sig": "${ATTESTATION_SIGNATURE_acceptance/vsa-test-image}" } ] } ] } ], - "key": "${vsa-no-upload_PUBLIC_KEY_JSON}", + "key": "${vsa-test_PUBLIC_KEY_JSON}", "policy": { "sources": [ { "policy": [ - "git::${GITHOST}/git/vsa-no-upload-policy.git?ref=${LATEST_COMMIT}" + "git::${GITHOST}/git/vsa-policy.git?ref=${LATEST_COMMIT}" ] } ], "rekorUrl": "${REKOR}", - "publicKey": "${vsa-no-upload_PUBLIC_KEY}" + "publicKey": "${vsa-test_PUBLIC_KEY}" }, "ec-version": "${EC_VERSION}", "effective-time": "${TIMESTAMP}" } --- -[VSA generation without upload backends shows warning:stderr - 1] -time="${TIMESTAMP}" level=error msg="[VSA] VSA files generated but not uploaded (no --vsa-upload backends specified)" +[VSA generation with local storage backend:stderr - 1] --- diff --git a/internal/applicationsnapshot/report.go b/internal/applicationsnapshot/report.go index ab21dc184..777e9025d 100644 --- a/internal/applicationsnapshot/report.go +++ b/internal/applicationsnapshot/report.go @@ -50,19 +50,20 @@ type Component struct { } type Report struct { - Success bool `json:"success"` - created time.Time - Snapshot string `json:"snapshot,omitempty"` - Components []Component `json:"components"` - Key string `json:"key"` - Policy ecc.EnterpriseContractPolicySpec `json:"policy"` - EcVersion string `json:"ec-version"` - Data any `json:"-"` - EffectiveTime time.Time `json:"effective-time"` - PolicyInput [][]byte `json:"-"` - ShowSuccesses bool `json:"-"` - ShowWarnings bool `json:"-"` - Expansion *ExpansionInfo `json:"-"` + Success bool `json:"success"` + created time.Time + Snapshot string `json:"snapshot,omitempty"` + Components []Component `json:"components"` + Key string `json:"key"` + Policy ecc.EnterpriseContractPolicySpec `json:"policy"` + EcVersion string `json:"ec-version"` + Data any `json:"-"` + EffectiveTime time.Time `json:"effective-time"` + PolicyInput [][]byte `json:"-"` + ShowSuccesses bool `json:"-"` + ShowWarnings bool `json:"-"` + ShowPolicyDocsLink bool `json:"-"` + Expansion *ExpansionInfo `json:"-"` } type summary struct { @@ -128,7 +129,7 @@ var OutputFormats = []string{ // WriteReport returns a new instance of Report representing the state of // components from the snapshot. -func NewReport(snapshot string, components []Component, policy policy.Policy, policyInput [][]byte, showSuccesses bool, showWarnings bool, expansion *ExpansionInfo) (Report, error) { +func NewReport(snapshot string, components []Component, policy policy.Policy, policyInput [][]byte, showSuccesses bool, showWarnings bool, showPolicyDocsLink bool, expansion *ExpansionInfo) (Report, error) { success := true // Set the report success, remains true if all components are successful @@ -149,18 +150,19 @@ func NewReport(snapshot string, components []Component, policy policy.Policy, po info, _ := version.ComputeInfo() return Report{ - Snapshot: snapshot, - Success: success, - Components: components, - created: time.Now().UTC(), - Key: string(key), - Policy: policy.Spec(), - EcVersion: info.Version, - PolicyInput: policyInput, - EffectiveTime: policy.EffectiveTime().UTC(), - ShowSuccesses: showSuccesses, - ShowWarnings: showWarnings, - Expansion: expansion, + Snapshot: snapshot, + Success: success, + Components: components, + created: time.Now().UTC(), + Key: string(key), + Policy: policy.Spec(), + EcVersion: info.Version, + PolicyInput: policyInput, + EffectiveTime: policy.EffectiveTime().UTC(), + ShowSuccesses: showSuccesses, + ShowWarnings: showWarnings, + ShowPolicyDocsLink: showPolicyDocsLink, + Expansion: expansion, }, nil } diff --git a/internal/applicationsnapshot/report_test.go b/internal/applicationsnapshot/report_test.go index 864f6a220..ab51b9527 100644 --- a/internal/applicationsnapshot/report_test.go +++ b/internal/applicationsnapshot/report_test.go @@ -52,7 +52,7 @@ func Test_ReportJson(t *testing.T) { ctx := context.Background() testPolicy := createTestPolicy(t, ctx) - report, err := NewReport("snappy", components, testPolicy, nil, true, true, nil) + report, err := NewReport("snappy", components, testPolicy, nil, true, true, true, nil) assert.NoError(t, err) testEffectiveTime := testPolicy.EffectiveTime().UTC().Format(time.RFC3339Nano) @@ -110,7 +110,7 @@ func Test_ReportYaml(t *testing.T) { ctx := context.Background() testPolicy := createTestPolicy(t, ctx) - report, err := NewReport("snappy", components, testPolicy, nil, true, true, nil) + report, err := NewReport("snappy", components, testPolicy, nil, true, true, true, nil) assert.NoError(t, err) testEffectiveTime := testPolicy.EffectiveTime().UTC().Format(time.RFC3339Nano) @@ -257,7 +257,7 @@ func Test_GenerateMarkdownSummary(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { ctx := context.Background() - report, err := NewReport(c.snapshot, c.components, createTestPolicy(t, ctx), nil, true, true, nil) + report, err := NewReport(c.snapshot, c.components, createTestPolicy(t, ctx), nil, true, true, true, nil) assert.NoError(t, err) report.created = time.Unix(0, 0).UTC() @@ -504,7 +504,7 @@ func Test_ReportSummary(t *testing.T) { for _, tc := range tests { t.Run(fmt.Sprintf("NewReport=%s", tc.name), func(t *testing.T) { ctx := context.Background() - report, err := NewReport(tc.snapshot, []Component{tc.input}, createTestPolicy(t, ctx), nil, true, true, nil) + report, err := NewReport(tc.snapshot, []Component{tc.input}, createTestPolicy(t, ctx), nil, true, true, true, nil) assert.NoError(t, err) assert.Equal(t, tc.want, report.toSummary()) }) @@ -641,7 +641,7 @@ func Test_ReportAppstudio(t *testing.T) { assert.NoError(t, err) ctx := context.Background() - report, err := NewReport(c.snapshot, c.components, createTestPolicy(t, ctx), nil, true, true, nil) + report, err := NewReport(c.snapshot, c.components, createTestPolicy(t, ctx), nil, true, true, true, nil) assert.NoError(t, err) assert.False(t, report.created.IsZero()) assert.Equal(t, c.success, report.Success) @@ -789,7 +789,7 @@ func Test_ReportHACBS(t *testing.T) { assert.NoError(t, err) ctx := context.Background() - report, err := NewReport(c.snapshot, c.components, createTestPolicy(t, ctx), nil, true, true, nil) + report, err := NewReport(c.snapshot, c.components, createTestPolicy(t, ctx), nil, true, true, true, nil) assert.NoError(t, err) assert.False(t, report.created.IsZero()) assert.Equal(t, c.success, report.Success) @@ -821,7 +821,7 @@ func Test_ReportPolicyInput(t *testing.T) { } ctx := context.Background() - report, err := NewReport("snapshot", nil, createTestPolicy(t, ctx), policyInput, true, true, nil) + report, err := NewReport("snapshot", nil, createTestPolicy(t, ctx), policyInput, true, true, true, nil) require.NoError(t, err) p := format.NewTargetParser(JSON, format.Options{}, defaultWriter, fs) @@ -890,8 +890,9 @@ func Test_TextReport(t *testing.T) { }{ {"nothing", Report{}}, {"bunch", Report{ - ShowSuccesses: true, - ShowWarnings: true, + ShowSuccesses: true, + ShowWarnings: true, + ShowPolicyDocsLink: true, Components: []Component{ { SnapshotComponent: app.SnapshotComponent{ @@ -1032,7 +1033,8 @@ func Test_DocumentationLink_OnlySuccesses(t *testing.T) { func Test_DocumentationLink_OnlyWarnings(t *testing.T) { // Test case: Only warnings - should show documentation link r := Report{ - ShowWarnings: true, + ShowWarnings: true, + ShowPolicyDocsLink: true, Components: []Component{ { Warnings: []evaluator.Result{ @@ -1060,6 +1062,7 @@ func Test_DocumentationLink_OnlyWarnings(t *testing.T) { func Test_DocumentationLink_OnlyFailures(t *testing.T) { // Test case: Only failures - should show documentation link r := Report{ + ShowPolicyDocsLink: true, Components: []Component{ { Violations: []evaluator.Result{ @@ -1087,6 +1090,7 @@ func Test_DocumentationLink_OnlyFailures(t *testing.T) { func Test_DocumentationLink_WarningsAndFailures(t *testing.T) { // Test case: Both warnings and failures - should show documentation link r := Report{ + ShowPolicyDocsLink: true, Components: []Component{ { Violations: []evaluator.Result{ @@ -1122,8 +1126,9 @@ func Test_DocumentationLink_WarningsAndFailures(t *testing.T) { func Test_DocumentationLink_MultipleComponents(t *testing.T) { // Test case: Multiple components with mixed results - should show documentation link r := Report{ - ShowSuccesses: true, - ShowWarnings: true, + ShowSuccesses: true, + ShowWarnings: true, + ShowPolicyDocsLink: true, Components: []Component{ { // Component 1: Only successes @@ -1345,12 +1350,12 @@ func Test_NewReport_ShowWarningsParameter(t *testing.T) { } // Test with showWarnings=true - report1, err := NewReport("test", components, testPolicy, nil, false, true, nil) + report1, err := NewReport("test", components, testPolicy, nil, false, true, true, nil) require.NoError(t, err) assert.True(t, report1.ShowWarnings, "ShowWarnings should be true when passed as true") // Test with showWarnings=false - report2, err := NewReport("test", components, testPolicy, nil, false, false, nil) + report2, err := NewReport("test", components, testPolicy, nil, false, false, true, nil) require.NoError(t, err) assert.False(t, report2.ShowWarnings, "ShowWarnings should be false when passed as false") } diff --git a/internal/applicationsnapshot/templates/text_report.tmpl b/internal/applicationsnapshot/templates/text_report.tmpl index f9c315ba7..95aafdc3d 100644 --- a/internal/applicationsnapshot/templates/text_report.tmpl +++ b/internal/applicationsnapshot/templates/text_report.tmpl @@ -22,6 +22,6 @@ Results:{{ nl -}} {{- end -}} {{- end -}} -{{- if or (gt $t.Failures 0) (and (gt $t.Warnings 0) $r.ShowWarnings) -}} +{{- if and $r.ShowPolicyDocsLink (or (gt $t.Failures 0) (and (gt $t.Warnings 0) $r.ShowWarnings)) -}} For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/{{ nl -}} {{- end -}} diff --git a/internal/input/report.go b/internal/input/report.go index 27656ca79..e8d74eb6a 100644 --- a/internal/input/report.go +++ b/internal/input/report.go @@ -44,16 +44,17 @@ type Input struct { } type Report struct { - Success bool `json:"success"` - created time.Time - FilePaths []Input `json:"filepaths"` - Policy ecc.EnterpriseContractPolicySpec `json:"policy"` - EcVersion string `json:"ec-version"` - Data any `json:"-"` - EffectiveTime time.Time `json:"effective-time"` - PolicyInput [][]byte `json:"-"` - ShowSuccesses bool `json:"-"` - ShowWarnings bool `json:"-"` + Success bool `json:"success"` + created time.Time + FilePaths []Input `json:"filepaths"` + Policy ecc.EnterpriseContractPolicySpec `json:"policy"` + EcVersion string `json:"ec-version"` + Data any `json:"-"` + EffectiveTime time.Time `json:"effective-time"` + PolicyInput [][]byte `json:"-"` + ShowSuccesses bool `json:"-"` + ShowWarnings bool `json:"-"` + ShowPolicyDocsLink bool `json:"-"` } type summary struct { @@ -97,7 +98,7 @@ const ( // WriteReport returns a new instance of Report representing the state of // the filepaths provided. -func NewReport(inputs []Input, policy policy.Policy, policyInput [][]byte, showSuccesses bool, showWarnings bool) (Report, error) { +func NewReport(inputs []Input, policy policy.Policy, policyInput [][]byte, showSuccesses bool, showWarnings bool, showPolicyDocsLink bool) (Report, error) { success := true // Set the report success, remains true if all the files were successfully validated @@ -111,15 +112,16 @@ func NewReport(inputs []Input, policy policy.Policy, policyInput [][]byte, showS info, _ := version.ComputeInfo() return Report{ - Success: success, - created: time.Now().UTC(), - FilePaths: inputs, - Policy: policy.Spec(), - EcVersion: info.Version, - EffectiveTime: policy.EffectiveTime().UTC(), - PolicyInput: policyInput, - ShowSuccesses: showSuccesses, - ShowWarnings: showWarnings, + Success: success, + created: time.Now().UTC(), + FilePaths: inputs, + Policy: policy.Spec(), + EcVersion: info.Version, + EffectiveTime: policy.EffectiveTime().UTC(), + PolicyInput: policyInput, + ShowSuccesses: showSuccesses, + ShowWarnings: showWarnings, + ShowPolicyDocsLink: showPolicyDocsLink, }, nil } diff --git a/internal/input/report_test.go b/internal/input/report_test.go index fba64cbd0..1ac2ab454 100644 --- a/internal/input/report_test.go +++ b/internal/input/report_test.go @@ -36,7 +36,7 @@ func Test_ReportJson(t *testing.T) { inputs := testInputsFor(filePaths) ctx := context.Background() testPolicy := createTestPolicy(t, ctx) - report, err := NewReport(inputs, testPolicy, nil, false, true) + report, err := NewReport(inputs, testPolicy, nil, false, true, true) assert.NoError(t, err) testEffectiveTime := testPolicy.EffectiveTime().UTC().Format(time.RFC3339Nano) @@ -126,7 +126,7 @@ func Test_ReportYaml(t *testing.T) { inputs := testInputsFor(filePaths) ctx := context.Background() testPolicy := createTestPolicy(t, ctx) - report, err := NewReport(inputs, testPolicy, nil, false, true) + report, err := NewReport(inputs, testPolicy, nil, false, true, true) assert.NoError(t, err) testEffectiveTime := testPolicy.EffectiveTime().UTC().Format(time.RFC3339Nano) @@ -232,7 +232,7 @@ func Test_ReportSummary(t *testing.T) { for _, tc := range tests { t.Run(fmt.Sprintf("NewReport=%s", tc.name), func(t *testing.T) { ctx := context.Background() - report, err := NewReport(tc.input, createTestPolicy(t, ctx), nil, false, true) + report, err := NewReport(tc.input, createTestPolicy(t, ctx), nil, false, true, true) // report, err := NewReport(tc.snapshot, []Component{tc.input}, createTestPolicy(t, ctx), nil, nil) assert.NoError(t, err) fmt.Println("\n\nExpected:\n", tc.want, "\n\nActual:\n", report.toSummary()) @@ -318,7 +318,7 @@ func Test_ReportText(t *testing.T) { } ctx := context.Background() testPolicy := createTestPolicy(t, ctx) - report, err := NewReport(inputs, testPolicy, nil, false, true) + report, err := NewReport(inputs, testPolicy, nil, false, true, true) assert.NoError(t, err) reportText, err := report.toFormat(Text) @@ -357,7 +357,7 @@ func Test_ReportText_ShowSuccesses(t *testing.T) { } ctx := context.Background() testPolicy := createTestPolicy(t, ctx) - report, err := NewReport(inputs, testPolicy, nil, true, true) + report, err := NewReport(inputs, testPolicy, nil, true, true, true) assert.NoError(t, err) reportText, err := report.toFormat(Text) @@ -382,7 +382,7 @@ func Test_ReportText_NoResultsSection(t *testing.T) { } ctx := context.Background() testPolicy := createTestPolicy(t, ctx) - report, err := NewReport(inputs, testPolicy, nil, false, true) + report, err := NewReport(inputs, testPolicy, nil, false, true, true) assert.NoError(t, err) reportText, err := report.toFormat(Text) diff --git a/internal/input/templates/text_report.tmpl b/internal/input/templates/text_report.tmpl index 02c204cc9..f8bc9ab32 100644 --- a/internal/input/templates/text_report.tmpl +++ b/internal/input/templates/text_report.tmpl @@ -22,6 +22,6 @@ Results:{{ nl -}} {{- end -}} {{- end -}} -{{- if or (gt $t.Failures 0) (and (gt $t.Warnings 0) $r.ShowWarnings) -}} +{{- if and $r.ShowPolicyDocsLink (or (gt $t.Failures 0) (and (gt $t.Warnings 0) $r.ShowWarnings)) -}} For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/{{ nl -}} {{- end -}} diff --git a/internal/validate/report.go b/internal/validate/report.go index 3699b36b1..e4b2b5c47 100644 --- a/internal/validate/report.go +++ b/internal/validate/report.go @@ -138,13 +138,14 @@ func CollectComponentResults( // ReportData contains the data needed to create an application snapshot report type ReportData struct { - Snapshot string - Components []applicationsnapshot.Component - Policy policy.Policy - PolicyInputs [][]byte - Expansion *applicationsnapshot.ExpansionInfo - ShowSuccesses bool - ShowWarnings bool + Snapshot string + Components []applicationsnapshot.Component + Policy policy.Policy + PolicyInputs [][]byte + Expansion *applicationsnapshot.ExpansionInfo + ShowSuccesses bool + ShowWarnings bool + ShowPolicyDocsLink bool } // ReportOutputOptions contains options for formatting and writing the report @@ -164,6 +165,7 @@ func WriteReport(data ReportData, opts ReportOutputOptions, cmd *cobra.Command) data.PolicyInputs, data.ShowSuccesses, data.ShowWarnings, + data.ShowPolicyDocsLink, data.Expansion, ) if err != nil {