Harden M9: Ed25519 attestation, full SHA-256 integrity, locked-by-default, prompt improvements, registry verification
This commit is contained in:
@@ -339,6 +339,146 @@ class TestPublishPreflightEndpoint:
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
@flask_required
|
||||
class TestM9RegistryTrustAndCommunity:
|
||||
def test_signed_publish_download_and_content_lookup(
|
||||
self, client, auth_headers
|
||||
):
|
||||
from cmdforge.attestation import (
|
||||
Attestation, generate_keypair, sign_tool, verify_attestation,
|
||||
)
|
||||
from cmdforge.registry.db import connect_db
|
||||
|
||||
private_key, public_key = generate_keypair()
|
||||
response = client.put(
|
||||
"/api/v1/me/signing-key", headers=auth_headers,
|
||||
json={"public_key": public_key},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
config = "name: signed-tool\nversion: 1.0.0\noutput: stable\n"
|
||||
preflight = client.post(
|
||||
"/api/v1/tools", headers=auth_headers,
|
||||
json={"config": config, "dry_run": True},
|
||||
)
|
||||
assert preflight.status_code == 200
|
||||
content_hash = preflight.get_json()["data"]["content_hash"]
|
||||
attestation = sign_tool(
|
||||
"signed-tool", "1.0.0", content_hash, "testuser", private_key
|
||||
)
|
||||
published = client.post(
|
||||
"/api/v1/tools", headers=auth_headers,
|
||||
json={"config": config, "attestation": attestation.to_dict()},
|
||||
)
|
||||
assert published.status_code == 201
|
||||
assert published.get_json()["data"]["content_hash"] == content_hash
|
||||
|
||||
conn = connect_db()
|
||||
try:
|
||||
conn.execute(
|
||||
"UPDATE tools SET moderation_status = 'approved' "
|
||||
"WHERE owner = 'testuser' AND name = 'signed-tool'"
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
downloaded = client.get(
|
||||
"/api/v1/tools/testuser/signed-tool/download?install=false"
|
||||
)
|
||||
assert downloaded.status_code == 200
|
||||
data = downloaded.get_json()["data"]
|
||||
assert data["content_hash"] == content_hash
|
||||
assert verify_attestation(Attestation.from_dict(data["attestation"]), public_key)
|
||||
lookup = client.get(f"/api/v1/tools/by-content-hash/{content_hash}")
|
||||
assert lookup.status_code == 200
|
||||
assert lookup.get_json()["data"]["name"] == "signed-tool"
|
||||
|
||||
def test_registered_key_requires_valid_signature(self, client, auth_headers):
|
||||
from cmdforge.attestation import generate_keypair
|
||||
_, public_key = generate_keypair()
|
||||
assert client.put(
|
||||
"/api/v1/me/signing-key", headers=auth_headers,
|
||||
json={"public_key": public_key},
|
||||
).status_code == 200
|
||||
response = client.post(
|
||||
"/api/v1/tools", headers=auth_headers,
|
||||
json={"config": "name: unsigned-tool\nversion: 1.0.0\n"},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert response.get_json()["error"]["code"] == "ATTESTATION_REQUIRED"
|
||||
|
||||
def test_improvement_is_tested_reviewed_and_credited(
|
||||
self, client, auth_headers
|
||||
):
|
||||
from cmdforge.registry.db import connect_db
|
||||
config = (
|
||||
"name: improvable\nversion: 1.0.0\noutput: '{result}'\n"
|
||||
"input_schema:\n type: string\noutput_schema:\n type: string\n"
|
||||
"steps:\n - type: prompt\n prompt: 'Summarize: {input}'\n"
|
||||
" provider: mock\n output_var: result\n"
|
||||
)
|
||||
published = client.post(
|
||||
"/api/v1/tools", headers=auth_headers, json={"config": config}
|
||||
)
|
||||
assert published.status_code == 201
|
||||
conn = connect_db()
|
||||
try:
|
||||
conn.execute(
|
||||
"UPDATE tools SET moderation_status = 'approved' "
|
||||
"WHERE owner = 'testuser' AND name = 'improvable'"
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
submitted = client.post(
|
||||
"/api/v1/tools/testuser/improvable/1.0.0/improvements",
|
||||
headers=auth_headers,
|
||||
json={
|
||||
"step_index": 0,
|
||||
"proposed": "Summarize the input accurately and concisely: {input}",
|
||||
"rationale": "Clearer expected behavior",
|
||||
},
|
||||
)
|
||||
assert submitted.status_code == 201
|
||||
submission_id = submitted.get_json()["data"]["id"]
|
||||
reviewed = client.patch(
|
||||
f"/api/v1/improvements/{submission_id}", headers=auth_headers,
|
||||
json={"decision": "approve", "notes": "Validated"},
|
||||
)
|
||||
assert reviewed.status_code == 200
|
||||
assert reviewed.get_json()["data"]["ready_to_apply"] is True
|
||||
improved_config = config.replace("version: 1.0.0", "version: 1.0.1").replace(
|
||||
"Summarize: {input}",
|
||||
"Summarize the input accurately and concisely: {input}",
|
||||
)
|
||||
applied = client.post(
|
||||
"/api/v1/tools", headers=auth_headers,
|
||||
json={"config": improved_config, "improvement_id": submission_id},
|
||||
)
|
||||
assert applied.status_code == 201
|
||||
conn = connect_db()
|
||||
try:
|
||||
conn.execute(
|
||||
"UPDATE tools SET moderation_status = 'approved' "
|
||||
"WHERE owner = 'testuser' AND name = 'improvable' "
|
||||
"AND version = '1.0.1'"
|
||||
)
|
||||
conn.commit()
|
||||
credited = conn.execute(
|
||||
"SELECT COUNT(*) AS count FROM tool_contributors"
|
||||
).fetchone()["count"]
|
||||
finally:
|
||||
conn.close()
|
||||
assert credited == 1
|
||||
detail = client.get("/api/v1/tools/testuser/improvable?version=1.0.1")
|
||||
assert detail.status_code == 200
|
||||
assert detail.get_json()["data"]["badges"] == [
|
||||
"optimized", "community-reviewed"
|
||||
]
|
||||
|
||||
|
||||
@flask_required
|
||||
class TestPostCollectionsEndpoint:
|
||||
"""Tests for POST /api/v1/collections endpoint."""
|
||||
|
||||
Reference in New Issue
Block a user