From 27cde6a9d39047d0e45ced5bec05dab8a1eba757 Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Sat, 22 Aug 2026 21:58:11 +0000 Subject: [PATCH] [misc] Report a failed discovery by its shape, not its body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A discovery failure in the live e2e rendered the vendor's response into the assertion message. When the vendor is Bedrock, that response is an AWS refusal naming the resource it refused, and the name is an ARN carrying the 12-digit account id — into a job log anyone who can see the run can read. The earlier change kept the body out of the success log and left the failure paths quoting it, which is the path that actually carries the refusal. Report the response's size and top-level keys instead. That is what the failure is diagnosed from anyway: which envelope arrived, not what was in it. --- e2e/agentnetwork/discovery_live_test.go | 32 +++++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/e2e/agentnetwork/discovery_live_test.go b/e2e/agentnetwork/discovery_live_test.go index 86f6a4408..22c9f31c2 100644 --- a/e2e/agentnetwork/discovery_live_test.go +++ b/e2e/agentnetwork/discovery_live_test.go @@ -328,15 +328,16 @@ func runLiveDiscoveryCase(t *testing.T, ctx context.Context, tc liveDiscoveryCas // Status only, not the body. A Bedrock listing embeds inference-profile // ARNs carrying the 12-digit AWS account id, and these job logs are // readable by anyone who can see the run. The ids line below is the finding - // anyway; the assertion messages still carry the body, and those only - // render on a failure that needs diagnosing. + // anyway. The failure paths below are the same log: a listing that fails to + // arrive is an AWS refusal naming the resource it refused, and that name is + // an ARN carrying the same account id. t.Logf("[discovery] %s GET %s -> %d", tc.name, tc.path, code) - require.Equal(t, 200, code, "%s discovery must be served; body: %s", tc.name, truncate(body, 2000)) + require.Equal(t, 200, code, "%s discovery must be served; response was %s", tc.name, bodyShape(body)) ids, ok := listingIDs(body) require.Truef(t, ok, - "%s answered discovery with something other than a {\"data\":[{\"id\":…}]} listing, which the filter forwards untouched — the caller would get an unbounded picker; body: %s", - tc.name, truncate(body, 2000)) + "%s answered discovery with something other than a {\"data\":[{\"id\":…}]} listing, which the filter forwards untouched — the caller would get an unbounded picker; response was %s", + tc.name, bodyShape(body)) sort.Strings(ids) t.Logf("[discovery] %s: %d ids after filtering: %s", tc.name, len(ids), strings.Join(ids, ", ")) @@ -415,6 +416,27 @@ func caseNames(cases []liveDiscoveryCase) []string { return names } +// bodyShape describes a response without quoting any of it: its size and the +// top-level keys it arrived under. That is what a discovery failure is +// diagnosed from — which envelope the vendor answered with — and it is all +// that may go in a message rendered into a public job log, because the values +// underneath can carry an ARN and its account id. +func bodyShape(body string) string { + var doc map[string]json.RawMessage + if err := json.Unmarshal([]byte(body), &doc); err != nil { + return strconv.Itoa(len(body)) + " bytes, not a JSON object" + } + keys := make([]string, 0, len(doc)) + for key := range doc { + keys = append(keys, key) + } + sort.Strings(keys) + if len(keys) == 0 { + return strconv.Itoa(len(body)) + " bytes, an empty JSON object" + } + return strconv.Itoa(len(body)) + " bytes, keyed by: " + strings.Join(keys, ", ") +} + // truncate bounds a logged response body. A live catalogue can run to tens of // kilobytes, and the useful part is the front. func truncate(s string, limit int) string {