gabriel / muse public
feat BREAKING task/verify-tag #1 / 1
gabriel · 166 days ago · Apr 14, 2026 · Diff

feat: implement muse verify-tag with Ed25519 signature verification

- Add message, signature, signer_public_key, signer_key_id fields to TagRecord and TagDict (backward-compatible defaults) - Add get_tag_by_name() helper to store.py for tag lookup by label - Implement muse/cli/commands/verify_tag.py: tag_payload(), _verify_tag_one(), _fetch_key_status(), register(), run() - Register verify-tag in app.py - 25 tests covering unit (payload determinism, tamper detection), integration (CLI valid/invalid/batch/strict/json/text), security (ANSI rejection, bit-flip), and stress (50 tags, cache deduplication)

sha256:a620c05b021bf0adad01d38991be9b8d17799265a5336f04e0df51c66a9c3c68 sha
+87 ~37 symbols
sha256:1cbd284f8e3801a1c22d3aab3282205c872ca6b48d747079331ac73c0d9860f1 snapshot
+87
symbols added
~37
symbols modified
0
dead code introduced
Semantic Changes 124 symbols
~ muse/cli/commands/verify_tag.py .py 27 symbols added
+ _KEY_STATUS_TIMEOUT variable variable _KEY_STATUS_TIMEOUT L75–75
+ _SAFE_TAG_RE variable variable _SAFE_TAG_RE L78–78
+ _TAG_PROV_PREFIX variable variable _TAG_PROV_PREFIX L84–84
+ _TAG_PROV_SEP variable variable _TAG_PROV_SEP L81–81
+ _fetch_key_status function function _fetch_key_status L130–146
+ _verify_tag_one function function _verify_tag_one L149–236
+ Any import import Any L64–64
+ ExitCode import import ExitCode L66–66
+ ThreadPoolExecutor import import ThreadPoolExecutor L63–63
+ _json import import _json L59–59
+ annotations import import annotations L54–54
+ argparse import import argparse L56–56
+ as_completed import import as_completed L63–63
+ base64 import import base64 L57–57
+ get_all_tags import import get_all_tags L69–69
+ get_tag_by_name import import get_tag_by_name L69–69
+ hashlib import import hashlib L58–58
+ logging import import logging L60–60
+ re import import re L61–61
+ require_repo import import require_repo L68–68
+ sanitize_display import import sanitize_display L70–70
+ sys import import sys L62–62
+ verify_commit_ed25519 import import verify_commit_ed25519 L67–67
+ logger variable variable logger L72–72
+ register function function register L244–277
+ run function function run L285–371
+ tag_payload function function tag_payload L92–122
~ tests/test_cmd_verify_tag.py .py 58 symbols added
+ _REPO_ID variable variable _REPO_ID L43–43
+ _commit_files function function _commit_files L77–107
+ _counter variable variable _counter L44–44
+ _env function function _env L68–69
+ _force_write_tag function function _force_write_tag L144–151
+ _init_repo function function _init_repo L56–65
+ _invoke function function _invoke L154–156
+ _make_key function function _make_key L72–74
+ _make_tag function function _make_tag L110–141
+ _sha function function _sha L52–53
+ CliRunner import import CliRunner L27–27
+ CommitRecord import import CommitRecord L31–31
+ Manifest import import Manifest L39–39
+ SnapshotRecord import import SnapshotRecord L31–31
+ TagRecord import import TagRecord L31–31
+ annotations import import annotations L15–15
+ base64 import import base64 L17–17
+ compute_commit_id import import compute_commit_id L30–30
+ compute_snapshot_id import import compute_snapshot_id L30–30
+ datetime import import datetime L18–18
+ encode_public_key import import encode_public_key L29–29
+ hashlib import import hashlib L19–19
+ json import import json L20–20
+ patch import import patch L23–23
+ pathlib import import pathlib L21–21
+ pytest import import pytest L25–25
+ sign_commit_ed25519 import import sign_commit_ed25519 L29–29
+ uuid import import uuid L22–22
+ write_commit import import write_commit L31–31
+ write_object import import write_object L28–28
+ write_snapshot import import write_snapshot L31–31
+ write_tag import import write_tag L31–31
+ runner variable variable runner L41–41
+ test_tag_payload_changes_with_commit_id function function test_tag_payload_changes_with_commit_id L179–183
+ test_tag_payload_changes_with_key_id function function test_tag_payload_changes_with_key_id L193–197
+ test_tag_payload_changes_with_message function function test_tag_payload_changes_with_message L186–190
+ test_tag_payload_changes_with_tag_name function function test_tag_payload_changes_with_tag_name L172–176
+ test_tag_payload_is_deterministic function function test_tag_payload_is_deterministic L164–169
+ test_verify_tag_50_signed_tags function function test_verify_tag_50_signed_tags L443–451
+ test_verify_tag_ansi_in_name_rejected function function test_verify_tag_ansi_in_name_rejected L432–435
+ test_verify_tag_batch_all_valid function function test_verify_tag_batch_all_valid L395–402
+ test_verify_tag_batch_one_invalid_exits_nonzero function function test_verify_tag_batch_one_invalid_exits_nonzero L405–413
+ test_verify_tag_check_key_status_unknown_no_hub function function test_verify_tag_check_key_status_unknown_no_hub L416–424
+ test_verify_tag_invalid_exits_nonzero function function test_verify_tag_invalid_exits_nonzero L340–359
+ test_verify_tag_json_output function function test_verify_tag_json_output L323–337
+ test_verify_tag_key_status_cache_deduplicates function function test_verify_tag_key_status_cache_deduplicates L454–475
+ test_verify_tag_nonexistent_exits_nonzero function function test_verify_tag_nonexistent_exits_nonzero L380–383
+ test_verify_tag_one_bit_flip function function test_verify_tag_one_bit_flip L256–276
+ test_verify_tag_one_json_schema function function test_verify_tag_one_json_schema L298–306
+ test_verify_tag_one_missing_public_key function function test_verify_tag_one_missing_public_key L279–295
+ test_verify_tag_one_nonexistent_returns_error function function test_verify_tag_one_nonexistent_returns_error L227–232
+ test_verify_tag_one_tampered_message function function test_verify_tag_one_tampered_message L235–253
+ test_verify_tag_one_unsigned function function test_verify_tag_one_unsigned L217–224
+ test_verify_tag_one_valid function function test_verify_tag_one_valid L205–214
+ test_verify_tag_text_output_contains_tag_name function function test_verify_tag_text_output_contains_tag_name L386–392
+ test_verify_tag_unsigned_no_strict_exits_zero function function test_verify_tag_unsigned_no_strict_exits_zero L362–369
+ test_verify_tag_unsigned_strict_exits_nonzero function function test_verify_tag_unsigned_strict_exits_nonzero L372–377
+ test_verify_tag_valid_exits_zero function function test_verify_tag_valid_exits_zero L314–320
~ muse/core/store.py .py 1 symbol added, 5 symbols modified
+ get_tag_by_name function function get_tag_by_name L2136–2143
← Older Oldest on task/verify-tag
All commits
Newer → Latest on task/verify-tag

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:a620c05b021bf0adad01d38991be9b8d17799265a5336f04e0df51c66a9c3c68 --body "your comment"