Repository navigation
Commit 4f4e1bb
authored
fix(cli): keep truncated table cells on a rune boundary (#1727)
# Pull Request
## Description
Finishes the UTF-8-safe truncation sweep of #1647 / #1664 / #1665 in the
part of `cmd/mcpproxy` those PRs explicitly set aside ("I left the CLI
table description truncations in `cmd/mcpproxy` alone to keep this
focused" — #1664). Companion to #1726, which covers the remaining
`internal/` sites.
Four table cuts existed as independent copies of the same arithmetic,
and all four cut at a raw byte offset:
| Site | Column | Data |
|---|---|---|
| `shorten` (`profile_cmd.go`) | 30 | `EffectiveServers`, comma-joined |
| `truncateStr` (`registry_cmd.go`, `catalog_cmd.go`) | 60 / 45 / 40 |
registry `description`, catalog `Title` |
| inline `desc[:57] + "..."` (`upstream_cmd.go`) | 60 | upstream tool
`Description` |
| inline `result[:maxLen-3] + "..."` (`token_cmd.go`) | 23 |
`allowed_servers`, comma-joined |
**Reachability.** Every one of these cells is upstream- or
operator-authored text:
- `mcpproxy registry list` / `registry search` print descriptions
straight from the registry API response (`mapString(r, "description")`),
and `catalog list` prints `r.Title`. Both are free text from a public
registry.
- `mcpproxy upstream tools` prints the tool `Description` advertised by
the upstream server.
- `allowed_servers` and `EffectiveServers` are server names, which the
config only forbids from being empty or containing `:`
(`internal/config/server_edition_config.go:176`) — a non-ASCII name is
legal.
A value longer than its column whose byte at the cut offset is a UTF-8
continuation byte ends in a partial rune on the terminal. With a 3-byte
rune, 2 of every 3 offsets are mid-rune; the test sweeps all three at
each of the six real column widths.
All four now go through one `truncateCell` built on
`stringutil.UTF8Prefix`, in a file of its own so a fifth table does not
grow a fifth copy. `joinInterfaceSlice` keeps `maxLen == 0` meaning "do
not truncate".
ASCII output is byte-for-byte unchanged and the result still never
exceeds the column width — both asserted.
**Left alone, deliberately:**
- `cmd/mcpproxy/security_cmd.go` and `cmd/mcpproxy/main.go` have the
same shape but are touched by open PRs (#1714, #1720, #1725), so I have
not gone near them. Happy to follow up once those land.
- `activity_cmd.go`'s `actType[:12]` and `upstream_cmd.go`'s `hash[:12]`
cut an internal activity-type enum and a hex digest, where no multi-byte
rune can reach the boundary. Not touched — a guard there would protect
against a state the code cannot produce.
## Testing
- [x] I have tested these changes locally
- [x] I have added/updated tests that prove my fix is effective or my
feature works
- [x] All existing tests pass
New tests in `cmd/mcpproxy/table_cell_utf8_test.go`:
- `TestTruncateCellKeepsRuneBoundary` — 6 real column widths x 3 byte
offsets.
- `TestTruncateCellASCIIUnchanged` — pins the ASCII output of all four
removed helpers, including the `maxLen <= 3` edge.
- `TestJoinInterfaceSliceTruncationIsRuneSafe` — drives the composition
(`joinInterfaceSlice` -> `truncateCell`), not just the helper, and pins
`maxLen == 0`.
**Mutation check.** With `truncateCell` reverted to the raw byte cut
(`s[:maxLen-3] + "..."`) the two boundary tests fail by name — 12
sub-cases in `TestTruncateCellKeepsRuneBoundary`, plus
`TestJoinInterfaceSliceTruncationIsRuneSafe` — while
`TestTruncateCellASCIIUnchanged` still passes, which is what shows the
change is behaviour-preserving for ASCII. Restoring the fix returns the
package to green.
Commands run (exit status in brackets):
```
gofmt -l cmd/mcpproxy [0, no output]
git diff --check [0]
CGO_ENABLED=0 go vet ./cmd/mcpproxy [0]
CGO_ENABLED=0 go build ./cmd/mcpproxy [0]
CGO_ENABLED=0 go test -count=1 ./cmd/mcpproxy [0, whole package]
```
`CGO_ENABLED=0` because this machine's Command Line Tools SDK is
currently broken for cgo linking (`arm64e.x1-macos: unknown
architecture` out of `CoreFoundation.tbd`), which is unrelated to this
change. Nothing here is cgo-dependent. I did not run `-race` or
`./scripts/run-all-tests.sh` (local disk constraints); none of this code
is concurrent.1 parent f321b47 commit 4f4e1bb
8 files changed
Lines changed: 119 additions & 34 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
429 | 429 | | |
430 | 430 | | |
431 | 431 | | |
432 | | - | |
| 432 | + | |
433 | 433 | | |
434 | 434 | | |
435 | 435 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
333 | 333 | | |
334 | 334 | | |
335 | 335 | | |
336 | | - | |
337 | | - | |
338 | | - | |
339 | | - | |
340 | | - | |
341 | | - | |
342 | | - | |
343 | | - | |
344 | | - | |
345 | | - | |
346 | 336 | | |
347 | 337 | | |
348 | 338 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
90 | 90 | | |
91 | 91 | | |
92 | 92 | | |
93 | | - | |
| 93 | + | |
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
| |||
125 | 125 | | |
126 | 126 | | |
127 | 127 | | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | 128 | | |
136 | 129 | | |
137 | 130 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
559 | 559 | | |
560 | 560 | | |
561 | 561 | | |
562 | | - | |
| 562 | + | |
563 | 563 | | |
564 | 564 | | |
565 | 565 | | |
| |||
586 | 586 | | |
587 | 587 | | |
588 | 588 | | |
589 | | - | |
| 589 | + | |
590 | 590 | | |
591 | 591 | | |
592 | 592 | | |
| |||
611 | 611 | | |
612 | 612 | | |
613 | 613 | | |
614 | | - | |
615 | | - | |
616 | | - | |
617 | | - | |
618 | | - | |
619 | | - | |
620 | | - | |
621 | 614 | | |
622 | 615 | | |
623 | 616 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
668 | 668 | | |
669 | 669 | | |
670 | 670 | | |
671 | | - | |
672 | | - | |
| 671 | + | |
| 672 | + | |
673 | 673 | | |
674 | 674 | | |
675 | 675 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2536 | 2536 | | |
2537 | 2537 | | |
2538 | 2538 | | |
2539 | | - | |
2540 | | - | |
2541 | | - | |
2542 | | - | |
| 2539 | + | |
2543 | 2540 | | |
2544 | 2541 | | |
2545 | 2542 | | |
| |||
0 commit comments