|
1 | | -"""SEP-2640 conformance checks in `mcp.shared.skills`: types, validation, and verification. |
| 1 | +"""SEP-2640 conformance checks in `mcp.shared.skills`: types and validation. |
2 | 2 |
|
3 | 3 | Server- and client-side end-to-end wiring live in `tests/server/test_skills.py` and |
4 | 4 | `tests/client/test_skills.py`; this file pins the pure functions both depend on. |
5 | 5 | """ |
6 | 6 |
|
7 | | -import hashlib |
8 | 7 | from typing import Any |
9 | 8 |
|
10 | 9 | import pytest |
|
21 | 20 | parse_directory_uri, |
22 | 21 | skill_name_from_uri, |
23 | 22 | validate_directory_result, |
24 | | - verify_skill_resource, |
25 | 23 | ) |
26 | 24 |
|
27 | 25 | _DIGEST = "sha256:" + "a" * 64 |
@@ -356,51 +354,3 @@ def test_validate_directory_result_rejects_a_uri_outside_the_directory() -> None |
356 | 354 | result = ReadDirectoryResult(resources=[Resource(uri="skill://other/file.md", name="file.md")]) |
357 | 355 | with pytest.raises(ValueError, match="not a child"): |
358 | 356 | validate_directory_result("skill://pdf/templates", result) |
359 | | - |
360 | | - |
361 | | -def test_verify_skill_resource_accepts_matching_content() -> None: |
362 | | - content = b"hello skill" |
363 | | - digest = f"sha256:{hashlib.sha256(content).hexdigest()}" |
364 | | - uri = "skill://git-workflow/SKILL.md" |
365 | | - skill = Skill( |
366 | | - uri=uri, |
367 | | - frontmatter={"name": "git-workflow", "description": "d"}, |
368 | | - resources=[SkillResource(uri=uri, digest=digest, size=len(content))], |
369 | | - ) |
370 | | - verify_skill_resource(skill, uri, content) |
371 | | - |
372 | | - |
373 | | -def test_verify_skill_resource_rejects_a_digest_mismatch() -> None: |
374 | | - """SEP-2640 Integrity and verification: a mismatch MUST be treated as a verification failure.""" |
375 | | - uri = "skill://git-workflow/SKILL.md" |
376 | | - skill = Skill( |
377 | | - uri=uri, |
378 | | - frontmatter={"name": "git-workflow", "description": "d"}, |
379 | | - resources=[SkillResource(uri=uri, digest=_DIGEST, size=5)], |
380 | | - ) |
381 | | - with pytest.raises(ValueError, match="digest"): |
382 | | - verify_skill_resource(skill, uri, b"wrong") |
383 | | - |
384 | | - |
385 | | -def test_verify_skill_resource_rejects_a_size_mismatch_before_hashing() -> None: |
386 | | - uri = "skill://git-workflow/SKILL.md" |
387 | | - skill = Skill( |
388 | | - uri=uri, |
389 | | - frontmatter={"name": "git-workflow", "description": "d"}, |
390 | | - resources=[SkillResource(uri=uri, digest=_DIGEST, size=999)], |
391 | | - ) |
392 | | - with pytest.raises(ValueError, match="size"): |
393 | | - verify_skill_resource(skill, uri, b"short") |
394 | | - |
395 | | - |
396 | | -def test_verify_skill_resource_rejects_dynamic_resources() -> None: |
397 | | - uri = "skill://generated/SKILL.md" |
398 | | - skill = Skill(uri=uri, frontmatter={"name": "generated", "description": "d"}, resources="dynamic") |
399 | | - with pytest.raises(ValueError, match="dynamic"): |
400 | | - verify_skill_resource(skill, uri, b"anything") |
401 | | - |
402 | | - |
403 | | -def test_verify_skill_resource_rejects_a_uri_not_in_the_manifest() -> None: |
404 | | - skill = _skill() |
405 | | - with pytest.raises(ValueError, match="not in skill"): |
406 | | - verify_skill_resource(skill, "skill://git-workflow/unlisted.md", b"x") |
0 commit comments