Skip to content

Persist --hd-path on plain seed-phrase keys#2540

Merged
fnando merged 3 commits into
mainfrom
keys-add-hd-path-plain-seed
May 6, 2026
Merged

Persist --hd-path on plain seed-phrase keys#2540
fnando merged 3 commits into
mainfrom
keys-add-hd-path-plain-seed

Conversation

@fnando
Copy link
Copy Markdown
Member

@fnando fnando commented Apr 30, 2026

What

Persist --hd-path on seed-phrase identities (both plain seed-phrase and Secure Store) for stellar keys generate and stellar keys add, and honor it as a default in later derivations:

  • Secret::SeedPhrase gains an optional hd_path field that travels with the identity.
  • Secret::public_key / private_key / signer fall back to the persisted hd_path when the caller passes None.
  • Secret::SecureStore already persisted hd_path on disk (see Cache secure-store public key in identity files. #2533), but ignored it at derivation time. It now also falls back to the persisted value when the caller passes None, matching Secret::SeedPhrase. Caller-supplied indices still take precedence.
  • keys add rejects --hd-path against incompatible inputs (raw secret keys, --public-key).

Closes #2538.

Why

--hd-path was accepted but silently dropped on the plain seed-phrase path, and was persisted-but-ignored for Secure Store, so later commands derived index 0 unless the user re-passed the flag every time. Approach (3) from the issue (persist on the identity, schema-bumped with #[serde(default)]) keeps behavior consistent across all storage modes — without breaking identity files written before this field existed.

The Secure Store fallback was added during review after empirical testing showed keys public-key <name> returned the index-0 key even though hd_path was already on disk.

Known limitations

  • Identity files written before this PR have no hd_path field; they parse fine and behave as before (derivation index defaults to 0). Re-running keys add / keys generate with --hd-path is the way to migrate them, but this is not required.
  • --hd-path against a raw secret key or --public-key is now a hard error rather than being silently ignored. This is intentional but is a behavior change for anyone who was passing the flag in those modes.

Copilot AI review requested due to automatic review settings April 30, 2026 21:21
@github-project-automation github-project-automation Bot moved this to Backlog (Not Ready) in DevX Apr 30, 2026
@fnando fnando moved this from Backlog (Not Ready) to Needs Review in DevX Apr 30, 2026
@fnando fnando self-assigned this Apr 30, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 updates the Stellar CLI identity/secret model so --hd-path is persisted for plain seed-phrase identities (non-secure-store, non---as-secret) and then reused as the default derivation index in later commands.

Changes:

  • Extend Secret::SeedPhrase with an optional persisted hd_path and make key derivation fall back to it when the caller doesn’t pass an index.
  • Persist --hd-path for stellar keys generate and stellar keys add when storing a plain seed phrase; reject --hd-path for incompatible keys add modes (--public-key, raw secret key).
  • Add/update unit tests and refresh help docs to reflect the new behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
cmd/soroban-cli/src/config/secret.rs Add hd_path to SeedPhrase secrets; default derivation uses persisted index; add TOML/back-compat tests.
cmd/soroban-cli/src/config/key.rs Update key round-trip test construction for the new SeedPhrase shape.
cmd/soroban-cli/src/commands/keys/secret.rs Update pattern match to tolerate the new SeedPhrase field.
cmd/soroban-cli/src/commands/keys/generate.rs Persist hd_path for plain seed-phrase identities; update help text and add a test.
cmd/soroban-cli/src/commands/keys/add.rs Persist hd_path when parsing seed phrases; reject hd_path for public key / secret key inputs; add tests.
cmd/crates/soroban-test/tests/it/util.rs Update helper to construct SeedPhrase with hd_path: None.
FULL_HELP_DOCS.md Update CLI help output text for --hd-path.

Comment thread cmd/soroban-cli/src/config/secret.rs
Comment thread cmd/soroban-cli/src/commands/keys/generate.rs
Comment thread cmd/soroban-cli/src/commands/keys/add.rs Outdated
Comment thread cmd/soroban-cli/src/commands/keys/add.rs Outdated
@fnando fnando force-pushed the keys-add-hd-path-plain-seed branch from 24c7ccd to 7ad0fe1 Compare April 30, 2026 22:00
@fnando fnando requested a review from Copilot April 30, 2026 22:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment thread cmd/soroban-cli/src/commands/keys/generate.rs
Comment thread cmd/soroban-cli/src/commands/keys/generate.rs
@fnando fnando force-pushed the keys-add-hd-path-plain-seed branch from 7ad0fe1 to 008c002 Compare April 30, 2026 22:15
@fnando fnando enabled auto-merge (squash) April 30, 2026 23:46
@fnando fnando force-pushed the keys-add-hd-path-plain-seed branch from d51c3ec to c07d2c8 Compare May 2, 2026 01:44
Copy link
Copy Markdown
Contributor

@mootz12 mootz12 left a comment

Choose a reason for hiding this comment

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

LG2M. Two somewhat related things flagged in comments. IMO we should either create issues to fix before the next release or fix in this PR.

The impl for plain seed-phrase keys approved, tho.

Comment thread cmd/soroban-cli/src/commands/keys/add.rs Outdated
Comment thread cmd/soroban-cli/src/commands/keys/add.rs
Comment thread cmd/soroban-cli/src/config/secret.rs
fnando added 2 commits May 5, 2026 10:54
Plain seed-phrase identities now persist --hd-path and honor it as a
default for later derivations. Secure Store identities did the same on
disk but ignored the persisted hd_path at derivation time, falling back
to index 0 unless the user re-passed --hd-path; Secret::SecureStore now
also falls back to the persisted value when the caller passes None,
matching the behavior of Secret::SeedPhrase. Caller-supplied indices
still take precedence.
@fnando fnando force-pushed the keys-add-hd-path-plain-seed branch from 75bc981 to 4ba81a3 Compare May 5, 2026 19:14
Copy link
Copy Markdown
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

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

The code changes here look good, but I'm wondering if this will be experienced as a breaking change and if any thought needs to be given to a rollout, or protecting existing uses from happening?

For anybody who's already stored a key and they're using it in some places without passing the --hd-path, are they going to see changes?

...without breaking identity files written before this field existed.

From the PR description it sounds like this concern has been addressed already. If that's the case looks good to me.

@fnando
Copy link
Copy Markdown
Member Author

fnando commented May 6, 2026

@leighmcculloch this is a follow up on #2539, which defaults to --hd-path=0 if you have no saved path.

@fnando fnando merged commit 0de9759 into main May 6, 2026
211 checks passed
@fnando fnando deleted the keys-add-hd-path-plain-seed branch May 6, 2026 04:08
@github-project-automation github-project-automation Bot moved this from Needs Review to Done in DevX May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

--hd-path is silently ignored for plain seed phrase storage in keys generate

4 participants