Feature Specification: Setups and Wiring
Created: 2026-09-22
Status: Implemented
Input: Reconstructed from the code at 0bf4ecd36 (core/setups/groups/, core/setups/hosts-common.nix, core/setups/wiring/, core/setups/nixos/, core/apex.nix), pull requests #1818, #1822, #1828, #1831 and #1836, commit ba2b92c41, issue #527, and the design notes of the maintainers.
User Scenarios & Testing (mandatory)
User Story 1 - Generate a full deployment from a minimal configuration (Priority: P1)
A hosting provider gives a group of machines, an apex domain and a hosting configuration. The setups generate the full NixOS configuration of each machine: DNS records and zones, TLS certificates and trust, SMTP, secrets, workload identity, the database roster, and the routing of resources to their providers.
Why this priority: without the setups, each provider writes this wiring by hand, and the deployment programs have nothing to deploy.
Independent Test: evaluate the nixosConfigurations of the operator
group with the default configuration. Each machine evaluates, and the zone
has a record for each published name.
Acceptance Scenarios:
- Given a group with published and internal machines, When the setups evaluate, Then only the published machines get public DNS names.
- Given
DNS_DOMAIN, When the setups evaluate, Then all names are under that apex. - Given a component that provides a capability (for example OIDC or SMTP), When another component needs it, Then the wiring connects them, whatever the node names are.
User Story 2 - Change one wiring decision with confidence (Priority: P2)
A developer changes how one decision is made (for example which node gets a
TLS certificate). The decision is a pure function in core/setups/wiring/,
and a nix-unit test asserts on the same expression that the deployment
uses.
Independent Test: change a decision function so it gives a wrong result.
Its nix-unit-setups-* check fails.
Edge Cases
- A node has no address. The zones do not include it.
- The public uplink value is not a CIDR. The evaluation fails.
DNS_DOMAINis not set. The evaluation fails with an error that namesDNS_DOMAIN.
Requirements (mandatory)
Functional Requirements
- FR-001: The setups MUST define the groups (
operator,hosting-provider,dev,hypervisor), each with published and internal machines. - FR-002: The setups MUST generate the NixOS configuration of each machine from the group, the apex and the hosting configuration.
- FR-003: Each wiring decision MUST be a pure function with its own
nix-unittest that asserts on the expression the deployment uses. - FR-004: Wiring MUST read the capabilities that components provide and need, not node names.
- FR-005: The setups MUST read the apex domain once, from
DNS_DOMAIN, and MUST NOT fall back to a default apex. A fallback apex conflicts with the goal of portable infrastructure. - FR-006: The setups MUST NOT include a machine without an address in a zone.
- FR-007: The groups of
coreMUST NOT contain machines whose components only a front-end provides. A front-end adds such machines with the fold helpers. - FR-008: The setups MUST give the
overviewpage the browser UIs of only the nodes that the deployment deploys (usedNodes). A node that an external service replaces (such asnetboxwith an external NetBox) MUST NOT get a tile. - FR-009: When the
overviewpage setsservedAtApex(the default), the setups MUST also serve it at the apex domain. Both zone sources (the eval-time zone and the NetBox renderer) MUST give the apex a copy of theAandAAAArecords of theoverviewnode, because aCNAMEcannot be at the apex. At most one node MUST setservedAtApex. - FR-010: The central group (the one group whose roster provides
varsBackend) MUST find the other groups from their group data or components, not from their names. The apex and the deploy runners come from the central group. The operator groups are the groups that statefqdnFor. The central-login groups are the groups that setcentralLogin. The central group selects these groups from the groups of the caller, and evaluates the model of each selected group from the same groups, so a group that only the caller defines has a model. The node that runs the containers is the one published node that providesinstances. The other groups read the central group ascentralGroup.
Key Entities
- Group: a named set of published and internal machines.
- Machine: a node with hardware, addresses and a set of components.
- Apex: the domain that all names of a deployment are under.
- Wiring decision: a pure function from the model to one part of the configuration (DNS, TLS, SMTP, routing, served domains, node selection, workload identity, database roster, NetBox pinning, public uplink, S3 keys).
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: All
nix-unit-setups-*checks pass. - SC-002: The
integrations-bridge-dns,integrations-smtp-*,integrations-spire-*,integrations-openbao-pkiandintegrations-incus-*checks pass.
Assumptions
- The groups of the hosting provider and of the operator are in
coretoday.corecan split after the split of the monorepo (issue #527).
[NEEDS CLARIFICATION: the central OpenBao and OpenTelemetry hosts are read from the central group (the group whose roster provides varsBackend) in core/setups/hosts-common.nix (a TODO says they must come from remote state). Must a deployment of one provider work without the group of another?]
Known Deviations
None.