"""Compare a command-string filter with a read-only filesystem boundary.

Synthetic canary writes only. Requires a local Docker daemon and a pre-pulled
Python image; never mounts a checkout, credentials, home, or the Docker socket.
The caller observes file state outside each container. No model is involved.
"""

import argparse
import base64
import hashlib
import json
import pathlib
import platform
import subprocess
import tempfile


def docker_run(
    image: str,
    protected: pathlib.Path,
    work: pathlib.Path,
    readonly: bool,
    command: list[str],
) -> subprocess.CompletedProcess[str]:
    mount = f"type=bind,src={protected},dst=/lab/protected"
    if readonly:
        mount += ",readonly"
    return subprocess.run(
        [
            "docker",
            "run",
            "--rm",
            "--pull=never",
            "--network=none",
            "--read-only",
            "--cap-drop=ALL",
            "--security-opt=no-new-privileges",
            "--user=65534:65534",
            "--pids-limit=32",
            "--memory=128m",
            "--cpus=1",
            "--mount",
            mount,
            "--mount",
            f"type=bind,src={work},dst=/lab/work",
            image,
            *command,
        ],
        capture_output=True,
        text=True,
        timeout=45,
        check=False,
    )


def run(image: str) -> dict:
    inspected = subprocess.run(
        ["docker", "image", "inspect", image],
        capture_output=True,
        text=True,
        timeout=15,
        check=True,
    )
    image_info = json.loads(inspected.stdout)[0]
    # The image ID, rather than a mutable tag, is used for every actual run.
    image_id = image_info["Id"]
    writer = (
        "from pathlib import Path\n"
        "import sys\n"
        "try:\n"
        "    Path('/lab/protected/canary.txt').write_text('synthetic change')\n"
        "except OSError:\n"
        "    print('permission denied')\n"
        "    sys.exit(17)\n"
        "print('protected unchanged')\n"
    )
    encoded = base64.b64encode(writer.encode()).decode()
    attempts = {
        "direct": ["python", "-c", writer],
        "script": ["python", "/lab/work/payload.py"],
        "encoded": [
            "python",
            "-c",
            f"import base64;exec(base64.b64decode('{encoded}'))",
        ],
        "child": ["python", "/lab/work/parent.py"],
    }
    useful = [
        "python",
        "-c",
        "from pathlib import Path; Path('/lab/work/result.txt').write_text('useful task complete')",
    ]
    rows = []
    with tempfile.TemporaryDirectory(prefix="ra-boundary-lab-") as directory:
        root = pathlib.Path(directory)
        protected, work = root / "protected", root / "work"
        protected.mkdir(mode=0o755)
        work.mkdir(mode=0o777)
        work.chmod(0o777)
        canary = protected / "canary.txt"
        output = work / "result.txt"
        (work / "payload.py").write_text(writer)
        (work / "parent.py").write_text(
            "import subprocess, sys\n"
            "sys.exit(subprocess.run([sys.executable, '/lab/work/payload.py']).returncode)\n"
        )
        for readonly in (False, True):
            for form, command in attempts.items():
                canary.write_text("synthetic original")
                canary.chmod(0o666)
                before = hashlib.sha256(canary.read_bytes()).hexdigest()
                task = docker_run(image_id, protected, work, readonly, useful)
                if task.returncode or not output.exists():
                    raise RuntimeError(f"Legitimate task/setup failed: {task.stderr}")
                useful_completed = output.read_text() == "useful task complete"
                if not useful_completed:
                    raise AssertionError("Legitimate task produced unexpected output")
                output.unlink()
                # Intentionally weak: inspects invocation text, not script contents.
                blocked = "/lab/protected" in " ".join(command)
                attempt = (
                    None
                    if blocked
                    else docker_run(image_id, protected, work, readonly, command)
                )
                changed = hashlib.sha256(canary.read_bytes()).hexdigest() != before
                if blocked:
                    if changed:
                        raise AssertionError("A blocked invocation changed the fixture")
                else:
                    expected_exit = 17 if readonly else 0
                    if attempt.returncode != expected_exit:
                        raise RuntimeError(
                            f"Unexpected execution failure ({attempt.returncode}): {attempt.stderr}"
                        )
                    if changed == readonly:
                        raise AssertionError(
                            f"Unexpected independent effect: {form}, readonly={readonly}"
                        )
                rows.append(
                    {
                        "configuration": "read-only boundary"
                        if readonly
                        else "writable baseline",
                        "form": form,
                        "filter_blocked": blocked,
                        "useful_task_completed": useful_completed,
                        "protected_file_changed": changed,
                        "attempt_exit": None if blocked else attempt.returncode,
                        "untrusted_stdout": None if blocked else attempt.stdout.strip(),
                    }
                )
    return {
        "kind": "synthetic filesystem experiment; no model or coding-client test",
        "host_kernel": platform.release(),
        "image_id": image_id,
        "image_digests": image_info.get("RepoDigests", []),
        "observations": rows,
    }


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--image",
        default="python:3.12-slim",
        help="Pre-pulled Python image; actual runs use its immutable image ID",
    )
    args = parser.parse_args()
    print(json.dumps(run(args.image), indent=2))
