gabriel / muse public
feat patch feat/100-auth-show-public-key #1 / 1
AI Agent gabriel · 1 day ago · Oct 21, 2026 · Diff

feat: add muse auth show --public-key to recover a registered public key

muse#100. muse sign verify --public-key-b64 needs the raw base64url Ed25519 public key (no ed25519: prefix). The only time that value was ever printed was at keygen/register time -- muse auth whoami/show/key list all expose only the one-way fingerprint, which can't be reversed back to the public key bytes. The only recovery path was re-deriving it from the keychain mnemonic via internal Python modules.

Adds --public-key (+ --agent-id for agent identities) to muse auth show. Resolves via the exact same path muse sign itself uses (get_signing_identity + sign.py's own _public_key_info) rather than a parallel reimplementation -- guarantees the printed value is always byte-identical to what muse sign verify actually expects, never a plausible-looking but subtly different derivation. Text mode prints just the raw key (scriptable: muse sign verify --public-key-b64 "$(muse auth show --hub URL --public-key)"); --json wraps it with hub/handle/fingerprint.

Tests: new tests/test_auth_show_public_key.py, 6 tests -- unit test proving byte-identical output to sign.py's own _public_key_info, no-identity returns None cleanly, CLI text/json round-trips, clean structured error (no crash) when no identity is registered, and a full end-to-end round trip through the real build_msign_header/verify_msign_header functions. All green.

Fixed 4 pre-existing tests in test_auth_show_migrate.py that broke from this change: they stand up `ns = MagicMock()` for run_show's argparse Namespace without setting the new public_key/agent_id attributes -- MagicMock auto-creates any attribute access as a truthy MagicMock rather than raising AttributeError, so getattr(args, "public_key", False) never hit the False default and accidentally routed into the new code path. Explicitly setting ns.public_key = False / ns.agent_id = None in these tests (matching how they already explicitly set ns.hub) fixes this -- same hazard will resurface for any future boolean flag added to run_show unless tests move off bare MagicMock for argparse stand-ins.

Verified against a real registered identity (muse-dev, staging.musehub.ai): printed public key's derived fingerprint matches muse sign header's own reported fingerprint exactly; a header signed with muse sign header and verified with muse sign verify --public-key-b64 using the exact value this command printed returns {"valid": true} -- the ticket's acceptance criterion, proven end-to-end with a real identity, not just mocked tests.

sha256:78acbed7a7a67d36a9080f3f2bf851be873e69fe8851cdd29b7bd59827504cbc sha
+23 ~13 symbols
3 changed · 1212 in snapshot files
sha256:e8f9d5f671b1bd4d1149e59e9b9e5125f14a7e46540bdb3975f781b2969425bd snapshot
+23
symbols added
~13
symbols modified
3
files changed
1212
files in snapshot
0
dead code introduced
Semantic Changes 36 symbols
~ tests/test_auth_show_public_key.py .py 21 symbols added
+ FAKE_FINGERPRINT variable variable FAKE_FINGERPRINT L37–37
+ FAKE_HANDLE variable variable FAKE_HANDLE L38–38
+ FAKE_HD_PATH variable variable FAKE_HD_PATH L36–36
+ FAKE_MNEMONIC variable variable FAKE_MNEMONIC L32–35
+ HOSTNAME variable variable HOSTNAME L31–31
+ HUB variable variable HUB L30–30
+ _patch_home function function _patch_home L41–52
+ _write_hd_identity function function _write_hd_identity L55–76
+ CliRunner import import CliRunner L24–24
+ annotations import import annotations L18–18
+ json import import json L20–20
+ kp_mod import import kp_mod L26–26
+ pathlib import import pathlib L21–21
+ pytest import import pytest L23–23
+ runner variable variable runner L28–28
+ test_auth_show_public_key_matches_sign_commands_own_derivation function function test_auth_show_public_key_matches_sign_commands_own_derivation L84–109
+ test_auth_show_public_key_no_identity_returns_none function function test_auth_show_public_key_no_identity_returns_none L112–117
+ test_cli_auth_show_public_key_json function function test_cli_auth_show_public_key_json L141–157
+ test_cli_auth_show_public_key_no_identity_clean_error function function test_cli_auth_show_public_key_no_identity_clean_error L160–171
+ test_cli_auth_show_public_key_roundtrips_through_sign_verify function function test_cli_auth_show_public_key_roundtrips_through_sign_verify L174–195
+ test_cli_auth_show_public_key_text function function test_cli_auth_show_public_key_text L125–138
~ muse/cli/commands/auth.py .py 2 symbols added, 2 symbols modified
+ _resolve_public_key function function _resolve_public_key L2387–2408
+ _show_public_key function function _show_public_key L2410–2445
Files Changed
+1 ~2
1212 in snapshot
← Older Oldest on feat/100-auth-show-public-key
All commits
Newer → Latest on feat/100-auth-show-public-key

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:78acbed7a7a67d36a9080f3f2bf851be873e69fe8851cdd29b7bd59827504cbc --body "your comment"