Skip to content

chore: render CLI errors as TOON - #7239

Open
octavian-snyk wants to merge 1 commit into
mainfrom
chore/CLI-1828
Open

chore: render CLI errors as TOON#7239
octavian-snyk wants to merge 1 commit into
mainfrom
chore/CLI-1828

Conversation

@octavian-snyk

@octavian-snyk octavian-snyk commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Pull Request Submission Checklist

  • Follows CONTRIBUTING guidelines
  • Commit messages
    are release-note ready, emphasizing
    what was changed, not how.
  • Includes detailed description of changes
  • Contains risk assessment (Low | Medium | High)
  • Highlights breaking API changes (if applicable)
  • Links to automated tests covering new functionality
  • Includes manual testing instructions (if necessary)
  • Updates relevant GitBook documentation (PR link: ___)
  • Includes product update to be announced in the next stable release notes

What does this PR do?

Adds TOON-encoded error output when --toon is selected.

Normal command errors are written to stdout using a structured document containing
error, ok, and path. The existing JSON error behavior is preserved.

The PR also makes --toon, --json, --sarif, and --html mutually exclusive.
Selecting more than one output format fails before command execution with
SNYK-CLI-0024. Format-selection and rendering diagnostics are written to stderr
so they do not corrupt structured stdout.

The implementation does not add a TOON encoder dependency. It formats the small
error document locally, including the quoting and escaping required for TOON values.

Where should the reviewer start?

Start with cliv2/cmd/cliv2/behavior/output.go, which contains output-format
validation and structured error rendering. Then review the integration in
cliv2/pkg/core/main.go.

The corresponding tests are in:

  • cliv2/cmd/cliv2/behavior/output_test.go
  • cliv2/pkg/core/main_test.go

How should this be manually tested?

  1. Run a command that returns a catalog error with --toon.
  2. Verify stdout is a TOON document containing error, ok: false, and path.
  3. Redirect stdout and stderr separately and confirm that normal TOON errors remain
    parseable on stdout.
  4. Combine --toon with each of --json, --sarif, and --html.
  5. Verify each combination exits with SNYK-CLI-0024, writes the diagnostic to
    stderr, and leaves stdout empty.
  6. Run the equivalent command with --json and confirm its existing structured
    error output is unchanged.

What's the product update that needs to be communicated to CLI users?

CLI errors can now be rendered as TOON by passing --toon.

The --toon, --json, --sarif, and --html output options are mutually
exclusive. Combining them returns SNYK-CLI-0024 before the command runs.

Risk assessment (Medium)

This changes error formatting and stream selection for structured-output consumers.
Default human-readable output remains unchanged, and the existing JSON error shape
is preserved.

Breaking API changes

None.

What are the relevant tickets?

CLI-1828


Note

Medium Risk
Changes structured error shape/stream routing for --toon/--json consumers and adds pre-run rejection of conflicting output flags; default human output is largely unchanged.

Overview
Adds TOON structured error output when --toon is set, alongside existing JSON (error / ok / path), with local TOON quoting/escaping and no new encoder dependency.

Centralizes output behavior in behavior/output.go: rejects more than one of --toon, --json, --sarif, and --html before the command runs (including conflicts from config/env), while allowing SARIF/JSON alias pairs registered via AddAlternativeKeys. Validation is skipped when SNYK_FORCE_LEGACY_CLI is set.

Wires this into main.go: persistent --toon flag, pre-run validation, displayError uses RenderStructuredError and writes structured failures to stdout; human/diagnostic errors go to the stream chosen by SelectErrorOutputWriter (fixes CLI-1828 so redirects like --html do not mix errors into the redirected file). Data-rendering catalog errors stay on stderr even with TOON/JSON.

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

@octavian-snyk
octavian-snyk requested a review from a team as a code owner September 8, 2026 07:24
@snyk-io

snyk-io Bot commented Sep 8, 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-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 cliv2/pkg/core/main.go Outdated
@snyk-pr-review-bot

This comment has been minimized.

Comment thread cliv2/go.mod Outdated
@robertolopezlopez

robertolopezlopez commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

product update: probably you may add the conflicting flags validation. In such case, the error will be shown as standard output. (From the pitch)

@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 cliv2/cmd/cliv2/behavior/output.go Outdated

@robertolopezlopez robertolopezlopez left a comment

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.

Hi,

It looks good to me. The change is tight. I have also done manual validation and it does what it should. Just one not blocking observation.

Approved

@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 cliv2/pkg/core/main.go Outdated
@snyk-pr-review-bot

This comment has been minimized.

@octavian-snyk
octavian-snyk force-pushed the chore/CLI-1828 branch 2 times, most recently from fdb64ea to 0c0391d Compare September 8, 2026 13:24

@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 cliv2/pkg/core/main.go
Comment thread cliv2/cmd/cliv2/behavior/output.go
@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.

@octavian-snyk
octavian-snyk force-pushed the chore/CLI-1828 branch 2 times, most recently from b999b5d to 79e329d Compare September 9, 2026 08:37

@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 cliv2/pkg/core/main.go
func validateOutputFormatSelection(config configuration.Configuration, cmd *cobra.Command) error {
if config.GetBool(constants.SNYK_FORCE_LEGACY_CLI_ENV) {
return nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Legacy force env unwired

Low Severity

validateOutputFormatSelection skips format checks when config.GetBool(constants.SNYK_FORCE_LEGACY_CLI_ENV) is true, but this PR only adds the SNYK_FORCE_LEGACY_CLI config key constant without registering it in initApplicationConfiguration or supported env wiring. Setting the homonymous environment variable may not disable validation.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 79e329d. Configure here.

@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.

@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 7ce6f53. Configure here.

displayError(tt.err, console, config, t.Context(), false)

expected := fmt.Sprintf("error: %s\nok: false\npath: /workspace\n", getErrorMessage(tt.err))
assert.Equal(t, expected, stdout.String())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

TOON test expects extra newline

Low Severity

The TOON catalog-error test expects stdout to end with a newline after the path line, but renderTOONError formats the document without a trailing newline. That mismatch with the approved fixture test (which compares trimmed output) can fail CI or confuse consumers about the canonical TOON error shape.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7ce6f53. Configure 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 25 relevant code sections from 12 files (average relevance: 0.97)

🤖 Repository instructions applied (from AGENTS.md)

@@ -0,0 +1,3 @@
error: No supported files found
ok: false

@PeterSchafer PeterSchafer Sep 9, 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.

question: does ok false or true have any meaning for an agent?

const SNYK_OAUTH_ACCESS_TOKEN_ENV = "SNYK_OAUTH_TOKEN"
const SNYK_API_TOKEN_ENV = "SNYK_TOKEN"
const SNYK_ANALYTICS_DISABLED_ENV = "SNYK_DISABLE_ANALYTICS"
const SNYK_FORCE_LEGACY_CLI_ENV = "SNYK_FORCE_LEGACY_CLI"

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.

Question: Where is this Env Var coming from.

@PeterSchafer PeterSchafer left a comment

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 don't think this is ready yet.

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