Skip to content

feat: TOON field selection - #766

Open
robertolopezlopez wants to merge 26 commits into
mainfrom
feat/CLI-1859
Open

robertolopezlopez wants to merge 26 commits into
mainfrom
feat/CLI-1859

Conversation

@robertolopezlopez

@robertolopezlopez robertolopezlopez commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Description

Adds default and --full TOON output for SCA and Secrets.

  • context, feedback and scanner diagnostics
  • --full adds SCA title, CVSS and upgrade details
  • stdout and file output render the same TOON
  • extraction errors and unfinished scans stop rendering
  • to align with AXI behavior: replaced results[] with sca[] and secrets[]

Checklist

  • Tests added and all succeed (make test)
  • Regenerated mocks, etc. (make generate)
  • Linted (make lint)
  • Test your changes work for the CLI -> feat: TOON flags and field selection cli#7267
    1. Clone / pull the latest CLI main.
    2. Run go get github.com/snyk/go-application-framework@YOUR_LATEST_GAF_COMMIT in the cliv2 directory.
      • Tip: for local testing, you can uncomment the line near the bottom of the CLI's go.mod to point to your local GAF code.
    3. Run go mod tidy in the cliv2 directory.
    4. Run the CLI tests and do any required manual testing.
    5. Open a PR in the CLI repo now with the go.mod and go.sum changes.
    • Once this PR is merged, repeat these steps, but pointing to the latest GAF commit on main and update your CLI PR.

Note

Medium Risk
Changes CLI structured output format and flag semantics (--toon), which can break consumers expecting the old results[] envelope; issue grouping and primary-problem selection also affect SCA/license presentation.

Overview
Reworks UFM TOON output from a raw results[] JSON dump to compact, scanner-specific tables (sca[], secrets[], generic findings[]) with org/project context, interaction ID, diagnostics (*_error, *_hint, *_warning), and a compact-mode hint to use --toon=full.

--toon becomes a string flag (compact / full, bare --toon → full) with validation; full mode renders SARIF-derived runs[] via a new renderFullTOON path instead of toon.PrepareResults. Rendering is context-aware through RenderTemplateWithContext and new template helpers (mapTOONIssue, jsonFields, issue conversion from test results).

Issue extraction changes in testapi: deterministic grouping order, safer keyless grouping, and primary problem preference (snyk_vuln over license/generic). Malformed SCA data and unfinished scans fail without writing partial output.

Reviewed by Cursor Bugbot for commit 0083347. Bugbot is set up for automated code reviews on this repo. Configure here.

@snyk-io

snyk-io Bot commented Sep 15, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@snyk-io

snyk-io Bot commented Sep 15, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues
Secrets 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@robertolopezlopez
robertolopezlopez marked this pull request as ready for review September 15, 2026 11:34
@robertolopezlopez
robertolopezlopez requested review from a team as code owners September 15, 2026 11:34
@snyk-pr-review-bot

This comment has been minimized.

@snyk-pr-review-bot

This comment has been minimized.

@snyk-pr-review-bot

This comment has been minimized.

Comment thread internal/presenters/templates/ufm.toon.tmpl Outdated
@snyk-pr-review-bot

This comment has been minimized.

@robertolopezlopez
robertolopezlopez enabled auto-merge (squash) September 15, 2026 19:58

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread internal/presenters/templates/ufm.toon.tmpl Outdated
@snyk-pr-review-bot

This comment has been minimized.

@robertolopezlopez

Copy link
Copy Markdown
Contributor Author

@PeterSchafer ready for review again after your comments. I also have #767 which depends on this change. I am starting work on the final CLI PR for TOON in parallel.

@snyk-pr-review-bot

This comment has been minimized.

Comment thread pkg/local_workflows/output_workflow/constants.go Outdated
Comment thread pkg/local_workflows/output_workflow/constants.go Outdated
@snyk-pr-review-bot

This comment has been minimized.

Comment thread internal/presenters/templates/ufm.toon.tmpl Outdated
Comment thread internal/presenters/templates/ufm.toon.tmpl Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread pkg/local_workflows/output_workflow/writer.go Outdated
@snyk-pr-review-bot

This comment has been minimized.

Comment thread pkg/local_workflows/output_workflow/writer.go Outdated
@snyk-pr-review-bot

This comment has been minimized.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread internal/presenters/toon_issues.go
severity := strings.ToLower(string(attributes.Rating.Severity))
if severity == "" {
severity = "low"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Secrets rows ignore effective severity

Low Severity

Secret TOON rows take severity from each finding’s raw rating.severity, while sortAndFilterIssues includes or excludes issues using GetEffectiveSeverity(). Policy-adjusted severities can disagree between the table and filtering.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9496f5e. Configure here.

Comment thread pkg/apiclients/testapi/issues.go Outdated
FindingTypeLicense = "license"
)

const dataKeyComponentVersions = "component-versions"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I noticed the string is also duplicated in internal/presenters/toon_issues.go. Would it make sense to move this logic entirely into internal/presenters/toon_issues.go so we can avoid introducing any new symbols here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I wrote the same answer in packageVersions below:

The problem about moving dataKeyComponentVersions is that it is used here and I wouldn't see clean/logical having issues.go depending on toon_issues.go - don't you think?

@snyk-pr-review-bot

This comment has been minimized.

@snyk-pr-review-bot

This comment has been minimized.

Comment thread pkg/apiclients/testapi/issues.go Outdated
problemID string
packageName string
packageVersion string
packageVersions []string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If we can move dataKeyComponentVersions to internal/presenters/toon_issues.go, I think we can also remove packageVersions. We can keep the shared pkg/apiclients/testapi/issues.go changes minimal and iterate on TOON separately as needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

the problem about moving dataKeyComponentVersions is that it is used here and I wouldn't see clean/logical having issues.go depending on toon_issues.go - don't you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agreed, issues.go shouldn't depend on toon_issues.go. That's not what I'm proposing.

issues.go drops packageVersions and dataKeyComponentVersions entirely.

toon_issues.go builds the same list itself, reading each finding's own problem and package location, the way singleFindingComponent already does for a single finding. Neither package needs a new shared symbol.

Could this work?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

}
return *value
}
defaultMap["number"] = func(value int) json.Number { return json.Number(strconv.Itoa(value)) }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am not entirely sure these are needed. Could we keep them in TOON for the time being, and move them to default once we confirm our last iteration requires these and would be useful to other consumers as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

moved to getToonTemplateFuncMap

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

sorry, I don't think these were moved.
I am not sure if jsonStrings, jsonNumbers, getSourceLocation, runes, runeString, and number have any consumer?

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread internal/presenters/presenter_ufm_full_toon.go
@snyk-pr-review-bot

This comment has been minimized.

// Add finding types derived from actual findings
// todo: this is potentially an expensive intermediate conversion to issues, which we could cache or optimize differently.
issues, err := testapi.NewIssuesFromTestResult(context.Background(), testResults)
issues, err := testapi.NewIssuesFromTestResult(ctx, testResults)

@octavian-snyk octavian-snyk Sep 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not testapi.GetIssuesFromTestResult ? Could this also simplify the changes to pkg/apiclients/testapi/issues.go further?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

because GetIssuesFromTestResult creates a new context. And using NewIssuesFromTestResult we carry forward the context from the template rendering

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

also, GetIssuesFromTestResult adds filtering and sorting -> we do not need that here

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Reviewer Guide 🔍

🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected
📚 Repository Context Analyzed

This review considered 97 relevant code sections from 11 files (average relevance: 1.00)

🤖 Repository instructions applied (from AGENTS.md)

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0083347. Configure here.

]}]`)
requireTOONEqual(t, `sca[1]{fixable,id,pkg,severity}:
no,same,"example@1.10,1.2",high
sca_summary: 1 unique vulns (2 paths) | 1 high | 0 fixable`, output)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing sca_summary in compact TOON

Medium Severity

The new grouped-SCA mapping test expects a top-level sca_summary field in compact TOON output, but the main template only appends sca table rows and never sets sca_summary on the envelope, so rendered output cannot match the documented contract for grouped vulnerabilities.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0083347. Configure here.

return err
}

if mimeType == ApplicationTOONMimeType {

@octavian-snyk octavian-snyk Sep 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not necessarly an actionable comment for now; perhaps we should pick this in a later iteration.

just to keep in mind: it may be a good idea to split TOON Full MimeType from Compact TOON MimeType.

Perhaps:
text/toon; schema=full
text/toon; schema=compact

return findingTypes
}

func getFindingTypesFromTestResultWithContext(ctx context.Context, testResults testapi.TestResult) ([]testapi.FindingType, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

reading the body of the function before this, could we fold getFindingTypesFromTestResultWithContext directly into getFindingTypesFromTestResult? I'm not sure why there's a need to add the getFindingTypesFromTestResultWithContext.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants