+4
-3
.github/actions/spelling/expect.txt
+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
-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
+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
+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
+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
+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
+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
-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
+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
+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
+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
+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=