Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions cmd/validate/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {

showSuccesses, _ := cmd.Flags().GetBool("show-successes")
showWarnings, _ := cmd.Flags().GetBool("show-warnings")
// Show policy docs link when validating from a snapshot file
// Don't show for single image validation (demos/tutorials)
showPolicyDocsLink := data.images != "" || data.filePath != ""

// 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.
Expand Down Expand Up @@ -429,13 +432,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,
Expand Down
4 changes: 3 additions & 1 deletion cmd/validate/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ func validateInputCmd(validate InputValidationFunc) *cobra.Command {

showSuccesses, _ := cmd.Flags().GetBool("show-successes")
showWarnings, _ := cmd.Flags().GetBool("show-warnings")
// Don't show policy docs link for input validation (not snapshot-based)
showPolicyDocsLink := false

// Set numWorkers to the value from our flag. The default is 5.
numWorkers := data.workers
Expand Down Expand Up @@ -210,7 +212,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
}
Expand Down
16 changes: 9 additions & 7 deletions cmd/validate/vsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -1095,13 +1095,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.images != "", // Show docs link when using snapshot file
}, nil
}

Expand All @@ -1121,6 +1122,7 @@ func createFallbackReport(allData AllSectionsData, vsaData *validateVSAData) (*a
reportData.PolicyInputs,
reportData.ShowSuccesses,
reportData.ShowWarnings,
reportData.ShowPolicyDocsLink,
reportData.Expansion,
)
if err != nil {
Expand Down
54 changes: 28 additions & 26 deletions internal/applicationsnapshot/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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
}

Expand Down
33 changes: 19 additions & 14 deletions internal/applicationsnapshot/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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())
})
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")
}
Expand Down
2 changes: 1 addition & 1 deletion internal/applicationsnapshot/templates/text_report.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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)) -}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Fallback link always hidden 🐞 Bug ✓ Correctness

In VSA text output, the fallback validate-image section omits the policy documentation link even
when --show-policy-docs-link=true (default), because the fallback text capture builds format.Options
without ShowPolicyDocsLink and applicationsnapshot.Report.WriteAll overwrites the report setting
with the default false option. The new template guard added in this PR then prevents the link from
rendering in that fallback section.
Agent Prompt
### Issue description
VSA text output captures fallback validate-image text via `captureFallbackText`. That function constructs `format.Options` without `ShowPolicyDocsLink`, causing `applicationsnapshot.Report.WriteAll()` to overwrite `Report.ShowPolicyDocsLink` to `false`. Since the text template now requires `ShowPolicyDocsLink` to print the documentation link, the fallback section never shows the link even when `--show-policy-docs-link=true`.

### Issue Context
- The fallback report data correctly includes `ShowPolicyDocsLink`, but it is later overridden by target options.
- `applicationsnapshot.Report.WriteAll()` always applies `target.Options` to the report before rendering.

### Fix Focus Areas
- cmd/validate/vsa.go[1432-1446]

Suggested change: include `ShowPolicyDocsLink: fallbackReport.ShowPolicyDocsLink` in `formatOpts` inside `captureFallbackText`, and consider adding/adjusting a test that asserts the fallback section contains/omits the docs link based on the flag.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/{{ nl -}}
{{- end -}}
42 changes: 22 additions & 20 deletions internal/input/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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
}

Expand Down
Loading
Loading