-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Summary
The shared format_value formatter (crates/google-workspace-cli/src/formatter.rs) has several issues that affect all helpers using non-JSON output formats.
1. No terminal escape sanitization
value_to_cell() returns raw strings from API responses without sanitizing terminal escape sequences. Any API response field containing ANSI escape codes (e.g. \x1b]0;...) will render them directly when using --format table, --format yaml, or --format csv.
JSON output is safe because serde escapes control characters automatically. Non-JSON formats pass untrusted content straight through to the terminal.
This is a security concern — API responses may contain user-generated content that an attacker could craft to inject terminal escape sequences.
2. extract_items() discards envelope metadata
extract_items() finds the first array field in a JSON response and returns only that array, discarding all sibling fields. For a typical paginated response like:
{
"items": [...],
"totalCount": 42,
"nextPageToken": "abc123"
}Table/CSV/YAML output renders only the items array. nextPageToken is explicitly skipped, but all other envelope fields (totalCount, any echoed query parameters, etc.) are silently dropped too. Helpers can work around this by printing metadata to stderr, but it would be nice for there to be a standard way of handling this at the formatter level — e.g. format_value accepting an optional configuration or callback that tells it how to handle envelope fields.
3. Arrays of objects render as raw JSON blobs in table/CSV cells
When a table cell contains an array of objects, value_to_cell() joins them with , but renders each object via serde_json::to_string(). The result is something like:
{"id":"1","name":"Alice"}, {"id":"2","name":"Bob"}
Flat arrays of strings work fine (alice, bob), but arrays of objects produce a hybrid of comma-joined raw JSON that's difficult to use downstream.
Similar to the envelope metadata issue, a callback or configuration for format_value could let helpers specify how to render nested arrays — pick a representative field, flatten with a custom function, etc.
4. 60-character column width cap with no line wrapping
Table columns are hard-capped at 60 characters in format_array_as_table() and truncated with an ellipsis. For fields with longer content, this silently loses data.
It might be worth looking at existing Rust table-rendering crates (e.g. comfy-table, tabled) that handle dynamic column sizing, terminal width detection, and line wrapping within cells. The current hand-rolled implementation is simple but limited — a dedicated library could handle these edge cases without adding complexity to maintain.