Harden M9: Ed25519 attestation, full SHA-256 integrity, locked-by-default, prompt improvements, registry verification

This commit is contained in:
rob
2026-07-20 16:50:49 -03:00
parent 04153a4bbd
commit 56cb34276e
34 changed files with 2549 additions and 257 deletions
+88 -1
View File
@@ -29,6 +29,12 @@ def cmd_registry(args):
return _cmd_registry_update(args)
elif args.registry_cmd == "publish":
return _cmd_registry_publish(args)
elif args.registry_cmd == "signing-key":
return _cmd_registry_signing_key(args)
elif args.registry_cmd == "improve":
return _cmd_registry_improve(args)
elif args.registry_cmd == "review-improvement":
return _cmd_registry_review_improvement(args)
elif args.registry_cmd == "update-readme":
return _cmd_registry_update_readme(args)
elif args.registry_cmd == "my-tools":
@@ -51,6 +57,8 @@ def cmd_registry(args):
print(" info <tool> Show tool information")
print(" update Update local index cache")
print(" publish [path] Publish a tool")
print(" signing-key Manage Ed25519 release signing")
print(" improve Submit a community improvement")
print(" update-readme Update README for published tool(s)")
print(" my-tools List your published tools")
print(" status <tool> Check moderation status of a tool")
@@ -598,6 +606,7 @@ def _cmd_registry_publish(args):
from ..tool import load_tool, Tool, ToolStep
dep_result = None
my_owner = ""
try:
client = get_client()
@@ -737,6 +746,7 @@ def _cmd_registry_publish(args):
_print_quality_summary(preflight_result.get("quality"))
if remote_report.get("errors"):
return 1
release_content_hash = preflight_result.get("content_hash", "")
if sys.stdin.isatty() and not getattr(args, "force", False):
try:
if input("Publish this validated version? [y/N] ").strip().lower() != "y":
@@ -751,7 +761,26 @@ def _cmd_registry_publish(args):
try:
client = get_client()
owner = getattr(args, "owner", "")
result = client.publish_tool(config_yaml, readme, defaults, owner=owner)
attestation = None
from ..signing import load_signing_key
signing_key = load_signing_key()
if signing_key:
if not release_content_hash:
print(
"Registry did not return a content identity; refusing to sign.",
file=sys.stderr,
)
return 1
from ..attestation import sign_tool
signer = owner or my_owner
attestation = sign_tool(
name, version, release_content_hash, signer, signing_key[0]
).to_dict()
result = client.publish_tool(
config_yaml, readme, defaults, owner=owner,
attestation=attestation,
improvement_id=getattr(args, "improvement_id", None),
)
pr_url = result.get("pr_url", "")
status = result.get("status", "")
@@ -826,6 +855,64 @@ def _cmd_registry_publish(args):
return 0
def _cmd_registry_signing_key(args):
"""Initialize a local key and register its public half with the registry."""
from ..signing import SIGNING_KEY_FILE, initialize_signing_key, load_signing_key
from ..registry_client import RegistryError, get_client
if args.action == "status":
key = load_signing_key()
print(
f"Signing key: {SIGNING_KEY_FILE}"
if key else "No release signing key configured."
)
return 0 if key else 1
try:
_, public_key = initialize_signing_key()
get_client().set_signing_public_key(public_key)
except (OSError, ValueError, RegistryError) as exc:
print(f"Could not initialize signing key: {exc}", file=sys.stderr)
return 1
print(f"Release signing key initialized: {SIGNING_KEY_FILE}")
print("The private key is stored locally with mode 0600; back it up securely.")
return 0
def _cmd_registry_improve(args):
from ..registry_client import RegistryError, get_client
if "/" not in args.tool:
print("Tool must be specified as owner/name.", file=sys.stderr)
return 2
owner, name = args.tool.split("/", 1)
try:
proposed = Path(args.file).read_text(encoding="utf-8")
result = get_client().submit_improvement(
owner, name, args.version, args.step_index, proposed,
args.rationale,
)
except (OSError, RegistryError) as exc:
print(f"Could not submit improvement: {exc}", file=sys.stderr)
return 1
print(f"Improvement {result.get('id')} tested and submitted for review.")
return 0
def _cmd_registry_review_improvement(args):
from ..registry_client import RegistryError, get_client
try:
result = get_client().review_improvement(args.id, args.decision, args.notes)
except RegistryError as exc:
print(f"Could not review improvement: {exc}", file=sys.stderr)
return 1
print(f"Improvement {args.id}: {result.get('status')}")
if result.get("ready_to_apply"):
print(
"Publish the updated version with "
f"--improvement-id {args.id} to apply credit and badges."
)
return 0
def _cmd_registry_update_readme(args):
"""Update README for published tool(s) on the registry."""
from ..registry_client import RegistryError, get_client