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>
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>
- configgen: input model shared by derivation and renderers
- derive: forward zones per domain, reverse zones (IPv4 octet, IPv6 nibble
boundaries), A/AAAA/PTR from static and manual_dhcp entries, Kea subnets
with effective pools and reservations; pure and deterministic
- bindgen: zone-statement include, options include, zone files with strict
validation, canonical ordering and RFC 1035 TXT escaping
- keagen: typed Kea DHCPv4 JSON with strict validation
- golden-file, validation, determinism and fuzz tests
- integration tests check generated files with real named-checkconf,
named-checkzone (BIND 9.18, 9.20) and kea-dhcp4 -t (Kea 2.6, 3.2);
new CI job
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- end-to-end OIDC test: discovery, PKCE (S256) verified by the IdP, nonce,
state cookie, ID token signature, user creation, role sync, refused
login without role, forged state
- make run-server / dev-admin with deploy/config/server.dev.yaml
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Creates the product and the standard policy in Keygen (one server per
license, license-key activation, daily heartbeat), issues licenses with
limits in metadata and writes offline license files. The admin token is
only read from the environment.
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>
- route the UI as "/" (GET/HEAD only) to avoid a ServeMux conflict with /api/
- constraint violations carry their specific top-level code
- MAC search accepts '-' and '.' separators
- CSV import reports syntax and validation problems in one pass
- license write lock is evaluated against the clock on every request
- enabling TOTP keeps the consumed time step (no replay of the setup code)
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>
- one route table with access level, permission and write flag
- session cookie auth, MFA and forced password change gates, CSRF token
plus Origin/Sec-Fetch-Site checks, license read-only lock
- RFC 9457 problem responses with stable codes and field problems
- OIDC authorization code flow with PKCE, state cookie and nonce
- contract tests: spec valid, routes == spec, every request/response in
the API tests validated against the spec
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- every mutation writes its audit entry in the same transaction
- stable error codes; constraint violations mapped to field problems
- bulk changes and CSV import are all-or-nothing, using savepoints so that
all problems are reported at once
- CSV export neutralizes spreadsheet formulas
- OIDC settings with encrypted client secret, role mapping from claims
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- every Keygen response is verified: Ed25519 signature over request target,
host, date and digest; body digest; date freshness; validation nonce
- machine activation by HMAC-based fingerprint, entitlements, heartbeats
- offline license files (base64+ed25519, aes-256-gcm+ed25519)
- pure state evaluation trial -> valid <-> grace -> read_only with one grace
period for unreachable, suspended and expired licenses
- encrypted cache, periodic revalidation; account ID and public key are
embedded at build time
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server-side filtering/sorting/pagination with whitelisted sort keys, usage
aggregation in SQL, optimistic locking, FQDN maintenance on domain change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- config: YAML file plus environment overrides, day durations, validation
- secrets: AES-256-GCM keyring with key IDs, AAD binding and rotation
- store: pgx pool, embedded goose migrations with downgrade protection,
initial schema with overlap/containment/uniqueness constraints
- storetest: per-test schemas; CI runs them against a PostgreSQL service
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>