Skip to content

feat(network): require explicit root-key for connected networks#645

Open
lwshang wants to merge 1 commit into
mainfrom
lwshang/enhance_root_key_config
Open

feat(network): require explicit root-key for connected networks#645
lwshang wants to merge 1 commit into
mainfrom
lwshang/enhance_root_key_config

Conversation

@lwshang

@lwshang lwshang commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

The root-key for a connected network was optional and silently defaulted to the IC mainnet key. That masked misconfiguration: a connected network pointing somewhere non-mainnet would appear to work until the first real message-verification failure.

This makes root-key required for connected networks and gives it three forms:

  • mainnet — use the canonical IC mainnet root key (e.g. to reach mainnet through a custom boundary node without repeating the 266-char literal). Responses are still fully verified against the real mainnet key.
  • fetch — fetch the key from the network on each use. Trust-on-first-use and unverified, so intended only for testnets you (or someone you trust) operate. A WARN is printed on every fetch.
  • a hex-encoded key — pin a specific key, as before.

Only the built-in ic network keeps the implicit mainnet key.

Design notes

  • The fetch ordering problem. root-key is needed to verify delegated (Internet Identity) chains before the agent exists, but fetch_root_key() needs an agent + a round-trip. Resolved by doing the fetch inside the network Accessor via an anonymous bootstrap agent, so NetworkAccess already carries resolved bytes by the time identity verification runs. Context's agent-build flow is unchanged.
  • No caching. The motivating use case is "a testnet rebooted and got a new key," so a cache would serve a stale key. Matches dfx: always fetch fresh (one cheap unauthenticated status call).
  • Provenance reporting. network status gains a root_key_source field in --json (managed / mainnet / configured / fetched) and a plain-ASCII label in text output, e.g. Root Key: 3081… (fetched - unverified, trust-on-first-use). The root_key field stays a flat hex string (non-breaking for JSON consumers); the warning goes to stderr so --json stdout stays clean.

Breaking change (staying on v1.x)

Technically breaking — a connected network with no root-key now fails to load. But non-mainnet connected networks already needed an explicit key to work, so in practice only a mainnet-via-custom-URL network must add root-key: mainnet. Small, acceptable radius → no major-version bump. See CHANGELOG.

Also in this PR

Fixes the icp-network-inline / icp-network-connected examples, which defined a staging network but no matching environment and told users to run icp deploy --network staging — but deploy takes --environment, not --network. Both now define a staging environment and the READMEs use icp deploy --environment staging.

Testing

  • cargo test, cargo fmt --check, cargo clippy --tests --benches -- -D warnings all green.
  • New end-to-end test status_connected_network_fetches_root_key: starts a managed local network in one project, connects to it from a second project with root-key: fetch, and asserts the fetch warning, the fetched label/root_key_source, and that the fetched key matches the running network's actual root key — no external network required.
  • Schemas and CLI docs regenerated.

🤖 Generated with Claude Code

The root-key for a connected network was optional and silently defaulted
to the IC mainnet key. That masked misconfiguration: a connected network
pointing somewhere non-mainnet would appear to work until the first real
message-verification failure.

Make root-key required for connected networks and give it three forms:
- `mainnet`: use the canonical IC mainnet root key (e.g. to reach mainnet
  through a custom boundary node without repeating the literal).
- `fetch`: fetch the key from the network on each use. Trust-on-first-use
  and unverified, so intended only for testnets you or someone you trust
  operate; a warning is printed on every fetch.
- a hex-encoded key, as before.

The fetch happens in the network Accessor via an anonymous bootstrap agent,
so the key is resolved before identity/delegation verification needs it.
`network status` now reports provenance: a `root_key_source` field in
--json and a `(fetched - ...)` / `(mainnet)` / `(configured)` label in text.

Only the built-in `ic` network keeps the implicit mainnet key. This is
technically breaking, but non-mainnet connected networks already needed an
explicit key, so in practice only mainnet-via-custom-URL configs must add
`root-key: mainnet`.

Also fixes the icp-network-inline / icp-network-connected examples, which
defined a `staging` network but no matching environment and told users to
run `icp deploy --network staging` (deploy takes --environment, not
--network); both now define a `staging` environment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes connected-network root key handling explicit and safer by requiring users to choose how the root key is obtained (pinned, canonical mainnet, or fetched trust-on-first-use), and surfaces root-key provenance in network status output. It updates schemas, docs, examples, and adds an end-to-end test for the fetch flow.

Changes:

  • Require root-key for all connected networks (except the built-in ic network which still uses the implicit mainnet key).
  • Add root-key: mainnet | fetch | <hex> support, including runtime fetching via a bootstrap anonymous agent and provenance reporting (root_key_source).
  • Update examples/docs and add an E2E test covering root-key: fetch without relying on external networks.

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated no comments.

Show a summary per file
File Description
examples/icp-network-inline/README.md Fixes example usage to deploy via an environment instead of --network.
examples/icp-network-inline/icp.yaml Adds root-key: mainnet and defines a staging environment targeting the staging network.
examples/icp-network-connected/README.md Fixes example usage to deploy via an environment instead of --network.
examples/icp-network-connected/networks/staging.yaml Adds root-key: mainnet to the connected network definition.
examples/icp-network-connected/icp.yaml Adds a staging environment mapping to the staging network.
docs/schemas/network-yaml-schema.json Updates schema: root-key is required and supports mainnet/fetch/hex via RootKeySpec.
docs/schemas/icp-yaml-schema.json Updates schema: root-key is required and supports mainnet/fetch/hex via RootKeySpec.
docs/reference/configuration.md Documents root-key requirement and the three supported forms.
docs/reference/cli.md Updates --root-key option docs to include mainnet/fetch/hex.
docs/migration/from-dfx.md Updates migration guidance to reflect explicit root-key choice and new options.
docs/concepts/project-model.md Updates example connected network configuration to include root-key: mainnet.
docs/concepts/environments.md Updates connected-network examples to include root-key: fetch.
crates/icp/src/project.rs Ensures built-in ic network uses RootKeySpec::Mainnet explicitly.
crates/icp/src/network/mod.rs Switches connected root_key to RootKeySpec and wires bootstrap agent into accessor.
crates/icp/src/network/access.rs Resolves root key bytes for connected networks (mainnet/configured/fetched) and records provenance.
crates/icp/src/manifest/network.rs Makes connected root_key required and introduces RootKeySpec parsing + schema.
crates/icp/src/lib.rs Updates mock project loader/test data to use RootKeySpec::Mainnet and include root-key where required.
crates/icp/src/context/tests.rs Updates tests to populate new root_key_source field in NetworkAccess.
crates/icp/src/context/mod.rs Updates URL network selection to carry RootKeySpec rather than raw bytes.
crates/icp/src/context/init.rs Initializes network accessor with an agent creator for bootstrap root-key fetches.
crates/icp-cli/tests/project_tests.rs Updates test manifest to include required root-key for connected networks.
crates/icp-cli/tests/network_tests.rs Updates test manifest to include required root-key for connected networks.
crates/icp-cli/tests/network_status_tests.rs Adds E2E test validating root-key: fetch warning + provenance + key correctness.
crates/icp-cli/src/options.rs Updates --root-key parsing to accept mainnet/fetch/hex via RootKeySpec.
crates/icp-cli/src/commands/network/status.rs Adds root_key_source to JSON and provenance labeling in text output.
CHANGELOG.md Documents the new required root-key behavior and provenance reporting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@raymondk raymondk marked this pull request as ready for review July 13, 2026 16:24
@raymondk raymondk requested a review from a team as a code owner July 13, 2026 16:24
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.

3 participants