fix(output): narrow rows for every column format, not just the three spelled exactly (#353) - #376
Merged
Merged
Conversation
…spelled exactly (#353) `config list -o Table` rendered a different table from `config list -o table`, dropping the `ENVIRONMENT-ID` column and blanking `DEFAULT`. Three call sites decided whether to narrow their row type with an exact-match switch on the format string and a `default` arm returning the wide shape: internal/commands/config.go listRowsForFormat internal/commands/protect_helpers.go printResult internal/scope/scope.go OutputScope Nothing normalises that string — `output.New` takes the `--output` value verbatim and `ResolveFormat` returns it untouched — while `Print` has no case for `Table` and renders a table through its own default arm. So any value outside the three literals took the wide shape to a column renderer. On `config list` that reopened the bug the code documents two comments above: a table's columns are the keys of its *first* row, `EnvironmentID` and `Default` carry `omitempty`, and `configProfileTableRow` exists precisely to remove it. An instance profile sorting first therefore hid the scope of every platform profile below it. `--wide` did not help; it reads `rows[0]` too. Polarity inverted at all three: the narrow shape is the default and the keep-set is named, via `output.RendersStructureVerbatim` — json, yaml, ndjson, xml, raw. That is correct rather than merely safer, because the formatter renders a table for anything it does not recognise, so the narrow shape is the matching one. `internal/commands/root.go`'s `isFullDetailFormat` already had this polarity and is the precedent. `json-multi` is deliberately outside the keep-set. It means JSON on the wire and a table on the screen — `multi.go` sets it as the capture format and `Print` has no case for it — so keeping the wide shape for it would put that shape back on a terminal by way of `jamf-cli multi`. The generated `selectTableColumns` excludes it from its own keep-set for the same reason, so the hand-written and generated paths now agree by construction rather than by coincidence. Tests cover each site against the mis-cased, unrecognised and json-multi values as well as the keep-set, and were checked against the pre-fix code — reverting `OutputScope` alone fails five cases. Not a credential exposure: `configProfileRow` declares `Token` and `ClientID`, which the narrow type omits, but both are populated only by `config show`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
neilmartin83
enabled auto-merge
September 9, 2026 10:01
grahampugh
approved these changes
Sep 9, 2026
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.
Fixes #353.
config list -o Tablerendered a different table fromconfig list -o table— theENVIRONMENT-IDcolumn gone,DEFAULTblanked, and so the scope of every platform profile invisible.Cause
Three call sites decided whether to narrow their row type with an exact-match switch on the format string, and a
defaultarm returning the wide shape:internal/commands/config.golistRowsForFormatinternal/commands/protect_helpers.goprintResultinternal/scope/scope.goOutputScopeNothing normalises that string —
output.Newtakes the--outputvalue verbatim andResolveFormatreturns it untouched — whilePrinthas no case forTableand renders a table through its own default arm. So any value outside the three literals took the wide shape to a column renderer.On
config listthat reopened the bug the code documents two comments above its own switch: a table's columns are the keys of its first row,EnvironmentIDandDefaultcarryomitempty, andconfigProfileTableRowexists precisely to remove it. An instance profile sorting first therefore hid the scope of every platform profile below it.--widedid not help; it readsrows[0]too.Fix
Polarity inverted at all three: the narrow shape is the default and the keep-set is named, via a new
output.RendersStructureVerbatim—json,yaml,ndjson,xml,raw.That is correct rather than merely safer: the formatter renders a table for anything it does not recognise, so the narrow shape is the matching one.
internal/commands/root.go'sisFullDetailFormatalready had this polarity and is the precedent.json-multiis deliberately outside the keep-set. It means JSON on the wire and a table on the screen —multi.gosets it as the capture format andPrinthas no case for it either — so keeping the wide shape for it would put that shape back on a terminal by way ofjamf-cli multi. The generatedselectTableColumnsexcludes it from its own keep-set for the same reason, so the hand-written and generated paths now agree by construction rather than by coincidence.Tests
Each site is covered against the mis-cased, unrecognised and
json-multivalues as well as the keep-set, plusoutput.RendersStructureVerbatimitself in both directions.Verified against the pre-fix code rather than assumed: restoring
OutputScope's old switch alone fails five cases.Not a credential exposure
configProfileRowdeclaresTokenandClientID, which the narrow type omits, so this looked like it might print credential references. Both are populated only byconfig show, never byconfig list. Checked before filing.Notes
mainmerged in (through fix(report): keep blueprint-status' count columns when the first row is NOT_DEPLOYED #374). Full suite andmake lintgreen.rows[0]class inblueprint-statusby giving every row every key — no overlap with this change.🤖 Generated with Claude Code