- Add secmarks (id-keyed) and vars (key-keyed) resources: migration 0009, model,
store CRUD, REST handlers.
- Compiler rendering for the global-compiled tail: blrules, conntrack, secmarks
render on enforcing devices; vars render on every device. This closes the
rendering gap left by batch 1 (blrules/conntrack were stored but not rendered).
Storage + CRUD (migration 0007, model, id-keyed store, REST handlers) + compiler
rendering, each owned by a device. proxy_arp/proxy_ndp share the ProxyEntry
shape via table-parameterized store helpers.
Storage + CRUD (migration 0006, model, id-keyed store, REST handlers) plus
compiler rendering: each section is owned by a device and projected into that
device's rendered config (hosts/providers/routes/routing_rules).
- Wire policy CRUD (the policies table existed from 0001 but had no endpoint;
policies already render in the compiler, so this closes that loop).
- Add blrules (blacklist/whitelist) and conntrack resources: migration 0005,
model types, id-keyed store CRUD (generation-bumping), and REST handlers.
Compiler rendering of blrules/conntrack into device configs is a tracked
follow-up (policy already renders).
Devices carry a reachable_prefixes set (migration 0004) reported by their agent
from the kernel FIB, via a new agent-authed POST /devices/{name}/routes endpoint.
This is scoping/observability data, so it does not bump the config generation and
is exposed on the device resource.
It deliberately does NOT limit which rules a device enforces: the compiler still
emits every applicable rule on every enforcing device. The interface-agnostic,
address-matched rule form is correct under ECMP precisely because it does not
depend on which device is on the path, and most routers hold a default route
anyway — so reachability could not meaningfully narrow the rule set. The reported
FIB is kept for fleet visibility and future zone-origin validation.
- Add snat/masquerade, netmap, and 1:1 nat as stored, terraformable resources:
migration 0003, model types, store CRUD (id-keyed, generation-bumping), and
REST handlers. These are the global-intent/device-resolved NAT tier; compiler
rendering of NAT into per-device configs is a tracked follow-up.
- Add a testcontainers-backed store integration suite exercising the CRUD
lifecycle, generation bumping, source/dest grammar validation, and FK cascade
against a real Postgres. It self-skips under 'go test -short' (the CI path) so
a container runtime is only needed for the full run.
Add GET /{name} and DELETE /{name} for zones, address-groups, portgroups,
fabrics, devices, and bindings, plus GET /rules/{id}, with the matching store
Get/Delete methods (deletes bump the generation and 404 on no-match). This gives
the resources full read/update/delete lifecycle so the Terraform provider can
manage them.
Project the fleet-global model through a device's bindings into a rendered,
interface-agnostic config: rules compile to saddr/daddr forward matches with no
iif/oif so they are correct under FRR/ECMP. Firewalls always enforce; routers
enforce only when their fabric opts into defense-in-depth. Referenced address
groups are emitted as named sets carrying their source (static CIDRs, dns FQDNs,
or asn numbers) so membership churns out-of-band without a rule reload. Wire
GET /devices/{name}/config to compile and serve YAML, generation-stamped. Add
portgroups/policies/settings store methods and portgroup CRUD. Pure Render is
unit-tested for enforcement gating, ASN set emission, and resolver precedence.
Add the store package (pgx-backed repository) with CRUD for the core resources
the compiler needs: fabrics, zones, address groups, portgroups, devices,
bindings, rules, policies. Every mutation bumps a global config generation.
Wire real JSON CRUD handlers with token auth, source/dest grammar validation on
rule create, and the agent status-report endpoint. Migration 0001 verified
against Postgres 17.