ESD-1666: Route Cobra command errors to result.error in the WASM CLI#542
Open
Phil-Browne wants to merge 3 commits into
Open
ESD-1666: Route Cobra command errors to result.error in the WASM CLI#542Phil-Browne wants to merge 3 commits into
Phil-Browne wants to merge 3 commits into
Conversation
Parser-layer failures (unknown command, invalid flags, missing required args) wrote the error text into result.output and left result.error empty, so the Portal rendered failures uncolored and never fired the cli_terminal_command_failed telemetry event. ExecuteWithArgs now returns the failure error, and the async bridge routes it to result.error while keeping only the usage hint in output. The root command's unknown-command handling becomes RunE so it surfaces a real error instead of printing to the buffer, and SilenceErrors is set so cobra does not stream the error before it can be routed. The JSON-envelope and streamed-error paths still return nil to avoid double-rendering. The error string is sanitized before it reaches result.error, since a parser error can echo a user-typed flag name verbatim and the host writes result.error straight to xterm.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #542 +/- ##
=======================================
Coverage 79.50% 79.50%
=======================================
Files 193 193
Lines 18859 18859
=======================================
Hits 14993 14993
Misses 2818 2818
Partials 1048 1048 🚀 New features to boost your workflow:
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes WASM CLI “parser-layer” failures (unknown command, invalid flags, missing required args) so they populate result.error (instead of being buried in result.output), enabling the Portal to correctly render failures as errors and emit failure telemetry. It also ensures error strings routed to result.error are sanitized to prevent terminal control-sequence injection.
Changes:
- Update the WASM async bridge to set
result.errorfromExecuteWithArgs’ returned error (sanitized), while keeping only the usage hint inresult.output. - Change WASM
ExecuteWithArgsto return an error when it should be surfaced by the host, and setrootCmd.SilenceErrors = trueto prevent Cobra from pre-printingError:lines. - Add/adjust WASM tests to enforce the new error-routing contract and sanitization behavior.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| main_wasm.go | Routes returned command errors into result.error (sanitized) in the async JS bridge. |
| main_wasm_test.go | Adds bridge-level regression tests for unknown-command routing and sanitization. |
| cmd/megaport/megaport_wasm.go | Changes ExecuteWithArgs to return an error for host routing; silences Cobra error printing; preserves JSON/streamed no-double-render behavior. |
| cmd/megaport/common_wasm.go | Switches unknown-command handling to RunE returning real errors (instead of writing Error: into the output buffer). |
| cmd/megaport/error_routing_wasm_test.go | Adds contract tests covering parser-layer routing, handler behavior, and streamed-error no-double-render. |
| cmd/megaport/unknown_flags_wasm_test.go | Updates unknown-flag test to assert error is returned (not left in captured output). |
| cmd/megaport/session_expired_wasm_test.go | Adjusts call sites for new ExecuteWithArgs return signature. |
| cmd/megaport/nat_gateway_wasm_test.go | Adjusts call sites for new ExecuteWithArgs return signature. |
| cmd/megaport/modules_wasm_test.go | Adjusts call sites for new ExecuteWithArgs return signature. |
| cmd/megaport/ix_wasm_test.go | Adjusts call sites for new ExecuteWithArgs return signature. |
| cmd/megaport/colors_wasm_test.go | Adjusts call sites for new ExecuteWithArgs return signature. |
Review-pass follow-ups on the Cobra-error routing change: - Sanitize result.error with SanitizeTerminalText (strip all control bytes) instead of the SGR-allowing SanitizeTerminalOutput; the host styles the error line itself, so no escape sequence should survive. Apply the same sanitization to the panic-recovery result.error. - Cover the JSON-envelope branch (returns nil) and the browser-unavailable commands (config/completion/generate-docs/version) routing to result.error. - Install an in-memory localStorage shim in TestMain so the config-file and localStorage tests run under bare node instead of panicking, and stop TestOutputBufferReset/TestConcurrentCommands from asserting the now-error 'version' command succeeds.
The root package is now node-runnable via the localStorage shim, so add it to the wasm.yml test list; the executeMegaportCommandAsync bridge tests that most directly exercise the result.error contract now gate in CI. Also trim three over-long comments to the short WHY form.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Parser-layer failures in the WASM CLI (unknown command, invalid flags, missing required args) wrote the error into
result.outputand leftresult.errorempty. The Portal keys success/failure offresult.error, so those failures rendered uncolored and never fired thecli_terminal_command_failedtelemetry event (ENG-33590). This routes the failure toresult.errorinstead.ExecuteWithArgsnow returns the failure error; the async bridge setsresult.errorfrom it and keeps only the usage hint inresult.output.RunEreturning a real error, instead of printingError: ...to the output buffer (that was whylocation listnever reachedresult.error).SilenceErrorsis set so cobra doesn't stream its ownError:line before we can route it (which would double-render under a live-output handler).nil, so an error already shown to the terminal isn't rendered twice.result.error(and the panic-recovery error) is sanitized withSanitizeTerminalText, which strips every control byte: a parser error can echo a user-typed flag name verbatim and the host writesresult.errorstraight to xterm, and the host styles the error line itself so no escape sequence needs to survive.localStorageshim inTestMain(the config-file and localStorage tests previously panicked, which masked later failures) and repointed two tests off the now-unavailableversioncommand.No Portal-side changes required.
Verified against Portal source (web-monorepo)
result.errorstraight to xterm viaterminal.write(\\x1b[31mError: ${result.error}\x1b[0m\r\n`)(useXtermShell.ts), no HTML escaping, wrapped in its own red SGR. So the sanitization is genuinely required andSanitizeTerminalText` (strip all control bytes) is the right choice: the host supplies the color, nothing in the message should survive.onError) fires only whenresult.erroris non-empty (useXtermShell.ts->useCliTelemetry.ts, eventcli_terminal_command_result_error), confirming the fix is what makes failure telemetry fire.HasOutputHandler()is false and every failure takes the capture path. That means command-execution errors (an action callingoutput.PrintError) also route toresult.errorthere, so telemetry fires for those too. The streamed-error "no telemetry" case only applies to a hypothetical consumer that registers a live-output handler, which the Portal does not.