Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion charts/nudgebee-agent/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ runnerServiceAccount:
runner:
image:
repository: ghcr.io/nudgebee/nudgebee-agent
tag: 2026-07-14T03-38-04_fbc9436d684526a0b45488ac510a33e5168b5ae7
tag: 2026-07-14T09-20-14_17a3cbad58bd80c14dee85a158cc4ec2de19e09f
# Image template the pod_profiler action launches debugger pods from.
# The agent substitutes `{}` for the variant (bpf, jvm, python, perf, ruby).
# Surfaces as PROFILER_IMAGE; leave empty to fall back to the binary default.
Expand Down
6 changes: 6 additions & 0 deletions runner/pkg/enrichers/loki.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ func (l *LokiCompat) rawGet(ctx context.Context, path string) ([]byte, error) {
if err != nil {
return nil, err
}
// LOKI_USERNAME/LOKI_PASSWORD → Basic-Auth, mirroring the primitive
// loki.Client.get (client.go). The compat path was dropping these,
// causing 401s on any basic-auth Loki.
if l.c.Username != "" && l.c.Password != "" {
req.SetBasicAuth(l.c.Username, l.c.Password)
}
for k, vv := range l.c.ExtraHeaders {
for _, v := range vv {
req.Header.Add(k, v)
Expand Down
63 changes: 63 additions & 0 deletions runner/pkg/enrichers/loki_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package enrichers

import (
"context"
"net/http"
"net/http/httptest"
"testing"
"time"

"github.com/nudgebee/nudgebee-agent/pkg/observability/loki"
)

// TestLokiCompat_SendsBasicAuth verifies the compat handlers apply
// LOKI_USERNAME/LOKI_PASSWORD basic auth, matching the primitive
// loki.Client path. Regression guard for the 401-on-basic-auth-Loki bug.
func TestLokiCompat_SendsBasicAuth(t *testing.T) {
var gotUser, gotPass string
var gotOK bool
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotUser, gotPass, gotOK = r.BasicAuth()
_, _ = w.Write([]byte(`{"status":"success"}`))
}))
defer srv.Close()

lc := loki.New(srv.URL, &http.Client{Timeout: 5 * time.Second})
lc.Username = "loki-user"
lc.Password = "loki-pass"
compat := NewLokiCompat(lc)

h := compat.Handlers()["query_loki"]
if _, err := h(context.Background(), map[string]any{"query": "query={foo=\"bar\"}"}); err != nil {
t.Fatal(err)
}
if !gotOK {
t.Fatal("no basic auth header reached upstream")
}
if gotUser != "loki-user" || gotPass != "loki-pass" {
t.Errorf("basic auth = %q/%q; want loki-user/loki-pass", gotUser, gotPass)
}
}

// TestLokiCompat_NoAuthWhenUnset confirms we don't send basic auth when
// username/password aren't configured (only one set counts as unset).
func TestLokiCompat_NoAuthWhenUnset(t *testing.T) {
var sawAuth bool
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _, sawAuth = r.BasicAuth()
_, _ = w.Write([]byte(`{}`))
}))
defer srv.Close()

lc := loki.New(srv.URL, &http.Client{Timeout: 5 * time.Second})
lc.Username = "only-user" // password empty → must not send basic auth
compat := NewLokiCompat(lc)

h := compat.Handlers()["query_loki"]
if _, err := h(context.Background(), map[string]any{"query": "query=x"}); err != nil {
t.Fatal(err)
}
if sawAuth {
t.Error("basic auth sent even though password is empty")
}
}