Commit Graph

28 Commits

Author SHA1 Message Date
taylanbakircioglu 2e7db4d99f fix: v1.5.1 — Round-23 + Round-24 audit follow-ups (Bulgu #83 → #93)
A live-deployment audit pass over the v1.5.0 Site Wizard + ACME
Diagnostic Panel surface. Two adversarial review rounds (R23, R24)
each capped by an end-to-end smoke test against a multi-cluster
staging deployment.

Bulgu #83 — Frontend Management page warned about stale data
without a clear retry CTA. The toast now carries an in-place
"Reload" action and the page-level Empty state surfaces the same
recovery affordance, so operators never get stuck on a stale-data
view without an obvious way out.

Bulgu #84 — ACME diagnostics ran with the wrong "last_heartbeat"
column reference against the agents table. Aligned the SELECT
with the actual schema column (`last_seen`); pinned by an idempotent
regression test in `test_acme_diagnostics.py`.

Bulgu #85 — ACME order error_detail rendering could leak the raw
asyncpg/SQL exception class name when humanize_error_detail
encountered an unhandled CA response shape. Added a backwards-
compatible fallback branch that emits an "ACME error (raw)" panel
without exposing parse_error class name to the user.

Bulgu #86 — Multi-cluster apply with concurrent rejects could
leave wizard_staged orders dangling without their parent draft.
Pinned via reject_order_with_cluster_orphan test.

Bulgu #87 — Frontend Management page list virtualization
mis-keyed during a re-sort + stale-row replace race; fixed by
keying rows on `id + version` so React reconciler does not reuse
DOM for a logically different row.

Bulgu #88 — Site Wizard "Cancel" mid-flow now surfaces an
unsaved-draft prompt with explicit Save / Discard buttons (and
the same prompt on browser tab close), so the operator never
loses 5 steps of input to an accidental ESC.

Bulgu #89 — Existing-cert SSL mode showed an empty dropdown when
the cluster had >100 certs because the listing endpoint
default-limited results. Endpoint now exposes pagination AND
the wizard switches to client-side filtering above 50 rows.

Bulgu #90 — ACME pre-check on the wizard preview path did NOT
re-validate the account against `letsencrypt_accounts` if the
operator stepped Back/Forward between SSL and Review. Added a
debounced re-validation on Review entry.

Bulgu #93 — Site Wizard hsts_enabled toggle in HTTPS frontend
was idempotent-by-name (the generated `http-response set-header
Strict-Transport-Security` line could duplicate across a Save +
Apply cycle). The renderer now upserts the header in place.

Cumulative outcome: backend pytest 1084/1084, frontend lint
clean, and a 6-hour live-deployment smoke session against staging
with no regressions reported.
2026-05-14 00:06:02 +03:00
taylanbakircioglu 02b1cb2bca feat: v1.5.0 — Site Wizard (Issue #14) + ACME Diagnostic Panel (Issue #13)
Closes #13, Closes #14.

This release squashes the v1.4.0 → v1.5.0 development line. v1.4.0
shipped the ACME stability & enterprise audit (Issues #10/#11/#12).
v1.5.0 builds on that foundation with two co-equal headline features
plus a 22-round audit campaign hardening the prior configuration
surface. License remains MIT for v1.5.0 (relicense to AGPL-3.0
lands in v1.5.2).

------------------------------------------------------------------
HEADLINE FEATURE A — ACME Diagnostic Panel (Issue #13)
------------------------------------------------------------------
A live pre-flight + post-failure diagnostic surface for every ACME
order, reachable from the ACME Automation page. The panel exists
to make ACME failures legible to operators who do NOT have shell
access to the API host.

Endpoints (`backend/routers/acme_diagnostics.py`):
  POST /api/letsencrypt/orders/{order_id}/diagnostics
       Run the full 5-check suite (DNS / port-80 / routing /
       account / agents) and humanize the order's `error_detail`
       (>=11 RFC-8555 problem types, backwards compatible with
       legacy plain-string failures).
  POST /api/letsencrypt/orders/{order_id}/diagnostics/
                                {check_id}/rerun
       Re-run a single check in place — used by the "Re-run"
       button on every row of the modal's pre-flight table.
  GET  /api/letsencrypt/orders/{order_id}/events
       Merged event timeline combining the typed
       `acme_order_events` rows with correlated
       `user_activity_logs` entries (resource_type =
       'letsencrypt_order' AND resource_id = order_id). The
       diagnostic modal auto-tails this timeline every 5 seconds
       while open.

Service-level checks (`backend/services/acme_diagnostics.py`):
  * DNS resolution via stdlib socket.gethostbyname_ex through
    run_in_executor (intentionally avoiding an aiodns runtime
    dep for v1.5.0).
  * Port-80 HEAD probe, target locked to the order's domains,
    success on HTTP 200 OR 404, warns on egress timeout
    (corp egress policies routinely blackhole outbound 80 —
    fail-hard would be too noisy).
  * SSRF guard: probe refuses non-public IPs and surfaces the
    skip in the diagnostic result; IPv4-mapped IPv6 normalisation
    closes the `::ffff:169.254.169.254` cloud-metadata vector.
  * HAProxy routing presence check: matches the order's
    cluster_ids to a port-80 HTTP frontend.
  * ACME account validity check against `letsencrypt_accounts`.
  * Agent presence check (>=1 active agent in target cluster).
  * Every sub-check wrapped in a wall-clock timeout to bound
    impact on the API event loop.

RBAC: ssl.read for run, ssl.read for events. Per-user 5/min rate
limit on both run and rerun, backed by the (user_id, action,
created_at DESC) composite index.

Frontend (`frontend/src/components/ACMEAutomation.js`):
  * "Diagnose" button on every order row + the existing
    "stuck order" warning row.
  * Modal with two tabs:
    - Pre-flight Checks (Antd Table with status pills + Re-run
      buttons + humanized error banner)
    - Event Log (Antd Timeline with auto-tail polling, scroll-
      to-bottom, pause-on-hover)
  * Correlation IDs surfaced in error banners and individual
    check fail details for backend-log lookup.

------------------------------------------------------------------
HEADLINE FEATURE B — Site Setup Wizard (Issue #14)
------------------------------------------------------------------
A single guided flow that creates a Backend + Servers + HTTP
Frontend (and optional HTTPS Frontend) in one atomic transaction.

Endpoints (`backend/routers/site_wizard.py`):
  POST /api/site-wizard/preview     — diff-preview the changeset
  POST /api/site-wizard/create      — atomic execute
  POST /api/site-wizard/reject      — clean rollback (including
                                       any wizard_staged ACME
                                       orders)
  GET  /api/site-wizard/drafts      — draft persistence
  PUT  /api/site-wizard/drafts/{id} — save/update
  DELETE /api/site-wizard/drafts/{id}

Feature surface:
  * One screen captures both backend (mode + servers) AND
    frontend (http + optional https + SSL mode) inputs.
  * SSL modes: ACME (new order, HTTP-01 only for v1.5.0),
    Upload (existing PEM), Existing (link to a stored cert),
    or None.
  * ACME-staged path: wizard_staged_until watermark on the
    `letsencrypt_orders` row defers finalisation until agent
    confirmation; per-mode reject cleanly cancels and rolls
    back the staged order.
  * Live diff preview against the cluster's current generated
    config (renderer-evolution noise stripped — track-sc<N>
    dedup, per-server cookie strip, defaults-cookie
    inheritance, listen-block flattening).
  * Draft persistence with PEM stripped at save time (private
    keys never round-trip through the drafts table).
  * Per-cluster multi-tenancy: drafts and wizard_staged orders
    are isolated to the creating user's cluster scope.

Frontend (`frontend/src/components/SiteWizard.js`):
  * 4-step Antd Steps flow: Backend → Frontend → SSL → Review.
  * Render the live diff preview inline before commit.
  * Antd Form-level validation mirrors backend Pydantic
    validators (numeric bounds, HAProxy reserved keywords, ALPN
    consistency, IPv6 scope-id, domain regex, server name
    dedup).

------------------------------------------------------------------
AUDIT CAMPAIGN — Rounds 1 → 22 (Bulgu #1 → #82)
------------------------------------------------------------------
v1.5.0 includes 22 adversarial review passes. Each round produced
its own commit set in the corporate development line; this squash
collapses those into the v1.5.0 release artefact. Highlights:

  Round 1-4   Site Wizard core: dry-run parity, single-line
              value injection guard, ACL -f pattern-file block,
              SSL parity, timeout regex, form-state pin.
  Round 5-7   defaults-cookie inheritance, server-named-cookie
              guard, fe/be mode mismatch, duplicate server
              names, health_check_uri + server_address
              validators.
  Round 8-10  cookie_name / cookie_options newline-injection
              guard, dry-run parity (round 9), TCP-mode HTTP-only
              feature blockers.
  Round 11    SSL name path traversal + health-check >= 1.
  Round 12-13 SSL & ACME deep dive (Bulgu #23-#32).
  Round 14    single-line value injection (Bulgu #33).
  Round 15-17 ACME multi-tenant UX, numeric bounds, HAProxy
              reserved keywords, ALPN/TLS consistency,
              all-backup, multi-domain & multi-user enterprise
              edges, drain/HSTS/post-completion (Bulgu
              #34-#53).
  Round 18-21 concurrency, agent state, TCP-mode HTTP-only,
              list size caps, IPv6 scope-id, preview account
              validation, TCP backend + balance uri reject
              (Bulgu #54-#61).
  Round 22    FE error visibility + 3x stale-data lockouts,
              referential integrity + cascade safety,
              authentication & authorization, multi-cluster
              isolation, apply_pending_changes concurrency,
              script injection + bulk import multi-tenancy,
              prefix-stripped signature comparison
              (Bulgu #62-#82).

------------------------------------------------------------------
NO CORPORATE-SPECIFIC ARTIFACTS
------------------------------------------------------------------
This squash deliberately sanitises corporate hostnames, container
registry references, and TLS secret names into generic
placeholders (`your-registry.example.com/your-org`,
`haproxy-openmanager*.example.com`, `wildcard-tls`,
`taylanbakircioglu/haproxy-openmanager-*`) so the public artefact
contains no internal infrastructure detail. Pilot / development
history that retained those values stays in the corporate fork
and is NOT part of this commit.
2026-05-14 00:04:19 +03:00
taylanbakircioglu f37f3afd71 feat: bulk import change detection, multi-select delete, auto-content stripping
- Server-level change detection in bulk import (field-by-field comparison
  for 17 server attributes with UPDATE/NO CHANGES status and tooltip)
- Multi-select delete for backends and frontends with dependency checks
- Dashboard "Backends Summary" address column for servers
- Fix unique constraint violation on bulk-create for existing servers
  (natural key lookup matching DB constraint instead of backend_id FK)
- ORDER BY is_active DESC on all entity lookups to prefer active records
- Strip auto-generated content (ACME, rate-limit, WAF) from bulk import
  comparison to eliminate false positive changes on re-import
- Fix toolbar overflow with Space wrap prop
- Frontend bulk delete modal clarity (selected vs deletable count)
- Version bump to 1.3.0

Made-with: Cursor
2026-04-14 20:21:07 +03:00
taylanbakircioglu 71c717364c fix: allow dot character in entity names for UI and backend validation
Bulk import accepted dots in frontend/backend/server names but UI and
backend validators rejected them with ^[a-zA-Z0-9_-]+$. After import,
entities with dots could not be edited. HAProxy itself allows dots in
section names, so the regex is expanded to ^[a-zA-Z0-9_.-]+$ across
all 12 validation points (5 React form rules, 1 ACL char-strip,
3 Pydantic validators, 1 WAF validator, 2 config-validator warnings).
2026-04-14 01:26:03 +03:00
taylanbakircioglu 13179279d6 fix: port conflict validation ignoring bind_address and CORS on non-standard ports
- Fix frontend port conflict validation to consider bind_address+port
  combination instead of port-only. HAProxy allows same port on different
  bind addresses (e.g., bind 10.0.0.1:443 vs bind 10.0.0.2:443). This
  was blocking frontend edit/save in multi-VIP environments.
- Add form field dependency so port re-validates when bind_address changes.
- Fix API URL construction using window.location.host instead of hostname
  to preserve non-standard ports (e.g., :8080), preventing CORS errors
  in BulkConfigImport.
- Make CORS_ORIGINS configurable via environment variable.
2026-04-13 05:24:03 +03:00
taylanbakircioglu c2766eadbd feat: dark mode support, UI improvements, and version bump to v1.2.0
- Full dark mode support across all pages with lightbulb toggle in header
- Theme preference persisted in localStorage across sessions
- Ant Design 5 token-based theming (40+ components updated)
- Recharts dark mode: axes, grids, tooltips adapt to theme
- Login page redesigned with product-consistent blue-gray palette
- Overscroll bounce background matches dark theme
- All Servers search with multi-field filtering
- Bulk Config Import UI streamlined with collapsible guidelines
- ConfigProvider moved above AppContent for correct token resolution

Made-with: Cursor
2026-04-03 01:16:05 +03:00
taylanbakircioglu 93d7ad8fdb feat: add ACME Auto SSL with Let's Encrypt integration (v1.1.0)
Add automated SSL certificate management via ACME protocol (RFC 8555):
- Full ACME client implementation (account registration, HTTP-01 challenges, certificate issuance/renewal)
- Configurable ACME providers (Let's Encrypt, ZeroSSL, custom CA) via Settings UI
- Auto-renewal scheduler with PENDING -> Apply -> APPLIED flow alignment
- ACME account management (register, deactivate) from UI
- Certificate request wizard with domain validation and cluster targeting
- Zero changes to HAProxy agent scripts - challenges routed through existing architecture
- Comprehensive security hardening (no private key exposure in API responses)
- Full backward compatibility with existing SSL, Apply, Rollback, and Restore workflows
- Updated README, API documentation, and Kubernetes deployment notes
- Version management embedded in code (v1.1.0)
- UI messaging improvements for agent-pull architecture accuracy

Made-with: Cursor
2026-04-02 00:25:50 +03:00
taylanbakircioglu 922bc2ce6d improve: SSL certificate listing reliability, error visibility, and ARM64 support
Fixes #6

- Fix NameError in soft-deleted certificate reactivation path by
  reordering variable extraction before DB operations
- Replace silent empty-array returns with HTTP 500 on SQL errors,
  making failures visible in both API responses and server logs
- Add primary_domain migration for schema consistency across fresh
  and upgraded installations (backfill from legacy domain column)
- Use primary_domain in non-cluster SSL query branch for schema
  compatibility
- Surface SSL fetch errors in frontend via toast notifications
- Harden connection cleanup in error handlers with try/except
- Add QEMU + Buildx for linux/amd64,linux/arm64 multi-platform
  Docker image builds
- Update GitHub Actions to latest versions (checkout v4, login v3,
  build-push v6)

Made-with: Cursor
2026-03-30 10:42:28 +03:00
taylanbakircioglu 4780f0c4d6 feat: add visual ACL Rule Builder for frontend management
Replace plain TextArea inputs with an interactive card-based visual builder
for ACL rules, backend routing rules, and redirect rules. Includes:

- Structured ACL definition cards with match type, flags, and value fields
- Backend routing cards with operator (if/unless) and ACL condition selector
- Redirect rule cards with type, target, code, and condition fields
- Visual ↔ Raw mode toggle for each section
- HAProxy config preview panel
- Safe flag serialization order (-i → -m → -f) to prevent parse errors
- Guard against empty/incomplete rules in serializers
- Context-aware flag placeholder hints per match type category

Made-with: Cursor
2026-03-18 18:45:35 +03:00
taylanbakircioglu 946b1a8e84 fix: Default Backend select filterOption crash on search
Fixed TypeError "t.children.toLowerCase is not a function" when searching
in Default Backend dropdown after editing a frontend.

Root cause: option.children was a React element array (multiple JSX parts),
not a string, so toLowerCase() failed.

Solution: Added label prop to Option and use optionLabelProp="label" pattern
(consistent with SSL Certificates Select in same file).

Changes:
- Added optionLabelProp="label" to Select component
- Added label={backendLabel} to each Option
- Changed filterOption to use option.label instead of option.children
- Users can now search by backend name, server count, or "No servers"
2026-01-28 16:04:42 +03:00
taylanbakircioglu 8076f3fcfd feat: add intelligent HAProxy validation error display in UI
- Add haproxy_error_parser.py: Parses HAProxy validation errors with
  confidence scoring, extracts entity type/name, line number, error type
- Add ValidationErrorModal.js: Rich modal with parsed error summary,
  quick fix suggestions, and manual troubleshooting guide
- Update cluster.py: Integrate error parser into agent-sync and
  config-versions endpoints with graceful fallback
- Update ApplyManagement.js: Add validation error banner with quick
  navigation buttons and error detail modal
- Update FrontendManagement.js & BackendServers.js: Handle URL params
  for deep-linking to entity edit forms with field highlighting

Enables users to see actionable validation failure details directly
in the UI without needing server access for debugging.
2026-01-26 15:25:15 +03:00
Taylan Bakırcıoğlu ac5ba4dc58 fix(ssl): add SSL advanced options to GET /api/frontends SELECT queries
CRITICAL BUG FIX: SSL advanced options were not being returned by GET API

Problem:
- Database has ssl_alpn, ssl_npn, ssl_ciphers, etc. columns ✅
- Response builder tries to access them (Line 341-347) ✅
- BUT SELECT statements did NOT include these fields ❌
- Result: f.get('ssl_alpn') returned None for all frontends

Impact:
- Frontend Edit modal always showed empty SSL advanced options fields
- User edits would overwrite existing values with NULL
- Data loss on every frontend edit!

Solution:
- Added all 7 SSL advanced options to ALL 6 SELECT queries:
  1. cluster_id filter (line 174)
  2. cluster_id fallback (line 190)
  3. global include_inactive=True (line 219)
  4. global include_inactive=False (line 231)
  5. global fallback include_inactive=True (line 246)
  6. global fallback include_inactive=False (line 258)

Testing:
- Added debug console.log for SSL advanced options (line 551-559)
- After deployment, check browser console for 'SSL ADVANCED OPTIONS DEBUG'
- Should now show: ssl_alpn: 'h2,http/1.1' etc.

Files Changed:
- backend/routers/frontend.py: All 6 SELECT statements
- frontend/src/components/FrontendManagement.js: Debug logging
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu cb645b5ef9 CRITICAL FIX: Agent Offline Issue - Backend Tolerance for Legacy Agents
🔴 PRODUCTION CRITICAL FIX - Agent HTTP 422 Validation Error

PROBLEM:
- Production agents sending heartbeat with flat system_info fields
- Backend Pydantic model was strict and rejecting unknown fields
- Agents going offline with 'Validation error in request data' (HTTP 422)

ROOT CAUSE:
- Legacy agents embed system_info as flat key-value pairs in heartbeat JSON
- Backend expected only defined fields, rejected extra fields
- No backward compatibility for agent format variations

SOLUTION - BACKEND ONLY (NO AGENT CHANGES):
✅ Added 'extra = "allow"' to AgentHeartbeat Pydantic Config
✅ Backend now accepts both formats:
   - Flat format: operating_system, kernel_version, etc. (legacy agents)
   - Nested format: system_info: {...} (future agents)
✅ Updated comments to clarify backward compatibility

IMPACT:
- ✅ ZERO CHANGES to production agent scripts
- ✅ Existing agents will work immediately after backend deploy
- ✅ Forward compatible with future agent upgrades
- ✅ Tolerant to agent format variations

SAFETY:
- Minimal change (3 lines)
- Pydantic still validates required fields
- Extra fields ignored silently (no breaking changes)
- Production agents continue without restart or upgrade

DEPLOYMENT:
1. Deploy backend (this commit)
2. Agents come online automatically (no action needed)
3. Agent upgrades can happen later (when convenient)

This fix ensures production stability without touching agent scripts.
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu c75b5572d9 fix: Change validation strategy - soft warnings instead of hard blocks
PHILOSOPHY: Don't block what HAProxy allows - guide users instead

Changes:
1. Frontend → Backend (server-less): REMOVED validation, ADDED warning
2. WAF → Frontend: KEPT validation (risk of global apply)

Problem with Previous Approach:
- Backend validation too strict
- Blocked valid HAProxy configs
- Bulk import would fail
- Users confused: "Why can't I do this?"

HAProxy Validation Standards:
- Frontend → Backend without servers: VALID (backend DOWN, 503 errors)
- Frontend without default_backend: VALID (ACL-only routing)
- WAF without frontend: INVALID (applies to ALL frontends - dangerous!)

Solution Part 1: Frontend Validation REMOVED

frontend.py CREATE + UPDATE:
- REMOVED: Backend server check validation
- Reason: HAProxy allows this (valid syntax)
- User can: Create frontend, assign backend, add servers later
- Production: Traffic gets 503 until servers added (acceptable)

frontend.py Changes:
- Lines 408-428: REMOVED backend server validation (CREATE)
- Lines 650-670: REMOVED backend server validation (UPDATE)
- Result: No API blocking, user has full control

Solution Part 2: Frontend UI Warning ADDED

FrontendManagement.js (lines 1402-1443):
BEFORE:
- Backend dropdown: Shows server count
- No warning when selecting server-less backend
- User unaware of consequences

AFTER:
- Tooltip: "Optional: Leave empty for ACL-only routing"
- Placeholder: "Select default backend (optional)"
- onChange handler: Checks server count
- Warning message if no servers:
  "Warning: Backend 'X' has no active servers. Traffic will receive 503 errors until you add servers."
- Visual indicator: Red text for backends without servers
- Display: "backend-name (0 servers) - No servers"

Solution Part 3: WAF Validation KEPT

waf.py CREATE (lines 418-426):
- KEPT: Frontend selection required
- Reason: WAF without frontend = applies to ALL frontends
- Risk: Unintentional global WAF application
- Too dangerous to allow without explicit user action

waf.py UPDATE (lines 676-683):
- KEPT: Cannot remove all frontend assignments
- Reason: Same risk as CREATE

User Experience:
FRONTEND:
- Before: HTTP 400 error, blocked
- After: Warning message, allowed
- Message: Clear consequences, user decides

WAF:
- Before: HTTP 400 error, blocked
- After: Same (still blocked - too risky)
- Reason: Global apply risk too high

Bulk Import Impact:
- Before: Would FAIL on frontends with server-less backends
- After: SUCCESS - no validation blocking
- Result: Bulk import works smoothly

Test Scenarios:
1. Create frontend with server-less backend:
   - API: SUCCESS (no validation)
   - UI: WARNING shown (6 seconds)
   - User: Can proceed with awareness

2. Select backend without servers:
   - Dropdown: Shows "backend (0 servers) - No servers" in RED
   - OnChange: Warning message appears
   - Submit: Allowed

3. Create WAF without frontend:
   - API: HTTP 400 (blocked)
   - UI: Required field validation
   - Reason: Too risky to allow

4. Bulk import with server-less backends:
   - API: SUCCESS (no blocking)
   - Frontends created successfully
   - Users can add servers later

Philosophy:
- HAProxy validation = source of truth
- Backend validation = guidance, not blocking
- Dangerous operations = strict validation (WAF global apply)
- User empowerment = soft warnings with clear info

Related: bcb8ef0 (backend without servers), 595d981 (WAF validation)
Refs: #validation-strategy #soft-warnings #bulk-import #ux
2025-11-17 14:15:44 +03:00
taylanbakircioglu 8a24d22e5d debug: Add console logs for tcp_request_rules in frontend edit modal
Added debug logging to track tcp_request_rules value when frontend edit modal opens.
This will help diagnose why tcp_request_rules from bulk import are not appearing in the edit form.
2025-11-14 01:06:38 +03:00
taylanbakircioglu 1276725f45 fix: Frontend modal - preserve tcp_request_rules, redirect_rules and use-service on update
🐛 Bug Düzeltmeleri:

1. tcp_request_rules field'ı edit modal'da gösterilmiyordu
   - handleEdit() setFieldsValue'ya tcp_request_rules eklendi
   - Artık DB'deki TCP rules edit modal'da görünüyor

2. use-service header'ları (prometheus-exporter gibi) bulk import'ta siliniyordu
   - config.py bulk_create_entities'e merge stratejisi eklendi
   - Mevcut use-service direktifleri parse edilip yeni header'larla birleştiriliyor
   - Manuel eklenmiş servisler korunuyor

3. redirect_rules field'ı form'da hiç yoktu (yeni bulgu!)
   - ACL Rules panel'ına redirect_rules textarea eklendi
   - HTTP to HTTPS redirect kuralları için kullanılabilir

✅ Diğer modaller kontrol edildi:
   - Backend modal: Tam ✓
   - Server modal: Tam ✓
   - SSL modal: Tam ✓
   - WAF modal: Tam ✓
2025-11-14 01:06:38 +03:00
taylanbakircioglu 4272dbb4ef feat: Add 'option httpchk' validation and auto-filtering across all layers
CRITICAL FIX: Prevent 'option httpchk' duplication in HAProxy config by implementing 3-layer validation:

1. BULK IMPORT PARSER:
   - Frontend: Filter out 'option httpchk' with warning (not applicable to frontends)
   - Backend: Already filtering 'option httpchk' (handled by health_check_uri field)

2. BACKEND API:
   - Backend create/update: Auto-filter 'option httpchk' from options field
   - Frontend create/update: Auto-filter 'option httpchk' from options field
   - Added filter_httpchk_from_options() helper function in both routers

3. FRONTEND UI:
   - Backend modal: Real-time warning when 'option httpchk' is typed
   - Frontend modal: Real-time warning when 'option httpchk' is typed
   - Warning messages guide users to use proper fields instead

Changes:
- backend/utils/haproxy_config_parser.py: Added httpchk filtering for frontend parsing
- backend/routers/backend.py: Added filter function + applied to create/update
- backend/routers/frontend.py: Added filter function + applied to create/update
- frontend/src/components/BackendServers.js: Added dynamic warning for httpchk
- frontend/src/components/FrontendManagement.js: Added dynamic warning for httpchk

User Experience:
✅ Bulk Import: Automatically filters httpchk, shows warning in preview
✅ Manual Entry: Shows real-time warning, auto-filters on save
✅ No Config Duplication: 'option httpchk' never appears twice in generated config

Impact: Users can safely paste or type 'option httpchk' without breaking HAProxy config. System automatically filters it and guides users to use the Health Check URI field instead.
2025-11-13 10:12:30 +03:00
taylanbakircioglu 0fc18fde38 feat: Add HAProxy options support for backends and frontends
Implemented comprehensive HAProxy options field support for both backend and frontend entities to enable standard HAProxy directives like 'option http-keep-alive', 'option httplog', 'option forwardfor', etc.

Changes:
- Database: Added 'options' TEXT column to backends and frontends tables
- Models: Added options field to BackendConfig, BackendConfigUpdate, and FrontendConfig
- API Endpoints: Updated CREATE, UPDATE, and GET endpoints to handle options field
  * Backend: CREATE/UPDATE/GET with options support
  * Frontend: CREATE/UPDATE/GET with options support (fixed 5 SELECT queries)
- Config Generator: Added options block generation for both backends and frontends
- Bulk Import Parser:
  * Added options field to ParsedBackend and ParsedFrontend dataclasses
  * Implemented option directive parsing with validation
  * Added unknown option warnings
  * Fixed bulk parse response to include options field
- Bulk Import Merge: Added options field comparison in UPDATE logic
- UI Components:
  * BackendServers.js: Added options TextArea form field
  * FrontendManagement.js: Added options TextArea form field

Features:
- Multi-line options support (newline-separated format)
- Option validation with known HAProxy options list
- Backward compatible (NULL options for existing entities)
- Bulk import support with merge strategy
- Full CRUD support for both manual and bulk operations

Technical Details:
- Format: Newline-separated TEXT field for multiple options
- Validation: Warns about unknown options but allows them
- Config Generation: Each option written as separate directive
- Agent: Standard HAProxy config validation applies

Total: 10 files modified, ~195 lines added, 26 integration points verified
2025-11-13 10:12:30 +03:00
taylanbakircioglu 281e23ea27 feat: Add SSL usage_type (Frontend/Server) with conditional private key requirement
This is a comprehensive update that adds SSL certificate differentiation
for frontend (HAProxy bind) and server (backend verification) use cases.

FEATURES:
- SSL certificates can be marked as 'frontend' or 'server' usage type
- Frontend SSL: Private key REQUIRED (for HAProxy bind ssl crt)
- Server SSL: Private key OPTIONAL (CA cert only for backend verification)
- UI dropdown for usage type selection
- Dynamic form validation based on usage type
- Filtering: Frontends see only Frontend SSL, Backends see only Server SSL

DATABASE:
- Added usage_type column to ssl_certificates (default: 'frontend')
- Made private_key_content nullable for server SSL support
- Migration automatically runs on pod restart

BACKEND:
- Pydantic v2 compatibility (@field_validator, @model_validator)
- SSL router: usage_type filtering support
- Agent endpoint: usage_type field included
- Improved migration robustness with better error handling
- Fixed duplicate ensure_agents_table() function
- Fixed JSONB permissions insert with json.dumps()
- Fixed ON CONFLICT constraints with explicit checks

FRONTEND:
- SSL Management: Usage Type dropdown with visual feedback
- Frontend Management: Filters only Frontend SSL certificates
- Backend Servers: Filters only Server SSL certificates
- Dynamic private key validation (required for Frontend, optional for Server)
- Improved form UX with color-coded hints

AGENT SCRIPTS (Linux & macOS):
- Support for Server SSL without private key
- Conditional PEM file creation (cert+key vs cert-only)
- usage_type awareness in SSL deployment
- Backward compatible with existing Frontend SSL certificates

DOCKER:
- Increased npm timeout for slow networks (300s → 600s)
- Increased fetch-retries (5 → 10)
- Reduced maxsockets for stability (3 → 1)

All changes are backward compatible. Existing SSL certificates
default to 'frontend' type and continue working unchanged.

Tested with: HAProxy 2.8+, PostgreSQL 15, React 18
2025-11-11 03:41:47 +03:00
taylanbakircioglu e7f2bc30aa Cleanup: Remove emoji from Frontend SSL field description
Code cleanup - removed emoji from form field
Changed: extra="🆕 Select one or more..."
To: extra="Select one or more..."

Note: Backend Server SSL is single select (correct)
Frontend SSL is multiple select (correct - supports SNI)
2025-11-07 11:51:15 +03:00
taylanbakircioglu a1a2206098 Fix: Race condition in FrontendManagement - Guard clauses added
CRITICAL RACE CONDITION FIX - FrontendManagement:
Same race condition pattern found and fixed

Component Analysis:
  BackendServers: FIXED (guard clause added)
  FrontendManagement: FIXED (guard clause added)
  SSLManagement: Already has guard clause
  WAFManagement: Already has guard clause

FrontendManagement Issues Fixed:
1. fetchFrontends() - Added guard clause
   if (!selectedCluster) → Clear state and return

2. fetchBackends() - Added guard clause
   if (!selectedCluster) → Clear state and return

Race Condition Pattern:
  Mount → selectedCluster=undefined → fetch() → API returns ALL
  Load → selectedCluster=1 → fetch() → API returns filtered
  Problem: First response arrives late and overwrites correct data

Solution - Guard Clauses:
  if (!selectedCluster) {
    setEntities([]);
    setFilteredEntities([]);
    return; // Don't call API
  }

Risk Assessment - SAFE:
  - Only adds early return if no cluster selected
  - Doesn't change existing logic when cluster IS selected
  - Same pattern already used in SSLManagement and WAFManagement
  - No breaking changes to other functions

Impact:
  - Prevents race condition on component mount
  - Prevents all entities appearing briefly
  - Consistent behavior across all management pages

Tested Components:
  Backend/Frontend/SSL/WAF Management all now protected
2025-11-07 11:51:15 +03:00
taylanbakircioglu 97fd0e7dad Migration: Add ssl_certificate_id to backend_servers + Remove emojis
Database Migration:
- Added ssl_certificate_id column to backend_servers table
- Added FK constraint to ssl_certificates table
- ON DELETE SET NULL behavior
- Idempotent migration (safe to run multiple times)

Column Details:
  Name: ssl_certificate_id
  Type: INTEGER
  Nullable: YES
  Foreign Key: ssl_certificates(id)
  On Delete: SET NULL

Migration Function:
  add_ssl_certificate_id_to_backend_servers()
  Called in run_migrations() at Line 1523

Code Cleanup:
- Removed emojis from migration logs
- Removed emojis from SSL dropdown status icons
- Changed to text: Valid, Expiring, Expired
- Changed to text: Global, Cluster

Error Fixed:
  GET /api/backends - 500
  column "ssl_certificate_id" does not exist

After migration runs on startup, column will exist and API will work
2025-11-07 11:51:15 +03:00
taylanbakircioglu a5e281b284 Feature: Backend Server SSL certificate support + Frontend SSL dropdown enhancement
✨ Backend Server SSL Certificate - Complete Implementation:

1. Model Update (backend/models/backend.py):
   - Added ssl_certificate_id field to ServerConfig model
   - Allows selecting SSL certificate from dropdown

2. API Endpoints (backend/routers/backend.py):
   - CREATE server: Added ssl_certificate_id to INSERT query
   - UPDATE server: Added ssl_certificate_id to allowed_fields
   - GET servers: Added ssl_certificate_id to SELECT queries (2 places)

3. Config Generation (backend/services/haproxy_config.py):
   - SSL certificate lookup by ID
   - Auto-generate ca-file path: /etc/ssl/haproxy/{cert_name}.pem
   - Added to server line in HAProxy config

Example Generated Config:
  Before: server es1 10.0.0.1:9200 ssl verify required
  After:  server es1 10.0.0.1:9200 ssl verify required ca-file /etc/ssl/haproxy/star-burgan-com-tr.pem

✨ Frontend SSL Dropdown Enhancement:
- Added Global/Cluster-specific tags to Frontend SSL dropdown
- Matches Backend Server SSL dropdown design
- Shows: [🌍 Global] or [📍 Cluster] with color coding

🔧 Complete SSL Workflow:
1. User edits Backend Server
2. Enables SSL
3. Selects SSL certificate from dropdown
4. Saves → ssl_certificate_id stored in DB
5. Apply Changes → Config generated with ca-file path
6. Agent downloads SSL cert to /etc/ssl/haproxy/
7. HAProxy uses ca-file for SSL verification

✅ Database Schema:
  backend_servers table now includes:
  - ssl_enabled (bool)
  - ssl_verify (str: none/required)
  - ssl_certificate_id (int, FK to ssl_certificates)

✅ HAProxy Config Format:
  server {name} {addr}:{port} ssl verify required ca-file {path}

Impact: Backend Server SSL now fully functional with certificate management
2025-11-07 11:51:15 +03:00
taylanbakircioglu 8c4d7c246c Fix: Cross-cluster data bleeding + Enhanced SSL dropdown UI
🐛 Critical Cross-Cluster Data Bleeding - System-Wide Fix:
Fixed old cluster's data appearing when switching clusters across 4 components

Root Cause:
- User switches from Cluster A to Cluster B
- Old cluster data remains in React state during API fetch
- Race condition: UI shows Cluster A data while fetching Cluster B
- Backend page: Data persisted after fetch
- Frontend page: Data briefly appeared then disappeared

✅ Components Fixed (State Clearing on Cluster Change):

1. BackendServers.js (Line 115-122)
   - Clear: backends, filteredBackends, frontends, sslCertificates

2. FrontendManagement.js (Line 150-157)
   - Clear: frontends, filteredFrontends, backends, sslCertificates

3. WAFManagement.js (Line 277-282)
   - Clear: rules, filteredRules, frontends

4. DashboardV2.js (Line 402-407)
   - Clear: statsData, frontendOptions, backendOptions, backendHealth, slowestBackends

Already Had State Clearing:
  ✓ SSLManagement.js
  ✓ AgentManagement.js
  ✓ Configuration.js
  ✓ ApplyManagement.js

✨ UI Enhancement: Backend Server SSL Dropdown

Redesigned to match Frontend SSL dropdown design:

Before:
  star-burgan-com-tr - *.burgan.com.tr (Expires: 2/25/2026)

After:
  star-burgan-com-tr - *.burgan.com.tr [🌍 Global] ✅ (125 days)
  demo-cert - *.apps.cluster.example.com [📍 Cluster] ✅ (1502 days)

Features Added:
  ✅ Status icons: valid, ⚠️ expiring soon, ❌ expired
  ✅ Days until expiry countdown
  ✅ SSL type tags: 🌍 Global (blue) or 📍 Cluster (green)
  ✅ Better layout with flex spacing
  ✅ optionLabelProp for compact selected view

🎯 Impact Analysis - All Components Safe:

Tested 8 components with selectedCluster dependency:
  ✓ BackendServers - State clearing added
  ✓ FrontendManagement - State clearing added
  ✓ WAFManagement - State clearing added
  ✓ DashboardV2 - State clearing added
  ✓ SSLManagement - Already had clearing
  ✓ AgentManagement - Already had clearing
  ✓ Configuration - Already had clearing
  ✓ ApplyManagement - Already had clearing

No Breaking Changes:
  - Only added state clearing in useEffect
  - Fetch logic unchanged
  - Response handling unchanged
  - UI components unchanged (except SSL dropdown enhancement)

✅ Cross-cluster data bleeding completely resolved
2025-11-07 11:51:14 +03:00
taylanbakircioglu 199ade8ce5 Fix: Browser cache causing phantom deleted entities across all pages
🐛 Critical Browser Cache Bug - System-Wide Fix:
- Fixed deleted entities reappearing on normal page refresh
- Hard refresh (Cmd+Shift+R) worked, normal refresh showed stale cache data
- Applied cache-busting to ALL entity fetch operations across entire application

🔧 Cache-Control Headers Added to 10 Components:

1. BackendServers.js - fetchBackends(), fetchFrontends(), fetchSSLCertificates()
2. FrontendManagement.js - fetchFrontends(), fetchBackends(), fetchSSLCertificates()
3. SSLManagement.js - fetchCertificates()
4. ApplyManagement.js - fetchPendingChanges() (4 API calls: frontends, backends, WAF, SSL)
5. WAFManagement.js - fetchFrontends()
6. AgentManagement.js - fetchAgents(), fetchPools()
7. PoolManagement.js - fetchPools(), fetchPoolAgents()
8. UserManagement.js - fetchUsers()
9. Configuration.js - fetchAgents()
10. ClusterContext.js - fetchClusters()

Headers Applied:
  'Cache-Control': 'no-cache, no-store, must-revalidate'
  'Pragma': 'no-cache'
  'Expires': '0' (some components)

🎯 Impact Analysis - SAFE Changes:

✅ Only GET requests affected (POST/PUT/DELETE unchanged)
✅ Response format unchanged (only headers added to request)
✅ No breaking changes to existing functionality
✅ Performance impact minimal (entities change frequently anyway)

🛡️ Protected Against Cache:
- Deleted backends/frontends won't reappear
- Deleted agents won't show in lists
- SSL certificates always fresh
- User list always current
- Cluster/Pool data always accurate

🔍 Testing Performed:
- Backend API verified: Only active backends returned (is_active=TRUE)
- SSL API verified: Returns 4 certificates correctly
- All axios.get calls now have cache-control headers
- No linter errors

✅ Root Cause Solved:
Browser/Axios caching GET responses → Stale data on normal refresh
Solution: Force fresh data from API on every request

Impact: Phantom entities bug completely resolved across entire application
2025-11-07 11:51:14 +03:00
taylanbakircioglu bfa0caa006 Feature: Full UI support for use_backend rules editing
✨ New Features:
- Added use_backend_rules validator to Frontend model
- UI now supports editing use_backend rules from Frontend Management page
- Array to string conversion for use_backend rules in edit modal

🔧 Model Improvements:
- Changed use_backend_rules field type from Optional[str] to Any (list support)
- Added parse_use_backend_rules validator (same logic as ACL/redirect rules)
- Handles 3 formats: Array, Textarea string (newline-separated), JSON string

💡 UI Improvements:
- Frontend edit modal automatically converts use_backend array to multi-line text
- Users can edit routing rules line by line in textarea
- Format: 'use_backend BackendName if condition'

✅ Complete Workflow:
1. Bulk Import: Config parsed → ACL + use_backend stored as array
2. Frontend Edit: Arrays converted to multi-line string in textarea
3. User edits ACL/use_backend rules in UI
4. Save: Textarea string → validator → array → database
5. Config Generation: Array → HAProxy config format

Example workflow:
  Parse: ['use_backend API if is_api']
  → Edit UI: 'use_backend API if is_api' (textarea)
  → User edits: 'use_backend API_v2 if is_api_v2'
  → Save: ['use_backend API_v2 if is_api_v2']
  → Generate: 'use_backend API_v2 if is_api_v2' (HAProxy config)
2025-11-07 11:51:14 +03:00
taylanbakircioglu 704a0c0022 Fix: Bulk import parsing and entity status management improvements
🐛 Bug Fixes:
- Fixed http-response capture directive parsing with improved regex pattern
- Fixed ACL rules display in Frontend UI (array to multi-line string conversion)
- Added SSL certificate dropdown to Backend Server edit when ssl_enabled=true
- Fixed rejected entity config status remaining after apply operation

🔧 Improvements:
- Enhanced SSL ca-file detection with user-friendly warnings
- Apply operation now correctly updates both PENDING and REJECTED entities to APPLIED
- Added dynamic SSL certificate selection for backend servers with validation
- Improved bulk import warnings for SSL management workflow

📝 Technical Details:
- Parser: Enhanced capture pattern matching for flexible http-response directives
- UI: Added conditional SSL certificate select field in BackendServers component
- Backend: Updated apply cleanup to handle REJECTED status in addition to PENDING
- Frontend: Fixed ACL/redirect rules formatting for proper textarea display

✅ All changes tested and verified with scenario analysis
2025-11-07 11:51:14 +03:00
taylanbakircioglu 6aae0f4309 Initial commit 2025-10-27 12:14:03 +03:00