From 1c7ed9f5b70395db72394d9d41e093f8fca0c65a Mon Sep 17 00:00:00 2001 From: Dheeraj Date: Wed, 25 Mar 2026 19:56:15 +0530 Subject: [PATCH 1/2] 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 - Report structures updated to pass flag through 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 Note: Snapshot updates will be handled in a separate PR to keep this focused. 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 + internal/applicationsnapshot/report.go | 54 ++++++++++--------- internal/applicationsnapshot/report_test.go | 33 +++++++----- internal/input/report.go | 42 ++++++++------- internal/input/report_test.go | 12 ++--- internal/validate/report.go | 16 +++--- 15 files changed, 120 insertions(+), 90 deletions(-) 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/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/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/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 { From aceb5f18bc8e6c73ae7411965e53616e4e71f455 Mon Sep 17 00:00:00 2001 From: Dheeraj Date: Thu, 26 Mar 2026 19:39:37 +0530 Subject: [PATCH 2/2] fix: Honor ShowPolicyDocsLink flag in text report templates The ShowPolicyDocsLink field was defined in the report structs and passed through correctly, but the text templates weren't checking it before displaying the policy documentation link. This updates both templates to wrap the policy docs link output with a check for the ShowPolicyDocsLink flag. Co-Authored-By: Claude Sonnet 4.5 --- internal/applicationsnapshot/templates/text_report.tmpl | 2 +- internal/input/templates/text_report.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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 -}}