70 lines
2.7 KiB
Python
70 lines
2.7 KiB
Python
"""Run with the current ARTEMIS Python; no pytest/device/service/config needed."""
|
|
|
|
import asyncio
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
import tempfile
|
|
|
|
from artemis.plugins.evidence import persist_attachments, validate_tools
|
|
from artemis.plugins.models import PluginManifest, PluginProfile
|
|
from artemis.plugins.sdk_checks import run_checks
|
|
from artemis.plugins.session import PluginSession, resolve_server
|
|
|
|
|
|
async def run_contract():
|
|
directory = Path(__file__).resolve().parent
|
|
manifest = PluginManifest.model_validate_json((directory / "plugin.json").read_text("utf-8"))
|
|
with tempfile.TemporaryDirectory(prefix="artemis-template-contract-") as temporary:
|
|
trace = Path(temporary).resolve()
|
|
artifacts = trace / "artifacts" / "plugins" / manifest.id
|
|
artifacts.mkdir(parents=True)
|
|
content = "synthetic local sample\n中文\x00".encode()
|
|
(artifacts / "样例.txt").write_bytes(content)
|
|
server = resolve_server(
|
|
manifest, PluginProfile(values={"python": sys.executable}), directory
|
|
)
|
|
server.env["ARTEMIS_ARTIFACTS_DIR"] = str(artifacts)
|
|
server.env["PYTHONDONTWRITEBYTECODE"] = "1"
|
|
session = await PluginSession(server, directory).start()
|
|
try:
|
|
validate_tools(manifest, session.tools)
|
|
success = await session.call(
|
|
"verify_note", {"name": "样例.txt", "sha256": hashlib.sha256(content).hexdigest()}
|
|
)
|
|
if success.isError:
|
|
raise AssertionError("MCP 校验入口失败")
|
|
receipt = success.structuredContent["artemis"]
|
|
attachments = persist_attachments(trace, manifest.id, receipt["attachments"])
|
|
if len(attachments) != 1:
|
|
raise AssertionError("宿主未回读到校验回执")
|
|
for name, digest in (("样例.txt", "0" * 64), ("../outside.txt", "0" * 64)):
|
|
denied = await session.call("verify_note", {"name": name, "sha256": digest})
|
|
if (
|
|
not denied.isError
|
|
or denied.structuredContent["artemis"]["execution"] != "not_started"
|
|
):
|
|
raise AssertionError("无效输入没有在工具启动前拒绝")
|
|
finally:
|
|
await session.aclose()
|
|
return {
|
|
"status": "passed",
|
|
"scope": "template_offline_contract",
|
|
"mcp_calls": 3,
|
|
"host_attachments_verified": 1,
|
|
"real_device_actions": False,
|
|
}
|
|
|
|
|
|
async def main():
|
|
print(
|
|
json.dumps(
|
|
{"sdk": await run_checks(), "template": await run_contract()}, ensure_ascii=False
|
|
)
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|