Commit Graph

159 Commits

Author SHA1 Message Date
taylanbakircioglu eabbb2a987 fix: SSL page header layout - prevent Add Certificate button wrapping
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:36:27 +03:00
taylanbakircioglu 0b40d7b8a2 refactor: replace Expiring Soon alert banner with hover tooltip
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:36:27 +03:00
taylanbakircioglu 1f100d01e7 fix: SSL reject rollback, expiry calculation, and UI improvements
- SSL Reject: Remove conditional has_same_update_applied check, always
  rollback since Auto-Reject handles cross-cluster consistency
- SSL Rollback: Restore expiry_date by parsing ISO string back to datetime
- SSL UI: Add In Use filter toggle, fix Expiring Soon count using actual
  date calculation, smart Private Key content validation messages
- Remove emojis from log messages

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:36:27 +03:00
taylanbakircioglu 6c8d771c3a fix: restrict INCOMPLETE status to SSL only, remove emojis from code
- Timeout/INCOMPLETE logic now applies only to ssl_certificates entity type
- Non-SSL entities (frontend, backend, waf) retain original APPLYING behavior
- Remove all emoji characters from console.log and UI strings

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:36:27 +03:00
taylanbakircioglu 7dedd0f573 feat: SSL sync status tracking and smart reload optimization
- Add per-cluster SSL sync status tracking with APPLYING/SYNCED/PARTIAL states
- Add timeout detection (10min) for stalled SSL deployments showing PARTIAL status
- Add SSL-specific info in Apply Management dialog (cluster count, auto-apply notice)
- Add Deployment Status tab in SSL details showing per-cluster agent sync progress
- Implement SSL auto-reject (reject propagates to all clusters) and auto-undo
- Add conditional entity rollback for SSL reject (time-window based safety check)
- Filter REJECTED status from SSL last_config_status display
- Add pending_cluster_names to SSL list API response
- Optimize agent SSL reload: only trigger HAProxy reload when changed cert is
  actually referenced in the cluster's HAProxy config (grep -qF check), preventing
  unnecessary reloads on clusters that don't use the updated certificate
- Applied to all 4 SSL deploy paths: Linux/macOS standalone and daemon embedded modes

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:36:27 +03:00
taylanbakircioglu 9b8016588c feat: show SSL certificate usage status (In Use / Not In Use)
Replace the always-Active status badge with actual usage information by
querying which frontends and backend servers reference each certificate.

Backend: detail endpoint returns used_by_frontends, used_by_servers and
usage_count; list endpoint includes usage_count via scalar subqueries
checking both ssl_certificate_id and ssl_certificate_ids JSONB fields.

Frontend: General Info badge shows In Use/Not In Use, new Usage tab with
searchable frontend and server tables, summary card shows In Use count.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:36:27 +03:00
taylanbakircioglu 7ca036ef3c fix: add missing is_active field to SSL certificate API responses
The detail endpoint (GET /api/ssl/certificates/{id}) was missing is_active
in its SQL SELECT/GROUP BY, causing the frontend details modal to always
show "Inactive". The list endpoint included is_active in its SQL query but
omitted it from the response dict, causing the Active counter card to
always show 0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:36:27 +03:00
taylanbakircioglu c19f0b5275 fix: SSL certificate updates now trigger HAProxy reload after self-upgrade
Root cause: After agent self-upgrade, the embedded daemon (SKIP_TO_DAEMON
block) runs instead of run_daemon(). HAPROXY_BIN and HAPROXY_CONFIG
variables were uninitialized before the daemon loop, causing SSL-triggered
HAProxy reloads to silently fail with empty path validation.

Changes:
- Initialize HAPROXY_BIN/HAPROXY_CONFIG before embedded daemon loop
- Add md5 checksum comparison in deploy_ssl_certificates() to detect
  actual cert file changes (avoid unnecessary writes and reloads)
- Add check_ssl_updates() for independent SSL sync every ~2.5 min
  in run_daemon(), independent of config version changes
- Add SSL-aware reload in check_config_updates(): if config validation
  fails but SSL certs changed, reload HAProxy with existing config
- Add "full" fetch mode to fetch_and_deploy_ssl_certificates() to
  bypass incremental timestamp filter for standalone SSL checks

Applied to both linux_install.sh and macos_install.sh.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:36:27 +03:00
taylanbakircioglu 45d5919dc2 fix: resolve stale closure in agent actions after cluster change
- Remove useMemo from table columns to prevent stale closures for
  upgradeAgent, toggleAgent, deleteAgent after cluster switches
- Add selectedClusterRef and fetchAgentsRef for safe async access
  in setTimeout callbacks (upgrade delayed refresh)
- Force-fetch (bypass throttle) after all user actions: toggle,
  refresh button, reset scripts, update version
- Remove unused useMemo import

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 20:37:49 +03:00
taylanbakircioglu 4002c89d58 fix: agent list not loading on cluster change due to throttle race condition
- Combine cluster change clear + fetch into single useEffect to prevent
  race between clearing agents and throttled fetch being skipped
- Force-fetch agents on cluster change (bypass throttle and loading guard)
- Use loadingRef to avoid stale closure in fetchAgents useCallback
- Reset throttle timer on cluster change so fetch is never blocked

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 20:37:49 +03:00
taylanbakircioglu dc978f847d fix: prevent daemon crash-loop on exit 1 with retry-backoff mechanism
- Replace immediate exit 1 with retry-with-backoff in all daemon mode paths
  (dependency checks: 5 retries, 30/60/90/120/150s; config file: 5 retries, 15/30/45/60/75s)
- Make socat missing non-fatal in daemon mode (agent continues without stats)
- Add SystemD StartLimitBurst=5/StartLimitIntervalSec=120 for new installs
- Add macOS launchd ThrottleInterval=30 for new installs
- Fix Linux daemon fallback to installer mode (would hang on interactive read)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 20:04:42 +03:00
taylanbakircioglu 93602fa65d fix: check and install jq before cluster validation in agent scripts
Move jq dependency check to run before cluster validation which requires
it. Auto-install jq via the detected package manager (apt, dnf, yum,
zypper, apk for Linux; brew for macOS). Exit with clear manual install
instructions if automatic installation fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 20:04:42 +03:00
taylanbakircioglu e6142a9a9c feat: add search capability to cluster selector dropdown
Enable showSearch on the header cluster selector so users can quickly
filter clusters by name, pool, connection type or description.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:49:59 +03:00
taylanbakircioglu 4c7a6d79f3 fix: apply sync for empty config, UI responsiveness improvements
- Fix backend cleanup order: delete backend_servers before backends
  to prevent orphan records and foreign key constraint violations
- Fix Apply progress getting stuck at "0/55" when all entities deleted
  by using verifyRealAgentSync result for accurate syncedCount
- Add completion condition for "all entities deleted" scenario
- Fix cluster selector truncation with dynamic width calculation
- Fix sidebar menu label truncation: increase sider width to 240px,
  use concise menu labels, add CSS overflow handling
- Add responsive breakpoints for header title and content padding
- Auto-collapse/expand sidebar on breakpoint change

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:45:29 +03:00
taylanbakircioglu cc10015952 fix: prevent install script from killing itself during cleanup
Same pgrep self-kill bug as uninstall scripts. When user downloads
install script as install-haproxy-agent.sh, pgrep -f "haproxy-agent"
matches the installer's own bash process and kills it before
installation starts. Now filters out INSTALLER_PID and PPID.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:45:29 +03:00
taylanbakircioglu 2d5c863735 fix: replace static protected paths with dynamic safety in uninstall
Instead of a hardcoded PROTECTED_PATHS list (varies per environment):
- safe_rm() blocks any path not containing "haproxy-agent"
- Process killer verifies ps output contains "haproxy-agent"
- Pre/post HAProxy integrity check via md5 hash comparison of config
  and service status diff (was running -> still running?)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:45:29 +03:00
taylanbakircioglu 8351a6439b fix: add HAProxy safety guards to uninstall scripts
- PROTECTED_PATHS array prevents accidental removal of haproxy.cfg,
  haproxy binary, haproxy.service, haproxy logs
- safe_rm() blocks any path not containing "haproxy-agent"
- Process killer verifies command line contains "haproxy-agent" and
  skips HAProxy master PID
- Binary removal validates filename is exactly "haproxy-agent"
- Pre-flight safety check reports HAProxy status before starting
- Post-uninstall HAProxy integrity check confirms nothing was touched

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:45:29 +03:00
taylanbakircioglu 08c500855e fix: rewrite uninstall scripts - simple and reliable
Replaced overcomplicated 380-line scripts with clean ~125-line versions.
Steps: stop service, kill processes (excluding self), remove binary,
remove config/logs/temps, verify. No emojis, no fragile helpers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:45:29 +03:00
taylanbakircioglu b7dde62972 fix: prevent uninstall script from killing itself via pgrep
pgrep -f "haproxy-agent" was matching the uninstall script's own
process (uninstall-haproxy-agent-linux.sh contains "haproxy-agent"),
causing the script to terminate itself at step 1/7 before reaching
file cleanup. Now filters out $$ (own PID) and $PPID from kill lists.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:45:29 +03:00
taylanbakircioglu 5cec6cf85a fix: remove emojis from all agent scripts and fix install/uninstall bugs
- Remove all emoji characters from install scripts (linux, macos)
- Rewrite uninstall scripts: remove set -e, fix safe_remove to always
  return 0, replace ((var++)) with $((var + 1)), fix local keyword
  usage, add comprehensive cleanup including config.json
- Fix install script QUIET_MODE/DAEMON_MODE detection to correctly
  handle interactive runs when old config.json exists

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:45:29 +03:00
taylanbakircioglu 6349f1ad7c fix: exclude disabled (OFF) agents from sync calculations
Disabled agents were blocking apply sync progress indefinitely because
they were counted in total_agents but could never report as synced.

Backend:
- agent-sync endpoint: disabled agents excluded from total/synced/unsynced
  counts, added disabled_agents and total_agents_including_disabled fields
- SSL cert agent-sync endpoint: same disabled agent exclusion
- Both endpoints still return disabled agents in the list with
  sync_excluded: true for UI display

Frontend:
- ApplyManagement: cluster sync complete logic handles 0 enabled agents,
  all updateEntityCounts calls pass disabled count, agent table shows
  OFF/Excluded tags for disabled agents
- GlobalProgress: shows "(X off)" indicator, visible even when all
  agents are disabled
- ProgressContext: agentCounts state supports disabled field
- agentSync utility: verifyRealAgentSync treats null/0-agent sync_status
  as synced (nothing to wait for)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 16:45:28 +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 eac00b3e39 fix: consistent section header detection in listen extraction
Additional fix for listen block extraction:
- Section boundary check now uses ([[:space:]]|$) pattern
- Previously only checked [[:space:]], missing 'defaults' at end of line
- Ensures listen extraction stops correctly at any section header

Pattern consistency verified across all 4 locations:
- Linux install mode: global, defaults, listen extraction ✓
- Linux daemon mode: global, defaults, listen extraction ✓
- macOS install mode: global, defaults, listen extraction ✓
- macOS daemon mode: global, defaults, listen extraction ✓

Edge cases tested:
- Named defaults (defaults http): works correctly
- Multiple listen blocks: all preserved
- Tab characters: handled by [[:space:]]
- User's actual config structure: produces clean merge

No impact on other agent functions (self-upgrade, metrics, etc.)
2026-01-26 15:25:16 +03:00
taylanbakircioglu 25408a618e fix: awk patterns now match keywords at end of line
CRITICAL BUG FIX:
- Previous pattern `/^defaults[[:space:]]/` required whitespace after keyword
- HAProxy allows `defaults` without a name (no trailing whitespace)
- Pattern failed to match, causing global extraction to include defaults section

New pattern uses `([[:space:]]|$)`:
- Matches keyword followed by whitespace OR end of line
- `defaults` (no name) now correctly triggers exit
- `defaults http` (named) also correctly triggers exit

Test results:
- Old pattern: extracted 8 lines (included defaults) 
- New pattern: extracted 4 lines (stopped at defaults) 
2026-01-26 15:25:16 +03:00
taylanbakircioglu 995d87df43 fix: defaults extraction captures only first defaults section
CRITICAL BUG FIX:
- Previous awk pattern allowed multiple defaults sections to be captured
- Pattern `!/^defaults/` meant "don't exit if line IS defaults"
- This caused duplicate defaults when config had listen before defaults

New pattern uses `started` flag:
- First `defaults` line: set started=1, begin capturing
- Second `defaults` line: started is set, EXIT immediately
- Any `frontend/backend/listen`: started is set, EXIT

Also includes: debug logging for validation error storage with fallback

Tested scenarios:
- Normal config (defaults → listen → frontend): ✓
- Listen before defaults: ✓
- Two defaults sections: ✓ Only first captured
- No defaults section: ✓ Empty output
- Defaults at end of file: ✓
- Empty defaults section: ✓
2026-01-26 15:25:15 +03:00
taylanbakircioglu 4a6bc1b139 fix: global section extraction includes listen blocks when listen comes before defaults
Bug: When haproxy.cfg has 'listen stats' BEFORE 'defaults' section,
the global extraction incorrectly included listen stats because it
only stopped at 'defaults', not at any section header.

Fix: Changed extraction to stop at ANY section (defaults/listen/frontend/backend)
This prevents duplicate listen blocks in merged config.

Root cause of 'proxy stats has same name as proxy stats' HAProxy validation error.
2026-01-26 15:25:15 +03:00
taylanbakircioglu 83204c86a8 fix: critical security and UX improvements for config management
SECURITY FIX (agent.py):
- Ensure ONLY APPLIED versions are sent to agents
- Fixed fallback query that could return PENDING versions
- Agents will never receive unapproved configurations

UX FIX (cluster.py):
- Clear validation_error when creating new version via Apply
- Prevents stale validation errors from showing after re-apply

UX FIX (agent.py):
- Clear validation_error when agent successfully applies config
- Clear last_validation_error on agent record after success
2026-01-26 15:25:15 +03:00
taylanbakircioglu 1dcf45b1bb fix: dynamic collision detection in config generation
Query agent preserved_listen_blocks dynamically and skip
conflicting entities to prevent HAProxy validation errors.

Falls back to static reserved list if no agent data available.
2026-01-26 15:25:15 +03:00
taylanbakircioglu e75bfdf706 feat: dynamic HAProxy binary path from cluster configuration
- /api/agents/{name}/config now returns haproxy_bin_path, haproxy_config_path, stats_socket_path from cluster
- Agent daemon uses these dynamic paths from API response for validation
- Fallback to local config file if API values not present
- Allows cluster admin to change paths without reinstalling agents

This fixes validation when HAProxy binary is in non-standard location
2026-01-26 15:25:15 +03:00
taylanbakircioglu 97e32114e0 fix: translate Turkish error messages to English
- Updated SUGGESTION_TEMPLATES in haproxy_error_parser.py
- Fixed fallback error messages in cluster.py
- Product language should be English throughout
2026-01-26 15:25:15 +03:00
taylanbakircioglu 095c682fa3 fix: handle soft-deleted entities in bulk import and frontend deletion
Bulk Import Fix (config.py):
- Check for existing servers (including soft-deleted) before INSERT
- If server exists: UPDATE and reactivate instead of INSERT
- Create snapshot for ALL updated servers (enables reject/rollback)
- Add backend_name to UPDATE for field consistency
- Track updated/reactivated servers in response
- Prevents duplicate key constraint violation on re-import

Frontend Deletion Fix (frontend.py):
- Add hard delete support for already soft-deleted frontends
- Follows same pattern as backend.py hard delete
- Deletes WAF associations and config versions before frontend
- Works with existing orphan cleanup in Apply/Reject flows

Both fixes are safe because:
- Orphan version cleanup handles hard-deleted entities in Apply/Reject
- Consistent with existing backend.py patterns
- Snapshot-based rollback fully supported
2026-01-26 15:25:15 +03:00
taylanbakircioglu ecbaebf451 feat: report invalid config format errors to backend for UI display
When config content doesn't look like valid HAProxy config (missing
global/defaults/frontend/backend/listen keywords), agent now reports
this to backend via config-validation-failed endpoint.

This catches backend-side config generation errors (like Python
exceptions) that prevented actual HAProxy config from being generated.

Changes:
- Add invalid config format detection and reporting in daemon mode
- Use same curl pattern as existing HAProxy validation failure reporting
- Same endpoint, headers, error handling, and spam prevention
- Follows exact existing pattern for consistency
- Does not affect self-upgrade flow (runs before upgrade check)

Both linux and macos scripts updated identically.
2026-01-26 15:25:15 +03:00
taylanbakircioglu d40c701272 fix: resolve Python scoping error in config generation
Remove redundant local 'import json' statements that caused:
"cannot access local variable 'json' where it is not associated with a value"

Root cause: Local import inside try block made 'json' a local variable,
but except clause referenced json.JSONDecodeError before assignment.

Changes:
- Line 197: Remove local import, use global json (line 5)
- Line 514: Remove 'import json as _json', use global json
- Use ValueError instead of json.JSONDecodeError (equivalent, JSONDecodeError
  is a subclass of ValueError)

This was causing config generation to fail completely, returning error
message as config content instead of actual HAProxy configuration.
2026-01-26 15:25:15 +03:00
taylanbakircioglu 5947caa46d fix: move uninstall scripts to backend/utils/agent_scripts for deployment
- Copy uninstall-agent-linux.sh and uninstall-agent-macos.sh to
  backend/utils/agent_scripts/ (same location as install scripts)
- Update generate-uninstall-script endpoint to use the same path
  pattern as working install script endpoint
- Add container-specific fallback paths for robustness
- Add debug logging to track which path is used

Fixes 404 error when fetching uninstall script in production
where /utils/ directory at project root is not deployed.
2026-01-26 15:25:15 +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
taylanbakircioglu 0c1d68eb01 feat: add uninstall script UI with modern design
- Add new API endpoint to serve uninstall scripts by platform
- Display uninstall script alongside install script in setup wizard
- Add dedicated delete agent modal with 2-step workflow
- Modern UI with gradient banners, platform icons, and info cards
- Enhanced uninstall scripts to clean all agent temp/backup files
- HAProxy service and config remain untouched during uninstall
2026-01-26 15:25:15 +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
taylanbakircioglu bc8563d455 fix: Update agent token association on config change and improve Security UI
- Fix token-agent relationship not updating when agent config changes
- Agent's api_key now syncs with DB on heartbeat when using different token
- Change Security page badge color from red to blue for better UX
2026-01-26 15:25:15 +03:00
taylanbakircioglu 86c7b3a57f feat: Display HAProxy versions with agent names in Cluster Management
- Add HAProxy Version column to cluster list table
- Show version number with agent names directly (no hover required)
- Fetch agents for each cluster to get haproxy_version info
- Show warning icon (yellow) when agents have different HAProxy versions
- Green color for consistent versions, yellow for mismatched versions
- Agent names displayed below each version in smaller gray text
- UI-only change, no backend modifications
- Safe implementation using existing /api/agents endpoint
2025-12-26 15:26:46 +03:00
taylanbakircioglu 5edf53ec3e Update Docker registry to taylanbakircioglu 2025-12-24 19:11:57 +03:00
taylanbakircioglu 183b4fa9e2 fix: Auto-add 'verify none' for SSL backend servers without CA file
When ssl_enabled is true for a backend server but:
- No ssl_verify option is explicitly set AND
- No CA file (ssl_certificate_id) is specified

HAProxy 2.8+ defaults to 'verify required' which fails without a CA.
Now auto-adding 'verify none' in this case with a warning log.

Users can override this in UI by setting SSL Verification explicitly.

This fix is safe for:
- Bulk Import: Parser already sets ssl_verify='none' when removing ca-file
- Version Diff: Generated config correctly shows 'verify none'
- Restore: DB values unchanged, config regeneration applies same fix

Fixes: 'verify is enabled by default but no CA file specified' error
2025-12-23 13:28:49 +03:00
taylanbakircioglu 81d2b3b8d5 feat: Display HAProxy version in Agent Management page
- Add haproxy_version field to heartbeat payload in Linux agent script
- Add haproxy_version field to heartbeat payload in macOS agent script
- Display HAProxy version below IP address in Registered Agents list
- Safe extraction with fallback to 'unknown' if haproxy command fails
- Version is updated on every heartbeat (30s interval)
- Green color styling for easy visibility

Backend already supports haproxy_version field in AgentHeartbeat model
and saves it to database on each heartbeat.
2025-12-23 13:28:29 +03:00
Taylan Bakırcıoğlu 378710db3f fix(haproxy-config): ACL rules must come before http-request directives
CRITICAL HAProxy Validation Error Fix

Problem:
Generated HAProxy config failed validation with error:
[ALERT] error detected while parsing an 'http-request deny' condition:
no such ACL: 'waf_demo-rule1_path'.

Root Cause:
Config generator was writing http-request directives BEFORE ACL definitions.
HAProxy requires ACLs to be defined before they are referenced.

Generated Config (WRONG ORDER):
  http-request deny if waf_demo-rule1_path   ACL not defined yet!
  acl waf_demo-rule1_path path_reg ^/admin   Too late!

Fix:
Reordered frontend config generation:
1. ACL Rules (Line 339-362) - Define ACLs FIRST
2. HTTP Request Headers (Line 364-371) - Use ACLs AFTER

Generated Config (CORRECT ORDER):
  acl waf_demo-rule1_path path_reg ^/admin         Define first
  acl waf_demo-rule1_method method POST            Define first
  http-request deny if waf_demo-rule1_path waf_demo-rule1_method   Use after

Impact:
- Parsing logic: UNCHANGED (no breaking changes)
- Database storage: UNCHANGED (no schema changes)
- Config generation: FIXED (correct HAProxy syntax)
- Bulk import: Works correctly now
- Agent config apply: Validation passes

Testing:
1. Bulk import config with ACLs and http-request rules
2. Agent applies config successfully
3. HAProxy validation passes

Files Changed:
- backend/services/haproxy_config.py: Reordered ACL and request_headers generation
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu 1d17dd8fd5 fix(reject): prevent deletion of existing entities on bulk import reject
CRITICAL DATA LOSS BUG FIX

Problem:
- User updates existing entity via bulk import
- User clicks Reject
- EXPECTED: Entity reverts to old values
- ACTUAL: Entity is COMPLETELY DELETED!

Root Cause:
Reject logic tracked ALL bulk import entities for force deletion.
Did not distinguish between CREATE and UPDATE operations.

Fix:
Added operation check - only track CREATE operations for force deletion.
UPDATE operations are rolled back, not deleted.

Impact:
- CREATE scenarios: No change in behavior
- UPDATE scenarios: Data loss prevented
- Mixed CREATE+UPDATE: Only CREATE entities deleted
- Rollback failures: Safety mechanism preserved

Files Changed:
- backend/routers/cluster.py: Line 4494 added operation check
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu 589f865f59 fix(ssl): rollback support + improved ALPN validation error message
PART 1: Rollback Support for SSL Advanced Options
===================================================
Problem: SSL advanced options lost on reject/rollback operations

Root Cause:
- Snapshot creation uses SELECT * (includes all fields) 
- old_values contains SSL advanced options 
- Rollback UPDATE did NOT restore SSL fields 

Impact - Frontend:
- User changes ssl_alpn, then clicks Reject
- Rollback skipped: ssl_alpn, ssl_npn, ssl_ciphers, ssl_ciphersuites, ssl_min_ver, ssl_max_ver, ssl_strict_sni
- Result: All SSL advanced options lost (set to NULL)

Impact - Backend Server:
- User changes ssl_min_ver='TLSv1.2', then clicks Reject
- Rollback skipped: ssl_sni, ssl_min_ver, ssl_max_ver, ssl_ciphers
- Result: Security issue - TLS version constraints removed!

Fix:
- backend/utils/entity_snapshot.py line 285-286: Added 7 frontend SSL fields to rollback UPDATE
- backend/utils/entity_snapshot.py line 458: Added 4 server SSL fields to rollback UPDATE

PART 2: Improved ALPN Validation Error Message
===============================================
Problem: User enters 'http/2' in ALPN field, gets generic error

User feedback: Tried 'h2,http/1.1,http/2' → validation error not clear

Root Cause:
- ALPN standard uses 'h2' for HTTP/2 (not 'http/2')
- Validator rejected 'http/2' but didn't explain the correct format

Fix:
- backend/models/frontend.py line 255-260: Detect common mistakes (http/2, http2, http-2)
- Provide helpful error: 'For HTTP/2, use "h2" (not "http/2")'

Before:
  "Invalid ALPN protocol: http/2. Valid protocols: h2, http/1.1, ..."

After:
  "Invalid ALPN protocol: http/2. For HTTP/2, use 'h2' (not 'http/2'). Valid protocols: ..."

Testing:
1. Rollback test: Edit frontend SSL, reject, verify SSL fields restored
2. Validation test: Enter 'http/2', verify friendly error message

Files Changed:
- backend/utils/entity_snapshot.py: _rollback_update() for frontend and server
- backend/models/frontend.py: validate_alpn() with better error messages
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu 8e1a93f873 fix(ssl): add backend server SSL advanced options to haproxy config generation
CRITICAL BUG FIX: Backend server SSL advanced options not in generated HAProxy config

Problem:
- Database has ssl_sni, ssl_min_ver, ssl_max_ver, ssl_ciphers columns 
- Config generation code tries to write them to HAProxy config (line 680-687) 
- BUT SELECT statement did NOT include these fields 
- Result: server.get('ssl_sni') always returned None

Impact:
- User sets 'TLS Min Version: TLSv1.2' for backend server in UI
- Value saved to database correctly
- BUT generated HAProxy config missing 'ssl-min-ver TLSv1.2'
- Agent deploys incomplete config, SSL settings lost!

Solution:
- Added 4 server SSL advanced options to SELECT query (line 616):
  - ssl_sni (for SNI hostname)
  - ssl_min_ver (minimum TLS version)
  - ssl_max_ver (maximum TLS version)
  - ssl_ciphers (cipher suite override)

Config Generation Logic:
- Line 680-687: Code already writes these fields to HAProxy config
- Line 616: Now SELECT actually retrieves the values from database
- Example output: 'server backend1 10.0.0.1:443 ssl sni example.com ssl-min-ver TLSv1.2'

Testing:
- After deployment, bulk import a config with backend server SSL options
- Check generated HAProxy config on agent
- Should now see: 'server X ssl ssl-min-ver TLSv1.2 ciphers ...'

Files Changed:
- backend/services/haproxy_config.py: Line 616 SELECT statement
2025-11-18 21:58:05 +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 e8690245af fix(ssl): add change detection and validators for SSL advanced options
Critical additions:
1. Change Detection (backend/routers/config.py)
   - Added SSL advanced options to bulk import change detection logic
   - Detects changes in ssl_alpn, ssl_npn, ssl_ciphers, ssl_ciphersuites
   - Detects changes in ssl_min_ver, ssl_max_ver, ssl_strict_sni
   - Changes will now appear in version diff

2. Pydantic Validators (backend/models/frontend.py, backend/models/backend.py)
   - TLS version validator: Only allows valid versions (SSLv3, TLSv1.0-1.3)
   - ALPN protocol validator: Only allows h2, http/1.1, http/1.0, h2c, spdy/*
   - NPN protocol validator: Only allows http/1.1, http/1.0, spdy/*
   - Prevents invalid values from being saved to database
   - HAProxy validation will not fail due to invalid SSL options

Impact:
- Bulk import will correctly detect SSL option changes
- Apply Management diff will show SSL changes
- User cannot enter invalid TLS versions or protocols
- Improved UX with early validation errors

Previous fixes in this series:
- Frontend GET API: Added SSL fields to response
- Bulk Import UPDATE: Added SSL fields to UPDATE statement
- Backend Server GET API: Added SSL fields to response

Test: Bulk import with ALPN change → Should see change in version diff
2025-11-18 21:58:05 +03:00
Taylan Bakırcıoğlu 3e2f3e3d9f fix(ssl): comprehensive SSL advanced options handling across all endpoints
Critical fixes for SSL advanced options (alpn, npn, ciphers, ciphersuites, min-ver, max-ver, strict-sni):

1. Frontend GET API (backend/routers/frontend.py)
   - Added all 7 SSL advanced option fields to response
   - Frontend Edit modal will now display these fields
   - Prevents NULL overwrite when user edits frontend

2. Bulk Import Frontend UPDATE (backend/routers/config.py)
   - Added all 7 SSL advanced option fields to UPDATE statement
   - Previously skipped with comment 'MVP: DON'T update SSL settings'
   - Now bulk import re-runs preserve SSL settings

3. Backend Server GET API (backend/routers/backend.py)
   - Added 4 server SSL fields (ssl_sni, ssl_min_ver, ssl_max_ver, ssl_ciphers)
   - SQL SELECT query updated
   - Response object updated
   - Backend Server Edit modal will now display these fields

Root cause: GET APIs were not returning SSL advanced options, causing:
- UI forms to show empty fields
- User edits to overwrite with NULL
- Data loss on subsequent updates

All other endpoints (POST, PUT, INSERT) were already correct.

Impact:
- No more accidental data loss when editing frontends/servers
- Bulk import now preserves SSL advanced options
- UI will correctly display all SSL parameters

Test: Deploy backend, run bulk import, verify ssl_alpn appears in database
2025-11-18 21:58:05 +03:00