# Nucleic runner image — the Covalence runner's host-of-record container
# (docs/COVALENCE_RUNNER.md §2, §9; docs/NAROS.md §7.2, milestone N3).
#
# Layers `nucleicd` (the headless NucleicCore host) onto the **narOS agent tier**, so one
# container is simultaneously the host-of-record AND the agent sandbox (`RunSpec.container =
# nil` — the CLOUD_RUNTIME insight): claude/codex/grok, git, gh, the toolchains, and nash —
# FORCED as /bin/sh via the base's dpkg-divert (docs/NASH.md §7.1/§7.3) — all come from
# naros-agent; this image adds only the daemon, its runtime, and the runner-tier identity
# stamp. `nucleicd` itself stays a direct COPY, not a deb (NAROS.md §3.1 — versioned with
# the app, built by scripts/build-nucleicd-linux.sh).
#
# NOTE: every RUN below executes under nash — /bin/sh is already diverted in the base. That
# is deliberate dogfood (the same posture as os/images/agent/Dockerfile); nash's `-c`
# parse-failure fallback re-execs the preserved /usr/bin/bash.real, so a nash regression
# degrades loudly in CI rather than silently corrupting the image.
#
# ── Building the binary (linux/amd64 — Cloudflare Containers run amd64 ONLY) ─────────────────
# The `nucleicd` Linux build is REAL (the CLOUD_RUNTIME Phase-2 port landed: swift-crypto Noise
# interop proven by the protocol suite on Linux, GRDB-on-Linux green, BSD-socket approval
# server, 0600-file secret store, NIO relay WebSocket). The image binary is a fully-static
# x86_64-musl build via Swift's Static Linux SDK — cross-compiles at native speed from ANY host
# arch (including the arm64 swift container on an Apple-silicon Mac), no Swift runtime libs to
# ship. The proven recipe is scripted:
#
#   docker run --rm -v "$PWD":/src -w /src swift:6.3-bookworm scripts/build-nucleicd-linux.sh
#   cp .build/x86_64-swift-linux-musl/release/nucleicd containers/nucleic-runner/
#   docker build --platform linux/amd64 -t nucleic-runner containers/nucleic-runner
#
# Verified end to end: the static amd64 binary (run under qemu-x86_64) enrolls with the deployed
# relay, listens on it, and mints working pairing codes.
#
# ── Gates before this deploys to Cloudflare ──────────────────────────────────────────────────
#   • The FROM base below (naros-agent) must be PUBLISHED at the pinned version — the tag
#     exists only after .github/workflows/naros.yml has run green on dev (the N2 sequencing
#     caution). naros.yml publishes a multi-arch index (linux/amd64 + linux/arm64); this
#     build's --platform linux/amd64 takes the amd64 slice. runner-image.yml preflights
#     both the tag's availability and the NAROS_VERSION ↔ os/VERSION lockstep.
#   • Push this image to **Cloudflare's managed registry** (`registry.cloudflare.com/<ACCOUNT_ID>/
#     nucleic-runner`) — NOT GHCR, which Wrangler/Cloudflare Containers can't pull without extra
#     `wrangler containers registries configure` + credentials. `wrangler containers push` handles
#     auth (CLOUDFLARE_API_TOKEN) and Cloudflare pulls it at deploy with no further config;
#     .github/workflows/runner-image.yml does this in CI. Then the wrangler `containers` block in
#     cloud/nucleic-runner/wrangler.jsonc references it. The Worker + pool DO deploy and run without
#     it, and a self-hosted box runs `nucleicd` natively with no container at all.
#     (The FROM base below stays on GHCR — it's pulled only at build time, by Docker in CI.)
#
# Version lockstep (NAROS.md §8): NAROS_VERSION's default must equal os/VERSION — asserted
# in runner-image.yml, so an os/VERSION bump forces the matching edit here (which is also
# what triggers this image's rebuild onto the new base). Rollback: the last nucleic-sandbox
# based image tag remains published in the managed registry, exactly as v7 backs the
# sandbox pin.
ARG NAROS_VERSION=26.07
FROM ghcr.io/abkslm/naros-agent:${NAROS_VERSION}

COPY nucleicd /usr/local/bin/nucleicd

# Reachability transport, split by who operates the runner (WITH_TAILSCALE build arg):
#   • Nucleic-hosted (default, WITH_TAILSCALE=0): reachable ONLY over Nucleic's own relay infra
#     (nucleicd listens relay-only), so no tailscale is installed — it would be dead weight the
#     cloud runner never uses. This is the image CI builds + pushes to Cloudflare
#     (.github/workflows/runner-image.yml).
#   • Self-hosted (WITH_TAILSCALE=1, built + tagged separately — e.g. `:self-hosted`): an operator
#     may want the container reachable over THEIR tailnet, so we install the OS-level tailscale
#     package here. (nucleicd's own Tailnet transport is TailscaleKit, which is Darwin-only and has
#     no Linux build, so on Linux "tailscale" can only mean the system daemon — the operator brings
#     a TS_AUTHKEY and runs `tailscaled` + `tailscale up` alongside the daemon.) See
#     containers/nucleic-runner/README.md "Self-hosted variant".
#
# Base-specific notes: curl + ca-certificates ship in naros-base (no bootstrap install
# needed), the tailscale suite tracks the base's Debian release (trixie), and the base's
# hosted-repo apt entry (naros-keyring's naros.sources) is parked for the duration of the
# `apt-get update` — the apt domain isn't provisioned yet (NAROS.md N1 operator infra), and
# an unreachable source would fail the update. Drop the park/restore once the repo is live.
ARG WITH_TAILSCALE=0
RUN if [ "$WITH_TAILSCALE" = "1" ]; then \
        set -eu \
        && curl -fsSL https://pkgs.tailscale.com/stable/debian/trixie.noarmor.gpg \
            -o /usr/share/keyrings/tailscale-archive-keyring.gpg \
        && curl -fsSL https://pkgs.tailscale.com/stable/debian/trixie.tailscale-keyring.list \
            -o /etc/apt/sources.list.d/tailscale.list \
        && if [ -f /etc/apt/sources.list.d/naros.sources ]; then \
               mv /etc/apt/sources.list.d/naros.sources /tmp/naros.sources.parked; \
           fi \
        && apt-get update \
        && apt-get install -y --no-install-recommends tailscale \
        && if [ -f /tmp/naros.sources.parked ]; then \
               mv /tmp/naros.sources.parked /etc/apt/sources.list.d/naros.sources; \
           fi \
        && rm -rf /var/lib/apt/lists/*; \
    fi

# The runner's store lives on the container's own (ephemeral) disk; durable state rides git
# remotes + checkpoints per CLOUD_RUNTIME §3.5. Fixed path so checkpoint tooling can find it.
ENV NUCLEIC_RUNNER_DATA_DIR=/var/lib/nucleic-runner
RUN mkdir -p /var/lib/nucleic-runner

# Runner-tier identity (NAROS.md §4): stamp os-release VARIANT and the manifest tier so
# `naros info`, the host's custom-image probe (ID=naros + agent/runner VARIANT_ID fast
# path), and nucleicd's own narOS detection all observe the runner tier. Stamped directly
# rather than via the `naros-tier-runner` meta-package: the meta lives in the CI apt pool /
# hosted repo, neither of which is reachable from this build context (the hosted repo isn't
# live yet); it anchors nothing this image doesn't already inherit from naros-agent
# (its only Depends). Switch to `apt-get install naros-tier-runner` once the repo is live.
RUN set -eu; \
    sed -i -e 's/^VARIANT=.*/VARIANT="runner"/' -e 's/^VARIANT_ID=.*/VARIANT_ID=runner/' /etc/os-release; \
    jq '.tier = "runner" | .variant = "runner"' \
      /etc/naros/manifest.json > /etc/naros/manifest.json.new; \
    mv /etc/naros/manifest.json.new /etc/naros/manifest.json; \
    naros info --json | jq -e '.tier == "runner" and .variant == "runner"' > /dev/null

# The pool injects the rest of the contract at start (container.ts buildContainerEnv):
#   NUCLEIC_RUNNER_POOL_ID, NUCLEIC_RUNNER_INSTANCE_ID, NUCLEIC_RUNNER_EPOCH,
#   NUCLEIC_RUNNER_INSTANCE_TOKEN, NUCLEIC_RUNNER_CONTROL_URL, NUCLEIC_RELAY_URL (optional).
# nucleicd listens relay-only by default and serves the one-shot pairing payload on the
# loopback control port (9200) for the provisioning proxy (`GET /v1/pool/pairing`).
# nucleicd stays PID 1 (it is already a competent init for this role — NAROS.md §5);
# adopting naros-init here is an optional later step.
ENTRYPOINT ["/usr/local/bin/nucleicd"]
