← Files Plugin AutopilotARCHIVED FILE

tests/test_self_hosting.py

5.07 KB · Oct 3, 2026 · 06:34 UTC

↓ Download file

import hashlib
import json
import subprocess
import tempfile
import unittest
import zipfile
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]


class SelfHostingTests(unittest.TestCase):
    def run_script(self, *args):
        return subprocess.run(["python3", *map(str, args)], cwd=ROOT, text=True, capture_output=True)

    def test_self_check_validates_staged_plugin(self):
        proc = self.run_script("scripts/self_check.py", "--json")
        self.assertEqual(proc.returncode, 0, proc.stderr + proc.stdout)
        report = json.loads(proc.stdout)
        self.assertTrue(report["ok"])
        self.assertEqual(report["architecture"], "skills-only")
        self.assertEqual(report["skills"], 9)

    def test_validator_rejects_transient_python_bytecode(self):
        with tempfile.TemporaryDirectory() as temp:
            stage = Path(temp) / "plugin"
            subprocess.run(
                ["python3", "scripts/self_check.py", "--json"],
                cwd=ROOT,
                check=True,
                capture_output=True,
                text=True,
            )
            import sys
            sys.path.insert(0, str(ROOT / "scripts"))
            from self_check import stage_plugin

            stage_plugin(stage)
            cache = stage / "skills/chatgpt-codex-plugin-autopilot/scripts/__pycache__"
            cache.mkdir(parents=True)
            (cache / "validate_plugin.cpython-312.pyc").write_bytes(b"transient")
            validator = stage / "skills/chatgpt-codex-plugin-autopilot/scripts/validate_plugin.py"
            proc = subprocess.run(
                ["python3", str(validator), str(stage), "--json"],
                text=True,
                capture_output=True,
            )
            self.assertNotEqual(proc.returncode, 0, proc.stdout)
            self.assertIn("bytecode", proc.stdout.lower())

    def test_release_build_is_deterministic_and_installable(self):
        with tempfile.TemporaryDirectory() as temp:
            out = Path(temp)
            first = self.run_script("scripts/build_release.py", "--out-dir", out, "--json")
            self.assertEqual(first.returncode, 0, first.stderr + first.stdout)
            first_report = json.loads(first.stdout)
            archive = Path(first_report["archive"])
            first_bytes = archive.read_bytes()
            second = self.run_script("scripts/build_release.py", "--out-dir", out, "--json")
            self.assertEqual(second.returncode, 0, second.stderr + second.stdout)
            second_report = json.loads(second.stdout)
            second_bytes = Path(second_report["archive"]).read_bytes()
            self.assertEqual(first_bytes, second_bytes)
            self.assertEqual(hashlib.sha256(first_bytes).hexdigest(), first_report["sha256"])
            self.assertEqual(first_report["sha256"], second_report["sha256"])
            self.assertEqual(first_report["skills"], 9)
            sums = (out / "SHA256SUMS").read_text(encoding="utf-8")
            self.assertIn(first_report["sha256"], sums)
            with zipfile.ZipFile(archive) as zf:
                names = set(zf.namelist())
                self.assertIn(".codex-plugin/plugin.json", names)
                self.assertIn("skills/chatgpt-codex-plugin-autopilot/SKILL.md", names)
                self.assertIn("skills/chatgpt-codex-plugin-autopilot/scripts/analyze_repo.py", names)
                self.assertIn("skills/chatgpt-codex-plugin-autopilot/scripts/build_directory_pack.py", names)
                self.assertIn("skills/chatgpt-codex-plugin-autopilot/scripts/install_host_workspace_skill.py", names)
                self.assertIn("skills/chatgpt-codex-plugin-autopilot/references/host-python-sandbox.md", names)
                self.assertIn("skills/chatgpt-codex-plugin-autopilot/references/host-workspace-capabilities.md", names)
                self.assertIn("skills/agentic-repo-discovery/SKILL.md", names)
                self.assertIn("skills/workflow-to-skill-compiler/SKILL.md", names)
                self.assertIn("skills/plugin-experience-architect/SKILL.md", names)
                self.assertIn("skills/host-workspace-operator/SKILL.md", names)
                self.assertIn("skills/host-workspace-operator/agents/openai.yaml", names)
                self.assertIn("skills/sandbox-python-executor/SKILL.md", names)
                self.assertIn("skills/sandbox-python-executor/agents/openai.yaml", names)
                self.assertIn("skills/plugin-brand-identity-designer/SKILL.md", names)
                self.assertIn("skills/plugin-directory-listing-writer/SKILL.md", names)
                self.assertIn("skills/submission-pack-builder/SKILL.md", names)
                self.assertIn("assets/logo-light.svg", names)
                self.assertIn("assets/logo-dark.svg", names)
                self.assertNotIn("tests/test_self_hosting.py", names)
                self.assertNotIn("docs/superpowers/plans/2026-08-09-self-hosting-plugin.md", names)
                self.assertNotIn(".agents/plugins/marketplace.json", names)
                self.assertNotIn("submission/reviewer-packet.json", names)


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

SHA-256: 00f6efb2f5256c6b0f1d0fb27d433f443baa1f5fddaf8d260781b96ee3069a9c