18 Commits

Author SHA1 Message Date
taylanbakircioglu 9e2ea04777 feat(haproxy): preserve SPOE filter + frontend log-format on import/edit (v1.8.8, Issue #38)
Bulk import / manual edit silently dropped `filter spoe engine ...` (Coraza WAF)
and frontend `log-format` because the parser recognised only a fixed directive
set. The regenerated config then missed the SPOE engine, so HAProxy failed with
"unable to find SPOE engine 'coraza' used by the send-spoe-group".

- parser: capture `filter` + `log-format`/`log-format-sd` into new ParsedFrontend fields
- db: additive nullable `log_format` + `filters` TEXT columns on frontends (SCHEMA_VERSION 8->9)
- generator: new `filter` bucket flushed before http-request rules so `filter` precedes
  `send-spoe-group`; `log-format` kept in prelude
- bulk import: preview dict, change-detection, persist (create + merge-update); cluster-aware
  SPOE pre-flight advisories (missing-filter + host-prerequisite) surfaced in the UI
- manual CRUD: full round-trip (get/create/update) incl. React form fields (no null-wipe)
- reject/rollback: restore the new columns; restore path + wizard helper kept in parity
- backend `option spop-check` recognised (suppresses spurious warning for coraza-spoa)
- tests: test_spoe_filter_import.py; full suite green (1079 passed)
2026-07-10 18:34:36 +03:00
taylanbakircioglu 07942a82e8 feat: ACME stability & enterprise audit (v1.4.0) — fixes #10 #11 #12
Issue #10 — Silent timezone failure on ACME certificate save
- Normalize tz-aware expiry_date to UTC tz-naive before INSERT/UPDATE in
  ssl_certificates (TIMESTAMP WITHOUT TIME ZONE) — restores ACME download path

Issue #11 — Duplicate _acme_challenge_backend in generated config
- Generator guard: skip auto-append when backend already rendered
- Agent-sync filter: _should_sync_backend() drops system-managed backends and
  detaches their server rows to prevent orphans
- Restore filter: IGNORED_BACKENDS skips reserved names during cluster restore
- Parser warning: reserved_backend_names blocks accidental manual import
- Cleanup migration: removes orphan rows + cascading server entries (idempotent)

Issue #12 — Validated orders required manual completion
- New 60s background task complete_pending_acme_orders, flag-independent,
  multi-replica safe via FOR UPDATE SKIP LOCKED + 30s updated_at watermark
- Per-order pg_advisory_lock(0x41434D45, order_id) serializes UI-Complete and
  auto-task races; idempotency guard returns existing certificate cleanly
- retry_order endpoint reports in_progress: true within 30s window so the UI
  surfaces an info toast instead of duplicating CA requests
- ACMEAutomation surfaces stuck orders (status=valid && !ssl_certificate_id)
  with a one-click Complete action and Cancel fallback; conditional 30s polling

Other hardening
- ACME state machine error_detail persisted as structured JSON across challenge,
  finalize, download stages for actionable post-mortems
- CertificateRequest Pydantic model: domain regex + min_length/max_length and
  cluster_ids defaulting to all ACME-enabled clusters when "global" is selected
- Renewal cluster fallback now requires acme_enabled=TRUE in addition to active
- _complete_certificate preserves manual cluster assignments on renewal,
  surfaces cluster_errors, raises explicit error on missing private key
- Audit logging covers acme_certificate_requested/revoked, ca_chain_imported,
  account created/deactivated/purged, order retried/cancelled
- Settings UI exposes acme.staging_url_override for private test CAs (Pebble)
- Schema additions: acme_challenges.attempts (default 0) and last_attempt_at,
  index idx_letsencrypt_orders_status_updated; all migrations idempotent

Tests (41/41 passing)
- test_acme_expiry_normalize, test_acme_duplicate_backend,
  test_acme_state_machine, test_acme_pydantic_validation,
  test_acme_audit_logging, test_acme_concurrency

CI / packaging
- docker-build.yml reads version.json and pushes additional product-version
  tag (e.g. 1.4.0) alongside latest and timestamp build id

Closes #10
Closes #11
Closes #12
2026-05-06 23:53:43 +03:00
taylanbakircioglu 7fffaddaf8 fix: bulk import should not inject hardcoded timeout defaults
When a backend block in haproxy.cfg does not specify explicit timeout
values, the bulk import was injecting hardcoded defaults (connect 10s,
server 60s, queue 60s) into the database. These then appeared in the
generated config and overrode the agent's defaults section. Now, only
explicitly declared timeouts are stored; omitted ones remain NULL so
the agent's existing defaults section stays in effect.
2026-04-13 05:52:31 +03:00
taylanbakircioglu 851377aedf feat: Add HAProxy proxy name collision prevention system
- Add preserved_listen_blocks column to agents table for storing agent's local listen block names
- Implement reserved names check (stats, monitoring, admin, etc.) for frontend/backend creation
- Add dynamic collision detection against agent's preserved listen blocks
- Apply collision checks to CREATE, UPDATE endpoints and bulk import
- Add debug mode for failed config validation (saves to /tmp/haproxy-failed-*.cfg)
- Fix JSON character stripping for ACL and use_backend rules
- Remove collision protection from agent scripts (now handled by backend)
- All collision checks wrapped in try-except for backwards compatibility
2026-01-26 15:25:15 +03:00
taylanbakircioglu 5d054f3426 feat: Add random and first balance methods support
- Add 'random' and 'first' options to backend balance method selector
- Add balance method validation in config parser with warning for unknown methods
- Update API documentation with all supported balance algorithms
2026-01-26 15:25:15 +03:00
Taylan Bakırcıoğlu 7492d85649 FIX: Multiple SSL certificates & advanced params parsing
CRITICAL BUG FIX: Only 1 SSL cert matched instead of 3 for public_ssl

ROOT CAUSE:
- Parser only stored first cert path (ssl_cert_path)
- Bulk import SSL matching only checked single path
- ssl_certificate_ids = [2] (should be [2,3,4] for 3 certs)
- ssl_alpn = NULL (should be 'h2,http/1.1')

SOLUTION:
1. Added ssl_cert_paths List[str] to ParsedFrontend
2. Parser now stores ALL cert paths from bind directive
3. Bulk import loops through all cert paths for matching
4. SSL advanced options (alpn, npn, ciphers, etc.) included in frontends_data

EXAMPLE BIND DIRECTIVE:
bind 0.0.0.0:8443 ssl
  crt /etc/ssl/certs/example-cert1.pem
  crt /etc/ssl/certs/demo-cluster-cert.pem
  crt /etc/ssl/certs/example-cert3.pem
  alpn h2,http/1.1

BEFORE:
- ssl_certificate_ids: [2]  (only first cert)
- ssl_alpn: NULL            (not passed to bulk import)

AFTER:
- ssl_certificate_ids: [2, 3, 4]  (all 3 certs matched)
- ssl_alpn: 'h2,http/1.1'         (parsed & stored)

IMPACT:
- Multi-SSL frontends correctly imported
- SSL advanced params preserved & editable in UI
- SNI-based routing works correctly
- HTTP/2 ALPN negotiation preserved

TESTING:
- Parser: 3 crt paths → ssl_cert_paths = [path1, path2, path3]
- Matching: 3 paths → 3 IDs (if all SYNCED)
- Database: ssl_certificate_ids JSONB = [2,3,4]

Ref: demo-cluster public_ssl frontend issue
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu 5bd75c9614 ENHANCEMENT: Robust Multi-Value SSL Parameter Parsing in Bulk Import
🔧 IMPROVEMENT: Handle Quoted and Complex SSL Values

PROBLEM:
- Bulk import parser used simple line.split() for SSL parameters
- Failed to handle quoted values: ciphers "ECDHE-RSA:ECDHE-ECDSA:!MD5"
- Long cipher lists could be incorrectly parsed
- Edge cases with special characters not handled

SOLUTION - SHLEX PARSING:
 Frontend bind parsing:
   - Changed from line.split() to shlex.split()
   - Handles quoted values correctly
   - Removes quotes automatically
   - Fallback to simple split if malformed

 Backend server parsing:
   - Enhanced regex patterns for SSL params
   - Supports both quoted and unquoted values
   - Pattern: (?:"([^"]+)"|(\S+))
   - Applies to: sni, ssl-min-ver, ssl-max-ver, ciphers

EXAMPLES NOW SUPPORTED:

Frontend:
  bind :443 ssl crt cert.pem ciphers "ECDHE-RSA:ECDHE-ECDSA:!MD5:!aNULL" alpn "h2,http/1.1"
  → ciphers: ECDHE-RSA:ECDHE-ECDSA:!MD5:!aNULL (quotes removed)
  → alpn: h2,http/1.1 (quotes removed)

Backend:
  server s1 10.1.1.1:443 ssl sni "backend.example.com" ciphers "ECDHE-RSA:ECDHE-ECDSA"
  → sni: backend.example.com
  → ciphers: ECDHE-RSA:ECDHE-ECDSA

BENEFITS:
-  Production HAProxy configs with quoted values now parse correctly
-  Long cipher lists (100+ chars) handled properly
-  Special characters (!MD5, @STRENGTH) in cipher lists supported
-  Backward compatible (unquoted values still work)
-  Robust error handling (fallback to simple split)

TESTED WITH:
- User's problematic config with multiple crt + alpn
- Quoted cipher suites
- Mixed quoted/unquoted parameters
- Edge cases with special characters

This ensures bulk import handles ALL real-world HAProxy configurations correctly!
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu b212fb92bc Add SSL Advanced Options support (Backend) - Part 1
FEATURE: Complete SSL Advanced Options implementation for frontend and backend server SSL

 DATABASE:
- Added SSL parameter columns to frontends table:
  * ssl_alpn, ssl_npn, ssl_ciphers, ssl_ciphersuites
  * ssl_min_ver, ssl_max_ver, ssl_strict_sni
- Added SSL parameter columns to backend_servers table:
  * ssl_sni, ssl_min_ver, ssl_max_ver, ssl_ciphers
- Migration functions: add_ssl_advanced_options_to_frontends() and add_ssl_advanced_options_to_servers()

 MODELS:
- FrontendConfig: Added 7 new SSL fields for bind parameters
- ServerConfig: Added 4 new SSL fields for server parameters
- AgentHeartbeat: Added system_info field (fixes HTTP 422 validation error)

 BULK IMPORT PARSER:
- Parse alpn, npn, ciphers, ciphersuites, ssl-min-ver, ssl-max-ver, strict-sni from bind lines
- Parse sni, ssl-min-ver, ssl-max-ver, ciphers from server lines
- Store parsed values in frontend/server objects
- User-friendly warnings about imported SSL parameters

 CONFIG GENERATOR:
- Generate bind lines with SSL advanced options: 'bind :443 ssl crt file.pem alpn h2,http/1.1 ciphers ...'
- Generate server lines with SSL advanced options: 'server s1 addr:port ssl sni hostname ssl-min-ver TLSv1.2'
- Support both NEW MODE (multiple certs) and OLD MODE (single cert)

USER IMPACT:
- Bulk import now correctly parses SSL configs with alpn/npn/ciphers
- SSL parameters preserved during import (not lost anymore)
- Agent heartbeat fixed (no more offline agents)
- Ready for UI implementation (next commit)

EXAMPLE USAGE:
Frontend: bind 0.0.0.0:8443 ssl crt cert1.pem crt cert2.pem alpn h2,http/1.1
Server: server s1 10.1.1.1:443 ssl verify required sni backend.example.com ssl-min-ver TLSv1.2

NEXT: Frontend UI components for editing these SSL options
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu 5c1d2e11f9 Fix agent offline issue and bulk import SSL parsing
CRITICAL FIXES:
1. Agent Heartbeat Validation Error (HTTP 422)
   - Added missing 'system_info' field to AgentHeartbeat model
   - Agents were sending system_info but backend model didn't accept it
   - No agent script update needed - agents already send this field

2. Bulk Import SSL Parser Enhancement
   - Fixed parsing of multiple SSL certificates with alpn/npn parameters
   - Example: 'bind :443 ssl crt cert1.pem crt cert2.pem crt cert3.pem alpn h2,http/1.1'
   - Old parser stopped at first whitespace after crt path
   - New parser extracts all crt paths even with alpn/npn/ciphers after them
   - Added user-friendly warning for SSL parameters (alpn, npn, ciphers) that won't be imported

TECHNICAL DETAILS:
- backend/models/agent.py: Added system_info: Optional[Dict[str, Any]]
- backend/utils/haproxy_config_parser.py: Enhanced SSL bind parsing logic
  * Parse bind line by splitting and iterating through parts
  * Extract all crt paths before hitting SSL parameters
  * Detect and warn about alpn, npn, ciphers, ciphersuites parameters
  * Inform user these advanced options should be configured manually

USER IMPACT:
- Agents will come online after backend deployment (no reinstall needed)
- Bulk import will correctly parse configs with multiple SSL certs + alpn
- Clear warnings shown in UI about SSL parameters not imported
2025-11-18 21:58:05 +03:00
taylanbakircioglu 46735c1894 fix: Implement consistent use-service handling across frontend and backend
- Add use-service skip to backend parser (consistent with frontend)
- Add use-service preservation to backend bulk import merge strategy
- Remove use-service merge from frontend PUT endpoint (allows user deletion)
- Ensures frontend/backend full consistency for use-service directives

Changes:
1. Backend parser now skips use-service directives during bulk import
2. Backend bulk import preserves manually-added use-service directives
3. Frontend PUT no longer prevents use-service deletion by users

Impact:
- Prevents loss of manually configured services during bulk imports
- Allows users to freely add/remove use-service directives via UI
- Frontend and Backend now have identical use-service handling logic

Related fixes:
- Bug 2: use-service deleted on bulk import (now preserved)
- Bug 3: use-service cannot be deleted via UI (now deletable)
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 22bbd17a0c Fix: Frontend SSL auto-matching - Parser + UI display
COMPLETE FRONTEND SSL AUTO-MATCHING FIX:

Two Critical Fixes:

1. Parser SSL Path Storage (haproxy_config_parser.py Line 267):
   Added: frontend.ssl_cert_path = cert_paths[0]

   Before:
     Extracted SSL paths but didn't store
     Bulk import had no path to extract name from

   After:
     Stores first cert path
     Bulk import can extract name and match

2. UI SSL Display (BulkConfigImport.js Line 188-209):
   Replaced static "No SSL (Bulk Import)" with dynamic display

   Shows:
     - SSL Enabled + Auto-matched (X cert) [Green]
     - SSL (No Match) [Orange]
     - No SSL [Gray]

Complete Flow Verified:
  1. Config: bind :443 ssl crt /etc/ssl/certs/demo-cert.pem
  2. Parser: ssl_cert_path stored ✓
  3. Bulk import: Extracts demo-cert ✓
  4. Matches: SSL Management has demo-cert SYNCED ✓
  5. Response: ssl_enabled=True, ssl_certificate_ids=[3] ✓
  6. UI Parse: Shows [SSL Enabled] Auto-matched ✓
  7. Create: INSERT with ssl_certificate_ids ✓
  8. Edit modal: SSL enabled + demo-cert selected ✓
  9. Apply: Config with SSL path generated ✓
  10. HAProxy: Validation PASS ✓

Both frontend and backend SSL auto-matching now complete!
2025-11-07 11:51:15 +03:00
taylanbakircioglu 09157e8be1 Fix: HAProxy validation failure - Change verify to none when ca-file removed
CRITICAL HAProxy Validation Fix:
Bulk import was creating configs that fail HAProxy validation

HAProxy Validation Error:
  server es1 ... ssl verify required
  ALERT: verify is enabled but no CA file specified

Root Cause:
  Original config: ssl verify required ca-file /path/cert.pem
  After parse: ssl verify required (ca-file removed)
  Result: HAProxy validation FAILS

HAProxy Requirement:
  verify required → MUST have ca-file
  verify none → Can work without ca-file
  ssl (no verify) → Uses default verification

Fix Applied (Line 677-704):
When parsing server with both verify AND ca-file:
  1. Detect: verify=required + ca-file exists
  2. Remove ca-file (as planned)
  3. Change verify to 'none' (NEW - prevents validation error)
  4. Warning: Explain user needs to reconfigure after import

Three Scenarios Handled:
  1. verify + ca-file → verify=none, remove ca-file, warn user
  2. verify only → keep verify as-is
  3. ca-file only → set verify=none, remove ca-file, warn user

Generated Config Now:
  Before: server es1 ... ssl verify required (FAILS validation)
  After: server es1 ... ssl verify none (PASSES validation)

User Workflow:
  1. Bulk import → Servers created with verify=none
  2. HAProxy validation → PASSES
  3. User edits server → Selects SSL cert → Sets verify=required
  4. Apply → Config generated with ca-file path
  5. HAProxy validation → PASSES (has ca-file)

Warning Message:
  'verify required' changed to 'none' to pass HAProxy validation
  After import, select SSL certificate and set verify to 'required'

Impact: Bulk import now creates HAProxy-valid configurations
2025-11-07 11:51:15 +03:00
taylanbakircioglu 86298b911f Hotfix: Fix list.strip() error in config parser validation
🐛 Critical Bug Fix:
- Fixed 'list' object has no attribute 'strip' error
- Error occurred in _validate_parsed_config() at line 847
- use_backend_rules is now a list, not a string

🔧 Technical Details:
- Changed from: frontend.use_backend_rules.strip()
- Changed to: bool(frontend.use_backend_rules)
- Simple boolean check works for both list and None types

 Impact:
- Bulk import parsing now works without errors
- Config validation properly handles list-based use_backend_rules
- All warning messages display correctly

Error was:
  'list' object has no attribute 'strip'
  at _validate_parsed_config line 847

Fix applied:
  Line 847-848: Use bool() instead of .strip() for list validation
2025-11-07 11:51:14 +03:00
taylanbakircioglu 1158e5f2b1 Fix: HAProxy validation - ACL and use_backend parsing improvements
🐛 Critical Bug Fixes:
- Fixed duplicate 'acl' prefix in generated config (was: 'acl acl Name ...')
- Fixed duplicate 'use_backend' prefix in generated config
- Added use_backend directive parsing from bulk import configs
- Fixed redirect_rules list handling (was causing .strip() error)

🔧 Parser Improvements:
- Added use_backend rules parsing (stored as list like ACL rules)
- Changed use_backend_rules field from str to list for consistency
- Parser now captures all use_backend directives with conditions

🎯 Config Generation Improvements:
- Smart prefix detection: only add 'acl' if not already present
- Smart prefix detection: only add 'use_backend' if not already present
- Support both legacy (string) and new (list) format for rules
- Proper JSON parsing with fallback to newline-separated format

 HAProxy Validation:
- Generated config now passes HAProxy validation (haproxy -c -f)
- ACL and use_backend directives in correct HAProxy format
- Routing rules properly linked with ACL conditions

Example parsed config:
  acl Elasticsearch hdr(host) -i baremetal-elastic.burgan.com.tr
  use_backend Elasticsearch if Elasticsearch

Tested with full config including multiple ACLs and routing rules.
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