Skip to content

[management, proxy] Add CrowdSec IP reputation integration for reverse proxy#5722

Merged
lixmal merged 14 commits intomainfrom
crowdsec-integration
Apr 14, 2026
Merged

[management, proxy] Add CrowdSec IP reputation integration for reverse proxy#5722
lixmal merged 14 commits intomainfrom
crowdsec-integration

Conversation

@lixmal
Copy link
Copy Markdown
Collaborator

@lixmal lixmal commented Mar 28, 2026

Describe your changes

Add CrowdSec IP reputation checking to the reverse proxy, controlled per-service (off/enforce/observe) via the management API.

  • Add stream bouncer with local decision cache and refcounted lifecycle (starts on first service, stops on last)
  • Extend restrict.Filter with CrowdSec verdicts and observe mode support
  • Proxy reports supports_crowdsec capability so dashboard/API can gate the feature
  • Access log carries CrowdSec metadata for both enforce and observe hits
  • Configured via --crowdsec-api-url / --crowdsec-api-key flags or NB_PROXY_CROWDSEC_API_URL / NB_PROXY_CROWDSEC_API_KEY env vars

Restriction evaluation order

Access restrictions are evaluated as a pipeline: CIDR, country, then CrowdSec. Each layer can only further restrict. A denial at any layer is final and short-circuits later layers.

Layer What it does Deny behavior
1. CIDR Allowlist narrows to specific ranges; blocklist removes specific ranges Deny stops here, CrowdSec never runs
2. Country Allowlist/blocklist by geolocation Deny stops here, CrowdSec never runs
3. CrowdSec IP reputation check against LAPI decision cache Can block IPs that passed layers 1 and 2

Examples:

Config Client IP CIDR Country CrowdSec Result
allow 10.0.0.0/8 + enforce 10.1.2.3 (banned) pass skip ban crowdsec_ban
allow 10.0.0.0/8 + enforce 10.2.3.4 (clean) pass skip clean allow
allow 10.0.0.0/8 + enforce 192.168.1.1 deny skip skip ip_restricted
block 10.1.0.0/16 + enforce 10.1.2.3 (banned) deny skip skip ip_restricted
allow country US + enforce 1.2.3.4 US (banned) skip pass ban crowdsec_ban
allow country US + enforce 5.6.7.8 CN skip deny skip country_restricted
allow 10.0.0.0/8 + block country CN + enforce 10.1.2.3 US (banned) pass pass ban crowdsec_ban
allow 10.0.0.0/8 + observe 10.1.2.3 (banned) pass skip ban (logged) allow (observe)

CrowdSec can never relax a CIDR or country denial. Observe mode returns the verdict for logging but does not block.

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Summary by CodeRabbit

  • New Features

    • CrowdSec integration: runtime bouncer + shared registry with enforce/observe modes (observe logs but doesn't block).
    • Server accepts CrowdSec API URL/key, advertises cluster CrowdSec capability, and exposes per-domain CrowdSec support.
    • Access restrictions gain crowdsec_mode with stricter validation; access logs and API now include optional per-request metadata.
  • Chores

    • Updated Go module dependency versions and added CrowdSec client libraries.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

Adds CrowdSec integration (streaming Bouncer + registry), makes access restrictions CrowdSec-aware with enforce/observe semantics, threads per-request metadata into captured context → access logs → gRPC/API, extends proxy/management capability plumbing, and adds unit + integration tests.

Changes

Cohort / File(s) Summary
CrowdSec core
proxy/internal/crowdsec/bouncer.go, proxy/internal/crowdsec/bouncer_test.go, proxy/internal/crowdsec/registry.go, proxy/internal/crowdsec/registry_test.go
New streaming Bouncer (Start/Stop/Ready/CheckIP) with exact-IP and prefix caches, a refcounted Registry to manage shared bouncer lifecycle, and comprehensive unit/integration tests.
Restrictions & verdicts
proxy/internal/restrict/restrict.go, proxy/internal/restrict/restrict_test.go, management/internals/modules/reverseproxy/service/service.go
Refactors ParseFilter to ParseFilter(FilterConfig), adds CrowdSec checker and modes (off/enforce/observe), new CrowdSec verdicts and helpers, validation helpers, and expanded tests.
Captured metadata & access logs
proxy/internal/proxy/context.go, proxy/internal/accesslog/logger.go, proxy/internal/accesslog/middleware.go, management/internals/modules/reverseproxy/accesslogs/accesslogentry.go, shared/management/http/api/types.gen.go, shared/management/proto/proxy_service.proto, shared/management/http/api/openapi.yml
Adds per-request metadata storage API, threads metadata into L4 log entries and gRPC/API/OpenAPI types, and persists metadata on access log entries.
Request handling: TCP/UDP/Auth
proxy/internal/tcp/router.go, proxy/internal/udp/relay.go, proxy/internal/auth/middleware.go, proxy/internal/auth/middleware_test.go, proxy/internal/tcp/router_test.go
Implements observe-only handling (log-and-allow) for CrowdSec verdicts, records crowdsec verdict/mode into captured metadata, and updates tests for new ParseFilter usage.
Server & CLI wiring
proxy/cmd/proxy/cmd/root.go, proxy/server.go
Adds CLI/env flags for CrowdSec LAPI, server fields/registry and per-service acquire/release logic, shutdown cleanup, capability reporting, and moves restriction parsing into server scope.
Management domain & capabilities
management/internals/modules/reverseproxy/domain/domain.go, management/internals/modules/reverseproxy/domain/manager/api.go, management/internals/modules/reverseproxy/proxy/manager.go, management/internals/modules/reverseproxy/proxy/proxy.go
Adds SupportsCrowdSec *bool to domain/capabilities, surfaces it in API responses, and extends Manager interface with ClusterSupportsCrowdSec.
Manager/store SQL & mocks
management/internals/modules/reverseproxy/proxy/manager/manager.go, management/internals/modules/reverseproxy/proxy/manager_mock.go, management/server/store/store.go, management/server/store/store_mock.go, management/server/store/sql_store.go
Adds store/manager GetClusterSupportsCrowdSec methods and mocks; SQL implements unanimous-capability aggregation across active proxies and returns *bool semantics.
Access-log / API/type updates
management/internals/modules/reverseproxy/accesslogs/accesslogentry.go, shared/management/http/api/types.gen.go, shared/management/proto/proxy_service.proto, shared/management/http/api/openapi.yml
Access log entry persists Metadata map[string]string; API/proto/OpenAPI types updated to include metadata, crowdsec_mode, and supports_crowdsec.
Tests & integration
proxy/management_integration_test.go, management/internals/modules/reverseproxy/service/manager/l4_port_test.go, many updated tests under proxy/internal/*
Adds bouncer/registry tests and integration scenarios, updates tests for ParseFilter signature and new manager/store mock methods.
Dependencies
go.mod
Bumps multiple deps, adds CrowdSec client modules and related transitive updates.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Proxy
    participant Filter
    participant Bouncer
    participant LAPI
    participant Logger

    Client->>Proxy: Incoming request (source IP)
    Proxy->>Filter: Check(IP)
    alt CIDR/Country allows
        Filter-->>Proxy: Allow
    else CrowdSec evaluation needed
        Filter->>Bouncer: CheckIP(IP)
        Bouncer->>Bouncer: Lookup exact or prefix
        alt Decision found
            Bouncer-->>Filter: CrowdSecDecision
        else No decision
            Bouncer-->>Filter: nil
        end
        Filter->>Proxy: Verdict (Allow / Observe-only / Deny)
    end

    alt Verdict = Allow
        Proxy->>Logger: Log(allow, metadata)
        Proxy->>Client: Forward request
    else Verdict = Observe-only
        Proxy->>Logger: Log(observe, metadata[crowdsec_verdict, crowdsec_mode=observe])
        Proxy->>Client: Forward request
    else Verdict = Deny
        Proxy->>Logger: Log(deny, deny_reason, metadata)
        Proxy-->>Client: 403 Forbidden
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • pascal-fischer
  • pappz

Poem

🐇 I nibble logs and watch the stream,
Decisions dance in a bouncer's dream.
Observe, enforce, or quietly pass,
Metadata carrots tucked in my grass.
Hop safe, hop quick — a rabbit's small cheer.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main feature: CrowdSec IP reputation integration for reverse proxy in management and proxy components.
Description check ✅ Passed The description is comprehensive, explaining the feature implementation, configuration options, restriction evaluation pipeline, examples, and checklist completion. All major sections are addressed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch crowdsec-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@lixmal lixmal changed the base branch from main to persist-proxy-capabilities March 28, 2026 04:42
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@go.mod`:
- Line 25: The goxmldsig dependency is vulnerable (GHSA-479m-364c-43vc) due to a
loop variable capture in validateSignature; update the dependency reference for
github.com/russellhaering/goxmldsig to v1.6.0 or later in go.mod, run the module
update (e.g. go get github.com/russellhaering/goxmldsig@v1.6.0), then run go mod
tidy and your test suite to ensure no breakage; search for the dependency by the
module name github.com/russellhaering/goxmldsig to locate where to bump the
version.

In `@management/internals/modules/reverseproxy/service/service.go`:
- Around line 657-663: Service.Validate currently allows invalid CrowdSecMode
values bypassing the API check; ensure model-level validation by adding a check
in validateAccessRestrictions (called by Service.Validate) to call the enum
validator used in restrictionsFromAPI: if r.CrowdsecMode != nil then call
r.CrowdsecMode.Valid() and return an error (e.g., fmt.Errorf("invalid
crowdsec_mode %q", *r.CrowdsecMode)) on failure, and only assign or accept the
value when valid; update validateAccessRestrictions to mirror the same
validation for CrowdSecMode so restrictionsToAPI()/restrictionsToProto() never
receive unsupported values.

In `@management/internals/shared/grpc/proxy.go`:
- Around line 569-596: ClusterSupportsCrowdSec currently returns true if any
proxy reports SupportsCrowdsec, which permits mixed clusters to advertise
CrowdSec; change the aggregation to require unanimous true: iterate over proxies
from s.proxyController.GetProxiesForCluster(clusterAddr) and for each
connectedProxies entry (proxyConnection), tally SupportsCrowdsec values so that
any explicit false causes an immediate return of ptr(false), any unknown/nil
SupportsCrowdsec results in a conservative nil return (indicating
indeterminate/legacy cluster), and only when at least one proxy reports true and
no proxy reports false or unknown should you return ptr(true); update logic in
ClusterSupportsCrowdSec accordingly, using
proxyConnection.capabilities.SupportsCrowdsec and ptr(...) to construct the
returned pointer values.

In `@proxy/internal/crowdsec/bouncer.go`:
- Around line 171-208: Replace the misspelled word "unparseable" with
"unparsable" in the CrowdSec log messages: update the four logger.Debugf calls
that contain "skip unparseable CrowdSec range deletion", "skip unparseable
CrowdSec IP deletion", "skip unparseable CrowdSec range", and "skip unparseable
CrowdSec IP" found in the Bouncer methods (the deletion handler above applyNew
and the applyNew function) so codespell stops failing.

In `@proxy/server.go`:
- Around line 104-108: Shutdown currently never releases per-service CrowdSec
references, so modify shutdownServices() to iterate the crowdsecServices map
(populated by parseRestrictions()) and call the registry release method for each
entry on crowdsecRegistry (guarding against nil), then remove entries (or clear
the map) so the registry can close its background stream; reference the
crowdsecServices field, parseRestrictions(), shutdownServices(),
crowdsecRegistry and the registry's Release() method when making the change.
- Around line 1297-1304: The code currently downgrades requested CrowdSec modes
to CrowdSecOff when s.crowdsecRegistry.Acquire(svcID) returns nil; instead, do
not change csMode (leave csMode as the originally requested value such as
restrict.CrowdSecEnforce), log that the checker is unavailable, and record that
the service requested CrowdSec but has no active checker (e.g., set
s.crowdsecServices[svcID] = false or another flag indicating "requested but
unavailable") so the caller can treat it as unavailable/deny; also ensure
downstream logic (including restrict.ParseFilter) preserves the enforce value
when checker == nil so enforcement is surfaced as unavailable rather than
silently failing open.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3d625997-aabd-4a80-af79-669cec0ebc23

📥 Commits

Reviewing files that changed from the base of the PR and between 7abf730 and 39bec81.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • shared/management/proto/proxy_service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (32)
  • go.mod
  • management/internals/modules/reverseproxy/accesslogs/accesslogentry.go
  • management/internals/modules/reverseproxy/domain/domain.go
  • management/internals/modules/reverseproxy/domain/manager/api.go
  • management/internals/modules/reverseproxy/domain/manager/manager.go
  • management/internals/modules/reverseproxy/proxy/manager.go
  • management/internals/modules/reverseproxy/proxy/manager/controller.go
  • management/internals/modules/reverseproxy/proxy/manager_mock.go
  • management/internals/modules/reverseproxy/service/manager/l4_port_test.go
  • management/internals/modules/reverseproxy/service/service.go
  • management/internals/shared/grpc/proxy.go
  • management/internals/shared/grpc/proxy_test.go
  • proxy/cmd/proxy/cmd/root.go
  • proxy/internal/accesslog/logger.go
  • proxy/internal/accesslog/middleware.go
  • proxy/internal/auth/middleware.go
  • proxy/internal/auth/middleware_test.go
  • proxy/internal/crowdsec/bouncer.go
  • proxy/internal/crowdsec/bouncer_test.go
  • proxy/internal/crowdsec/registry.go
  • proxy/internal/crowdsec/registry_test.go
  • proxy/internal/proxy/context.go
  • proxy/internal/restrict/restrict.go
  • proxy/internal/restrict/restrict_test.go
  • proxy/internal/tcp/router.go
  • proxy/internal/tcp/router_test.go
  • proxy/internal/udp/relay.go
  • proxy/management_integration_test.go
  • proxy/server.go
  • shared/management/http/api/openapi.yml
  • shared/management/http/api/types.gen.go
  • shared/management/proto/proxy_service.proto

Comment thread management/internals/modules/reverseproxy/service/service.go
Comment thread management/internals/shared/grpc/proxy.go Outdated
Comment thread proxy/internal/crowdsec/bouncer.go Outdated
Comment thread proxy/server.go
@lixmal lixmal force-pushed the crowdsec-integration branch 4 times, most recently from 2d58252 to b8717a1 Compare March 28, 2026 10:46
@lixmal
Copy link
Copy Markdown
Collaborator Author

lixmal commented Mar 28, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@lixmal lixmal force-pushed the crowdsec-integration branch 2 times, most recently from 6b88bd1 to 0ef67c8 Compare March 28, 2026 11:06
@lixmal
Copy link
Copy Markdown
Collaborator Author

lixmal commented Mar 28, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@lixmal lixmal force-pushed the crowdsec-integration branch from 0ef67c8 to 64ca812 Compare March 28, 2026 11:37
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
proxy/internal/restrict/restrict.go (1)

140-149: Fragile: IsCrowdSec() relies on iota ordering.

The range check v >= DenyCrowdSecBan && v <= DenyCrowdSecUnavailable assumes these four verdicts remain contiguous in the const block. If someone adds a new verdict between them or reorders, this breaks silently.

Consider an explicit switch or a comment warning future maintainers.

♻️ Proposed explicit check
 // IsCrowdSec returns true when the verdict originates from a CrowdSec check.
 func (v Verdict) IsCrowdSec() bool {
-	return v >= DenyCrowdSecBan && v <= DenyCrowdSecUnavailable
+	switch v {
+	case DenyCrowdSecBan, DenyCrowdSecCaptcha, DenyCrowdSecThrottle, DenyCrowdSecUnavailable:
+		return true
+	default:
+		return false
+	}
 }

Also applies to: 175-178

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@proxy/internal/restrict/restrict.go` around lines 140 - 149, The IsCrowdSec()
function currently uses a numeric range check against the iota-ordered constants
(DenyCrowdSecBan through DenyCrowdSecUnavailable) which is fragile; replace the
range check with an explicit switch or set membership test listing the four
specific verdict constants (DenyCrowdSecBan, DenyCrowdSecCaptcha,
DenyCrowdSecThrottle, DenyCrowdSecUnavailable) so membership is explicit and
resilient to reordering, and apply the same change to the other similar check
that currently uses the v >= ... && v <= ... pattern (the second range check
referencing the same CrowdSec verdicts).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@go.mod`:
- Line 25: The grpc-go dependency declaration currently pins
google.golang.org/grpc to v1.77.0 which is vulnerable (CVE-2026-33186); update
the module version in go.mod to at least v1.79.3 (e.g., change
google.golang.org/grpc v1.77.0 to google.golang.org/grpc v1.79.3) and run go
get/google.golang.org/grpc@v1.79.3 followed by go mod tidy to ensure the
lockfile and transitive deps are updated so the invalid :path header is rejected
before interceptors/handlers.

In `@management/server/store/sql_store.go`:
- Around line 5517-5539: The current aggregation treats NULLs as absent and can
mark a capability unanimous when some active proxies have NULL; fix by counting
total active rows and requiring non-NULL and true counts to equal that total.
Update the result struct (e.g., add Total and NonNull/TrueCount fields) and
change the Select on Model(&proxy.Proxy{}) to SELECT COUNT(*) AS total,
COUNT(CASE WHEN <column> IS NOT NULL THEN 1 END) AS non_null, COUNT(CASE WHEN
<column> = true THEN 1 END) AS true_count, then after Scan(&result) only return
a pointer to AllTrue when result.non_null == result.total && result.true_count
== result.total (and still return nil when total == 0 or non_null != total). Use
the existing column variable and the same query context (s.db.WithContext) and
preserve the existing logging/return behavior on error.

In `@proxy/internal/crowdsec/bouncer.go`:
- Around line 59-109: The Start/Stop lifecycle leaks state and races with
consumeStream: Start doesn't clear b.ips, b.prefixes or reset b.ready before
launching a new stream, and done only waits for stream.Run so Stop can return
while consumeStream still mutates cache; fix by clearing the in-memory decision
state and resetting readiness at the start of Start (reset b.ips, b.prefixes,
any refcount maps, and set b.ready = false) before initializing the stream, and
change the goroutine coordination so Stop waits for both stream.Run and
consumeStream to exit (e.g. introduce a sync.WaitGroup or a dedicated
consumer-done channel used by consumeStream and close done only after both
complete); update references in Start/Stop and consumeStream (b.Start, b.Stop,
b.consumeStream, b.ips, b.prefixes, b.ready, b.cancel, b.done) accordingly while
holding b.lifeMu where appropriate to avoid races.

In `@proxy/server.go`:
- Around line 104-108: The crowdsecServices map is accessed concurrently by
parseRestrictions, releaseCrowdSec, and shutdownCrowdSec without
synchronization; protect all accesses by acquiring the existing portMu lock (or
add a dedicated mutex) around reads, writes, deletes and iterations on
crowdsecServices. Update parseRestrictions to lock portMu before modifying
crowdsecServices, update releaseCrowdSec to lock portMu around the read+delete,
and update shutdownCrowdSec to lock portMu while iterating/clearing the map so
all operations are serialized and race-free.

---

Nitpick comments:
In `@proxy/internal/restrict/restrict.go`:
- Around line 140-149: The IsCrowdSec() function currently uses a numeric range
check against the iota-ordered constants (DenyCrowdSecBan through
DenyCrowdSecUnavailable) which is fragile; replace the range check with an
explicit switch or set membership test listing the four specific verdict
constants (DenyCrowdSecBan, DenyCrowdSecCaptcha, DenyCrowdSecThrottle,
DenyCrowdSecUnavailable) so membership is explicit and resilient to reordering,
and apply the same change to the other similar check that currently uses the v
>= ... && v <= ... pattern (the second range check referencing the same CrowdSec
verdicts).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7bd5204a-b76b-48ef-a6d0-6ed18f26145e

📥 Commits

Reviewing files that changed from the base of the PR and between 39bec81 and 0ef67c8.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • shared/management/proto/proxy_service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (35)
  • go.mod
  • management/internals/modules/reverseproxy/accesslogs/accesslogentry.go
  • management/internals/modules/reverseproxy/domain/domain.go
  • management/internals/modules/reverseproxy/domain/manager/api.go
  • management/internals/modules/reverseproxy/domain/manager/manager.go
  • management/internals/modules/reverseproxy/proxy/manager.go
  • management/internals/modules/reverseproxy/proxy/manager/manager.go
  • management/internals/modules/reverseproxy/proxy/manager_mock.go
  • management/internals/modules/reverseproxy/proxy/proxy.go
  • management/internals/modules/reverseproxy/service/manager/l4_port_test.go
  • management/internals/modules/reverseproxy/service/service.go
  • management/internals/shared/grpc/proxy.go
  • management/server/store/sql_store.go
  • management/server/store/store.go
  • management/server/store/store_mock.go
  • proxy/cmd/proxy/cmd/root.go
  • proxy/internal/accesslog/logger.go
  • proxy/internal/accesslog/middleware.go
  • proxy/internal/auth/middleware.go
  • proxy/internal/auth/middleware_test.go
  • proxy/internal/crowdsec/bouncer.go
  • proxy/internal/crowdsec/bouncer_test.go
  • proxy/internal/crowdsec/registry.go
  • proxy/internal/crowdsec/registry_test.go
  • proxy/internal/proxy/context.go
  • proxy/internal/restrict/restrict.go
  • proxy/internal/restrict/restrict_test.go
  • proxy/internal/tcp/router.go
  • proxy/internal/tcp/router_test.go
  • proxy/internal/udp/relay.go
  • proxy/management_integration_test.go
  • proxy/server.go
  • shared/management/http/api/openapi.yml
  • shared/management/http/api/types.gen.go
  • shared/management/proto/proxy_service.proto
✅ Files skipped from review due to trivial changes (4)
  • management/internals/modules/reverseproxy/domain/manager/api.go
  • management/internals/modules/reverseproxy/proxy/proxy.go
  • management/internals/modules/reverseproxy/proxy/manager_mock.go
  • shared/management/http/api/types.gen.go
🚧 Files skipped from review as they are similar to previous changes (12)
  • proxy/internal/auth/middleware_test.go
  • management/internals/modules/reverseproxy/proxy/manager.go
  • management/internals/modules/reverseproxy/domain/manager/manager.go
  • proxy/internal/accesslog/middleware.go
  • management/internals/modules/reverseproxy/service/manager/l4_port_test.go
  • management/internals/modules/reverseproxy/accesslogs/accesslogentry.go
  • proxy/internal/auth/middleware.go
  • proxy/internal/proxy/context.go
  • proxy/internal/crowdsec/registry_test.go
  • proxy/internal/crowdsec/registry.go
  • management/internals/modules/reverseproxy/service/service.go
  • management/internals/shared/grpc/proxy.go

Comment thread go.mod Outdated
Comment thread management/server/store/sql_store.go
Comment thread proxy/internal/crowdsec/bouncer.go
Comment thread proxy/server.go
@lixmal lixmal force-pushed the crowdsec-integration branch 3 times, most recently from df9f2ca to 91b346d Compare March 29, 2026 06:17
@lixmal
Copy link
Copy Markdown
Collaborator Author

lixmal commented Mar 30, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@go.mod`:
- Around line 45-46: Replace the release-candidate version of the CrowdSec
dependency with the stable release or document why the RC is needed: update the
module entry for github.com/crowdsecurity/crowdsec from v1.7.7-rc1 to the stable
v1.7.6 in go.mod, or add a short comment in the repo (e.g., in README or a deps
justification file) explaining the specific feature/bugfix in v1.7.7-rc1 that
you require and why v1.7.6 is insufficient.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d3eb5d14-9944-471c-b1bc-f0bd57fe86bf

📥 Commits

Reviewing files that changed from the base of the PR and between 0ef67c8 and fdc5181.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • shared/management/proto/proxy_service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (35)
  • go.mod
  • management/internals/modules/reverseproxy/accesslogs/accesslogentry.go
  • management/internals/modules/reverseproxy/domain/domain.go
  • management/internals/modules/reverseproxy/domain/manager/api.go
  • management/internals/modules/reverseproxy/domain/manager/manager.go
  • management/internals/modules/reverseproxy/proxy/manager.go
  • management/internals/modules/reverseproxy/proxy/manager/manager.go
  • management/internals/modules/reverseproxy/proxy/manager_mock.go
  • management/internals/modules/reverseproxy/proxy/proxy.go
  • management/internals/modules/reverseproxy/service/manager/l4_port_test.go
  • management/internals/modules/reverseproxy/service/service.go
  • management/internals/shared/grpc/proxy.go
  • management/server/store/sql_store.go
  • management/server/store/store.go
  • management/server/store/store_mock.go
  • proxy/cmd/proxy/cmd/root.go
  • proxy/internal/accesslog/logger.go
  • proxy/internal/accesslog/middleware.go
  • proxy/internal/auth/middleware.go
  • proxy/internal/auth/middleware_test.go
  • proxy/internal/crowdsec/bouncer.go
  • proxy/internal/crowdsec/bouncer_test.go
  • proxy/internal/crowdsec/registry.go
  • proxy/internal/crowdsec/registry_test.go
  • proxy/internal/proxy/context.go
  • proxy/internal/restrict/restrict.go
  • proxy/internal/restrict/restrict_test.go
  • proxy/internal/tcp/router.go
  • proxy/internal/tcp/router_test.go
  • proxy/internal/udp/relay.go
  • proxy/management_integration_test.go
  • proxy/server.go
  • shared/management/http/api/openapi.yml
  • shared/management/http/api/types.gen.go
  • shared/management/proto/proxy_service.proto
✅ Files skipped from review due to trivial changes (11)
  • management/internals/modules/reverseproxy/domain/manager/api.go
  • management/internals/modules/reverseproxy/service/manager/l4_port_test.go
  • proxy/internal/accesslog/middleware.go
  • management/internals/modules/reverseproxy/proxy/proxy.go
  • proxy/internal/tcp/router_test.go
  • management/internals/modules/reverseproxy/domain/domain.go
  • management/internals/modules/reverseproxy/proxy/manager_mock.go
  • proxy/internal/auth/middleware.go
  • proxy/internal/crowdsec/registry_test.go
  • management/server/store/store_mock.go
  • proxy/internal/crowdsec/bouncer_test.go
🚧 Files skipped from review as they are similar to previous changes (11)
  • management/server/store/store.go
  • management/internals/modules/reverseproxy/proxy/manager.go
  • management/internals/modules/reverseproxy/domain/manager/manager.go
  • management/internals/shared/grpc/proxy.go
  • proxy/internal/auth/middleware_test.go
  • proxy/internal/proxy/context.go
  • management/internals/modules/reverseproxy/proxy/manager/manager.go
  • proxy/internal/udp/relay.go
  • management/server/store/sql_store.go
  • shared/management/http/api/openapi.yml
  • shared/management/http/api/types.gen.go

Comment thread go.mod Outdated
Base automatically changed from persist-proxy-capabilities to main March 30, 2026 11:03
@lixmal lixmal force-pushed the crowdsec-integration branch from fdc5181 to 9c1eb0d Compare March 30, 2026 11:06
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
proxy/internal/accesslog/logger.go (1)

163-173: ⚠️ Potential issue | 🟠 Major

Clone Metadata before passing it to the async goroutine.

log() captures entry.Metadata into a background goroutine and later reads it during proto marshaling. Since maps are reference types in Go, if the caller reuses or mutates the Metadata map after LogL4() returns, the goroutine will race with the write—resulting in a panic or corrupted data. Although current callers create fresh maps per call, the API contract allows unsafe reuse, so the function should defend against it.

Suggested fix
 func (l *Logger) log(entry logEntry) {
+	if entry.Metadata != nil {
+		copied := make(map[string]string, len(entry.Metadata))
+		for k, v := range entry.Metadata {
+			copied[k] = v
+		}
+		entry.Metadata = copied
+	}
+
 	// Fire off the log request in a separate routine.

Also applies to: 216–265

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@proxy/internal/accesslog/logger.go` around lines 163 - 173, The background
goroutine in log() captures entry.Metadata by reference, which can race if
callers reuse or mutate the map after LogL4()/LogL7() return; fix this by
cloning the Metadata map (create a new map and copy all key/value pairs) before
constructing the logEntry and before launching the async goroutine used in
log(), so the goroutine reads an immutable copy. Update code around the logEntry
construction (logEntry.Metadata) and the other occurrences noted (the async
logging path around lines 216–265) to always pass the copied map instead of
entry.Metadata, ensuring map type/element types are preserved during the copy.
🧹 Nitpick comments (1)
management/server/store/sql_store.go (1)

5482-5486: Split the capability allowlists by aggregation mode.

supports_crowdsec now has stricter unanimity semantics than the existing ANY-true flags. Keeping all three fields in one validCapabilityColumns map makes it easy for a future caller to route CrowdSec through getClusterCapability() and silently undo the mixed-cluster safeguard this PR adds.

Based on learnings, supports_custom_ports intentionally uses ANY-true for rolling upgrades while CrowdSec requires unanimity, so the validation layer should preserve that distinction.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@management/server/store/sql_store.go` around lines 5482 - 5486, The current
single validCapabilityColumns map mixes flags with different aggregation
semantics (supports_custom_ports and require_subdomain are ANY-true, while
supports_crowdsec must be unanimous), so split the allowlist into two distinct
maps (e.g., anyTrueCapabilityColumns and unanimousCapabilityColumns) and replace
usages of validCapabilityColumns accordingly; update validation logic and any
callers (notably getClusterCapability) to check supports_custom_ports and
require_subdomain against the ANY-true map and to check supports_crowdsec
against the unanimous map so the stricter CrowdSec unanimity semantics are
preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@go.mod`:
- Line 275: The project currently pins github.com/russellhaering/goxmldsig
v1.5.0 which has a critical signature bypass; update go.mod to ensure goxmldsig
is at v1.6.0 or later by either updating the indirect dependency or adding an
explicit replace directive for github.com/russellhaering/goxmldsig =>
github.com/russellhaering/goxmldsig v1.6.0 (or higher) so the vulnerable
validateSignature implementation is replaced; verify by running go mod tidy and
go list -m all to confirm the resolved version and rerun tests.
- Line 176: The go.mod currently pins github.com/docker/docker at
v28.0.1+incompatible which contains known vulnerabilities; when a patched
release (>= v29.3.1) becomes available, update the dependency to that patched
version (or update the indirect dependency by bumping testcontainers-go to a
release that depends on docker/docker v29.3.1+). Locate the module entry
"github.com/docker/docker v28.0.1+incompatible" in go.mod (and the indirect
reference via testcontainers-go), run the appropriate go get (or change the
version/replacement) to upgrade to v29.3.1 or later, run go mod tidy to refresh
go.sum, and run the test suite to verify compatibility; if testcontainers-go
hasn’t released a bump yet, add a temporary replace directive pointing to the
patched docker/docker module (or a fork) and remove it once upstream updates.

In `@management/internals/modules/reverseproxy/accesslogs/accesslogentry.go`:
- Around line 60-62: In FromProto, remove the conditional check around
serviceLog.GetMetadata() so that a.Metadata is always assigned (use a.Metadata =
maps.Clone(m) after obtaining m from serviceLog.GetMetadata()), ensuring an
empty proto map resets/clears the existing Metadata instead of leaking prior
values; update the block referencing serviceLog.GetMetadata(), a.Metadata and
maps.Clone accordingly so assignment is unconditional.

---

Outside diff comments:
In `@proxy/internal/accesslog/logger.go`:
- Around line 163-173: The background goroutine in log() captures entry.Metadata
by reference, which can race if callers reuse or mutate the map after
LogL4()/LogL7() return; fix this by cloning the Metadata map (create a new map
and copy all key/value pairs) before constructing the logEntry and before
launching the async goroutine used in log(), so the goroutine reads an immutable
copy. Update code around the logEntry construction (logEntry.Metadata) and the
other occurrences noted (the async logging path around lines 216–265) to always
pass the copied map instead of entry.Metadata, ensuring map type/element types
are preserved during the copy.

---

Nitpick comments:
In `@management/server/store/sql_store.go`:
- Around line 5482-5486: The current single validCapabilityColumns map mixes
flags with different aggregation semantics (supports_custom_ports and
require_subdomain are ANY-true, while supports_crowdsec must be unanimous), so
split the allowlist into two distinct maps (e.g., anyTrueCapabilityColumns and
unanimousCapabilityColumns) and replace usages of validCapabilityColumns
accordingly; update validation logic and any callers (notably
getClusterCapability) to check supports_custom_ports and require_subdomain
against the ANY-true map and to check supports_crowdsec against the unanimous
map so the stricter CrowdSec unanimity semantics are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91a06dc4-a353-4252-a255-6d7429284b6f

📥 Commits

Reviewing files that changed from the base of the PR and between fdc5181 and 9c1eb0d.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • shared/management/proto/proxy_service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (35)
  • go.mod
  • management/internals/modules/reverseproxy/accesslogs/accesslogentry.go
  • management/internals/modules/reverseproxy/domain/domain.go
  • management/internals/modules/reverseproxy/domain/manager/api.go
  • management/internals/modules/reverseproxy/domain/manager/manager.go
  • management/internals/modules/reverseproxy/proxy/manager.go
  • management/internals/modules/reverseproxy/proxy/manager/manager.go
  • management/internals/modules/reverseproxy/proxy/manager_mock.go
  • management/internals/modules/reverseproxy/proxy/proxy.go
  • management/internals/modules/reverseproxy/service/manager/l4_port_test.go
  • management/internals/modules/reverseproxy/service/service.go
  • management/internals/shared/grpc/proxy.go
  • management/server/store/sql_store.go
  • management/server/store/store.go
  • management/server/store/store_mock.go
  • proxy/cmd/proxy/cmd/root.go
  • proxy/internal/accesslog/logger.go
  • proxy/internal/accesslog/middleware.go
  • proxy/internal/auth/middleware.go
  • proxy/internal/auth/middleware_test.go
  • proxy/internal/crowdsec/bouncer.go
  • proxy/internal/crowdsec/bouncer_test.go
  • proxy/internal/crowdsec/registry.go
  • proxy/internal/crowdsec/registry_test.go
  • proxy/internal/proxy/context.go
  • proxy/internal/restrict/restrict.go
  • proxy/internal/restrict/restrict_test.go
  • proxy/internal/tcp/router.go
  • proxy/internal/tcp/router_test.go
  • proxy/internal/udp/relay.go
  • proxy/management_integration_test.go
  • proxy/server.go
  • shared/management/http/api/openapi.yml
  • shared/management/http/api/types.gen.go
  • shared/management/proto/proxy_service.proto
✅ Files skipped from review due to trivial changes (9)
  • management/internals/modules/reverseproxy/domain/manager/api.go
  • management/internals/shared/grpc/proxy.go
  • proxy/management_integration_test.go
  • proxy/internal/accesslog/middleware.go
  • proxy/internal/auth/middleware.go
  • management/internals/modules/reverseproxy/proxy/proxy.go
  • management/internals/modules/reverseproxy/proxy/manager/manager.go
  • proxy/internal/tcp/router_test.go
  • management/server/store/store_mock.go
🚧 Files skipped from review as they are similar to previous changes (11)
  • management/server/store/store.go
  • proxy/cmd/proxy/cmd/root.go
  • proxy/internal/proxy/context.go
  • management/internals/modules/reverseproxy/domain/domain.go
  • proxy/internal/crowdsec/registry_test.go
  • management/internals/modules/reverseproxy/proxy/manager.go
  • management/internals/modules/reverseproxy/proxy/manager_mock.go
  • management/internals/modules/reverseproxy/service/service.go
  • proxy/internal/crowdsec/bouncer_test.go
  • proxy/internal/restrict/restrict_test.go
  • shared/management/http/api/openapi.yml

Comment thread go.mod
Comment thread go.mod Outdated
Comment thread management/internals/modules/reverseproxy/accesslogs/accesslogentry.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
go.mod (1)

176-177: ⚠️ Potential issue | 🟠 Major

High-severity Docker CVEs still transitively present via testcontainers path.

github.com/docker/docker v28.0.1+incompatible remains in the graph; this was previously flagged and still appears unresolved in this diff. Please confirm whether a newer github.com/testcontainers/testcontainers-go now pulls a patched Docker module and bump if available.

#!/bin/bash
# Read-only verification of current module pins related to the issue
rg -n 'github.com/testcontainers/testcontainers-go|github.com/docker/docker|github.com/docker/go-connections' go.mod
What is the first github.com/testcontainers/testcontainers-go release that depends on github.com/docker/docker v29.3.1 or newer?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go.mod` around lines 176 - 177, The go.mod still contains
github.com/docker/docker v28.0.1+incompatible pulled transitively via
testcontainers; find the first github.com/testcontainers/testcontainers-go
release that depends on github.com/docker/docker v29.3.1+ (inspect
testcontainers-go release tags or its go.mod) and update the dependency
accordingly by bumping testcontainers-go to that release (e.g., run go get
github.com/testcontainers/testcontainers-go@<release>) then run go mod tidy and
re-run the verification (rg) to ensure github.com/docker/docker is now v29.3.1
or newer; target module symbols: github.com/testcontainers/testcontainers-go and
github.com/docker/docker.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@go.mod`:
- Around line 176-177: The go.mod still contains github.com/docker/docker
v28.0.1+incompatible pulled transitively via testcontainers; find the first
github.com/testcontainers/testcontainers-go release that depends on
github.com/docker/docker v29.3.1+ (inspect testcontainers-go release tags or its
go.mod) and update the dependency accordingly by bumping testcontainers-go to
that release (e.g., run go get
github.com/testcontainers/testcontainers-go@<release>) then run go mod tidy and
re-run the verification (rg) to ensure github.com/docker/docker is now v29.3.1
or newer; target module symbols: github.com/testcontainers/testcontainers-go and
github.com/docker/docker.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a810e4fc-f06e-475f-b6ac-f21ec792b3cb

📥 Commits

Reviewing files that changed from the base of the PR and between 9c1eb0d and 72a5cae.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (2)
  • go.mod
  • management/internals/modules/reverseproxy/accesslogs/accesslogentry.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • management/internals/modules/reverseproxy/accesslogs/accesslogentry.go

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
management/internals/modules/reverseproxy/accesslogs/accesslogentry.go (1)

123-126: Avoid exposing the internal metadata map by reference.

metadata = &a.Metadata returns a pointer to the mutable map owned by AccessLogEntry. Clone before attaching it to the API response to avoid accidental external mutation.

♻️ Proposed refactor
 	var metadata *map[string]string
 	if len(a.Metadata) > 0 {
-		metadata = &a.Metadata
+		cloned := maps.Clone(a.Metadata)
+		metadata = &cloned
 	}

Also applies to: 147-147

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@management/internals/modules/reverseproxy/accesslogs/accesslogentry.go`
around lines 123 - 126, The code currently sets metadata = &a.Metadata which
exposes the internal mutable map of AccessLogEntry; instead, deep-clone
a.Metadata into a new map (e.g., make(map[string]string) and copy each
key/value) and set metadata to a pointer to that new map so callers can't mutate
the original; apply the same change for the other occurrence that also takes
&a.Metadata (both places referencing the AccessLogEntry.Metadata field).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@go.mod`:
- Line 112: Update the vulnerable dependency entry
"go.opentelemetry.io/otel/sdk/metric v1.42.0" to v1.43.0 in go.mod to pick up
the GHSA-hfvc-g4fc-pqhx fix; after changing the version string, run the
canonical Go module update (e.g., go get
go.opentelemetry.io/otel/sdk/metric@v1.43.0 and then go mod tidy) to ensure the
lockfile/update is applied and verify no other modules require manual
adjustments.

---

Nitpick comments:
In `@management/internals/modules/reverseproxy/accesslogs/accesslogentry.go`:
- Around line 123-126: The code currently sets metadata = &a.Metadata which
exposes the internal mutable map of AccessLogEntry; instead, deep-clone
a.Metadata into a new map (e.g., make(map[string]string) and copy each
key/value) and set metadata to a pointer to that new map so callers can't mutate
the original; apply the same change for the other occurrence that also takes
&a.Metadata (both places referencing the AccessLogEntry.Metadata field).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2d11c35d-f687-4a14-9f64-66d283cd09ff

📥 Commits

Reviewing files that changed from the base of the PR and between 9c1eb0d and a9bca87.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • shared/management/proto/proxy_service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (9)
  • go.mod
  • management/internals/modules/reverseproxy/accesslogs/accesslogentry.go
  • management/internals/modules/reverseproxy/service/manager/l4_port_test.go
  • management/internals/modules/reverseproxy/service/service.go
  • management/server/store/sql_store.go
  • management/server/store/store.go
  • management/server/store/store_mock.go
  • shared/management/http/api/openapi.yml
  • shared/management/http/api/types.gen.go
✅ Files skipped from review due to trivial changes (1)
  • shared/management/http/api/openapi.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • management/internals/modules/reverseproxy/service/manager/l4_port_test.go

Comment thread go.mod Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
proxy/internal/restrict/restrict.go (1)

271-304: Normalize "off" before evaluating CrowdSec.

Management/API now preserve crowdsec_mode="off", but this guard only treats the empty-string sentinel as disabled. ParseFilter currently hides that mismatch for its own callers, yet any direct Filter{CrowdSecMode: "off"} would still fall through to CheckIP. Making the runtime check tolerant of both representations would keep the type self-contained.

♻️ Suggested hardening
 func (f *Filter) checkCrowdSec(addr netip.Addr) Verdict {
-	if f.CrowdSecMode == CrowdSecOff {
+	if f.CrowdSecMode == CrowdSecOff || f.CrowdSecMode == CrowdSecMode("off") {
 		return Allow
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@proxy/internal/restrict/restrict.go` around lines 271 - 304, The
checkCrowdSec method should treat the literal "off" value the same as the
existing CrowdSecOff sentinel so a Filter constructed with CrowdSecMode="off" is
treated as disabled; in checkCrowdSec (and not just ParseFilter) normalize or
compare f.CrowdSecMode against both the canonical CrowdSecOff constant and the
string "off" (case-insensitively) before proceeding, so the early-return branch
that returns Allow runs for either representation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@proxy/server.go`:
- Around line 1327-1335: The FilterConfig currently omits the trusted/bypass
CIDRs so restrict.ParseFilter can't skip them; update the parseRestrictions
return by adding the trusted CIDRs field to the struct passed to
restrict.ParseFilter (e.g., set TrustedCIDRs: r.GetTrustedCidrs() or the correct
field name expected by restrict.FilterConfig) so that restrict.ParseFilter and
downstream checks (CrowdSec/country rules) receive the bypass list; ensure you
use the existing r.GetTrustedCidrs() accessor and the exact field name defined
on restrict.FilterConfig.
- Around line 1541-1542: The releaseCrowdSec call is happening too early (using
svcID := types.ServiceID(mapping.GetId()) then s.releaseCrowdSec(svcID)); move
this call so the CrowdSec registry ref is released only after the route/relay
and any auth/routes/UDP relays/filters have been fully detached/removed (i.e.,
after the code that unregisters the mapping and stops/removes the old
relays/filters). Keep the same svcID (from mapping.GetId()) but invoke
s.releaseCrowdSec(svcID) after the existing relay-removal/route-detach logic
completes to avoid stopping the shared checker while stale filters are still
reachable.

---

Nitpick comments:
In `@proxy/internal/restrict/restrict.go`:
- Around line 271-304: The checkCrowdSec method should treat the literal "off"
value the same as the existing CrowdSecOff sentinel so a Filter constructed with
CrowdSecMode="off" is treated as disabled; in checkCrowdSec (and not just
ParseFilter) normalize or compare f.CrowdSecMode against both the canonical
CrowdSecOff constant and the string "off" (case-insensitively) before
proceeding, so the early-return branch that returns Allow runs for either
representation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d29b34e3-7db0-42b3-828f-4189cc37fb67

📥 Commits

Reviewing files that changed from the base of the PR and between a9bca87 and 4d10303.

⛔ Files ignored due to path filters (1)
  • shared/management/proto/proxy_service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (7)
  • management/internals/modules/reverseproxy/service/service.go
  • proxy/internal/restrict/restrict.go
  • proxy/internal/restrict/restrict_test.go
  • proxy/server.go
  • shared/management/http/api/openapi.yml
  • shared/management/http/api/types.gen.go
  • shared/management/proto/proxy_service.proto
🚧 Files skipped from review as they are similar to previous changes (2)
  • shared/management/http/api/openapi.yml
  • proxy/internal/restrict/restrict_test.go

Comment thread proxy/server.go
Comment thread proxy/server.go Outdated
…ing, otel CVE

- Clone Metadata map in LogL4 before passing to background goroutine
- Move releaseCrowdSec after route cleanup to avoid stopping bouncer mid-flight
- Bump otel SDK to v1.43.0 (GHSA-hfvc-g4fc-pqhx), restore otelgrpc/prometheus versions
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
go.mod (1)

178-178: ⚠️ Potential issue | 🟠 Major

Bump github.com/docker/docker to a patched version via explicit indirect pin.

Line 178 still pins github.com/docker/docker v28.0.1+incompatible, which is affected by the reported Docker/Moby advisories. Since testcontainers-go currently pulls vulnerable Docker versions, keep the testcontainers-go version if needed, but explicitly pin Docker to a patched version (>= 29.3.1) and validate resolution after tidy.

Proposed go.mod change
-	github.com/docker/docker v28.0.1+incompatible // indirect
+	github.com/docker/docker v29.3.1+incompatible // indirect
#!/bin/bash
set -euo pipefail

echo "== Current docker module pin in repository =="
rg -n 'github.com/docker/docker\s+v' go.mod

echo
echo "== testcontainers-go v0.37.0 docker dependency =="
curl -fsSL https://raw.githubusercontent.com/testcontainers/testcontainers-go/v0.37.0/go.mod | tr ' ' '\n' | rg 'github.com/docker/docker|v28|v29'

echo
echo "== testcontainers-go v0.41.0 docker dependency =="
curl -fsSL https://raw.githubusercontent.com/testcontainers/testcontainers-go/v0.41.0/go.mod | tr ' ' '\n' | rg 'github.com/docker/docker|v28|v29'

echo
echo "== Advisory fixed version references =="
curl -fsSL https://osv.dev/vulnerability/GO-2026-4883 | rg -n 'Patched versions|29\.3\.1|Affected versions' || true
curl -fsSL https://osv.dev/vulnerability/GO-2026-4887 | rg -n 'Patched versions|29\.3\.1|Affected versions' || true

Based on learnings: In Go modules, explicit // indirect pins for security-fixed transitive versions are acceptable and preserved by MVS/go mod tidy when parents have not yet caught up.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go.mod` at line 178, Update the explicit indirect pin for the Docker module
in go.mod: replace the current "github.com/docker/docker v28.0.1+incompatible"
entry with a patched version >= v29.3.1 (keep the // indirect comment), run "go
mod tidy" to validate module resolution, and verify the new version is preserved
and no incompatible upgrades break consumers (check testcontainers-go
compatibility and run unit/integration tests).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@go.mod`:
- Line 178: Update the explicit indirect pin for the Docker module in go.mod:
replace the current "github.com/docker/docker v28.0.1+incompatible" entry with a
patched version >= v29.3.1 (keep the // indirect comment), run "go mod tidy" to
validate module resolution, and verify the new version is preserved and no
incompatible upgrades break consumers (check testcontainers-go compatibility and
run unit/integration tests).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 11ac160f-192e-4696-8a4a-22f6f31e86a2

📥 Commits

Reviewing files that changed from the base of the PR and between 4d10303 and d73b6c7.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (3)
  • go.mod
  • proxy/internal/accesslog/logger.go
  • proxy/server.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants