Commit Graph

16 Commits

Author SHA1 Message Date
Debian
4f6b7b34fc feat: install.sh One-Liner-Bootstrap + System-Adressen-Card auf IP-Page
scripts/install.sh: full curl-Onliner für Debian 13 trixie analog
mail-gateway/scripts/install.sh — OS+Arch-Detection, Pre-flight-
Tools, GPG-Key (nmg.asc, geteilt mit mail-gateway), APT-Source-Line
trixie main, apt install edgeguard, Service-Smoke + healthz-Probe.
Bestimmungsort: get.netcell-edgeguard.de (Hosting separat).

UI: IP-Adressen-Page bekommt eine "Adressen am Kernel"-Card oben,
analog zur Networks-Page. Listet jede vom Kernel sichtbare IP
(lo + eth0 + …) mit Family-Tag (IPv4/IPv6) — read-only. Verwaltete
Adressen darunter wie zuvor. User-Feedback: "die bestehenden
IP-Adressen werden nicht angezeigt" — adressiert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 16:23:58 +02:00
Debian
ca03e69637 feat: Network/IP-Verwaltung + Mailguard-Design-Übernahme
Backend:
* Migration 0009_networks: network_interfaces (ethernet|vlan|bond|
  bridge|wireguard, role wan|lan|dmz|mgmt|cluster, parent + vlan_id
  für VLANs) + ip_addresses (interface_id FK, address+prefix, is_vip
  + vip_priority für Cluster-Failover-VIPs).
* Repos services/networkifs + services/ipaddresses + Models +
  Handler /api/v1/network-interfaces (CRUD + /:id/ip-addresses)
  und /api/v1/ip-addresses (CRUD).
* /api/v1/system/interfaces refactored auf Go-natives net.Interfaces()
  statt `ip -j addr show` shell-out — die systemd-Sandbox blockt
  AF_NETLINK auch für Go's runtime, deswegen edgeguard-api.service
  RestrictAddressFamilies um AF_NETLINK ergänzt. Output-Shape
  bleibt identisch (ifindex, ifname, flags[], mtu, link_type,
  address, addr_info[]) — Frontend muss nicht angepasst werden.

Frontend:
* Networks-Page (/networks): "System-discovered Interfaces"
  read-only Tags-Card oben, deklarierte Interfaces unten als
  Tabelle mit Modal-CRUD; Type-Switch zeigt parent+vlan_id-Felder
  bei type=vlan; Role-Tags farbig (wan blau, lan grün, dmz orange,
  mgmt purple, cluster magenta).
* IPAddresses-Page (/ip-addresses): Tabelle pro Interface, VIP-
  Toggle blendet vip_priority-Eingabe ein. Goldenes VIP-Tag in der
  Liste.
* Sidebar erweitert um Networks + IP-Adressen + section-grouping.

Design 1:1 von mail-gateway/management-ui/ übernommen:
* enterprise.css verbatim (Inter-Font via Google CDN statt local
  woff2), Sidebar 240px dunkler Gradient #0B1426→#101D33→#0D1829,
  branding-accent #1677ff für Active-State, abgerundete Cards mit
  shadow-Token, Header weiß mit subtilem backdrop-filter.
* AntD-Theme-Tokens: colorPrimary #0EA5E9, fontSize 13, fontFamily
  'Inter', controlHeight 34, borderRadius 6.
* Layout-Komponenten neu strukturiert: AppLayout/Sidebar/Header
  matchen mailguard-Klassen-Naming (.app-layout, .main-content,
  .sidebar-section, .sidebar-menu-item.active, .header-left, …).
* Sidebar mit 4 Sektionen (Übersicht / Routing / Netzwerk / System)
  + Logo-Header + Versions-Footer.

Live-deployed auf 89.163.205.6: Networks-Endpoint listet eth0
(89.163.205.6/24, MAC bc:24:11:64:29:e8) + lo, frontend zeigt sie
als System-Tags in der Networks-Page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 16:08:44 +02:00
Debian
f0589e5628 feat(deploy): (d) end-to-end .deb install on 89.163.205.6 grün
Box (Debian 13 Trixie, amd64): apt install ./edgeguard-{api,ui,meta}.deb
zieht postgresql-17, haproxy 3.0, certbot, openssl, etc. nach.
postinst flow läuft sauber: migrate check → initdb → migrate up
(8 migrations) → render-config → install HAProxy drop-in → restart
haproxy → enable api+scheduler. Self-register in ha_nodes nach
Setup-Wizard funktioniert.

End-to-end smoke gegen 89.163.205.6:
* :80  → 301 Moved Permanently → https://
* :443 → TLS termination (self-signed _default.pem aus postinst)
        → JSON envelope vom api_backend (HTTP/2 + HSTS)
* /    → React index.html aus /usr/share/edgeguard/ui/

Änderungen:
* control: keydb-server von Depends nach Recommends — single-node v1
  installiert ohne KeyDB. Phase-3.1 multi-node bringt es zurück nach
  Depends sobald ein eigenes APT-Repo das Paket bereitstellt.
* postinst: render-config (--no-reload) + HAProxy-Drop-in installen +
  systemctl restart haproxy als zusätzliche Schritte.
* postrm: drop-in auf remove + purge entfernen, daemon-reload, ggf.
  haproxy auf distro-default zurückreloaden.
* deploy/systemd/haproxy-edgeguard.conf: Drop-in lenkt HAProxy-Unit
  auf /etc/edgeguard/haproxy/haproxy.cfg statt /etc/haproxy/haproxy.cfg.
  After=edgeguard-api.service vermeidet 503-Race in den ersten 5s.
* scripts/apt-repo/build-package.sh: shippt Drop-in unter
  /etc/edgeguard/systemd/haproxy-edgeguard.conf in der edgeguard-api.deb.
* haproxy.cfg.tpl: http-request redirect vor use_backend → keine
  HAProxy-Warning beim Parsen mehr.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:02:14 +02:00
Debian
c7e5b28cf7 build: make deb pulls UI build via bun, drop stale angie comment
* Makefile: ui target prefers bun (with npm fallback) so make deb
  end-to-end reproduces a fresh dist/. deb-amd64/deb-arm64 now
  depend on ui, otherwise stale (or missing) management-ui/dist
  goes into edgeguard-ui.deb.
* deploy/systemd/edgeguard-api.service: stale "angie" reference
  in hardening comment removed.

Verified locally: make deb-amd64 produces three packages —
edgeguard-api_<v>_amd64.deb (6.9 MB), edgeguard-ui_<v>_all.deb
(320 KB), edgeguard_<v>_all.deb (4 KB meta). dpkg-deb -c
confirms layout matches packaging spec (binaries in /usr/bin,
units in /etc/systemd/system, UI under /usr/share/edgeguard/ui).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:08:13 +02:00
Debian
cb5691cf3c feat(cluster): (c) Phase-3 MVP — stable node-id + self-register + Cluster-Page
Minimal-Slice für Phase-3-Cluster:
* internal/cluster/node_id.go — stable UUID 'n-<16hex>' in
  /var/lib/edgeguard/node-id, idempotent über reboots.
* internal/cluster/store.go — ha_nodes-Repo (List/Get/UpsertSelf)
  via pgxpool. EnsureSelfRegistered upsertet die lokale Row beim
  Boot mit FQDN aus setup.json.
* internal/handlers/cluster.go — GET /api/v1/cluster/nodes liefert
  alle ha_nodes plus local_id (für UI-Highlighting).
* main.go: nach DB-Pool-Open wird EnsureSelfRegistered (nur wenn
  setup.completed) ausgeführt, ClusterHandler registriert.
* management-ui/src/pages/Cluster/index.tsx — Tabelle mit Node-ID,
  FQDN, Rolle, Beitrittszeit; eigene Node mit "diese Node"-Tag
  markiert. Sidebar-Eintrag + i18n de/en.

Bewusst NICHT in dieser Runde: cluster-init/cluster-join CLIs, KeyDB
Active-Active config-gen, PG streaming replication, mTLS zwischen
Peers, License-Leader-Election. Diese kommen mit dem ersten echten
Multi-Node-Test (Phase 3.1) — sonst Code ohne Smoke-Möglichkeit.

End-to-end-Smoke: setup → restart → ha_nodes hat 1 Row mit
fqdn=eg.example.com, /cluster/nodes liefert sie korrekt mit
local_id-Markierung.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:52:54 +02:00
Debian
6525cb1a41 feat(acme): (b) HTTP-01 Webroot-Handler in der API
internal/handlers/acme.go: GET /.well-known/acme-challenge/:token
serviert Token-Files aus /var/lib/edgeguard/acme/.well-known/
acme-challenge/ (default; override via EDGEGUARD_ACME_WEBROOT).
Validiert Token-Charset gegen RFC 8555 §8.3 (base64url, 1..128
chars) und prüft mit filepath.Abs+HasPrefix gegen path-traversal.
Mounted auf der bare gin Engine vor SetupGate/RequireAuth — ACME
muss unmittelbar nach HAProxy-Start funktionieren, lange bevor
ein Admin Setup abgeschlossen hat.

4 Unit-Tests (valid/missing/dir/invalid-charset). Live-Smoke gegen
/tmp/eg-acme bestanden.

Test gegen 89.163.205.6 mit echtem certbot wird Teil von (d) —
unnötig Let's-Encrypt-Rate-Limits zu verbrennen ohne stehendes
HAProxy-Frontend auf dem Server.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:24:42 +02:00
Debian
0b45b23d45 feat(ui): (a) Backends + Routing-Rules + Settings pages + Sidebar
CRUD-Pages analog Domains:
* Backends: AntD Table + Modal-Form mit name, scheme, address, port,
  health_check_path, active. TanStack-Query gegen /api/v1/backends.
* RoutingRules: Table mit Domain-Name- und Backend-Label-Resolution,
  Modal mit Select-Pickern für Domain + Backend, Path-Prefix,
  Priority, Active. Drei parallele Queries (rules, domains, backends)
  liefern die Listen.
* Settings: read-only Descriptions-Cards mit /system/health und
  /setup/status. Editable Werte folgen später.

Sidebar erweitert um Backends, Routing-Rules, Settings (mit AntD-
Icons). i18n de/en für alle drei neuen Seiten.

bun run build + npx tsc -b strict (0 errors). Live-Smoke gegen API:
SPA-Routes /backends, /routing-rules, /settings antworten 200 mit
index.html (NoRoute fallback wirkt).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:23:00 +02:00
Debian
b507d2a7d5 feat(ui): Frontend MVP — React 19 + AntD 6 + Vite + StaticFS-Wiring
Scaffold und Core-Infrastruktur 1:1 nach enconf-Pattern (netcell-
webpanel/management-ui), reduziert auf EdgeGuard-Scope (kein reseller/
customer-Roles, keine codemirror/extensions). Stack: React 19 + AntD 6
+ TS strict + Vite + TanStack-Query + zustand + react-i18next.

Layout: AppLayout (Sider+Header+Content), Sidebar (Dashboard/Domains),
Header (User-Dropdown + Logout). i18n mit de/en common.json.

Pages: Login (POST /auth/login), Setup-Wizard (POST /setup/complete),
Dashboard (Health-Polling + Statistics), Domains (volles CRUD via
TanStack-Query gegen /domains-API). UpdateBanner-Komponente
(/system/package-versions, alle 5 min poll, /system/upgrade trigger)
ist von Tag 1 wie vom User gefordert eingebaut.

API-Wiring: cmd/edgeguard-api/main.go mountUI() — gin StaticFS für
/usr/share/edgeguard/ui/ (overridebar via EDGEGUARD_UI_DIR), echte
Files werden direkt geserved, alle nicht-API-Pfade fallen via
NoRoute auf index.html für React-Router-SPA. Wenn dist/ fehlt:
HTML-Placeholder mit Build-Hinweis.

Verifiziert: bun install + npx tsc -b strict (0 errors) + bun run
build (12 chunks). End-to-end gegen /tmp/eg-api: / serviert echte
React-index.html, /domains SPA-Fallback, /api/v1/* JSON, /assets/*
direkt, /api/v1/nonexistent korrekt 404.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:16:04 +02:00
Debian
914538eed1 feat(configgen): Phase 2 Config-Generator + nginx → HAProxy-only Pivot
Architektur-Pivot: nginx fällt komplett weg. HAProxy 2.8+ übernimmt
TLS-Termination, L7-Routing per Host-Header und LB. ACME-Webroot
und Management-UI werden von edgeguard-api ausgeliefert (Phase 3
implementiert die zugehörigen Handler); HAProxy proxied
/.well-known/acme-challenge/* und Management-FQDN-Traffic an
127.0.0.1:9443. Eine Distro-Abhängigkeit weniger, ein Renderer
weniger, sauberere Trennung.

Renderer (alle mit Embed-Templates + Tests):
* internal/configgen/  — atomic write + systemctl reload helpers
* internal/haproxy/    — :80 + :443, ACME-ACL, Host-Header-Routing,
                         Stats-Frontend, api_backend Fallback
* internal/firewall/   — default-deny input, stateful baseline,
                         SSH-Rate-Limit, :80/:443 accept,
                         Cluster-Peer-Set für mTLS :8443,
                         Custom-Rules aus PG
* internal/{squid,wireguard,unbound}/ — Stubs (ErrNotImplemented)

Orchestrator + CLI:
* internal/services/configorch/  — fester Reihenfolge-Run, Stubs
                                   sind soft-skip statt fatal
* cmd/edgeguard-ctl render-config [--no-reload] [--only=svc1,svc2]

Packaging:
* postinst: /etc/edgeguard/nginx raus, /var/lib/edgeguard/acme rein,
  self-signed _default.pem via openssl req (damit HAProxy startet
  bevor certbot etwas issuet hat)
* control: Depends nginx raus, openssl rein
* edgeguard-ui: dependency auf nginx weg, "Served by edgeguard-api
  gin StaticFS"

Live-Smoke: render-config gegen lokale PG schreibt /etc/edgeguard/
haproxy/haproxy.cfg + nftables.d/ruleset.nft korrekt; CRUD-Test aus
Phase 2 läuft weiter unverändert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 10:59:52 +02:00
Debian
0a6f81beaa feat(api): Phase 2 — REST-API MVP + CRUD für Domains/Backends/Routing
REST-API mit Response-Envelope (1:1 mail-gateway), HS256-JWT-Signer
(Secret persistent unter /var/lib/edgeguard/.jwt_fingerprint),
Setup-Wizard (Bcrypt-Admin-Passwort in setup.json), Auth-Middleware
(Cookie + Bearer), Setup-Gate. Update-Banner-Endpoints
/system/package-versions + /system/upgrade ab Tag 1 wired (Pattern
aus enconf-management-agent: systemd-run detached, HTTP-Response
geht VOR dem Self-Replace raus).

CRUD-Repos für domains/backends/routing_rules mit pgxpool +
handgeschriebenem SQL (mail-gateway-Pattern, kein GORM zur Laufzeit).
Audit-Log-Schreiber auf jede Mutation, NodeID aus /etc/machine-id.
DB-Pool öffnet best-effort — ohne erreichbare PG bleiben CRUD-Routen
unregistriert, Auth/Setup/System antworten weiter (Dev ohne PG).

End-to-end live-getestet gegen lokale postgres-16: Setup → Login →
POST/PUT/DELETE Backends + Domains + Routing-Rules → audit_log
schreibt 5 Zeilen mit korrektem actor/action/subject. Graceful
degrade ohne DB ebenfalls verifiziert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:56:10 +02:00
Debian
106ef95f6d feat(ctl): edgeguard-ctl migrate + initdb wired into postinst
migrate up|down|check|dump (1:1 nmg-ctl-Pattern, ruft internal/database
Migrate/MigrateDown/ValidateMigrations/CopyEmbeddedMigrationsTo).
initdb prüft pg_roles/pg_database und legt Role + DB idempotent via
sudo -u postgres psql an, mit Identifier-Whitelist gegen Injection.
postinst wirt die drei Schritte vor systemd-enable: migrate check
(Pre-Flight ohne DB), initdb, migrate up (als edgeguard-User via
Socket-Peer-Auth). cluster-join/promote/dump-config bleiben explizit
Phase-3-Stubs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 08:18:55 +02:00
Debian
b307a7b1f7 feat(db): Phase 1 — DB-Schema, goose-Migrations, GORM-Models
Initialer Schema-Set (8 Migrationen, 13 Tabellen) für EdgeGuard v1:
users + audit_log + system_settings, ha_nodes, backends/domains/
routing_rules/tls_certs, forward_proxy_acls, wireguard_peers,
firewall_rules, dns_zones/dns_records, licenses. Migrations liegen
in internal/database/migrations/ (analog mail-gateway) und werden
per //go:embed ins Binary gepackt — keine separate SQL-Dateien im
.deb. ValidateMigrations + Test schützen vor Duplicate-Versionen
(mail-gateway 2026-05-08-Vorfall). GORM-Models für alle Tabellen,
sensible Felder (password_hash, private_key_enc) sind json:"-".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 23:44:44 +02:00
Debian
9f75eec756 refactor: Angie → nginx + Unbound (DNS Forwarder + Cluster-Split-Horizon)
Reverse-Proxy von Angie (eigenes APT-Repo) auf nginx (Distro) umgestellt
— vereinfacht Bootstrap (kein angie.software-Repo mehr), reduziert
Offene-Punkte (arm64-Verfügbarkeit entfällt). Neuer Service Unbound
übernimmt zwei Rollen: Caching-Forwarder mit DNSSEC und Cluster-internes
Split-Horizon (Local-Zone eg.cluster, Peer-Adressen aus PG ha_nodes,
Reload via unbound-control). Architektur-Spec §7.5 dokumentiert beide
Rollen + Config-Schichtung.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 23:06:56 +02:00
Debian
cf10bd4072 docs: CLAUDE.md + agent.md für Agent-Factory Pipeline 2026-05-08 19:46:15 +02:00
Felix Netzel
84ea8c86f5 feat: working .deb build for edgeguard-api + meta
scripts/apt-repo/build-package.sh produces:
  - edgeguard-api_<ver>_<arch>.deb  (3 Go binaries, systemd units,
    /etc/edgeguard/edgeguard.yaml as conffile)
  - edgeguard-ui_<ver>_all.deb       (skipped while management-ui/dist
    is empty)
  - edgeguard_<ver>_all.deb          (meta, Depends api+ui)

Verified locally on amd64:
  - go build ./...           ✓
  - make deb-amd64           ✓
  - api binary serves        ✓
    GET /api/health → 200 {"status":"ok","version":"0.0.1-dev"}
  - dpkg-deb -I + -c clean   ✓
2026-05-08 19:04:21 +02:00
Felix Netzel
0ceab4c814 chore: initial skeleton
- docs/architecture.md: native rewrite plan (5 services + control plane,
  Active-Active cluster like nmg, Floating-IP for HTTP ingress)
- cmd/edgeguard-{api,scheduler,ctl}: minimal Gin + CLI stubs
- packaging/debian/edgeguard-{api,ui,meta}: control + maintainer scripts
- deploy/systemd/edgeguard-api.service + edgeguard-scheduler.service
  with hardening defaults
- Makefile: build / cross-compile (amd64+arm64) / deb / publish targets
- scripts/install.sh + scripts/apt-repo/build-package.sh stubs
2026-05-08 18:45:41 +02:00