Arquitectura

Um comando, crates em cinco camadas (ADR-0040) — e nenhum processo residente.

Visão geral

O directório de cada crate é a sua camada, e o scripts/arch_fitness.py falha quando os dois discordam ou quando uma dependência vai contra a direcção das camadas (uma camada só depende das de baixo; um binário compõe UMA interface).

binários — delonix-runtime-bin · delonix-mcp-bin · delonix-mgmt-bin a CLI delonix é a única porta: container · image · build · vm · volume · network · stack · cluster · …; delonix mcp/serve api/serve cri executam os binários irmãos
delonix-criservidor CRI runtime.v1 — o kubelet fala com o Delonix
delonix-mgmtAPI de gestão LOCAL (HTTP+JSON num socket unix), métricas Prometheus
delonix-mcpservidor Model Context Protocol, local e sem inquilino
delonix-proxmoxVmBackend e SDN contra a API de um nó Proxmox VE
delonix-truenasdataset, quota e partilha numa appliance TrueNAS
delonix-opnsenseGatewayProvider contra a API REST do OPNsense (ADR-0051)
delonix-linuxclone() + namespaces, pivot_root, seccomp/caps, cgroups v2 delegados, exec, reconcile
delonix-sdnSDN rootless: holder netns + bridge + slirp único, DNAT/firewall nft, DNS interno, overlay WireGuard
delonix-ocipull OCI (digest verificado), build, export, buildpacks CNB, assinaturas
delonix-vmmicroVMs (VmBackend: Cloud Hypervisor · libvirt), cloud-init
delonix-volumevolumes nomeados, bind mounts, quotas, nfs/cifs/webdav
delonix-stateStore/JsonStore com flock, escrita atómica, cofre de segredos cifrado
delonix-scannerSBOM + CVE
delonix-telemetrylogging estruturado, spans OpenTelemetry, registo Prometheus
delonix-computecontexto: a especificação única de execução, registos Container/Vm
delonix-stackcontexto: tabela de Kinds, reconciliador de 3 vias, revisões
delonix-nodecontexto: eventos, verificações do host, contrato de dispatch
delonix-security-runtimecontexto: política e o único ponto de admissão
delonix-modelfundação pura: erro partilhado e códigos DX, Status, regras de firewall, modelo do segredo
delonix-net-rulesfundação pura, sem dependências: CIDR, nomes de bridge, IPAM

De cima para baixo: binários e interfaces · providers · adaptadores · contextos · fundação.

Daemonless a sério

Não há daemon, nem sequer um monitor por container (o conmon do podman). O run faz clone() directo; em modo detached, um shim de logging efémero fica só a escoar o stdout/stderr para o ficheiro de log (com rotação) e morre com o container. O estado (spec completa de cada container/VM/volume/rede) vive em JSON sob $DELONIX_ROOT — o ps/start/inspect reconstruem tudo daí, e reapers oportunistas limpam órfãos (slirp sem alvo, hostfwd sem container) a cada invocação relevante.

Rootless-first

Sem root, o isolamento vem de user namespaces com mapeamento de subuid (newuidmap/newgidmap, como o podman) — o uid 0 do container é um uid não-privilegiado do host. O rootfs é um overlayfs nos dois modos: as layers da imagem são partilhadas e cada container tem a sua upper persistente. Em rootless o mount é feito pelo init do container, dentro do seu user namespace, porque um utilizador sem privilégio não pode montar no host (desde a v0.59.0; um container antigo com cópia flat migra no start seguinte). Com --privileged + labels de node Kind, o runtime prepara a delegação de cgroup v2 dedicada que um systemd aninhado (kindest/node) exige.

Rede rootless: o ingress

hostportas publicadas (127.0.0.1 por omissão; DELONIX_PUBLISH_ADDR para expor)
holder netns (1 por utilizador)bridge delonix0 · slirp4netns único · nft (DNAT «pre», firewall) · DNS interno com os nomes dos containers
containersveth por container, ligados à bridge; IP determinístico por id

Publicar uma porta = um add_hostfwd no api-socket do slirp único + uma regra DNAT na chain de ingress — estado do dataplane, não do container. É por isso que portas (e volumes, via mounts live) se trocam a quente: o processo do container nunca é tocado. Com --net host + -p, o container recebe um netns próprio com um slirp4netns dedicado (modelo podman), que morre com ele.

Segurança

Rootless por omissão; seccomp e drop de capabilities fora de --privileged, com arranque a FALHAR se não ficarem mesmo activos; pull com verificação de digest (incluindo artefactos VM OCI); inputs de manifesto de recursos como Cluster/Vm validados por whitelist antes de chegarem a qualquer shell remoto.

Auditoria de 2026-07-21 — 6 achados de severidade alta, CORRIGIDOS em 2026-07-23 (o COPY do build, por exemplo, era contornável por symlink apesar de uma correcção anterior ter tentado fechá-lo — agora canonicaliza e confirma o confinamento). Não há indícios de RCE pela rede. Uma auditoria adversarial independente (2026-07-26) confirmou 5 das 6 correcções e fechou um TOCTOU residual no kubeconfig, e reviu o núcleo de syscalls (namespaces, seccomp, clone3, higiene de fds, SO_PEERCRED) sem achados altos novos; uma 3.ª auditoria (2026-08-10) varreu as classes de CVE conhecidas do Docker/runc/CRI-O e corrigiu o que encontrou. Isto reduz o risco, não o elimina: num host partilhado, trata imagens e manifestos de terceiros com a mesma cautela que terias com qualquer runtime. Detalhe completo em AUDITORIA-E2E.md — ver também a comparação com Docker/Podman para o estado geral do projecto.

Architecture

One command, crates in five layers (ADR-0040) — and no resident process.

Overview

A crate's directory is its layer, and scripts/arch_fitness.py fails when the two disagree or when a dependency runs against the direction of the layers (a layer depends only on the ones below it; a binary composes ONE interface).

binaries — delonix-runtime-bin · delonix-mcp-bin · delonix-mgmt-bin the delonix CLI is the one door: container · image · build · vm · volume · network · stack · cluster · …; delonix mcp/serve api/serve cri run the sibling binaries
delonix-criruntime.v1 CRI server — the kubelet talks to Delonix
delonix-mgmtLOCAL management API (HTTP+JSON over a unix socket), Prometheus metrics
delonix-mcpModel Context Protocol server, local and tenancy-free
delonix-proxmoxVmBackend and SDN against one Proxmox VE node's API
delonix-truenasdataset, quota and share on a TrueNAS appliance
delonix-opnsenseGatewayProvider against OPNsense's REST API (ADR-0051)
delonix-linuxclone() + namespaces, pivot_root, seccomp/caps, delegated cgroups v2, exec, reconcile
delonix-sdnrootless SDN: holder netns + bridge + single slirp, nft DNAT/firewall, internal DNS, WireGuard overlay
delonix-ociOCI pull (digest verified), build, export, CNB buildpacks, signatures
delonix-vmmicroVMs (VmBackend: Cloud Hypervisor · libvirt), cloud-init
delonix-volumenamed volumes, bind mounts, quotas, nfs/cifs/webdav
delonix-stateStore/JsonStore behind flock, atomic writes, encrypted secret vault
delonix-scannerSBOM + CVE
delonix-telemetrystructured logging, OpenTelemetry spans, Prometheus registry
delonix-computecontext: the one run specification, Container/Vm records
delonix-stackcontext: the Kind table, three-way reconciler, revisions
delonix-nodecontext: events, host checks, the dispatch contract
delonix-security-runtimecontext: policy and the single admission point
delonix-modelpure foundation: shared error and DX codes, Status, firewall rules, secret model
delonix-net-rulespure foundation, zero dependencies: CIDRs, bridge names, IPAM

Top to bottom: binaries and interfaces · providers · adapters · contexts · foundation.

Genuinely daemonless

There's no daemon, not even a per-container monitor (podman's conmon). run does a direct clone(); in detached mode, an ephemeral logging shim just drains stdout/stderr to the log file (with rotation) and dies with the container. State (the full spec of every container/VM/volume/network) lives as JSON under $DELONIX_ROOT — ps/start/inspect rebuild everything from there, and opportunistic reapers clean up orphans (slirp with no target, hostfwd with no container) on every relevant invocation.

Rootless-first

Without root, isolation comes from user namespaces with subuid mapping (newuidmap/newgidmap, like podman) — the container's uid 0 is an unprivileged host uid. The rootfs is an overlayfs in both modes: the image layers are shared and each container keeps its own persistent upper layer. In rootless mode the mount is done by the container's init, inside its user namespace, because an unprivileged user cannot mount on the host (since v0.59.0; an older container with a flat copy migrates on its next start). With --privileged plus Kind node labels, the runtime sets up the dedicated cgroup v2 delegation a nested systemd (kindest/node) needs.

Rootless networking: the ingress

hostpublished ports (127.0.0.1 by default; DELONIX_PUBLISH_ADDR to expose)
holder netns (1 per user)delonix0 bridge · single slirp4netns · nft (DNAT "pre", firewall) · internal DNS with container names
containersone veth per container, attached to the bridge; deterministic IP per id

Publishing a port = one add_hostfwd on the single slirp's api-socket plus one DNAT rule in the ingress chain — dataplane state, not container state. That's why ports (and volumes, via live mounts) swap on the fly: the container process is never touched. With --net host + -p, the container gets its own netns with a dedicated slirp4netns (the podman model), which dies with it.

Security

Rootless by default; seccomp and capability drop outside --privileged, with startup FAILING if they don't actually come up; pull with digest verification (including OCI VM artifacts); manifest inputs for resources like Cluster/Vm validated by whitelist before reaching any remote shell.

2026-07-21 audit — 6 high-severity findings, FIXED by 2026-07-23 (the build's COPY, for instance, was bypassable via symlink despite an earlier fix having tried to close it — it now canonicalizes and confirms confinement). There's no sign of remote code execution. An independent adversarial audit (2026-07-26) confirmed 5 of the 6 fixes, closed a residual TOCTOU on the kubeconfig, and reviewed the syscall core (namespaces, seccomp, clone3, fd hygiene, SO_PEERCRED) with no new high findings; a third audit (2026-08-10) swept the known Docker/runc/CRI-O CVE classes and fixed what it found. That lowers the risk, it does not remove it: on a shared host, treat third-party images and manifests with the same care you would with any runtime. Full detail in AUDITORIA-E2E.md — see also the comparison with Docker/Podman for the project's overall status.