- 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>
ADR 0023, generator input and output types per target, and the REST API
for clusters, TSIG keys, zones and records.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- PATCH /agents/{id} switches the mode and reconnects the agent
- POST /revisions/{n}/deploy creates pending push deployments, sends
ApplyRevisionCommand with the deployment ID, re-sends open pushes on
connect and announces them in GetDesiredState; reports with the ID
complete the deployment
- POST /revisions/{n}/rollback re-renders the stored generator input
with the next revision number
- GET /revisions/{n}/diff and GET /config/pending with unified diffs
- GET /events streams agent, deployment, revision and pending events
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fan-out to subscribers with bounded buffers; slow subscribers miss
events instead of blocking publishers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agents get a target revision (manual mode), revisions store their
generator input (jsonb) for rollbacks, deployments gain the outcomes
pending and superseded, a nullable end and the requesting user. The
duplicate protection now covers agent reports only. Transactions can
register hooks that run after the commit.
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>
New steps before the revoke step: /config/pending reports nothing after
revision 2 and the new address afterwards; the DHCP agent switched to
manual mode stays on revision 2 while the DNS agent reaches 3, and an
explicit push of revision 3 brings it there with a succeeded push
deployment; the diff of revision 3 contains the new host; rolling back
to revision 1 creates revision 4 with SOA serial 4 and without the later
names; /events announces a revision created while listening.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- GetDesiredStateResponse.deployment_id set: the desired revision is
applied as a push with that ID, also in manual mode (ADR 0022).
- The reports of the last 20 push deployments are kept in state.json.
A resent push with a handled deployment ID is not applied again; its
report is delivered again unless it is still queued.
- A push already queued with the same deployment ID is not queued twice.
- Reports the server refuses for good (InvalidArgument, NotFound,
AlreadyExists, FailedPrecondition, OutOfRange) are dropped instead of
blocking the report queue.
- Tests for polling pushes, resent pushes, mode changes via a new
Welcome, persistence and bounds of handled deployments.
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>
Docker Hub timed out on the shared runner; pulls now retry and fall back
to a local image. The e2e scripts were committed without the executable
bit. The truncation test checked letters that the marker itself contains.
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>
A driver is cross-compiled for the Docker daemon's architecture and
copied with fixture revisions into BIND 9.18/9.20 and Kea 2.6.5/3.2.1
containers (docker cp, no bind mounts or published ports). It runs the
core's pipeline: two revisions apply, broken revisions are rejected,
a failed live check and a failed health check roll back, a failed Kea
reload restores the previous file, and leases added with lease4-add
are listed page by page. make test-integration runs it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Validate requires exactly kea-dhcp4.conf with this agent's control
socket and runs kea-dhcp4 -t. Activate writes the file atomically and
sends config-reload; on failure the previous file is restored and
reloaded. Health uses status-get (pid, uptime, last reload, socket
state) and checks that the installed file is the expected revision.
Leases pages through lease4-get-page and maps Kea lease states
(default, declined, expired-reclaimed, released) to core lease states.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Validate maps ddi-suite*.conf to conf_dir and zones/db.<zone> to
zone_dir, rejects other files and a zone directory that differs from
dns.zone_dir, and runs named-checkconf on a temporary named.conf plus
strict named-checkzone per zone. Activate backs up all touched files,
writes zone files then includes atomically (unchanged files are kept),
never touches existing create-only files, removes files dropped since
the previous revision and the stale journal of a zone that became
managed, runs named-checkconf -z on the live named.conf and then
rndc reconfig and rndc reload; failures restore the backup (and reload
again). Health runs rndc status and compares the SOA serial of every
managed zone (UDP with TCP fallback, authoritative answers only).
golang.org/x/net becomes a direct dependency (dnsmessage).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Loads or creates the agent PKI at startup, serves the gRPC agent API on
agent_api.listen with graceful shutdown, exports ddi_agents_connected
and removes old enrollment tokens periodically.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keepalive MinTime 20 s (agents ping every 30 s, also without a stream),
send limit above bundle.MaxTotalSize, and resent deployment reports
(same agent, revision and start time) are dropped without error and
without touching the agent's state.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shared, role-internal helpers: programs run without a shell, with a
timeout and captured, truncated output quoted in errors; configuration
files are replaced atomically (temp file, fsync, rename, directory sync)
with explicit mode and the owner of the existing file or its directory;
an in-memory backup restores touched files after a failed activation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TLS 1.3 listener that requests client certificates and checks them in
interceptors: Enroll needs a valid one-time token (rate limited per
source IP), RenewCertificate accepts certificates expired up to 30 days,
every other call needs the agent's current, unrevoked certificate.
Connect registers the stream in the hub (pushes, revocation, shutdown);
FetchBundle signs the role's artifacts per agent; lease batches are
deduplicated by sequence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CLI: enroll, run, status, version, help (core.Main with a role
factory); the agent binaries use a placeholder factory until the
BIND and Kea roles are wired in.
- Enrollment: local ECDSA P-256 key and CSR, TLS 1.3 to the agent API
with the server chain pinned to the CA fingerprint.
- ServerSource: mTLS gRPC with keepalive, Connect stream (Hello,
Welcome, heartbeats, apply and renew commands), reconnect with
exponential backoff and jitter, GetDesiredState polling as fallback,
certificate renewal after half of the lifetime.
- Apply pipeline: fetch, bundle verification with replay protection,
store, Validate, Activate, Health with retries, rollback to the last
good revision; outcomes succeeded/rejected/rolled_back/failed are
queued in state.json and reported; failed revisions are retried only
by a newer revision or an explicit push.
- Lease reporting with change detection, persistent sequence and full
snapshots at start, per connection and periodically.
- Tests with fake roles, a fake source and an in-process fake
AgentService over real mTLS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent configuration (agent-<role>.yaml, strict decoding, role section
passed undecoded to the role factory) and the state directory of ADR
0011: identity with interrupted-renewal recovery, verified revisions
under revisions/<n>/, state.json with apply results, lease sequence and
queued deployment reports, atomic writes, pruning and a lock file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use cases for the REST API (agent list/revoke/delete, one-time tokens
with the ready enrollment command, immutable revisions with unchanged
detection, deployment and lease lists) and for the agent data plane
(enrollment, renewal, status, bundles, deployment and lease reports).
A hub of open agent streams pushes new revisions to auto_pull agents and
closes the stream of revoked agents.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CA (ECDSA P-256, 10 years) and the Ed25519 bundle signing key are
created on first start, sealed with the master key and stored once
(concurrent starts read back the winner). The agent-port server
certificate is issued in memory; agent CSRs are signed for 14 days.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Migration 00003 adds the PKI key table, agents, enrollment tokens,
immutable configuration revisions with their files, deployment reports
and DHCP leases, each with database constraints. Repositories and DB
tests for all of them.
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>