Skip to content

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

Open
fnando wants to merge 1 commit intomainfrom
keys-add-hd-path-plain-seed
Open

Persist --hd-path on plain seed-phrase keys#2540
fnando wants to merge 1 commit intomainfrom
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
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
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 d51c3ec to c07d2c8 Compare May 2, 2026 01:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Needs Review

Development

Successfully merging this pull request may close these issues.

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

2 participants