← Files KataARCHIVED FILE

tests/test_plugin_skill_layout.py

3.6 KB · Oct 3, 2026 · 06:31 UTC

↓ Download file

"""Plugin skill layout: Codex/OpenAI do not follow symlinks into skills/kata/."""

from __future__ import annotations

import filecmp
import json
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
PLUGIN_SKILL = ROOT / "skills" / "kata"


class PluginSkillLayoutTest(unittest.TestCase):
    def test_plugin_skill_files_are_real_copies(self) -> None:
        pairs = [
            (ROOT / "SKILL.md", PLUGIN_SKILL / "SKILL.md"),
            (ROOT / "scripts" / "runner.py", PLUGIN_SKILL / "scripts" / "runner.py"),
            (ROOT / "scripts" / "progress.py", PLUGIN_SKILL / "scripts" / "progress.py"),
            (ROOT / "assets" / "icon.svg", PLUGIN_SKILL / "assets" / "icon.svg"),
            (ROOT / "assets" / "icon.png", PLUGIN_SKILL / "assets" / "icon.png"),
            (ROOT / "assets" / "logo.png", PLUGIN_SKILL / "assets" / "logo.png"),
            (ROOT / "agents" / "openai.yaml", PLUGIN_SKILL / "agents" / "openai.yaml"),
            (
                ROOT / "references" / "session-protocol.md",
                PLUGIN_SKILL / "references" / "session-protocol.md",
            ),
        ]
        for canonical, packed in pairs:
            with self.subTest(packed=str(packed.relative_to(ROOT))):
                self.assertTrue(packed.is_file(), f"missing {packed}")
                self.assertFalse(packed.is_symlink(), f"symlink would be dropped: {packed}")
                self.assertTrue(
                    filecmp.cmp(canonical, packed, shallow=False),
                    f"{packed} drifted from {canonical}; run scripts/sync-plugin-skill.sh",
                )


class PluginListingLimitsTest(unittest.TestCase):
    def test_codex_interface_fits_openai_directory_limits(self) -> None:
        manifest = json.loads((ROOT / ".codex-plugin" / "plugin.json").read_text(encoding="utf-8"))
        interface = manifest["interface"]
        self.assertLessEqual(len(interface["displayName"]), 30)
        self.assertLessEqual(len(interface["shortDescription"]), 30)
        self.assertEqual(interface["shortDescription"].count("\n"), 0)
        self.assertLessEqual(len(interface["longDescription"]), 4000)
        self.assertEqual(manifest["author"]["name"], interface["developerName"])
        self.assertLessEqual(len(interface["defaultPrompt"]), 3)
        for prompt in interface["defaultPrompt"]:
            self.assertLessEqual(len(prompt), 128)
            self.assertNotIn("@", prompt)

    def test_openai_yaml_short_description_fits_limit(self) -> None:
        text = (ROOT / "agents" / "openai.yaml").read_text(encoding="utf-8")
        lines = [line for line in text.splitlines() if line.startswith("  short_description:")]
        self.assertEqual(len(lines), 1)
        value = lines[0].split(":", 1)[1].strip()
        self.assertLessEqual(len(value), 30)

    def test_openai_yaml_policy_only_allows_implicit_invocation(self) -> None:
        """Directory scanner: policy may contain only allow_implicit_invocation."""
        text = (ROOT / "agents" / "openai.yaml").read_text(encoding="utf-8")
        policy_lines = []
        in_policy = False
        for line in text.splitlines():
            if line.startswith("policy:"):
                in_policy = True
                continue
            if in_policy and line and not line.startswith(" "):
                break
            if in_policy:
                policy_lines.append(line)
        keys = [line.split(":", 1)[0].strip() for line in policy_lines if line.strip()]
        self.assertEqual(keys, ["allow_implicit_invocation"])
        self.assertIn("allow_implicit_invocation: false", text)


if __name__ == "__main__":
    unittest.main()

SHA-256: 0ae87a55b265babc33381bc1bec3adb3ab4b30297925db6019f05bb6b73c53f2