diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 2a3663d..ca32198 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -42,7 +42,6 @@ cgr chainguard chall challengemozilla -Chargement checkpath checkresult chibi @@ -54,6 +53,7 @@ containerbuild coreutils Cotoyogi CRDs +Cromite crt Cscript daemonizing @@ -75,6 +75,7 @@ droneblresponse duckduckbot eerror ellenjoe +emacs enbyware etld everyones @@ -166,7 +167,6 @@ Linting linuxbrew LLU loadbalancer -locahost lol LOMINSA maintainership @@ -283,6 +283,7 @@ unparseable uuidgen uvx UXP +Valkey Varis Velen vendored @@ -320,5 +321,5 @@ yourdomain yoursite Zenos zizmor -Zonbocom +zombocom zos diff --git a/anubis.go b/anubis.go index 8e5c1c1..5d3b8c4 100644 --- a/anubis.go +++ b/anubis.go @@ -13,9 +13,6 @@ var Version = "devel" // access. const CookieName = "techaro.lol-anubis-auth" -// WithDomainCookieName is the name that is prepended to the per-domain cookie used when COOKIE_DOMAIN is set. -const WithDomainCookieName = "techaro.lol-anubis-auth-for-" - const TestCookieName = "techaro.lol-anubis-cookie-test-if-you-block-this-anubis-wont-work" // CookieDefaultExpirationTime is the amount of time before the cookie/JWT expires. diff --git a/cmd/anubis/main.go b/cmd/anubis/main.go index 19f1ece..aeb8b85 100644 --- a/cmd/anubis/main.go +++ b/cmd/anubis/main.go @@ -384,20 +384,21 @@ func main() { } s, err := libanubis.New(libanubis.Options{ - BasePrefix: *basePrefix, - StripBasePrefix: *stripBasePrefix, - Next: rp, - Policy: policy, - ServeRobotsTXT: *robotsTxt, - ED25519PrivateKey: ed25519Priv, - HS512Secret: []byte(*hs512Secret), - CookieDomain: *cookieDomain, - CookieExpiration: *cookieExpiration, - CookiePartitioned: *cookiePartitioned, - RedirectDomains: redirectDomainsList, - Target: *target, - WebmasterEmail: *webmasterEmail, - OpenGraph: policy.OpenGraph, + BasePrefix: *basePrefix, + StripBasePrefix: *stripBasePrefix, + Next: rp, + Policy: policy, + ServeRobotsTXT: *robotsTxt, + ED25519PrivateKey: ed25519Priv, + HS512Secret: []byte(*hs512Secret), + CookieDomain: *cookieDomain, + CookieDynamicDomain: *cookieDynamicDomain, + CookieExpiration: *cookieExpiration, + CookiePartitioned: *cookiePartitioned, + RedirectDomains: redirectDomainsList, + Target: *target, + WebmasterEmail: *webmasterEmail, + OpenGraph: policy.OpenGraph, }) if err != nil { log.Fatalf("can't construct libanubis.Server: %v", err) diff --git a/data/botPolicies.yaml b/data/botPolicies.yaml index b4bfea4..dd64828 100644 --- a/data/botPolicies.yaml +++ b/data/botPolicies.yaml @@ -88,7 +88,7 @@ dnsbl: false # impressum: # # Displayed at the bottom of every page rendered by Anubis. # footer: >- -# This website is hosted by Zonbocom. If you have any complaints or notes +# This website is hosted by Zombocom. If you have any complaints or notes # about the service, please contact # contact@domainhere.example # and we will assist you as soon as possible. diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md index 519d49d..d74e538 100644 --- a/docs/docs/CHANGELOG.md +++ b/docs/docs/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Determine the `BIND_NETWORK`/`--bind-network` value from the bind address ([#677](https://github.com/TecharoHQ/anubis/issues/677)) - Implement localization system. Find locale files in lib/localization/locales/. +- Fix dynamic cookie domains functionality ([#731](https://github.com/TecharoHQ/anubis/pull/731)) ## v1.20.0: Thancred Waters diff --git a/lib/anubis.go b/lib/anubis.go index 940be04..006bd0a 100644 --- a/lib/anubis.go +++ b/lib/anubis.go @@ -69,7 +69,6 @@ type Server struct { policy *policy.ParsedConfig DNSBLCache *decaymap.Impl[string, dnsbl.DroneBLResponse] OGTags *ogtags.OGTagCache - cookieName string ed25519Priv ed25519.PrivateKey hs512Secret []byte opts Options @@ -88,8 +87,6 @@ func (s *Server) getTokenKeyfunc() jwt.Keyfunc { } } - - func (s *Server) challengeFor(r *http.Request, difficulty int) string { var fp [32]byte if len(s.hs512Secret) == 0 { @@ -149,24 +146,24 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS return } - ckie, err := r.Cookie(s.cookieName) + ckie, err := r.Cookie(anubis.CookieName) if err != nil { lg.Debug("cookie not found", "path", r.URL.Path) - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.RenderIndex(w, r, rule, httpStatusOnly) return } if err := ckie.Valid(); err != nil { lg.Debug("cookie is invalid", "err", err) - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.RenderIndex(w, r, rule, httpStatusOnly) return } if time.Now().After(ckie.Expires) && !ckie.Expires.IsZero() { lg.Debug("cookie expired", "path", r.URL.Path) - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.RenderIndex(w, r, rule, httpStatusOnly) return } @@ -175,7 +172,7 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS if err != nil || !token.Valid { lg.Debug("invalid token", "path", r.URL.Path, "err", err) - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.RenderIndex(w, r, rule, httpStatusOnly) return } @@ -183,7 +180,7 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS claims, ok := token.Claims.(jwt.MapClaims) if !ok { lg.Debug("invalid token claims type", "path", r.URL.Path) - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.RenderIndex(w, r, rule, httpStatusOnly) return } @@ -191,14 +188,14 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS policyRule, ok := claims["policyRule"].(string) if !ok { lg.Debug("policyRule claim is not a string") - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.RenderIndex(w, r, rule, httpStatusOnly) return } if policyRule != rule.Hash() { lg.Debug("user originally passed with a different rule, issuing new challenge", "old", policyRule, "new", rule.Name) - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.RenderIndex(w, r, rule, httpStatusOnly) return } @@ -222,7 +219,7 @@ func (s *Server) checkRules(w http.ResponseWriter, r *http.Request, cr policy.Ch s.ServeHTTPNext(w, r) return true case config.RuleDeny: - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) lg.Info("explicit deny") if rule == nil { lg.Error("rule is nil, cannot calculate checksum") @@ -241,7 +238,7 @@ func (s *Server) checkRules(w http.ResponseWriter, r *http.Request, cr policy.Ch s.RenderBench(w, r) return true default: - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) slog.Error("CONFIG ERROR: unknown rule", "rule", cr.Rule) s.respondWithError(w, r, fmt.Sprintf("%s \"maybeReverseProxy.Rules\"", localizer.T("internal_server_error"))) return true @@ -265,10 +262,10 @@ func (s *Server) handleDNSBL(w http.ResponseWriter, r *http.Request, ip string, if resp != dnsbl.AllGood { lg.Info("DNSBL hit", "status", resp.String()) localizer := localization.GetLocalizer(r) - s.respondWithStatus(w, r, fmt.Sprintf("%s: %s, %s https://dronebl.org/lookup?ip=%s", - localizer.T("dronebl_entry"), - resp.String(), - localizer.T("see_dronebl_lookup"), + s.respondWithStatus(w, r, fmt.Sprintf("%s: %s, %s https://dronebl.org/lookup?ip=%s", + localizer.T("dronebl_entry"), + resp.String(), + localizer.T("see_dronebl_lookup"), ip), s.policy.StatusCodes.Deny) return true } @@ -314,7 +311,7 @@ func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) { lg = lg.With("check_result", cr) chal := s.challengeFor(r, rule.Challenge.Difficulty) - s.SetCookie(w, anubis.TestCookieName, chal, "/", r.Host) + s.SetCookie(w, CookieOpts{Host: r.Host, Name: anubis.TestCookieName, Value: chal}) err = encoder.Encode(struct { Rules *config.ChallengeRules `json:"rules"` @@ -343,14 +340,14 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) { } if _, err := r.Cookie(anubis.TestCookieName); errors.Is(err, http.ErrNoCookie) { - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) - s.ClearCookie(w, anubis.TestCookieName, "/", r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) + s.ClearCookie(w, CookieOpts{Name: anubis.TestCookieName, Host: r.Host}) lg.Warn("user has cookies disabled, this is not an anubis bug") s.respondWithError(w, r, localizer.T("cookies_disabled")) return } - s.ClearCookie(w, anubis.TestCookieName, "/", r.Host) + s.ClearCookie(w, CookieOpts{Name: anubis.TestCookieName, Host: r.Host}) redir := r.FormValue("redir") redirURL, err := url.ParseRequestURI(redir) @@ -392,7 +389,7 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) { if err := impl.Validate(r, lg, rule, challengeStr); err != nil { failedValidations.WithLabelValues(rule.Challenge.Algorithm).Inc() var cerr *challenge.Error - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) lg.Debug("challenge validate call failed", "err", err) switch { @@ -415,12 +412,12 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) { }) if err != nil { lg.Error("failed to sign JWT", "err", err) - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.respondWithError(w, r, localizer.T("failed_to_sign_jwt")) return } - s.SetCookie(w, s.cookieName, tokenString, cookiePath, r.Host) + s.SetCookie(w, CookieOpts{Path: cookiePath, Host: r.Host, Value: tokenString}) challengesValidated.WithLabelValues(rule.Challenge.Algorithm).Inc() lg.Debug("challenge passed, redirecting to app") diff --git a/lib/anubis_test.go b/lib/anubis_test.go index e3089a8..111ca6b 100644 --- a/lib/anubis_test.go +++ b/lib/anubis_test.go @@ -189,8 +189,6 @@ func TestCVE2025_24369(t *testing.T) { srv := spawnAnubis(t, Options{ Next: http.NewServeMux(), Policy: pol, - - CookieName: t.Name(), }) ts := httptest.NewServer(internal.RemoteXRealIP(true, "tcp", srv)) @@ -235,13 +233,13 @@ func TestCookieCustomExpiration(t *testing.T) { var ckie *http.Cookie for _, cookie := range resp.Cookies() { t.Logf("%#v", cookie) - if cookie.Name == srv.cookieName { + if cookie.Name == anubis.CookieName { ckie = cookie break } } if ckie == nil { - t.Errorf("Cookie %q not found", srv.cookieName) + t.Errorf("Cookie %q not found", anubis.CookieName) return } @@ -264,7 +262,6 @@ func TestCookieSettings(t *testing.T) { CookieDomain: "127.0.0.1", CookiePartitioned: true, - CookieName: t.Name(), CookieExpiration: anubis.CookieDefaultExpirationTime, }) @@ -286,13 +283,13 @@ func TestCookieSettings(t *testing.T) { var ckie *http.Cookie for _, cookie := range resp.Cookies() { t.Logf("%#v", cookie) - if cookie.Name == srv.cookieName { + if cookie.Name == anubis.CookieName { ckie = cookie break } } if ckie == nil { - t.Errorf("Cookie %q not found", srv.cookieName) + t.Errorf("Cookie %q not found", anubis.CookieName) return } @@ -619,7 +616,6 @@ func TestRuleChange(t *testing.T) { Policy: pol, CookieDomain: "127.0.0.1", - CookieName: t.Name(), CookieExpiration: ckieExpiration, }) diff --git a/lib/config.go b/lib/config.go index 8041da8..4c322f3 100644 --- a/lib/config.go +++ b/lib/config.go @@ -35,7 +35,6 @@ type Options struct { CookieDynamicDomain bool CookieDomain string CookieExpiration time.Duration - CookieName string CookiePartitioned bool BasePrefix string WebmasterEmail string @@ -102,12 +101,6 @@ func New(opts Options) (*Server, error) { anubis.BasePrefix = opts.BasePrefix - cookieName := anubis.CookieName - - if opts.CookieDomain != "" { - cookieName = anubis.WithDomainCookieName + opts.CookieDomain - } - result := &Server{ next: opts.Next, ed25519Priv: opts.ED25519PrivateKey, @@ -116,7 +109,6 @@ func New(opts Options) (*Server, error) { opts: opts, DNSBLCache: decaymap.New[string, dnsbl.DroneBLResponse](), OGTags: ogtags.NewOGTagCache(opts.Target, opts.Policy.OpenGraph), - cookieName: cookieName, } mux := http.NewServeMux() diff --git a/lib/http.go b/lib/http.go index 1a5480c..0d8d9e7 100644 --- a/lib/http.go +++ b/lib/http.go @@ -22,18 +22,32 @@ import ( var domainMatchRegexp = regexp.MustCompile(`^((xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$`) -func (s *Server) SetCookie(w http.ResponseWriter, name, value, path, host string) { +type CookieOpts struct { + Value string + Host string + Path string + Name string +} + +func (s *Server) SetCookie(w http.ResponseWriter, cookieOpts CookieOpts) { var domain = s.opts.CookieDomain - if s.opts.CookieDynamicDomain && domainMatchRegexp.MatchString(host) { - if etld, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil { + var name = anubis.CookieName + var path = "/" + if cookieOpts.Name != "" { + name = cookieOpts.Name + } + if cookieOpts.Path != "" { + path = cookieOpts.Path + } + if s.opts.CookieDynamicDomain && domainMatchRegexp.MatchString(cookieOpts.Host) { + if etld, err := publicsuffix.EffectiveTLDPlusOne(cookieOpts.Host); err == nil { domain = etld - name = anubis.WithDomainCookieName + etld } } http.SetCookie(w, &http.Cookie{ Name: name, - Value: value, + Value: cookieOpts.Value, Expires: time.Now().Add(s.opts.CookieExpiration), SameSite: http.SameSiteLaxMode, Domain: domain, @@ -42,12 +56,19 @@ func (s *Server) SetCookie(w http.ResponseWriter, name, value, path, host string }) } -func (s *Server) ClearCookie(w http.ResponseWriter, name, path, host string) { +func (s *Server) ClearCookie(w http.ResponseWriter, cookieOpts CookieOpts) { var domain = s.opts.CookieDomain - if s.opts.CookieDynamicDomain && domainMatchRegexp.MatchString(host) { - if etld, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil { + var name = anubis.CookieName + var path = "/" + if cookieOpts.Name != "" { + name = cookieOpts.Name + } + if cookieOpts.Path != "" { + path = cookieOpts.Path + } + if s.opts.CookieDynamicDomain && domainMatchRegexp.MatchString(cookieOpts.Host) { + if etld, err := publicsuffix.EffectiveTLDPlusOne(cookieOpts.Host); err == nil { domain = etld - name = anubis.WithDomainCookieName + etld } } diff --git a/lib/http_test.go b/lib/http_test.go index 999a9d2..62e2257 100644 --- a/lib/http_test.go +++ b/lib/http_test.go @@ -24,20 +24,20 @@ func TestSetCookie(t *testing.T) { name: "domain techaro.lol", options: Options{CookieDomain: "techaro.lol"}, host: "", - cookieName: anubis.WithDomainCookieName + "techaro.lol", + cookieName: anubis.CookieName, }, { name: "dynamic cookie domain", options: Options{CookieDynamicDomain: true}, host: "techaro.lol", - cookieName: anubis.WithDomainCookieName + "techaro.lol", + cookieName: anubis.CookieName, }, } { t.Run(tt.name, func(t *testing.T) { srv := spawnAnubis(t, tt.options) rw := httptest.NewRecorder() - srv.SetCookie(rw, srv.cookieName, "test", "/", tt.host) + srv.SetCookie(rw, CookieOpts{Value: "test", Host: tt.host}) resp := rw.Result() cookies := resp.Cookies() @@ -55,7 +55,7 @@ func TestClearCookie(t *testing.T) { srv := spawnAnubis(t, Options{}) rw := httptest.NewRecorder() - srv.ClearCookie(rw, srv.cookieName, "/", "localhost") + srv.ClearCookie(rw, CookieOpts{Host: "localhost"}) resp := rw.Result() @@ -80,7 +80,7 @@ func TestClearCookieWithDomain(t *testing.T) { srv := spawnAnubis(t, Options{CookieDomain: "techaro.lol"}) rw := httptest.NewRecorder() - srv.ClearCookie(rw, srv.cookieName, "/", "locahost") + srv.ClearCookie(rw, CookieOpts{Host: "localhost"}) resp := rw.Result() @@ -92,8 +92,8 @@ func TestClearCookieWithDomain(t *testing.T) { ckie := cookies[0] - if ckie.Name != srv.cookieName { - t.Errorf("wanted cookie named %q, got cookie named %q", srv.cookieName, ckie.Name) + if ckie.Name != anubis.CookieName { + t.Errorf("wanted cookie named %q, got cookie named %q", anubis.CookieName, ckie.Name) } if ckie.MaxAge != -1 { @@ -105,7 +105,7 @@ func TestClearCookieWithDynamicDomain(t *testing.T) { srv := spawnAnubis(t, Options{CookieDynamicDomain: true}) rw := httptest.NewRecorder() - srv.ClearCookie(rw, srv.cookieName, "/", "xeiaso.net") + srv.ClearCookie(rw, CookieOpts{Host: "subdomain.xeiaso.net"}) resp := rw.Result() @@ -117,8 +117,12 @@ func TestClearCookieWithDynamicDomain(t *testing.T) { ckie := cookies[0] - if ckie.Name != anubis.WithDomainCookieName+"xeiaso.net" { - t.Errorf("wanted cookie named %q, got cookie named %q", srv.cookieName, ckie.Name) + if ckie.Name != anubis.CookieName { + t.Errorf("wanted cookie named %q, got cookie named %q", anubis.CookieName, ckie.Name) + } + + if ckie.Domain != "xeiaso.net" { + t.Errorf("wanted cookie domain %q, got cookie domain %q", "xeiaso.net", ckie.Domain) } if ckie.MaxAge != -1 { diff --git a/test/go.mod b/test/go.mod index 69e68a6..7edb678 100644 --- a/test/go.mod +++ b/test/go.mod @@ -24,8 +24,8 @@ require ( github.com/gaissmai/bart v0.20.4 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/google/cel-go v0.25.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/jsha/minica v1.1.0 // indirect github.com/kr/text v0.2.0 // indirect @@ -43,9 +43,9 @@ require ( golang.org/x/text v0.26.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect - google.golang.org/grpc v1.72.2 // indirect + google.golang.org/grpc v1.73.0 // indirect google.golang.org/protobuf v1.36.6 // indirect - k8s.io/apimachinery v0.33.1 // indirect + k8s.io/apimachinery v0.33.2 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/test/go.sum b/test/go.sum index f27608b..688f666 100644 --- a/test/go.sum +++ b/test/go.sum @@ -44,8 +44,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jsha/minica v1.1.0 h1:O2ZbzAN75w4RTB+5+HfjIEvY5nxRqDlwj3ZlLVG5JD8= @@ -113,6 +115,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -124,6 +127,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4= k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=