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).
delonix é a única porta: container · image · build · vm · volume · network · stack · cluster · …;
delonix mcp/serve api/serve node-api/serve cri executam os binários irmãosdelonix.node.v1 (gRPC + HTTP/JSON dos mesmos .proto num socket unix) — NodeService + openapi.jsonDe cima para baixo: binários e interfaces · providers · adaptadores · contextos · fundação — os 35 crates em cinco camadas (ADR-0040). O detalhe completo, com as dependências reais, está no modelo C4.
Providers
O engine fala com o mundo por portas (traits): o mesmo VmBackend,
GatewayProvider, porta de storage, NetworkZoneProvider e DNS servem tanto
drivers locais (no host) como sistemas externos — appliances e APIs
remotas (Proxmox, TrueNAS, OPNsense, PowerDNS).
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.
Execução local de um comando
Um comando é um processo efémero: fala directamente com o kernel (sem daemon, sem monitor por
container), escreve o estado em ficheiros e desaparece. A rede rootless é servida por um único par
holder-netns + slirp4netns partilhado, com DNAT nft para publicar portas.
O processo morre; ps/start/inspect reconstroem tudo a
partir do estado em $DELONIX_ROOT — e os reapers oportunistas limpam órfãos.
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
0.0.0.0:8080:80)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).
delonix CLI is the one door: container · image · build · vm · volume · network · stack · cluster · …;
delonix mcp/serve api/serve node-api/serve cri run the sibling binariesdelonix.node.v1 node contract (gRPC + HTTP/JSON of the same .proto over a unix socket) — NodeService + openapi.jsonTop to bottom: binaries and interfaces · providers · adapters · contexts · foundation — the 35 crates in five layers (ADR-0040). The full detail, with the real dependencies, is in the C4 model.
Providers
The engine talks to the world through ports (traits): the same VmBackend,
GatewayProvider, storage port, NetworkZoneProvider and DNS serve both
local drivers (on the host) and external systems — appliances and
remote APIs (Proxmox, TrueNAS, OPNsense, PowerDNS).
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.
Running a command locally
A command is an ephemeral process: it talks to the kernel directly (no daemon, no per-container
monitor), writes its state to files, and exits. Rootless networking is served by a single shared
holder-netns + slirp4netns pair, with nft DNAT to publish ports.
The process exits; ps/start/inspect rebuild everything
from the state under $DELONIX_ROOT — and opportunistic reapers clean up orphans.
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
0.0.0.0:8080:80)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.