Skip to content

RESOLVER_BASE_URL defaults to a host that does not resolve, and the value is signed #382

Description

@LKSNDRTMLKV

Found tracing the demo resolver path end to end.

The default is a dead host

crates/dpp-node/src/config.rs falls back to https://id.odal-node.io when
RESOLVER_BASE_URL is unset, and .env.example line 133 ships that value
uncommented, so a copy-paste .env inherits it.

id.odal-node.io is NXDOMAIN. Checked 2026-09-19 — the apex and docs.
resolve; id. does not.

Why it is worse than a bad default

build_carrier_url writes that base into every passports qr_code_url at
publish time
, and the passport is then signed. So the dead URL is inside
the signature. The .env.example comment already says the consequence plainly:

"It cannot be corrected afterwards — publishing starts the ESPR retention
window and odal passport archive refuses inside it, so the labels would have
to be reissued."

A silent default that produces unfixable output is the combination worth
removing. Nothing prints a warning; the node boots, publishes, and the QR codes
scan to nothing.

The prose is already honest.env.example says the default "is not wired
up yet". This issue is about the code default, which no one reads.

Three options

Behaviour Trade
A. No default RESOLVER_BASE_URL becomes required; the node refuses to boot without it Fail-closed and unambiguous. Breaking for anyone relying on the default — though what they are relying on is broken
B. Default to http://localhost:8003 Matches RESOLVER_PORTs own default, so a local node works out of the box A wrong value becomes obviously wrong rather than subtly wrong. Helps the local demo directly
C. Keep it, refuse under NODE_PROFILE=production Mirrors the existing trust gate, which already "refuses to boot on placeholder trust" Consistent with boot/trust.rs. Leaves the trap open in every non-production profile — which is where the demo runs

Recommendation: B, and C on top if cheap. B removes the trap at its root and
makes the default useful: a freshly-booted local node produces carrier URLs
that actually resolve against its own resolver. A localhost URL that escapes to
production is self-evidently wrong at a glance; id.odal-node.io is not.

A alone is defensible and more purist, but it makes the quickstart longer for
every developer to protect against a mistake B prevents by construction.

Not done here

This changes a value that lands inside signatures, so it is a decision rather
than a fix to apply unilaterally. No code changed.

Related

The same trace found that CREDENTIAL_ISSUERS_SELF being unset makes
/credential/dpp/{id} serve the public body with a 200 — also silent, also
worth its own look. Not filed separately yet.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    surface/persistenceMoves retention, archiving or the ESPR Art. 10(4) back-up copytype/decisionNeeds a call; analysis alone will not close iturgency/nextBlocks work already scheduled

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions