Weighs the soul of incoming HTTP requests to stop AI crawlers

fix: Dynamic cookie domain not working (#731)

* Fix cookieDynamicDomain option not being set in Options struct

* Fix using wrong cookie name when using dynamic cookie domains

* Adjust testcases for new cookie option structs

* Add known words to expect.txt and change typo in Zombocom

* Cleanup expect.txt

* Add changes to changelog

* Bump versions of grpc and apimachinery

* Fix testcases and add additional condition for dynamic cookie domain

authored by Martin and committed by GitHub 6aa17532 b1edf84a

Changed files
+98 -84
.github
actions
spelling
cmd
anubis
data
docs
lib
test
+4 -3
.github/actions/spelling/expect.txt
··· 42 42 chainguard 43 43 chall 44 44 challengemozilla 45 - Chargement 46 45 checkpath 47 46 checkresult 48 47 chibi ··· 54 53 coreutils 55 54 Cotoyogi 56 55 CRDs 56 + Cromite 57 57 crt 58 58 Cscript 59 59 daemonizing ··· 75 75 duckduckbot 76 76 eerror 77 77 ellenjoe 78 + emacs 78 79 enbyware 79 80 etld 80 81 everyones ··· 166 167 linuxbrew 167 168 LLU 168 169 loadbalancer 169 - locahost 170 170 lol 171 171 LOMINSA 172 172 maintainership ··· 283 283 uuidgen 284 284 uvx 285 285 UXP 286 + Valkey 286 287 Varis 287 288 Velen 288 289 vendored ··· 320 321 yoursite 321 322 Zenos 322 323 zizmor 323 - Zonbocom 324 + zombocom 324 325 zos
-3
anubis.go
··· 13 13 // access. 14 14 const CookieName = "techaro.lol-anubis-auth" 15 15 16 - // WithDomainCookieName is the name that is prepended to the per-domain cookie used when COOKIE_DOMAIN is set. 17 - const WithDomainCookieName = "techaro.lol-anubis-auth-for-" 18 - 19 16 const TestCookieName = "techaro.lol-anubis-cookie-test-if-you-block-this-anubis-wont-work" 20 17 21 18 // CookieDefaultExpirationTime is the amount of time before the cookie/JWT expires.
+15 -14
cmd/anubis/main.go
··· 384 384 } 385 385 386 386 s, err := libanubis.New(libanubis.Options{ 387 - BasePrefix: *basePrefix, 388 - StripBasePrefix: *stripBasePrefix, 389 - Next: rp, 390 - Policy: policy, 391 - ServeRobotsTXT: *robotsTxt, 392 - ED25519PrivateKey: ed25519Priv, 393 - HS512Secret: []byte(*hs512Secret), 394 - CookieDomain: *cookieDomain, 395 - CookieExpiration: *cookieExpiration, 396 - CookiePartitioned: *cookiePartitioned, 397 - RedirectDomains: redirectDomainsList, 398 - Target: *target, 399 - WebmasterEmail: *webmasterEmail, 400 - OpenGraph: policy.OpenGraph, 387 + BasePrefix: *basePrefix, 388 + StripBasePrefix: *stripBasePrefix, 389 + Next: rp, 390 + Policy: policy, 391 + ServeRobotsTXT: *robotsTxt, 392 + ED25519PrivateKey: ed25519Priv, 393 + HS512Secret: []byte(*hs512Secret), 394 + CookieDomain: *cookieDomain, 395 + CookieDynamicDomain: *cookieDynamicDomain, 396 + CookieExpiration: *cookieExpiration, 397 + CookiePartitioned: *cookiePartitioned, 398 + RedirectDomains: redirectDomainsList, 399 + Target: *target, 400 + WebmasterEmail: *webmasterEmail, 401 + OpenGraph: policy.OpenGraph, 401 402 }) 402 403 if err != nil { 403 404 log.Fatalf("can't construct libanubis.Server: %v", err)
+1 -1
data/botPolicies.yaml
··· 88 88 # impressum: 89 89 # # Displayed at the bottom of every page rendered by Anubis. 90 90 # footer: >- 91 - # This website is hosted by Zonbocom. If you have any complaints or notes 91 + # This website is hosted by Zombocom. If you have any complaints or notes 92 92 # about the service, please contact 93 93 # <a href="mailto:contact@domainhere.example">contact@domainhere.example</a> 94 94 # and we will assist you as soon as possible.
+1
docs/docs/CHANGELOG.md
··· 13 13 14 14 - Determine the `BIND_NETWORK`/`--bind-network` value from the bind address ([#677](https://github.com/TecharoHQ/anubis/issues/677)) 15 15 - Implement localization system. Find locale files in lib/localization/locales/. 16 + - Fix dynamic cookie domains functionality ([#731](https://github.com/TecharoHQ/anubis/pull/731)) 16 17 17 18 ## v1.20.0: Thancred Waters 18 19
+21 -24
lib/anubis.go
··· 69 69 policy *policy.ParsedConfig 70 70 DNSBLCache *decaymap.Impl[string, dnsbl.DroneBLResponse] 71 71 OGTags *ogtags.OGTagCache 72 - cookieName string 73 72 ed25519Priv ed25519.PrivateKey 74 73 hs512Secret []byte 75 74 opts Options ··· 87 86 } 88 87 } 89 88 } 90 - 91 - 92 89 93 90 func (s *Server) challengeFor(r *http.Request, difficulty int) string { 94 91 var fp [32]byte ··· 149 146 return 150 147 } 151 148 152 - ckie, err := r.Cookie(s.cookieName) 149 + ckie, err := r.Cookie(anubis.CookieName) 153 150 if err != nil { 154 151 lg.Debug("cookie not found", "path", r.URL.Path) 155 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 152 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 156 153 s.RenderIndex(w, r, rule, httpStatusOnly) 157 154 return 158 155 } 159 156 160 157 if err := ckie.Valid(); err != nil { 161 158 lg.Debug("cookie is invalid", "err", err) 162 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 159 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 163 160 s.RenderIndex(w, r, rule, httpStatusOnly) 164 161 return 165 162 } 166 163 167 164 if time.Now().After(ckie.Expires) && !ckie.Expires.IsZero() { 168 165 lg.Debug("cookie expired", "path", r.URL.Path) 169 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 166 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 170 167 s.RenderIndex(w, r, rule, httpStatusOnly) 171 168 return 172 169 } ··· 175 172 176 173 if err != nil || !token.Valid { 177 174 lg.Debug("invalid token", "path", r.URL.Path, "err", err) 178 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 175 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 179 176 s.RenderIndex(w, r, rule, httpStatusOnly) 180 177 return 181 178 } ··· 183 180 claims, ok := token.Claims.(jwt.MapClaims) 184 181 if !ok { 185 182 lg.Debug("invalid token claims type", "path", r.URL.Path) 186 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 183 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 187 184 s.RenderIndex(w, r, rule, httpStatusOnly) 188 185 return 189 186 } ··· 191 188 policyRule, ok := claims["policyRule"].(string) 192 189 if !ok { 193 190 lg.Debug("policyRule claim is not a string") 194 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 191 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 195 192 s.RenderIndex(w, r, rule, httpStatusOnly) 196 193 return 197 194 } 198 195 199 196 if policyRule != rule.Hash() { 200 197 lg.Debug("user originally passed with a different rule, issuing new challenge", "old", policyRule, "new", rule.Name) 201 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 198 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 202 199 s.RenderIndex(w, r, rule, httpStatusOnly) 203 200 return 204 201 } ··· 222 219 s.ServeHTTPNext(w, r) 223 220 return true 224 221 case config.RuleDeny: 225 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 222 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 226 223 lg.Info("explicit deny") 227 224 if rule == nil { 228 225 lg.Error("rule is nil, cannot calculate checksum") ··· 241 238 s.RenderBench(w, r) 242 239 return true 243 240 default: 244 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 241 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 245 242 slog.Error("CONFIG ERROR: unknown rule", "rule", cr.Rule) 246 243 s.respondWithError(w, r, fmt.Sprintf("%s \"maybeReverseProxy.Rules\"", localizer.T("internal_server_error"))) 247 244 return true ··· 265 262 if resp != dnsbl.AllGood { 266 263 lg.Info("DNSBL hit", "status", resp.String()) 267 264 localizer := localization.GetLocalizer(r) 268 - s.respondWithStatus(w, r, fmt.Sprintf("%s: %s, %s https://dronebl.org/lookup?ip=%s", 269 - localizer.T("dronebl_entry"), 270 - resp.String(), 271 - localizer.T("see_dronebl_lookup"), 265 + s.respondWithStatus(w, r, fmt.Sprintf("%s: %s, %s https://dronebl.org/lookup?ip=%s", 266 + localizer.T("dronebl_entry"), 267 + resp.String(), 268 + localizer.T("see_dronebl_lookup"), 272 269 ip), s.policy.StatusCodes.Deny) 273 270 return true 274 271 } ··· 314 311 lg = lg.With("check_result", cr) 315 312 chal := s.challengeFor(r, rule.Challenge.Difficulty) 316 313 317 - s.SetCookie(w, anubis.TestCookieName, chal, "/", r.Host) 314 + s.SetCookie(w, CookieOpts{Host: r.Host, Name: anubis.TestCookieName, Value: chal}) 318 315 319 316 err = encoder.Encode(struct { 320 317 Rules *config.ChallengeRules `json:"rules"` ··· 343 340 } 344 341 345 342 if _, err := r.Cookie(anubis.TestCookieName); errors.Is(err, http.ErrNoCookie) { 346 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 347 - s.ClearCookie(w, anubis.TestCookieName, "/", r.Host) 343 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 344 + s.ClearCookie(w, CookieOpts{Name: anubis.TestCookieName, Host: r.Host}) 348 345 lg.Warn("user has cookies disabled, this is not an anubis bug") 349 346 s.respondWithError(w, r, localizer.T("cookies_disabled")) 350 347 return 351 348 } 352 349 353 - s.ClearCookie(w, anubis.TestCookieName, "/", r.Host) 350 + s.ClearCookie(w, CookieOpts{Name: anubis.TestCookieName, Host: r.Host}) 354 351 355 352 redir := r.FormValue("redir") 356 353 redirURL, err := url.ParseRequestURI(redir) ··· 392 389 if err := impl.Validate(r, lg, rule, challengeStr); err != nil { 393 390 failedValidations.WithLabelValues(rule.Challenge.Algorithm).Inc() 394 391 var cerr *challenge.Error 395 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 392 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 396 393 lg.Debug("challenge validate call failed", "err", err) 397 394 398 395 switch { ··· 415 412 }) 416 413 if err != nil { 417 414 lg.Error("failed to sign JWT", "err", err) 418 - s.ClearCookie(w, s.cookieName, cookiePath, r.Host) 415 + s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) 419 416 s.respondWithError(w, r, localizer.T("failed_to_sign_jwt")) 420 417 return 421 418 } 422 419 423 - s.SetCookie(w, s.cookieName, tokenString, cookiePath, r.Host) 420 + s.SetCookie(w, CookieOpts{Path: cookiePath, Host: r.Host, Value: tokenString}) 424 421 425 422 challengesValidated.WithLabelValues(rule.Challenge.Algorithm).Inc() 426 423 lg.Debug("challenge passed, redirecting to app")
+4 -8
lib/anubis_test.go
··· 189 189 srv := spawnAnubis(t, Options{ 190 190 Next: http.NewServeMux(), 191 191 Policy: pol, 192 - 193 - CookieName: t.Name(), 194 192 }) 195 193 196 194 ts := httptest.NewServer(internal.RemoteXRealIP(true, "tcp", srv)) ··· 235 233 var ckie *http.Cookie 236 234 for _, cookie := range resp.Cookies() { 237 235 t.Logf("%#v", cookie) 238 - if cookie.Name == srv.cookieName { 236 + if cookie.Name == anubis.CookieName { 239 237 ckie = cookie 240 238 break 241 239 } 242 240 } 243 241 if ckie == nil { 244 - t.Errorf("Cookie %q not found", srv.cookieName) 242 + t.Errorf("Cookie %q not found", anubis.CookieName) 245 243 return 246 244 } 247 245 ··· 264 262 265 263 CookieDomain: "127.0.0.1", 266 264 CookiePartitioned: true, 267 - CookieName: t.Name(), 268 265 CookieExpiration: anubis.CookieDefaultExpirationTime, 269 266 }) 270 267 ··· 286 283 var ckie *http.Cookie 287 284 for _, cookie := range resp.Cookies() { 288 285 t.Logf("%#v", cookie) 289 - if cookie.Name == srv.cookieName { 286 + if cookie.Name == anubis.CookieName { 290 287 ckie = cookie 291 288 break 292 289 } 293 290 } 294 291 if ckie == nil { 295 - t.Errorf("Cookie %q not found", srv.cookieName) 292 + t.Errorf("Cookie %q not found", anubis.CookieName) 296 293 return 297 294 } 298 295 ··· 619 616 Policy: pol, 620 617 621 618 CookieDomain: "127.0.0.1", 622 - CookieName: t.Name(), 623 619 CookieExpiration: ckieExpiration, 624 620 }) 625 621
-8
lib/config.go
··· 35 35 CookieDynamicDomain bool 36 36 CookieDomain string 37 37 CookieExpiration time.Duration 38 - CookieName string 39 38 CookiePartitioned bool 40 39 BasePrefix string 41 40 WebmasterEmail string ··· 102 101 103 102 anubis.BasePrefix = opts.BasePrefix 104 103 105 - cookieName := anubis.CookieName 106 - 107 - if opts.CookieDomain != "" { 108 - cookieName = anubis.WithDomainCookieName + opts.CookieDomain 109 - } 110 - 111 104 result := &Server{ 112 105 next: opts.Next, 113 106 ed25519Priv: opts.ED25519PrivateKey, ··· 116 109 opts: opts, 117 110 DNSBLCache: decaymap.New[string, dnsbl.DroneBLResponse](), 118 111 OGTags: ogtags.NewOGTagCache(opts.Target, opts.Policy.OpenGraph), 119 - cookieName: cookieName, 120 112 } 121 113 122 114 mux := http.NewServeMux()
+30 -9
lib/http.go
··· 22 22 23 23 var domainMatchRegexp = regexp.MustCompile(`^((xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$`) 24 24 25 - func (s *Server) SetCookie(w http.ResponseWriter, name, value, path, host string) { 25 + type CookieOpts struct { 26 + Value string 27 + Host string 28 + Path string 29 + Name string 30 + } 31 + 32 + func (s *Server) SetCookie(w http.ResponseWriter, cookieOpts CookieOpts) { 26 33 var domain = s.opts.CookieDomain 27 - if s.opts.CookieDynamicDomain && domainMatchRegexp.MatchString(host) { 28 - if etld, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil { 34 + var name = anubis.CookieName 35 + var path = "/" 36 + if cookieOpts.Name != "" { 37 + name = cookieOpts.Name 38 + } 39 + if cookieOpts.Path != "" { 40 + path = cookieOpts.Path 41 + } 42 + if s.opts.CookieDynamicDomain && domainMatchRegexp.MatchString(cookieOpts.Host) { 43 + if etld, err := publicsuffix.EffectiveTLDPlusOne(cookieOpts.Host); err == nil { 29 44 domain = etld 30 - name = anubis.WithDomainCookieName + etld 31 45 } 32 46 } 33 47 34 48 http.SetCookie(w, &http.Cookie{ 35 49 Name: name, 36 - Value: value, 50 + Value: cookieOpts.Value, 37 51 Expires: time.Now().Add(s.opts.CookieExpiration), 38 52 SameSite: http.SameSiteLaxMode, 39 53 Domain: domain, ··· 42 56 }) 43 57 } 44 58 45 - func (s *Server) ClearCookie(w http.ResponseWriter, name, path, host string) { 59 + func (s *Server) ClearCookie(w http.ResponseWriter, cookieOpts CookieOpts) { 46 60 var domain = s.opts.CookieDomain 47 - if s.opts.CookieDynamicDomain && domainMatchRegexp.MatchString(host) { 48 - if etld, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil { 61 + var name = anubis.CookieName 62 + var path = "/" 63 + if cookieOpts.Name != "" { 64 + name = cookieOpts.Name 65 + } 66 + if cookieOpts.Path != "" { 67 + path = cookieOpts.Path 68 + } 69 + if s.opts.CookieDynamicDomain && domainMatchRegexp.MatchString(cookieOpts.Host) { 70 + if etld, err := publicsuffix.EffectiveTLDPlusOne(cookieOpts.Host); err == nil { 49 71 domain = etld 50 - name = anubis.WithDomainCookieName + etld 51 72 } 52 73 } 53 74
+14 -10
lib/http_test.go
··· 24 24 name: "domain techaro.lol", 25 25 options: Options{CookieDomain: "techaro.lol"}, 26 26 host: "", 27 - cookieName: anubis.WithDomainCookieName + "techaro.lol", 27 + cookieName: anubis.CookieName, 28 28 }, 29 29 { 30 30 name: "dynamic cookie domain", 31 31 options: Options{CookieDynamicDomain: true}, 32 32 host: "techaro.lol", 33 - cookieName: anubis.WithDomainCookieName + "techaro.lol", 33 + cookieName: anubis.CookieName, 34 34 }, 35 35 } { 36 36 t.Run(tt.name, func(t *testing.T) { 37 37 srv := spawnAnubis(t, tt.options) 38 38 rw := httptest.NewRecorder() 39 39 40 - srv.SetCookie(rw, srv.cookieName, "test", "/", tt.host) 40 + srv.SetCookie(rw, CookieOpts{Value: "test", Host: tt.host}) 41 41 42 42 resp := rw.Result() 43 43 cookies := resp.Cookies() ··· 55 55 srv := spawnAnubis(t, Options{}) 56 56 rw := httptest.NewRecorder() 57 57 58 - srv.ClearCookie(rw, srv.cookieName, "/", "localhost") 58 + srv.ClearCookie(rw, CookieOpts{Host: "localhost"}) 59 59 60 60 resp := rw.Result() 61 61 ··· 80 80 srv := spawnAnubis(t, Options{CookieDomain: "techaro.lol"}) 81 81 rw := httptest.NewRecorder() 82 82 83 - srv.ClearCookie(rw, srv.cookieName, "/", "locahost") 83 + srv.ClearCookie(rw, CookieOpts{Host: "localhost"}) 84 84 85 85 resp := rw.Result() 86 86 ··· 92 92 93 93 ckie := cookies[0] 94 94 95 - if ckie.Name != srv.cookieName { 96 - t.Errorf("wanted cookie named %q, got cookie named %q", srv.cookieName, ckie.Name) 95 + if ckie.Name != anubis.CookieName { 96 + t.Errorf("wanted cookie named %q, got cookie named %q", anubis.CookieName, ckie.Name) 97 97 } 98 98 99 99 if ckie.MaxAge != -1 { ··· 105 105 srv := spawnAnubis(t, Options{CookieDynamicDomain: true}) 106 106 rw := httptest.NewRecorder() 107 107 108 - srv.ClearCookie(rw, srv.cookieName, "/", "xeiaso.net") 108 + srv.ClearCookie(rw, CookieOpts{Host: "subdomain.xeiaso.net"}) 109 109 110 110 resp := rw.Result() 111 111 ··· 117 117 118 118 ckie := cookies[0] 119 119 120 - if ckie.Name != anubis.WithDomainCookieName+"xeiaso.net" { 121 - t.Errorf("wanted cookie named %q, got cookie named %q", srv.cookieName, ckie.Name) 120 + if ckie.Name != anubis.CookieName { 121 + t.Errorf("wanted cookie named %q, got cookie named %q", anubis.CookieName, ckie.Name) 122 + } 123 + 124 + if ckie.Domain != "xeiaso.net" { 125 + t.Errorf("wanted cookie domain %q, got cookie domain %q", "xeiaso.net", ckie.Domain) 122 126 } 123 127 124 128 if ckie.MaxAge != -1 {
+4 -4
test/go.mod
··· 24 24 github.com/gaissmai/bart v0.20.4 // indirect 25 25 github.com/golang-jwt/jwt/v5 v5.2.2 // indirect 26 26 github.com/google/cel-go v0.25.0 // indirect 27 - github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect 28 - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect 27 + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect 28 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect 29 29 github.com/joho/godotenv v1.5.1 // indirect 30 30 github.com/jsha/minica v1.1.0 // indirect 31 31 github.com/kr/text v0.2.0 // indirect ··· 43 43 golang.org/x/text v0.26.0 // indirect 44 44 google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect 45 45 google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect 46 - google.golang.org/grpc v1.72.2 // indirect 46 + google.golang.org/grpc v1.73.0 // indirect 47 47 google.golang.org/protobuf v1.36.6 // indirect 48 - k8s.io/apimachinery v0.33.1 // indirect 48 + k8s.io/apimachinery v0.33.2 // indirect 49 49 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect 50 50 sigs.k8s.io/yaml v1.4.0 // indirect 51 51 )
+4
test/go.sum
··· 44 44 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 45 45 github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= 46 46 github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= 47 + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= 47 48 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= 48 49 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= 50 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= 49 51 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 50 52 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 51 53 github.com/jsha/minica v1.1.0 h1:O2ZbzAN75w4RTB+5+HfjIEvY5nxRqDlwj3ZlLVG5JD8= ··· 113 115 google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= 114 116 google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= 115 117 google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= 118 + google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= 116 119 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 117 120 google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 118 121 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= ··· 124 127 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 125 128 k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4= 126 129 k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= 130 + k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= 127 131 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= 128 132 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= 129 133 sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=