Skip to content

Chore: Refactor CLI common functions - #722

Merged
esnible merged 3 commits into
rossoctl:mainfrom
esnible:refactor-mains
Jul 31, 2026
Merged

Chore: Refactor CLI common functions#722
esnible merged 3 commits into
rossoctl:mainfrom
esnible:refactor-mains

Conversation

@esnible

@esnible esnible commented Jul 31, 2026

Copy link
Copy Markdown
Member

Summary

Created using

Refactor the common code from authbridge/cmd/authbridge-proxy/main.go, authbridge/cmd/authbridge-cpex/main.go, and authbridge/cmd/authbridge-envoy/main.go into the authbridge/cmd package

with Opus 4.8 and

`❯ 1. In authlib (Recommended)`
`❯ 1. Safe helpers only (Recommended)`

Summary by CodeRabbit

  • New Features

    • Added shared runtime handling for logging, health checks, statistics, HTTP services, and reverse-proxy services.
    • Added configurable log levels through LOG_LEVEL.
    • Added signal-based toggling between DEBUG and INFO logging.
    • Improved health and readiness endpoint support.
  • Bug Fixes

    • Server startup now reports listener binding errors clearly.
    • Added graceful handling and logging of runtime server failures.
  • Tests

    • Added coverage for log-level parsing and signal-driven log-level changes.

Signed-off-by: Ed Snible <snible@us.ibm.com>
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@esnible, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 17c2484c-9f2d-45bc-8d58-52f13b04f746

📥 Commits

Reviewing files that changed from the base of the PR and between 2d8a5ea and 2ce5407.

📒 Files selected for processing (4)
  • authbridge/authlib/runtimeutil/runtimeutil.go
  • authbridge/cmd/authbridge-cpex/main.go
  • authbridge/cmd/authbridge-envoy/main.go
  • authbridge/cmd/authbridge-proxy/main.go
📝 Walkthrough

Walkthrough

Changes

Shared runtime integration

Layer / File(s) Summary
Process logging and signal control
authbridge/authlib/runtimeutil/runtimeutil.go, authbridge/authlib/runtimeutil/runtimeutil_test.go, authbridge/cmd/authbridge-cpex/main.go, authbridge/cmd/authbridge-envoy/main.go, authbridge/cmd/authbridge-proxy/main.go
Shared logging reads LOG_LEVEL, configures slog, and toggles DEBUG/INFO on SIGUSR1. Commands use the shared logging APIs and tests cover parsing and toggling.
Health and statistics serving
authbridge/authlib/runtimeutil/runtimeutil.go, authbridge/authlib/observe/statserver.go, authbridge/cmd/authbridge-cpex/main.go, authbridge/cmd/authbridge-envoy/main.go, authbridge/cmd/authbridge-proxy/main.go
Shared health, readiness, statistics, and configuration server helpers replace command-local implementations. StatServer serves on a caller-provided listener.
HTTP and reverse-proxy listeners
authbridge/authlib/runtimeutil/runtimeutil.go, authbridge/cmd/authbridge-cpex/main.go, authbridge/cmd/authbridge-proxy/main.go
Shared HTTP and reverse-proxy startup binds listeners, reports startup failures, serves asynchronously, and supports shutdown handling.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CommandMain
  participant RuntimeUtil
  participant HTTPServer
  participant ReverseProxyServer
  CommandMain->>RuntimeUtil: StartHTTPServer
  RuntimeUtil->>HTTPServer: Bind listener and serve
  CommandMain->>RuntimeUtil: StartReverseProxyServer
  RuntimeUtil->>ReverseProxyServer: Listen with TLS and mTLS handling
  ReverseProxyServer-->>CommandMain: Return server handle
Loading

Suggested reviewers: abigailgold

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the refactoring of common functionality across the CLI entry points.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
authbridge/authlib/runtime/runtime.go (2)

39-51: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a unit test for the LOG_LEVEL switch in InitLogging.

The level-mapping logic (debug/warn/error/default) is pure and easy to test in isolation, without needing to exercise the goroutines or network binding elsewhere in this file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/authlib/runtime/runtime.go` around lines 39 - 51, Add unit
coverage for the LOG_LEVEL mapping in InitLogging, testing debug, warn, error,
and an unset or unknown value mapping to the expected slog levels. Isolate the
switch logic from unrelated runtime behavior and restore any environment or
global logging state between cases.

72-97: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add read/write/idle timeouts to the server helpers to bound slow-client connections.

StartHealthServer (Line 93) calls http.ListenAndServe directly with no *http.Server and no timeouts at all. StartHTTPServer (Lines 117-121) and StartReverseProxyServer (Lines 144-148) set ReadHeaderTimeout but not ReadTimeout, WriteTimeout, or IdleTimeout. A slow or malicious client can hold a connection open past the header phase and exhaust server resources.

🔧 Proposed fix to bound connection lifetimes
 func StartHealthServer(inboundH, outboundH *pipeline.Holder) {
 	go func() {
 		mux := http.NewServeMux()
 		mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
 			w.WriteHeader(http.StatusOK)
 		})
 		mux.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
 			if name := inboundH.NotReadyPlugin(); name != "" {
 				http.Error(w, "inbound plugin not ready: "+name, http.StatusServiceUnavailable)
 				return
 			}
 			if name := outboundH.NotReadyPlugin(); name != "" {
 				http.Error(w, "outbound plugin not ready: "+name, http.StatusServiceUnavailable)
 				return
 			}
 			w.WriteHeader(http.StatusOK)
 		})
+		srv := &http.Server{
+			Addr:              ":9091",
+			Handler:           mux,
+			ReadHeaderTimeout: 10 * time.Second,
+			ReadTimeout:       15 * time.Second,
+			WriteTimeout:      15 * time.Second,
+			IdleTimeout:       60 * time.Second,
+		}
 		slog.Info("health server listening", "addr", ":9091")
-		if err := http.ListenAndServe(":9091", mux); err != nil {
+		if err := srv.ListenAndServe(); err != nil {
 			slog.Warn("health server failed", "error", err)
 		}
 	}()
 }

Apply the same ReadTimeout/WriteTimeout/IdleTimeout fields to the http.Server literals in StartHTTPServer and StartReverseProxyServer.

Also applies to: 116-133, 143-160

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/authlib/runtime/runtime.go` around lines 72 - 97, Update
StartHealthServer, StartHTTPServer, and StartReverseProxyServer to use
http.Server configurations with bounded ReadTimeout, WriteTimeout, and
IdleTimeout values, retaining the existing ReadHeaderTimeout settings. Replace
the direct health-server ListenAndServe call with the configured server’s method
while preserving current handlers and logging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@authbridge/authlib/runtime/runtime.go`:
- Around line 37-51: Update the InitLogging function signature in
authbridge/authlib/runtime/runtime.go (lines 37-51) to accept a binaryName
string parameter and attach it to the default logger using With("binary",
binaryName) on the slog.New call. Simultaneously update all three call sites:
authbridge/cmd/authbridge-cpex/main.go (lines 63-68) to call
runtime.InitLogging("authbridge-cpex"), authbridge/cmd/authbridge-envoy/main.go
(lines 61-66) to call runtime.InitLogging("authbridge-envoy"), and
authbridge/cmd/authbridge-proxy/main.go (lines 136-137) to call
runtime.InitLogging("authbridge-proxy"), ensuring each binary passes its own
name to satisfy the logging guideline.

---

Nitpick comments:
In `@authbridge/authlib/runtime/runtime.go`:
- Around line 39-51: Add unit coverage for the LOG_LEVEL mapping in InitLogging,
testing debug, warn, error, and an unset or unknown value mapping to the
expected slog levels. Isolate the switch logic from unrelated runtime behavior
and restore any environment or global logging state between cases.
- Around line 72-97: Update StartHealthServer, StartHTTPServer, and
StartReverseProxyServer to use http.Server configurations with bounded
ReadTimeout, WriteTimeout, and IdleTimeout values, retaining the existing
ReadHeaderTimeout settings. Replace the direct health-server ListenAndServe call
with the configured server’s method while preserving current handlers and
logging.
🪄 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 Plus

Run ID: 399053dd-ab5a-48d6-9fd2-ddef4b62aeaa

📥 Commits

Reviewing files that changed from the base of the PR and between 0c1c9a7 and 2d87632.

📒 Files selected for processing (4)
  • authbridge/authlib/runtime/runtime.go
  • authbridge/cmd/authbridge-cpex/main.go
  • authbridge/cmd/authbridge-envoy/main.go
  • authbridge/cmd/authbridge-proxy/main.go

Comment thread authbridge/authlib/runtimeutil/runtimeutil.go

@huang195 huang195 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Clean mechanical extraction — I diffed each of the six moved helpers against its original and they are byte-identical, so there is no behavioral drift here. Net -120 lines across three main.go files is a good trade.

All comments below are about the new shared package's design, not the move itself. Nothing blocking.

Note on CI: the red CodeQL Analysis (python) mark is a cancelled job (this PR touches only Go), not a real failure. Everything else is green.

Areas reviewed: Go (authlib + cmd), commit/PR conventions, security, tests
Commits: 1, signed-off ✓


Assisted-By: Claude Code

"time"

"github.com/rossoctl/cortex/authbridge/authlib/config"
"github.com/rossoctl/cortex/authbridge/authlib/listener/reverseproxy"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestion — The package doc (line 8) says this package is "intentionally listener-agnostic", but this import is the reverse-proxy listener. The claim and the code disagree.

The practical cost lands on authbridge-envoy: it uses only InitLogging, StartSignalToggle, StartStatServer, LogLevel, and StartHealthServer — none of the reverse-proxy helpers — and it does not import reverseproxy itself. By importing runtime it now transitively links listener/reverseproxy, listener/httpx, listener/internal/tlssniff, listener/internal/sseframe, and authlib/tls for nothing. That matters a bit more than usual given the authbridge-lite trimming comment in authbridge-proxy/main.go.

Two ways out. Either drop the "listener-agnostic" sentence and accept the coupling, or keep the claim true with a small local interface:

// Listenable is the subset of a listener server that StartReverseProxyServer
// needs, so this package stays free of concrete listener imports.
type Listenable interface {
	Handler() http.Handler
	Listen(addr string) (net.Listener, error)
	MTLSEnabled() bool
}

*reverseproxy.Server satisfies that structurally, so both call sites pass rpSrv unchanged and the import goes away.

Comment thread authbridge/authlib/runtime/runtime.go Outdated
}
listener, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("%s listen: %v", name, err)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestionlog.Fatalf was fine when this lived in package main; it reads differently now that it is in authlib. Three consequences:

  1. A bind failure os.Exit(1)s whatever process imports the package, with no chance for the caller to fall back or clean up. authlib otherwise behaves like a library.
  2. It makes these helpers effectively untestable — a test that exercises the bind-failure path takes the test binary down with it. Plausibly part of why there is no runtime_test.go yet.
  3. log.Fatalf goes through the stdlib log package, bypassing the slog handler InitLogging just installed. The fatal line lands outside the structured log stream operators are scraping.

Since the signature is already changing in this PR, this is the cheap moment to return (*http.Server, error) from StartHTTPServer/StartReverseProxyServer and let each main keep its own log.Fatalf. Same applies to StartStatServer at line 107. Fine to defer to a follow-up if you would rather keep this PR purely mechanical.

(Minor, same region: err != http.ErrServerClosed would be more robust as errors.Is(err, http.ErrServerClosed) now that it appears three times in one file.)

Comment thread authbridge/authlib/runtime/runtime.go Outdated
w.WriteHeader(http.StatusOK)
})
slog.Info("health server listening", "addr", ":9091")
if err := http.ListenAndServe(":9091", mux); err != nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestion:9091 is hardcoded here and in the log line above, while the sibling StartStatServer reads cfg.Stats.StatsAddress (config.go:489, defaulting to :9093 at config.go:523). The asymmetry was invisible when this was an inline goroutine in each main; it is more conspicuous as a shared helper, and it means the helper cannot be bound to an ephemeral port in a test or run twice in one process.

Taking addr string and having the three call sites pass ":9091" keeps behavior identical and matches the style of the other two Start* helpers. A Health.Address config field with a :9091 default would be the fuller fix, but that is arguably out of scope for a chore.

Comment thread authbridge/authlib/runtime/runtime.go Outdated

// InitLogging sets the process log level from the LOG_LEVEL env var (debug /
// warn / error, default info) and installs a slog text handler on stderr.
func InitLogging() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestion — No runtime_test.go. Every other package under authbridge/authlib/ has at least one (pipeline 14, spiffe 5, tlsbridge 5, and ≥1 for the remaining twelve), so this is the one gap in an otherwise consistent convention — and it is newly-shared code, where a regression now hits all three binaries at once.

The two cheapest wins need no refactor:

  • InitLogging: table test over LOG_LEVEL values (debug/warn/error/unset/garbage/mixed-case) asserting LogLevel().
  • StartSignalToggle: raise SIGUSR1 and assert the DEBUG↔INFO flip, including the case where the starting level is warn (today the first signal jumps straight to DEBUG — worth pinning that down as intended).

StartHTTPServer becomes testable against ":0" once the log.Fatalf point above is addressed.

Comment thread authbridge/authlib/runtime/runtime.go Outdated
// This package is intentionally listener-agnostic: it imports no gRPC and no
// cgo, so authlib does not gain the envoy (go-control-plane / grpc) or cpex
// (libcpex_ffi) dependency by hosting it.
package runtime

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nitruntime shadows the stdlib package of the same name. Nothing breaks today (I checked: none of the three main.go files use stdlib runtime), but any future runtime.NumCPU(), runtime.GC(), or pprof-adjacent code in these files will need an import alias, and the ambiguity costs a beat on every read of runtime.StartHealthServer.

Renaming a brand-new package is nearly free right now and gets expensive once other repos import it. Something like procruntime, bootstrap, or serve would keep the intent.

Signed-off-by: Ed Snible <snible@us.ibm.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
authbridge/authlib/runtimeutil/runtimeutil.go (1)

70-95: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Return health-listener bind errors to the caller.

StartHealthServer starts the goroutine before http.ListenAndServe binds addr. If the address is unavailable, the command continues without health endpoints, and the current log message appears before the bind succeeds. Bind with net.Listen before starting the goroutine, and return the bind error so callers can fail startup consistently with StartStatServer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/authlib/runtimeutil/runtimeutil.go` around lines 70 - 95, Update
StartHealthServer to bind addr with net.Listen before launching the serving
goroutine, returning the listener’s error to the caller when binding fails. Pass
the successfully created listener to the HTTP server inside the goroutine and
log that the server is listening only after binding succeeds, matching
StartStatServer’s startup behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@authbridge/authlib/runtimeutil/runtimeutil.go`:
- Around line 121-125: Set a nonzero ReadTimeout alongside ReadHeaderTimeout in
both StartHTTPServer and StartReverseProxyServer, using the same bounded
body-read timeout for each listener while preserving their existing server
configuration.

---

Outside diff comments:
In `@authbridge/authlib/runtimeutil/runtimeutil.go`:
- Around line 70-95: Update StartHealthServer to bind addr with net.Listen
before launching the serving goroutine, returning the listener’s error to the
caller when binding fails. Pass the successfully created listener to the HTTP
server inside the goroutine and log that the server is listening only after
binding succeeds, matching StartStatServer’s startup behavior.
🪄 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 Plus

Run ID: 28623217-c12b-401f-a073-408dd9243dd8

📥 Commits

Reviewing files that changed from the base of the PR and between 2d87632 and 2d8a5ea.

📒 Files selected for processing (6)
  • authbridge/authlib/observe/statserver.go
  • authbridge/authlib/runtimeutil/runtimeutil.go
  • authbridge/authlib/runtimeutil/runtimeutil_test.go
  • authbridge/cmd/authbridge-cpex/main.go
  • authbridge/cmd/authbridge-envoy/main.go
  • authbridge/cmd/authbridge-proxy/main.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • authbridge/cmd/authbridge-envoy/main.go
  • authbridge/cmd/authbridge-proxy/main.go
  • authbridge/cmd/authbridge-cpex/main.go

Comment on lines +121 to +125
func StartHTTPServer(name string, handler http.Handler, addr string) (*http.Server, error) {
srv := &http.Server{
Addr: addr,
Handler: handler,
ReadHeaderTimeout: 10 * time.Second,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file existence and line count =="
wc -l authbridge/authlib/runtimeutil/runtimeutil.go

echo "== relevant source =="
cat -n authbridge/authlib/runtimeutil/runtimeutil.go | sed -n '1,220p'

echo "== searches for runtimeutil exports/usages =="
rg -n "StartHTTPServer|StartReverseProxyServer|ReadHeaderTimeout|ReadTimeout|WriteTimeout" authbridge -S

echo "== reverse proxy server source references in authbridge =="
fd -a 'server\.go$|proxy' authbridge/authlib authbridge | sed 's#^\./##' | head -200
rg -n "type Server|func \(.*\) Handler|ReadHeaderTimeout|ReadTimeout|WriteTimeout|body" authbridge/authlib/authbridge -S | head -300

Repository: rossoctl/cortex

Length of output: 11201


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== reverseproxy source =="
cat -n authbridge/authlib/listener/reverseproxy/server.go | sed -n '1,260p'

echo "== forwardproxy source snippets =="
cat -n authbridge/authlib/listener/forwardproxy/server.go | sed -n '1,260p'

echo "== config definitions for listener section =="
rg -n "type Listener|ReverseProxyAddr|ForwardProxyAddr|MaxUpload|Upload|Buffer|size" authbridge/authlib/authlib authbridge/authlib -S | head -200
for f in $(fd -a 'config.*\.go$' authbridge/authlib | head -20); do
  echo "--- $f"
  cat -n "$f" | sed -n '1,220p'
done

echo "== request body read uses in listener packages =="
rg -n "\.Body|\.Request|ReadAll|io\.Copy|MaxMemory|WriteTimeout|ReadTimeout" authbridge/authlib/listener authbridge/authlib -S | head -300

echo "== static verifier: http.Server defaults and timeout fields in runtimeutil helper constructors =="
python3 - <<'PY'
from pathlib import Path
p = Path("authbridge/authlib/runtimeutil/runtimeutil.go")
text = p.read_text()
for start, fn in [
    ("StartHTTPServer", "func StartHTTPServer"),
    ("StartReverseProxyServer", "func StartReverseProxyServer"),
]:
    idx = text.index(fn)
    # until the next top-level func
    nxt = text.find("\nfunc ", idx + 1)
    if nxt == -1:
        nxt = len(text)
    body = text[idx:nxt]
    print(f"== {start} ==")
    print("has ReadHeaderTimeout:", "ReadHeaderTimeout:" in body)
    print("has ReadTimeout:", "ReadTimeout:" in body)
    print("has WriteTimeout:", "WriteTimeout:" in body)
PY

echo "== Go http.Server documentation in local tool if available =="
if command -v go >/dev/null 2>&1; then
  go doc net/http.Server 2>/dev/null | sed -n '1,120p' || true
else
  echo "go not available"
fi

Repository: rossoctl/cortex

Length of output: 37495


Add bounded request timeouts to both listener helpers.

ReadHeaderTimeout only covers headers. Clients can still stall body reads for the lifetime of the connection because ReadTimeout is unset. Set a nonzero body timeout on both StartHTTPServer and StartReverseProxyServer; this helper is used by both proxy listeners.

🧰 Tools
🪛 ast-grep (0.45.0)

[warning] 121-125: This http.Server is constructed without a ReadTimeout. Without a read timeout, a slow or malicious client can hold connections open indefinitely (e.g. a Slowloris attack), exhausting server resources and causing a denial of service. Set ReadTimeout (and ideally ReadHeaderTimeout, WriteTimeout, and IdleTimeout) on the http.Server to bound how long the server waits while reading a request.
Context: http.Server{
Addr: addr,
Handler: handler,
ReadHeaderTimeout: 10 * time.Second,
}
Note: [CWE-400] Uncontrolled Resource Consumption.

(http-server-missing-read-timeout-go)

📍 Affects 1 file
  • authbridge/authlib/runtimeutil/runtimeutil.go#L121-L125 (this comment)
  • authbridge/authlib/runtimeutil/runtimeutil.go#L148-L152
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/authlib/runtimeutil/runtimeutil.go` around lines 121 - 125, Set a
nonzero ReadTimeout alongside ReadHeaderTimeout in both StartHTTPServer and
StartReverseProxyServer, using the same bounded body-read timeout for each
listener while preserving their existing server configuration.

Source: Linters/SAST tools

Signed-off-by: Ed Snible <snible@us.ibm.com>
@esnible
esnible merged commit 510ce11 into rossoctl:main Jul 31, 2026
19 checks passed
@github-project-automation github-project-automation Bot moved this from New/ToDo to Done in Rossoctl Issue Prioritization Jul 31, 2026
@esnible
esnible deleted the refactor-mains branch July 31, 2026 17:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants