Clusters (DDI_CLUSTER), Kea HA pairs (DDI_KEA_HA), dynamic zones
(DDI_DYNAMIC_ZONES) and SSO (DDI_SSO) now need the matching Keygen
entitlement; the trial grants all of them. Only taking a feature into
use is blocked (403 license_feature): existing clusters, HA pairs,
dynamic zones and enabled SSO keep working and stay editable.
maxAgents is checked when creating an enrollment token and, under an
advisory lock, at enrollment; revoked agents do not count. GET /license
reports available_features and the agent usage. The UI shows the
features on the license page and disables locked controls, and
keygen-setup.sh creates the entitlements and assigns them to licenses
(ADR 0027).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The DNS agent now maintains DDI's records in dynamic zones (ADR 0026):
updated zone and record hints, the system key is marked and cannot be
deleted (key_system), API types regenerated. Project log updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An agent installed without token and enrolled with the command of the web
interface never ran as a service: the installer left the unit disabled and
the root-run enrollment left an identity the service user could not read.
The installer now always enables the agent unit (it waits for the
identity via ConditionPathExists), enroll as root hands the state over to
the service user and enables and starts the unit, and rerunning or
upgrading the installer repairs agents enrolled by hand. The web interface
shows the matching installer command next to the enroll command.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the user's server the check reported "socket: permission denied" for
ping and asked only the server's own resolver. Ping now falls back to a
raw ICMP socket (the server unit gets CAP_NET_RAW, like /bin/ping); DNS
asks the DNS agents outside clusters when no name server addresses are
configured, gives every server its own timeout, and explains missing
records (dynamic zone, system resolver, not deployed yet).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Covers expanding a network and paging its IPs, Shift-click and from/to
selection, range assignment and freeing with dry run, bulk dry run and
apply with per-address problems, the check dialog, adopting the lease
host name, the random host name hint, the network form without pools and
live reloads of the IP list. Test calls expose their query string.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lease name moves into the lease column, long descriptions are cut with a
tooltip, row actions get some air and the IP list on the network page
uses the available height.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New problems dynamic_is_gateway, dynamic_ipv6_unsupported and check_size;
range and type errors with their parameters; pool problems that no longer
exist removed. Bulk dry runs report effects per code with a count.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Networks expand inline (and on the detail page) to every host address from
GET /networks/{id}/ips with paging, checkbox and Shift-click selection and
from/to ranges. Selections can be assigned as dynamic, static or reserved
or freed via POST /networks/{id}/range after a dry run, changed in bulk
(dry run, then apply) and checked with POST /addresses/check. The pool
editor is gone; DHCP ranges are shown as derived. Dynamic entries hint at
the random host name and offer to adopt the lease host name. Live events
also refresh the IP lists. API types regenerated (ADR 0025).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Left sidebar navigation in groups, slim license/pending strips, page
headers with counts and one primary action, help texts behind a small
"?" instead of paragraphs, compact tables and panels, restrained palette
with small radii in light and dark mode, terse texts in both locales.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The DHCP agent writes the HA credentials only as ddi-suite-ha-password and
ddi-suite-ha-user; other names are now rejected when the settings are
saved instead of when a revision is generated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Clusters page: DNS/DHCP clusters with members, transfer key, DNS
options and Kea HA settings; member picking limited to free agents of
the role, client-side checks of the membership rules.
- TSIG keys page: create, edit, rotate, delete; secrets only after an
explicit, audited retrieval and shown once.
- Zones page with derived zones ("take over") and zone detail with
type-specific record forms and hints for dynamic zones and AD.
- Networks, agents and generator settings show/assign clusters; files,
diffs and pending changes are grouped by target, secret files are
never shown.
- Pages are lazy-loaded per route (main bundle 600 KB -> 480 KB).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revisions page lists the pending audit entries and file diffs above
"Neue Revision". The revision page compares with the previous revision
(or another one, or empty), pushes the revision to selected agents with
a per-agent delivery result, and rolls back by creating a new revision
with the old content.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server-sent events from /api/v1/events invalidate the affected queries
(agents, deployments, revisions, pending changes) and reconnect with
backoff; while connected, polling drops to a 60 s fallback. The footer
shows the live status, the header notes how many changes wait to be
deployed. Agents get a mode switch (auto_pull/manual) with their target
revision; deployments show the pending and superseded outcomes and who
requested a push. Translations for all M4 texts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ADR 0022, OpenAPI additions (agent mode, deploy, rollback, diff, pending
changes, server-sent events), deployment_id in GetDesiredStateResponse
for pushes picked up by polling, and the textdiff package (Myers,
unified format).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test/e2e runs server, PostgreSQL, BIND and Kea with both agents in
containers (make test-e2e, CI job End-to-end): enrollment with the
command from the API, revision 1 and 2 applied and served by BIND and
Kea, unchanged data creates no revision, revoking disconnects the agent
while BIND keeps serving.
Fixes from the first CI run: quote a spec description containing a
comma, exempt the agent lock-out routes in the route protection test,
whole-second certificate lifetimes, a push replacing queued pulls, the
truncation marker containing the letter checked, and curl|grep -q under
pipefail in the server smoke test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revoking or deleting an agent and deleting enrollment tokens lock agents
out, a security function that must stay available when the license is
read-only. Translations for the new problem codes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent overview with connection, health and revision state (polled every
five seconds until the live stream of M4), agent details with checks and
deployment history, enrollment token dialog showing the ready-to-run
command, revision list and creation, revision details with deployments
and files, and a lease list with network, state and text filters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shared Apache-2.0 packages for the signed bundle format and the agent
certificate conventions, the agent role interface, REST API spec for
agents, enrollment tokens, revisions, deployments and leases, and ADR
0021. Generator settings now hold the target paths on the managed hosts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- stable Kea subnet IDs per network (migration 00002)
- generator settings (SOA, name servers, TTLs, recursion, DHCP defaults)
- GET /config/preview renders the configuration for the current data
- UI: configuration preview page and DNS/DHCP settings page
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- login with TOTP step and SSO button, forced password change, account
page with password change and TOTP setup (QR code)
- layout with permission-based navigation, license banner, theme/language
- networks: list with utilization, create/edit with pool editor, detail
page with address map
- addresses: server-side filtered/sorted, virtualized table, inline type
switch with DNS/DHCP preview, bulk actions, saved filters, CSV import
(dry run first) and export
- license, users, audit log and OIDC settings pages
- typed API client from the OpenAPI spec; errors translated by code
- German default, English second language
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- commands: serve, migrate, bootstrap-admin, gen-master-key
- /metrics with route-pattern labels and license gauge, /readyz checks DB
- fix OpenAPI flow mappings with commas; generate TypeScript API types
(openapi-typescript) and check them in CI
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
German default with English as second language (i18next), light/dark/system
theme, server health indicator. ESLint (strict type-checked), Prettier,
Vitest. Product name injected at build time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- internal/brand: central product, binary and path names (ldflags-overridable)
- internal/buildinfo, internal/logging (slog, secret redaction)
- server: env config, HTTP server with /healthz, /readyz, request IDs,
access log, panic recovery, security headers, graceful shutdown
- web: embedded SPA handler with fallback page when UI is not built
- agent: ddi-agent-dns and ddi-agent-dhcp binaries on a shared core CLI
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>