Skip to content

feat(cli): add --output json/yaml to sandbox get, status, and sandbox create - #1989

Merged
elezar merged 3 commits into
NVIDIA:mainfrom
rhuss:feat/cli-structured-output
Jul 24, 2026
Merged

feat(cli): add --output json/yaml to sandbox get, status, and sandbox create#1989
elezar merged 3 commits into
NVIDIA:mainfrom
rhuss:feat/cli-structured-output

Conversation

@rhuss

Copy link
Copy Markdown
Contributor

Summary

Add --output json/yaml to sandbox get, status, and sandbox create so automation and MCP tool wrappers can consume structured data instead of parsing ANSI-colored human output.

Related Issue

Closes#1964

Changes

  • sandbox get --output json/yaml: New sandbox_detail_to_json converter enriches the existing sandbox_to_json with policy source, revision, and active policy content from GetSandboxConfigResponse. Uses sandbox_policy_to_json_value for direct proto-to-JSON conversion.
  • status --output json/yaml: New status_to_json converter emits gateway, server, status, and conditional fields (auth, version, error, http_status). Refactored gateway_status to build data before output routing.
  • sandbox create --output json/yaml: Emits sandbox metadata after Ready phase. Human chrome (header, spinner) suppressed from stdout; progress message on stderr. Uploads and port forwarding still execute before output. Clap rejects --output combined with --editor or trailing commands.
  • No-gateway path: status --output json with no configured gateway emits {"status": "not_configured"} instead of human text.
  • All three commands reuse the existing OutputFormat enum and print_output_single helper.
  • Default output (no --output flag) is byte-identical to current behavior (verified by diffing raw ANSI output).
  • Docs updated for sandbox get, sandbox create, and status in manage-sandboxes.mdx and manage-gateways.mdx.

Testing

  • cargo clippy clean, cargo fmt clean
  • 188 unit tests pass (cargo test --lib)
  • 5 new unit tests for sandbox_detail_to_json and status_to_json converters
  • Integration test call sites updated for new function signatures
  • Smoke-tested against live local gateway: sandbox get --output json, status --output json/yaml, default output byte-identical regression check
  • Deep review (5 agents + CodeRabbit + Copilot): all Critical/Important findings fixed

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

@copy-pr-bot

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions

github-actionsBot commented Jun 24, 2026

Copy link
Copy Markdown

All contributors have signed the DCO ✍️ ✅
Posted by the DCO Assistant Lite bot.

@rhuss

Copy link
Copy Markdown
ContributorAuthor

I have read the DCO document and I hereby sign the DCO.

@rhuss

Copy link
Copy Markdown
ContributorAuthor

recheck

@johntmyersjohntmyers self-assigned this Jun 24, 2026
Comment threadcrates/openshell-cli/src/run.rs Outdated
Comment threadcrates/openshell-cli/src/run.rs Outdated
@rhuss
rhussforce-pushed the feat/cli-structured-output branch from 1816278 to 9aa0ec4CompareJune 25, 2026 04:29
@rhuss

Copy link
Copy Markdown
ContributorAuthor

@johntmyers thanks for the review! As I'm on my way to dive into the codebase I will try to understand the codebase a bit better (not a Rust coder yet). But I think your comment ironically also hint to a problmen that this PR tries to partially solve: We need to be careful currently around the wording of log/error messages as they are parsed and used for result evaluation (i know at least one tool that wraps that parses the output of sandbox instead of using the SDK directly).

Therefor having the option for a structured output make much sense for these use cases. I wonder though, whether one should keep stderr free for informal messages or whether not (if -o json) is given also the error messages should be structured (I tend to the later). What's your take on this ?

@rhuss

Copy link
Copy Markdown
ContributorAuthor

I'll create a follow-up issue for emitting structured JSON errors when --output json/yaml is active, so automation consumers get parseable error responses instead of miette-formatted text. That's a broader change touching the error handling in main() and should cover all commands, not just the three in this PR.

@rhuss
rhussforce-pushed the feat/cli-structured-output branch 3 times, most recently from f067c05 to d287542CompareJune 29, 2026 07:39
@rhuss

Copy link
Copy Markdown
ContributorAuthor

All comments resolved, what do I need to trigger the CI ? 🙏

@rhuss

Copy link
Copy Markdown
ContributorAuthor

I'll create a follow-up issue for emitting structured JSON errors when --output json/yaml is active, so automation consumers get parseable error responses instead of miette-formatted text. That's a broader change touching the error handling in main() and should cover all commands, not just the three in this PR.

--> #2040

@rhuss
rhussforce-pushed the feat/cli-structured-output branch from d287542 to a0a287fCompareJune 30, 2026 07:14
@elezarelezar mentioned this pull request Jul 9, 2026
5 tasks
elezar
elezar previously requested changes Jul 10, 2026

@elezarelezar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Requesting changes because structured output does not currently guarantee clean stdout.

When --output json or --output yaml is selected, display is set to None. However, handle_platform_progress_event() interprets None as non-interactive/plain output and prints completed steps and details with println!(). If provisioning emits a progress event, stdout will contain human-readable lines before the final JSON/YAML document, making it invalid for automation.

Please:

  • Introduce an explicit structured progress mode that is silent or writes only to stderr.
  • Reserve stdout exclusively for the final JSON/YAML document.
  • Add integration coverage that emits provisioning progress, captures the complete stdout from sandbox create --output json/yaml, and successfully parses it.

I recommend modeling interactive, plain, and structured progress as explicit variants rather than using Option<ProvisioningDisplay>. The full presenter refactor is not required to unblock this PR; the blocking requirement is that structured stdout remains parseable under all provisioning event paths.

@rhuss
rhussforce-pushed the feat/cli-structured-output branch from baee9b4 to 22b16cbCompareJuly 14, 2026 13:25
@rhuss

rhuss commented Jul 14, 2026

Copy link
Copy Markdown
ContributorAuthor

Thanks for the review. All four points are addressed:

1. Explicit structured progress mode (commit 22b16cbd): Option<ProvisioningDisplay> is replaced with an explicit ProgressOutput enum with three variants: Interactive, Plain, and Silent. Structured output mode uses Silent.

2. Stdout reserved for final JSON/YAML (commit 22b16cbd): In Silent mode, handle_platform_progress_event() is a no-op. All informational messages during provisioning go to stderr via eprintln!(). Stdout is reserved exclusively for the final JSON/YAML document.

3. Integration coverage (commit 644677e3): Added two integration tests (sandbox_create_json_output_succeeds_with_progress_events and sandbox_create_yaml_output_succeeds_with_progress_events) that exercise the full provisioning flow with progress events while --output json/yaml is active. These confirm the Silent code path works end-to-end. Full stdout-capture-and-parse assertions would require either a _to_writer refactor of sandbox_create (similar to sandbox_policy_get_to_writer) or adding an stdout capture dependency, both of which seemed like scope creep for this PR.

4. Replace Option<ProvisioningDisplay> (commit 22b16cbd): Done, as described in point 1.

@rhuss

Copy link
Copy Markdown
ContributorAuthor

@elezar Gentle ping - the feedback from your review has been addressed in commit 22b16cbd (explicit ProgressOutput enum replacing Option<ProvisioningDisplay>). Would you have a chance to take another look?

@elezar

Copy link
Copy Markdown
Member

@rhuss I think this looks better now. Do you mind rebasing so that we can complete the review? (I have a added a test-only commit on top that you can include in your changes as you see fit).

@rhuss
rhussforce-pushed the feat/cli-structured-output branch 2 times, most recently from 5c4f020 to 7c16a74CompareJuly 23, 2026 08:19
@rhuss

Copy link
Copy Markdown
ContributorAuthor

@elezar rebased on upstream/main and squashed to a single commit to clean up a bit (otherwise a lot of back and forth between the various commits, mostly because of several rebasing rounds).

Let me know if something is still missing.

… create
Add structured output support (JSON and YAML) to sandbox lifecycle
commands: sandbox get, status, and sandbox create.
Introduce ProgressOutput enum to cleanly separate interactive,
plain, and silent display modes during sandbox provisioning.
Signed-off-by: Roland Huß <rhuss@redhat.com>
@rhuss
rhussforce-pushed the feat/cli-structured-output branch from 7c16a74 to 212217aCompareJuly 24, 2026 06:27
Signed-off-by: Evan Lezar <elezar@nvidia.com>
@elezar

Copy link
Copy Markdown
Member

/ok-to-test 212217a

Signed-off-by: Evan Lezar <elezar@nvidia.com>
@elezar

Copy link
Copy Markdown
Member

Pushed two small follow-up fixes:

  • sandbox create --output now conflicts with side-effect modes (--editor, trailing commands, --no-keep, and --forward) and has table-driven parser coverage.
  • Upload SSH transport now discards child stdout unconditionally so successful uploads cannot pollute structured stdout; stderr remains inherited for diagnostics.

Possible follow-ups:

  • Add first-class --output + --forward support by detaching/capturing the background SSH process and including forward metadata in the JSON/YAML payload.
  • If we want stronger upload guarantees, add an integration test for noisy SSH stdout or capture upload stdout and surface it only on failure.

@elezar

Copy link
Copy Markdown
Member

/ok-to-test 0a91547

@elezar
elezar dismissed their stale reviewJuly 24, 2026 09:41

Changes applied.

@elezarelezar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the patience here @rhuss.

@elezar
elezar enabled auto-merge July 24, 2026 09:41
@elezarelezar added the test:e2e Requires end-to-end coverage label Jul 24, 2026
@github-actions

Copy link
Copy Markdown

Label test:e2e applied for 0a91547. Open the existing run and click Re-run all jobs to execute with the label set. The run will execute the standard E2E suite after building the required gateway and supervisor images once. The matching required CI gate status on this PR will flip green automatically once the run finishes.

@elezar

Copy link
Copy Markdown
Member

@rhuss please resolve the comments that have been addressed. This should merge the PR.

@elezar
elezar added this pull request to the merge queueJul 24, 2026
Merged via the queue into NVIDIA:main with commit b422b67Jul 24, 2026
66 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:e2eRequires end-to-end coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extend --output json to sandbox list, sandbox create, and status commands

3 participants

@rhuss@elezar@johntmyers