Conversation
…entity - Redesign dashboard from stat cards to operational view with live system status (Caddy, DB, sync), proxy overview, and activity feed - Add Copper color palette (warm amber primary, cream neutrals) with tight 0.25rem radius and crisp shadows - Switch body font to Clash Grotesk, logo wordmark to Bricolage Grotesque - Create custom W Portal logo (SVG) inspired by Elden Ring waygates - Clarify form labels: rename "Upstream Servers" to "Backend Servers", "Skip TLS Verification" to "Allow Self-Signed Certificates", add field descriptions and format hints throughout - Add entrance animations (staggered fade-up) on dashboard - Improve login/signup: gradient background, autofocus, autoComplete attributes, signup success toast, friendlier error messages - Rename settings tabs: "Catchall" to "Default Page", "ACL Branding" to "Login Branding" - Add dashboard hooks for sync status, health, and app status - Add theme preview page for design iteration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Redesign login/signup as split layout with brand panel on desktop, centered form on mobile, tagline "Fast travel for your network" - Polish ACL login: match Copper palette default, fix radius to sharp theme, add autofocus, fix validation timing to onBlur, remove console.error, friendlier error messages, add entrance animation - Rewrite branding settings preview to use actual Card/CardContent components matching the real ACL login page structure - Fix branding background_color default to empty (use theme), fix preview to match actual page in both light and dark mode - Fix dark mode CSS specificity (.default.default.dark) and increase background/card contrast for better surface separation - Remove unused Mail import from branding settings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add filter bar (Type, Status, SSL) using Titanium Filters component, matching the audit logs page pattern - Replace plain text empty state with rich component: icon, description, and CTA buttons for HTTP and TCP/UDP proxy creation - Add tooltips and sr-only labels to edit/delete action buttons - Fix skeleton shapes from rounded-full to rounded for theme consistency - Improve search placeholder to clarify searchable fields - Add aria-label to search input for accessibility Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…s app - Fix all rounded-full/rounded-lg skeleton shapes to rounded across audit logs, L4 proxies, ACL groups, and group usage tab - Fix icon containers on proxy detail, L4 proxy detail, ACL group detail, and stat cards from rounded-lg/rounded-full to rounded - Add rich empty state with CTA button to ACL groups listing page - Fix type switcher pills from rounded-full to rounded on proxy create - Add autofocus on Name field in reverse proxy form (create mode only) - Fix ACL selector radius: assignment rows, icon containers, add form - Improve ACL groups search placeholder and add aria-label - Simplify ACL groups search wrapper Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove commented-out External Providers tab code from ACL detail page - Fix "ACL group" jargon in not-found state to "access control group" - Rename "ACL" filter label to "Access Control" in audit logs - Improve audit logs search placeholder and add aria-label Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename "L4 Proxies" to "TCP/UDP Proxies" in sidebar nav for consistency with the rest of the app - Fix profile dialog info container from rounded-lg to rounded - Change password form validation from onChange to onBlur - Add autoComplete attributes to all password change fields - Fix extra whitespace in dropdown menu icon classNames Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix health and app status hooks to unwrap ApiResponse.data (was
reading the full response object, causing status dots to always
show red)
- Format uptime from raw Go duration ("173h33m10s") to human-readable
("7 days 5 hours 33 minutes") using date-fns
- Add page-enter animation to all dashboard routes via keyed wrapper
that re-triggers on navigation
- Add animate-fade-in utility class for simple opacity transitions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Flag auth/acl events as security-critical with a Security badge, warn inline and require confirmation before disabling them, and add a master toggle, collapsible groups with enabled counts, per-key change tracking, and skeleton/error states. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The decorative mock login labels in the live preview triggered Biome's noLabelWithoutControl since they wrap no form control. They are inside an aria-hidden block, so swap <label> for <span> to keep the lint gate green without changing the rendered preview. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
caddy-l4 v0.1.1 requires caddy/v2 >= v2.11.3, but the builder image was pinned to caddy:2.10.2-builder, so 'xcaddy build --with .../caddy-l4' failed with a version conflict and the deployable image could not be built. Bump the builder to caddy:2.11.3-builder and pin caddy-l4 to v0.1.1 so an upstream release can't silently break the build again. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Design for an opt-in, build-tagged suite that drives real traffic through Caddy for both L7 (reverse_proxy/redirect/static + LB, ACL, block_exploits, custom_headers) and L4 (any/http/postgres/tls-SNI/remote_ip + LB) proxies, closing the gap where only config generation and the API were tested. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
15-task TDD plan: build-tagged testcontainers harness driving real traffic through Caddy for 7 L7 and 6 L4 scenarios, gated behind 'make test-traffic'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add TestTraffic_L7 with the reverse_proxy subtest (replacing the TestTraffic_Smoke placeholder). Also fix echoHostnameFromBody to read the backend container hostname from os.hostname instead of the top-level hostname field, which mendhak echo populates with the request Host header. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a custom_headers subtest to TestTraffic_L7 asserting that a configured
custom response header (X-Test: waygates) is present on the proxied response.
Confirmed shape: models.Proxy.CustomHeaders is a flat JSONField
(map[string]interface{}) of {"Header-Name":"value"} (models/proxy.go:29),
not the nested {"response":{...}} shape the plan guessed.
NOTE: this test currently FAILS (red). The product injects custom_headers as
REQUEST headers to the upstream (caddy/config/http_builder.go:206-212) and never
as RESPONSE headers to the client, so X-Test never reaches the client. The test
correctly documents the intended contract; the implementation fix is out of
scope for this test-only task.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The traffic E2E surfaced that custom_headers are applied only as request headers to the upstream (http_builder.go:206), so the response-header assertion cannot pass yet. Skip with a clear pointer; un-skip once the typed request/response custom-headers feature lands. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the acl_basic_auth subtest to TestTraffic_L7, driving real traffic through Caddy: unauthenticated GET -> 401, GET with valid Basic creds -> 200 reaching echo1. Fixes a real product bug it surfaced: the sync service only constructed the ACL builder when BOTH Waygates forward-auth URLs were set (ACL_WAYGATES_LOGIN_URL defaults to empty), which silently disabled all self-contained ACL methods (HTTP basic auth, IP allow/deny/bypass). The ACL builder is now always created; the Waygates URLs are only consulted by the forward-auth handler, which is still only emitted when a group configures Waygates/OAuth/external-provider auth. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add round_robin_lb subtest to TestTraffic_L4 verifying an L4 tcp proxy with an http matcher and round_robin policy distributes connections across two echo backends (echo1/echo2:8080). Disable HTTP keep-alives in httpEchoHostname so each probe opens a fresh TCP connection. Caddy's layer4 round_robin balances per connection, not per request; without this the pooled keep-alive connection pinned all 10 requests to a single backend, masking the LB. Observed distribution with the fix is an even 5/5 split. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When an ACL group enables Waygates forward-auth but ACL_WAYGATES_VERIFY_URL is empty, the builder previously emitted a reverse_proxy upstream with dial:"" which Caddy rejects, breaking the entire config reload. An empty login URL similarly produced a host-less self-redirect loop on 401. Guard both cases by emitting a static 503 deny response so the route fails CLOSED (never proxies to a blank upstream, never loops), keeping behavior unchanged when the URLs are set. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ath-only scope The L4 http matcher does protocol detection only: it matches any HTTP connection and intentionally ignores sni_hostnames (SNI is a TLS concept; HTTP host routing is L7). Document this on the http case in MapMatcherTypeToL4Matcher and note that sni_hostnames is not restricted to the tls matcher in validation (it is accepted but silently ignored for other matcher types, by design, to avoid breaking existing data/clients). Also note the known limitation that block_exploits rules match on URL path only (path_regexp) and do not inspect query strings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds both-direction custom headers (request to upstream + response to
client) with a flexible CustomHeaders type: flat map accepted as request
headers for back-compat, normalized to nested {request,response} on read,
no DB migration. Closes the gap the traffic E2E surfaced.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7-task TDD plan: flexible CustomHeaders model type, builder both-direction header application, E2E un-skip asserting both directions, and UI request/ response header editors. Backward-compatible (flat map = request), no DB migration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3 tasks
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #14 +/- ##
==========================================
+ Coverage 71.82% 73.64% +1.81%
==========================================
Files 48 57 +9
Lines 8614 10027 +1413
==========================================
+ Hits 6187 7384 +1197
- Misses 2066 2264 +198
- Partials 361 379 +18
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the Layer 4 (TCP/UDP) proxy feature to mergeable, production-verified state, adds an end-to-end traffic test suite for the whole proxy system (L7 + L4), and fixes the real bugs that surfaced.
Feature
layer4plugin — 9 matcher types (any/tls/ssh/postgres/http/rdp/socks5/remote_ip/regexp), load balancing, TLS passthrough/terminate, proxy-protocol. Full stack: model → repo → service → handler → routes, sync integration, RBAC, migrations, UI (list/create/detail + nested form), dashboard stats.Build/quality fixes
caddy-l4v0.1.1 requires Caddy 2.11.3 but the builder image was pinned to 2.10.2 → bumped tocaddy:2.11.3-builderand pinnedcaddy-l4@v0.1.1so an upstream release can't silently break the build again.Proxy traffic E2E suite (
make test-traffic)A build-tagged (
//go:build traffic) testcontainers suite that drives real traffic through Caddy — not just config generation. 13 scenarios::80): reverse_proxy, round-robin LB, redirect, static, block_exploits, ACL basic-auth. (custom_headers covered in the stacked PR.)SELECT 1, TLS SNI passthrough.Bugs the suite found and fixed
ACL_WAYGATES_LOGIN_URLwas unset (its default) — a proxy could show auth configured while Caddy served it wide open. Now the ACL builder is always constructed; forward-auth additionally fails closed when its URLs are unset.httpmatcher generated invalid Caddy config ({"http":{}}object vs the requiredcaddy-l4RawMatcherSetsarray) — sync 500'd and the entire layer4 app failed to load. Fixed to serialize as an array.Test plan
make backend-test(unit) — greenmake test-traffic(Docker required) — all L7 + L4 scenarios passpnpm --dir ui build+make lint-ui— green🤖 Generated with Claude Code