"""Runtime smoke tests for Docker HOME overrides and script behavior.

Build the real image and verify the actual runtime behavior:

  1. main-wrapper preserves the Docker ``-w`` working directory
  2. dashboard service resets HOME to /opt/data before privilege drop
  3. dashboard does not auto-add ``--insecure`` from a non-loopback bind host
  4. stage2 hook repairs profiles/ and cron/ ownership on every boot
"""
from __future__ import annotations

import subprocess

from tests.docker.conftest import docker_exec, docker_exec_sh, start_container, restart_container




def test_dashboard_service_resets_home(
    built_image: str, container_name: str,
) -> None:
    """The dashboard run script must export HOME=/opt/data before dropping
    privileges, so HOME-anchored state (discord lockfile, XDG dirs) doesn't
    try to write to /root (the /init context's HOME).

    We check this by inspecting the environment of the dashboard service
    process if it's running, or by verifying the run script sets HOME
    before the exec. At runtime, the cleanest check is: start the
    container with HERMES_DASHBOARD=1 and verify the dashboard process
    (if it starts) has HOME=/opt/data.

    Since the dashboard requires an auth provider on non-loopback binds,
    we bind to 127.0.0.1 where the auth gate doesn't engage, and check
    the process env.
    """
    start_container(built_image, container_name, "HERMES_DASHBOARD=1", "HERMES_DASHBOARD_HOST=127.0.0.1")

    # Check if the dashboard process is running and inspect its HOME.
    r = docker_exec_sh(
        container_name,
        # Find the dashboard process (hermes dashboard) and read its HOME
        # from /proc/<pid>/environ. If not running, verify the run script
        # itself exports HOME=/opt/data by grepping the script source.
        'pid=$(pgrep -f "hermes dashboard" | head -1); '
        'if [ -n "$pid" ]; then '
        '  tr "\\0" "\\n" < /proc/$pid/environ | grep "^HOME="; '
        'else '
        '  grep -q "export HOME=/opt/data" '
        '    /opt/hermes/docker/s6-rc.d/dashboard/run && '
        '  echo "HOME=/opt/data"; '
        'fi',
        timeout=15,
    )
    assert "HOME=/opt/data" in r.stdout, (
        f"dashboard process or run script does not set HOME=/opt/data: "
        f"stdout={r.stdout!r} stderr={r.stderr!r}"
    )


def test_dashboard_does_not_auto_insecure_from_host(
    built_image: str, container_name: str,
) -> None:
    """The dashboard MUST NOT auto-add ``--insecure`` based on
    HERMES_DASHBOARD_HOST. The auth gate is the authority now.

    The auth gate is the authority on whether non-loopback binds are
    safe; ``--insecure`` must never be auto-derived from the bind host.

    We start the container with a non-loopback bind host and verify
    the dashboard process does NOT receive ``--insecure`` in its
    command line. If the dashboard fails to start (because the auth
    gate correctly blocks an unauthenticated non-loopback bind), that's
    also acceptable — the point is no auto-insecure.
    """
    start_container(built_image, container_name, "HERMES_DASHBOARD=1", "HERMES_DASHBOARD_HOST=0.0.0.0")

    # Check the dashboard process command line for --insecure.
    r = docker_exec_sh(
        container_name,
        'pid=$(pgrep -f "hermes dashboard" | head -1); '
        'if [ -n "$pid" ]; then '
        '  tr "\\0" " " < /proc/$pid/cmdline; '
        'fi',
        timeout=10,
    )
    cmdline = r.stdout.strip()
    # If the process is running, it must NOT have --insecure.
    if cmdline:
        assert "--insecure" not in cmdline, (
            f"dashboard process has --insecure in cmdline (auto-derived "
            f"from host): {cmdline!r}"
        )


def test_stage2_repairs_profiles_and_cron_ownership(
    built_image: str, container_name: str,
) -> None:
    """profiles/ and cron/ must both be reclaimed after root-context writes.

    The stage2 hook chowns these dirs to hermes:hermes on every boot.
    We simulate a root-owned file in each, then restart the container
    and verify ownership is repaired.
    """
    start_container(built_image, container_name)

    # Create root-owned files in profiles/ and cron/ to simulate
    # docker exec (root) writes.
    docker_exec(
        container_name, "mkdir", "-p", "/opt/data/profiles/testprof",
        user="root", timeout=5,
    )
    docker_exec(
        container_name, "touch", "/opt/data/profiles/testprof/marker",
        user="root", timeout=5,
    )
    docker_exec(
        container_name, "touch", "/opt/data/cron/root_owned.json",
        user="root", timeout=5,
    )

    # Verify they're root-owned before restart.
    r = docker_exec_sh(
        container_name,
        'stat -c "%U" /opt/data/profiles/testprof/marker '
        '/opt/data/cron/root_owned.json',
        timeout=5,
    )
    assert "root" in r.stdout, (
        f"expected root-owned files before restart, got: {r.stdout!r}"
    )

    # Restart — stage2 hook runs again and repairs ownership.
    restart_container(container_name)

    # Verify files are now owned by hermes.
    r = docker_exec_sh(
        container_name,
        'stat -c "%U" /opt/data/profiles/testprof/marker '
        '/opt/data/cron/root_owned.json',
        timeout=5,
    )
    assert "hermes" in r.stdout, (
        f"expected hermes-owned files after restart, got: {r.stdout!r} — "
        f"stage2 hook did not repair profiles/ and cron/ ownership"
    )