Skip to content

fix(ipc): decode explicit null results and stop silent null degradation - #287

Open
cyberspace-cs wants to merge 1 commit into
Tencent:mainfrom
cyberspace-cs:fix/ipc-explicit-null-result
Open

cyberspace-cs wants to merge 1 commit into
Tencent:mainfrom
cyberspace-cs:fix/ipc-explicit-null-result

Conversation

@cyberspace-cs

Copy link
Copy Markdown

Summary

Fixes a silent-failure channel in the IPC protocol where JSON null
was treated as "field absent" instead of a legal value.

1. Decoder: explicit null results were rejected as ambiguous

ResponseFrame::deserialize and the Frame visitor modelled the
result field as Option<Value>. serde collapses JSON "result": null
into the same None as a missing field, so a reply like
{"id":"x","result":null} was rejected with a misleading
ambiguous response: expected exactly one of result or error.

That shape is not hypothetical: the daemon emits it through
serde_json::to_value(..).unwrap_or(Value::Null) (see below), and
Value::Null serialises back to "result": null — so the encoder and
decoder were asymmetric.

Both deserializers now parse the raw value
(#[serde(default, deserialize_with)]) so an explicit null result
decodes to Ok(Value::Null) while a missing field stays an error.

2. Daemon: result serialisation failures silently degraded to null

Every serde_json::to_value(..).unwrap_or(Value::Null) site silently
turned a result serialisation failure — e.g. a payload nested deeper
than serde_json's 128-level recursion limit — into a JSON null
result, hiding the real failure from the CLI client and colliding with
legitimate null results.

All of these now route through ok_value() / serialise_err()
helpers that return a structured protocol_error with the underlying
serde message. The upload/download param-staging paths (which
forwarded null params to the extension on failure) now return the
same error instead.

Testing

  • cargo test -p bsk-protocol — 158 passed (4 new: explicit-null
    decode for Frame and ResponseFrame, serialise round-trip
    symmetry, missing-field regression)
  • cargo test -p bsk --lib — 328 passed, 2 failed (both pre-existing
    environment failures in skill_install::harness on hosts with a real
    hermes install; unrelated to this change)
  • cargo fmt clean on both crates

The IPC protocol is JSON-RPC-style: a successful reply carries
"result" and a failed reply carries "error". Two defects made JSON
null a silent failure channel instead of a legal value.

1. Decoder (bsk-protocol): ResponseFrame::deserialize and the Frame
   visitor modelled the result field as Option<Value>, which serde
   collapses "result": null into the same None as a missing field.
   The daemon emits exactly that shape through its
   serde_json::to_value(..).unwrap_or(Value::Null) fallback, so a
   result serialisation failure surfaced on the CLI as a misleading
   "ambiguous response" / "expected result or error" decode error
   instead of a null result. Both deserializers now parse the raw
   value with #[serde(default, deserialize_with)] so an explicit
   null result decodes to Ok(Value::Null) while a missing field
   stays an error.

2. Daemon (bsk-cli): every serde_json::to_value(..).unwrap_or(Value::Null)
   site silently degraded a result serialisation failure (e.g. a
   payload nesting deeper than serde_json's recursion limit) to JSON
   null, hiding the real failure and colliding with legitimate null
   results. These now route through ok_value()/serialise_err()
   helpers that return a structured protocol_error instead, and the
   upload/download param staging paths return the same error rather
   than forwarding null params to the extension.

Adds unit tests on both sides: explicit-null decode for Frame and
ResponseFrame, serialise round-trip symmetry, missing-field
regression, and the daemon-side serialisation-failure path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant