Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions registry/client/binary_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,12 @@ func (c *BinaryClient) sendJSONLocked(msg map[string]interface{}) (map[string]in
if err := json.Unmarshal(payload, &resp); err != nil {
return nil, fmt.Errorf("json decode response: %w", err)
}
if errMsg, ok := resp["error"].(string); ok {
return resp, fmt.Errorf("registry: %s", errMsg)
if errVal, ok := resp["error"]; ok {
return resp, fmt.Errorf("registry: %v", errVal)
}
// PILOT-132: reject valid JSON that lacks the expected "type" envelope key.
if _, hasType := resp["type"]; !hasType && len(resp) > 0 {
return resp, fmt.Errorf("registry: malformed response (missing %q field)", "type")
}
return resp, nil
}
16 changes: 12 additions & 4 deletions registry/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,12 @@ func (c *Client) sendOnEntry(entry *pooledConn, msg map[string]interface{}) (map
if err != nil {
return nil, fmt.Errorf("recv: %w", err)
}
if errMsg, ok := resp["error"].(string); ok {
return resp, fmt.Errorf("registry: %s", errMsg)
if errVal, ok := resp["error"]; ok {
return resp, fmt.Errorf("registry: %v", errVal)
}
// PILOT-132: reject valid JSON that lacks the expected "type" envelope key.
if _, hasType := resp["type"]; !hasType && len(resp) > 0 {
return resp, fmt.Errorf("registry: malformed response (missing %q field)", "type")
}
return resp, nil
}
Expand Down Expand Up @@ -514,8 +518,12 @@ func (c *Client) sendLocked(msg map[string]interface{}) (map[string]interface{},
if err != nil {
return nil, fmt.Errorf("recv: %w", err)
}
if errMsg, ok := resp["error"].(string); ok {
return resp, fmt.Errorf("registry: %s", errMsg)
if errVal, ok := resp["error"]; ok {
return resp, fmt.Errorf("registry: %v", errVal)
}
// PILOT-132: reject valid JSON that lacks the expected "type" envelope key.
if _, hasType := resp["type"]; !hasType && len(resp) > 0 {
return resp, fmt.Errorf("registry: malformed response (missing %q field)", "type")
}
return resp, nil
}
Expand Down
51 changes: 51 additions & 0 deletions registry/client/zz_client_branch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,57 @@ func TestSendOnEntryReturnsServerErrorResponse(t *testing.T) {
}
}

// TestSendOnEntryReturnsErrorOnNonStringError verifies that a server error
// value of a non-string type (e.g. int) is still treated as an error (PILOT-132).
// Previously only resp["error"].(string) would trigger, silently swallowing
// numeric or object error values.
func TestSendOnEntryReturnsErrorOnNonStringError(t *testing.T) {
t.Parallel()
srv := newFakeJSONServer(t, func(_ map[string]interface{}) map[string]interface{} {
return map[string]interface{}{"error": float64(403)}
})
defer srv.close()

c, err := DialPool(srv.addr(), 2)
if err != nil {
t.Fatalf("DialPool: %v", err)
}
defer c.Close()

_, err = c.Send(map[string]interface{}{"type": "x"})
if err == nil {
t.Fatalf("expected error for non-string error value")
}
if !strings.Contains(err.Error(), "403") {
t.Fatalf("error should contain the numeric error value 403, got: %v", err)
}
}

// TestSendReturnsErrorOnMalformedResponse verifies that a valid-JSON response
// that lacks both an "error" key and a "type" key is treated as a protocol
// violation, not silently accepted (PILOT-132).
func TestSendReturnsErrorOnMalformedResponse(t *testing.T) {
t.Parallel()
srv := newFakeJSONServer(t, func(_ map[string]interface{}) map[string]interface{} {
return map[string]interface{}{"unexpected": "key"}
})
defer srv.close()

c, err := Dial(srv.addr())
if err != nil {
t.Fatalf("dial: %v", err)
}
defer c.Close()

_, err = c.Send(map[string]interface{}{"type": "ping"})
if err == nil {
t.Fatalf("expected error for malformed response (missing 'type' key)")
}
if !strings.Contains(err.Error(), "malformed") {
t.Fatalf("error should describe malformed response: %v", err)
}
}

// --- DialTLS happy path ---------------------------------------------------

func TestDialTLSHappyPathConnects(t *testing.T) {
Expand Down
Loading