nuts-foundation / nuts-foundation/nuts-node

connectToDID doesn't resolve DID URL service references, silently skipping peer discovery

Open
#4,448 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Go
Stars
28
Forks
23
Avg merge
1d 10h
Merged PRs (30d)
76

Description

Description

Network.connectToDID (network/network.go) iterates a discovered peer's node.Service entries and calls service.UnmarshalServiceEndpoint(&nutsCommUrl) directly on the raw NutsComm service entry.

This works for a literal serviceEndpoint (e.g. "grpc://example.com:5555"), but not when the serviceEndpoint is itself a DID URL reference, e.g.:

"serviceEndpoint": "did:nuts:C79u41fohcBHt7EwBF7KQdkhqerLCvAceGuLrEjHUq3S/serviceEndpoint?type=NutsComm"

This is a valid, spec-compliant way to publish a service endpoint (an indirection to another DID document's service) — used e.g. by a care organization's (child) DID document referencing its vendor's (parent) DID document. UnmarshalServiceEndpoint tries to parse this string directly as an absolute URL and fails, which is logged (at Debug level) and that service entry is silently skipped:

msg="Failed to extract NutsComm address from service" did="did:nuts:..." error="url must contain scheme and host"

Because the error is Debug-level and per-service, the node never surfaces that it failed to resolve that DID's NutsComm address.

Root cause

connectToDID reads the service entry directly instead of resolving it. Compare with Network.checkNodeDIDHealth, which correctly follows DID URL service references before parsing:

serviceRef := resolver.MakeServiceReference(nodeDID, transport.NutsCommServiceType)
nutsCommService, err := n.serviceResolver.Resolve(serviceRef, resolver.DefaultMaxServiceReferenceDepth)

connectToDID has access to the same n.serviceResolver but never uses it.

Impact

Discovery through a care organization's (child) DID document that references its vendor's (parent) DID document's NutsComm service fails via this path. In practice this is likely low severity: the vendor's (parent) DID document is discovered separately and publishes the endpoint as a literal URL, so the underlying node still gets discovered and connected to through that document. The gap is that discovery specifically through the child DID document silently fails instead of resolving the reference, which is still worth fixing since it's a valid, spec-compliant endpoint format.

Suggested fix

In connectToDID, resolve the service via n.serviceResolver.Resolve(...) (as checkNodeDIDHealth already does) before unmarshalling into transport.NutsCommURL, instead of unmarshalling the raw did.Service entry directly.

Assisted by AI

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in network/network.go at Network.connectToDID, then compare its service handling with Network.checkNodeDIDHealth. Use the existing serviceResolver path to resolve DID URL service references before unmarshalling into transport.NutsCommURL; done means NutsComm services published by reference are discovered instead of silently skipped.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
networking
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.