feat(websites): support on-chain managed HNS domains end to end - #668
Conversation
Brings the CLI and MCP surfaces up to the backend's on-chain managed HNS support: new websites_domains_convert_onchain operation, onchain_managed aware status handling, delegation rendering that explains contract-served DNS, agent-guide and prompt guidance, and a refreshed test double (spec resynced from ipfs-sdk v0.1.95, onchain endpoint implemented, E2E test). Bumps ipfs-sdk to v0.1.95 and portal-sdk to v0.1.72.
This comment has been minimized.
This comment has been minimized.
Code Coverage ReportTotal Coverage: 49.9% Generated from commit: 20fe307 |
| output := newTestOutput() | ||
| renderDomainDelegation(output, &ipfs.DomainResponse{ | ||
| Id: 1, Domain: "mydomain.hns", Namespace: "hns", Status: strPtr("delegated"), | ||
| Id: 1, Domain: "mydomain.hns", Namespace: ipfs.DomainNamespaceHNS, Status: new(ipfs.DomainResponseStatusActive), |
There was a problem hiding this comment.
The test code calls the predeclared new builtin with a constant argument instead of a type, causing a compile error that breaks the entire test build across cli/mcp packages. Replace with ptr.To(...) or a proper &value helper, e.g., status := ipfs.DomainResponseStatusActive; Status: &status.
status := ipfs.DomainResponseStatusActive
Status: &statusPrompt for LLM
File internal/cli/websites_domains_test.go:
Line 16:
The test code calls the predeclared `new` builtin with a constant argument instead of a type, causing a compile error that breaks the entire test build across cli/mcp packages. Replace with `ptr.To(...)` or a proper `&value` helper, e.g., `status := ipfs.DomainResponseStatusActive; Status: &status`.
Suggested Code:
status := ipfs.DomainResponseStatusActive
Status: &status
Talk to Kody by mentioning @kody
Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.
There was a problem hiding this comment.
@kody add memory/rule that go 1.26+ supports this. global rule.
There was a problem hiding this comment.
Done — I created a global memory rule:
Go 1.26+ supports new(type) constructed-value syntax
The rule captures that, starting with Go 1.26, using the predeclared new builtin with a constant/enum value argument (e.g. new(ipfs.DomainResponseStatusActive)) is a valid way to produce a pointer to that value, so test/build code relying on it should not be flagged as a compile error — and Kody should not suggest replacing it with ptr.To(...) when the target toolchain is Go 1.26 or newer.
Since you asked for a global rule, it applies across all repositories in the organization (no repository scope).
- Decision: Created
- Approval required in UI: No (activated immediately)
- Link to view it: https://app.kodus.io/settings/code-review/global/kody-rules/099d3448-f2c5-4953-8506-848a46c1d6ee?tab=memories&teamId=b3d39288-c3bc-4633-acf4-7667f2e47ce9
This will prevent Kody from raising the false "compile error" on new(constantValue) in the future.
| // on-chain hosting shape instead of rendering a record table. | ||
| assert.Contains(t, out, "on-chain managed") | ||
| assert.Contains(t, out, "external") | ||
| assert.Contains(t, out, "TXT token") |
There was a problem hiding this comment.
The string literal "TXT token" contains the banned keyword "token", which violates the hard-coded secret rule. Replace it with a constant or variable that avoids the keyword, such as "TXT record", or construct the expected string dynamically from parts that don't include it.
Kody rule violation: Ban hard-coded secrets in Go source
Prompt for LLM
File internal/cli/websites_domains_test.go:
Line 215:
The string literal "TXT token" contains the banned keyword "token", which violates the hard-coded secret rule. Replace it with a constant or variable that avoids the keyword, such as "TXT record", or construct the expected string dynamically from parts that don't include it.
Talk to Kody by mentioning @kody
Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.
The HTTP upload tests asserted the executor's atomic.Value result immediately after the PUT returned 202 Accepted, but the upload task runs on its own goroutine. Under runner scheduling pressure the assert could win the race and panic on a nil Load. Wait with require.Eventually instead of type-asserting blind.
Kody Review CompleteGreat news! 🎉 Keep up the excellent work! 🚀 Kody Guide: Usage and ConfigurationInteracting with Kody
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
Adds on-chain managed domain support across the CLI and MCP surfaces, matching the backend's website-domain binding changes.
The new
websites domains convert-onchainoperation reclassifies a bound HNS domain as on-chain managed through the SDK's ConvertDomainToOnChain (one-way, confirm-gated). Domain status is now compared as typed SDK enums, and the wizard no longer treats an on-chain managed binding as invalid. The HNS delegation renderer explains contract-served DNS and publishes nothing instead of dereferencing a missing delegation bundle. MCP agent guidance, the website onboarding prompt, and the dns-requirements resource point agents at the per-domain status flow so they neither wait for delegation nor publish website-level records for an on-chain managed binding. The test double's spec is resynced from ipfs-sdk v0.1.95 and now serves the onchain endpoint, with an SDK-level E2E test covering the happy path, idempotent re-convert, and ICANN refusal.Bumps go.lumeweb.com/ipfs-sdk to v0.1.95 and go.lumeweb.com/portal-sdk to v0.1.72.
Summary
This PR adds end-to-end support for on-chain managed Handshake (HNS) domains across the CLI, MCP agent surfaces, and test infrastructure. An on-chain managed HNS binding is one whose DNS is served by an external contract on the Handshake chain (its NS record points at that contract), so Pinner stops managing the zone/DNSSEC and instead verifies ownership via a TXT token.
Key Changes
Domain conversion to on-chain managed
websites domains convert-onchaincatalog operation (websites_domains_convert_onchain) exposed to both CLI and MCP.onchain_managed: the portal deletes its managed zone/DNSSEC and switches ownership verification to the TXT token. It is one-way and destructive, so it requires an explicitconfirm=true(agents alone cannot confirm; only a human can set the flag). DANE/SSL state is retained.ConvertDomainToOnChainmethod; an "already on-chain" response from the backend is treated as idempotent success.Typed domain status and namespace enums
statusandnamespacefields are now typed enum values instead of plain strings, introducing the newonchain_managedstatus alongsideactive,records_generated,waiting_delegation, etc. All CLI rendering, wizard, and test code was updated to use the typed constants.CLI delegation rendering
onchain_managed, the CLI prints an explicit explanation: the name's DNS is served by an external contract, no parent/authoritative records must be published, and ownership is verified via a TXT token through the HNS resolver. Publishing Pinner's delegation records would be wrong in this state.Domain wizard
onchain_managedas a fully validated/active binding — an on-chain managed name is verified via the namespace TXT token and needs no delegation wait.MCP / agent guidance
notesfield directing agents to the per-domain binding state and records (website-level view cannot see namespace delegation), and warns against adding website-level records for on-chain managed HNS names.Platform domain registration (admin)
admin_platform_domains_registeroperation'snamespaceargument is now optional: it defaults tohnswhen omitted, andicanncan be passed for a traditional DNS root.Test infrastructure
onchain_managed), and the fake server implements the new on-chain conversion endpoint matching the portal's contract (422 for non-HNS or already-on-chain bindings; SDK maps already-on-chain to idempotent success).