From 85b11af210ad005e9a6cc028fc0a8af50abab63c Mon Sep 17 00:00:00 2001 From: hardy Date: Sun, 24 May 2026 21:56:25 +0800 Subject: [PATCH 1/7] feat: secure managed agent bootstrap flow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- config/install_agent.tpl | 80 +++-- docs/content.en/docs/release-notes/_index.md | 2 + modules/security/credential/api/credential.go | 18 ++ plugin/managed/server/config.go | 4 + plugin/managed/server/credential.go | 298 ++++++++++++++++++ plugin/managed/server/instance.go | 27 +- plugin/managed/server/managed_token.go | 131 ++++++++ plugin/managed/server/manager.go | 5 + plugin/managed/server/register_token_test.go | 170 ++++++++++ plugin/managed/server/script.go | 100 ++++-- plugin/managed/server/token_exchange.go | 243 ++++++++++++++ plugin/managed/server/token_exchange_test.go | 29 ++ 12 files changed, 1058 insertions(+), 49 deletions(-) create mode 100644 plugin/managed/server/credential.go create mode 100644 plugin/managed/server/managed_token.go create mode 100644 plugin/managed/server/register_token_test.go create mode 100644 plugin/managed/server/token_exchange.go create mode 100644 plugin/managed/server/token_exchange_test.go diff --git a/config/install_agent.tpl b/config/install_agent.tpl index e130b6c0..75997b77 100644 --- a/config/install_agent.tpl +++ b/config/install_agent.tpl @@ -220,28 +220,42 @@ function install_config() { echo "[agent] waiting generate config" port={{port}} console_endpoint="{{console_endpoint}}" - - location_ep=$(echo "$console_endpoint" | sed -nE 's/(.*):\/\/([^/:]*):?([0-9]*).*/\1:\/\/\2:\3/p') - server=${register_server:-$location_ep} + + # Keep the console base path in managed server URLs so register/sync/exchange + # requests still work when Console is deployed under a non-root path prefix. + server=${register_server:-$console_endpoint} echo "[agent] agent listening port $port, will register to console endpoint [ $server ]" cat < ${install_dir}/agent.yml configs.auto_reload: true env: - API_BINDING: "0.0.0.0:${port}" + WEB_BINDING: "0.0.0.0:${port}" + MANAGED: true + REMOTE_CONFIG_SERVERS: ["${server}"] + REMOTE_CONFIG_INTERVAL: "10s" + SECURITY_ENABLED: true + SECURITY_MANAGED_ENABLED: false path.data: data path.logs: log -path.configs: config +path.configs: "config" resource_limit.cpu.max_num_of_cpus: 1 -resource_limit.memory.max_in_bytes: 533708800 + +resource_limit: + memory: + max_in_bytes: 533708800 #50MB + +task: + max_concurrent_tasks: 3 stats: include_storage_stats_in_api: false elastic: skip_init_metadata_on_start: true + metadata_refresh: + enabled: false health_check: enabled: true interval: 60s @@ -252,24 +266,33 @@ elastic: disk_queue: max_msg_size: 20485760 max_bytes_per_file: 20485760 - max_used_bytes: 524288000 + max_used_bytes: 524288000 #500MB retention.max_num_of_local_files: 1 compress: - idle_threshold: 0 + idle_threshold: 1 num_of_files_decompress_ahead: 0 segment: enabled: true api: + disable_api_directory: true + enabled: false + +web: + embedding_api: false enabled: true - tls: - enabled: false - cert_file: "config/client.crt" - key_file: "config/client.key" - ca_file: "config/ca.crt" - skip_insecure_verify: false network: - binding: \$[[env.API_BINDING]] + binding: \$[[env.WEB_BINDING]] + ui: + vfs: true + security: + enabled: \$[[env.SECURITY_ENABLED]] + managed: \$[[env.SECURITY_MANAGED_ENABLED]] + +agent: + +metrics: + enabled: true badger: value_threshold: 1024 @@ -279,11 +302,13 @@ badger: configs: #for managed client's setting - managed: true # managed by remote servers + managed: \$[[env.MANAGED]] # managed by remote servers panic_on_config_error: false #ignore config error - interval: "10s" - servers: # config servers - - "${server}" + allow_generated_metrics_tasks: false # allow auto-generated metrics tasks (e.g. k8s) + interval: \$[[env.REMOTE_CONFIG_INTERVAL]] + servers: \$[[env.REMOTE_CONFIG_SERVERS]] # config servers + manager: + access_token: '$[[keystore.CONFIGS_MANAGER_ACCESS_TOKEN]]' soft_delete: false max_backup_files: 5 tls: #for mTLS connection with config servers @@ -298,6 +323,22 @@ node: EOF } +function install_keystore() { + access_token="{{access_token}}" + agent_svc=${install_dir}/${program_name}-${file_ext%%.*} + + if [[ -z "${access_token}" ]]; then + echo "Error: access token is empty." >&2 + exit 1 + fi + + echo "[agent] waiting write access token to keystore" + ( + cd "${install_dir}" + printf '%s' "${access_token}" | "./$(basename "${agent_svc}")" keystore add CONFIGS_MANAGER_ACCESS_TOKEN --stdin --force >/dev/null + ) +} + function uninstall_service() { agent_svc=${install_dir}/${program_name}-${file_ext%%.*} chmod 755 $agent_svc @@ -351,6 +392,7 @@ function main() { install_binary install_certs install_config + install_keystore uninstall_service install_service diff --git a/docs/content.en/docs/release-notes/_index.md b/docs/content.en/docs/release-notes/_index.md index ac9e2bec..0c8cb753 100644 --- a/docs/content.en/docs/release-notes/_index.md +++ b/docs/content.en/docs/release-notes/_index.md @@ -11,7 +11,9 @@ Information about release notes of INFINI Console is provided here. ### ❌ Breaking changes ### 🚀 Features ### 🐛 Bug fix +- fix: secure managed Agent install, registration, token exchange, and config sync with scoped API tokens instead of the previous unauthenticated path ### ✈️ Improvements +- chore: align managed Agent bootstrap with the web endpoint and simplify the post-register token exchange flow and credential naming ## 1.30.2 (2026-03-16) ### ❌ Breaking changes diff --git a/modules/security/credential/api/credential.go b/modules/security/credential/api/credential.go index 6f5c0f10..ac26435c 100644 --- a/modules/security/credential/api/credential.go +++ b/modules/security/credential/api/credential.go @@ -132,6 +132,22 @@ func (h *APIHandler) updateCredential(w http.ResponseWriter, req *http.Request, } } } + case credential.AccessToken: + var oldToken string + if oldParams, ok := obj.Payload[newObj.Type].(map[string]interface{}); ok { + if token, ok := oldParams["access_token"].(string); ok { + oldToken = token + } else { + http.Error(w, fmt.Sprintf("invalid access token of credential [%s]", obj.ID), http.StatusInternalServerError) + return + } + } + if params, ok := newObj.Payload[newObj.Type].(map[string]interface{}); ok { + if token, ok := params["access_token"].(string); ok && token != oldToken { + obj.Payload = newObj.Payload + encodeChanged = true + } + } default: h.WriteError(w, fmt.Sprintf("unsupport credential type [%s]", newObj.Type), http.StatusInternalServerError) return @@ -276,6 +292,7 @@ func (h *APIHandler) searchCredential(w http.ResponseWriter, req *http.Request, for _, hit := range searchRes.Hits.Hits { delete(hit.Source, "encrypt") util.MapStr(hit.Source).Delete("payload.basic_auth.password") + util.MapStr(hit.Source).Delete("payload.access_token.access_token") } } @@ -296,5 +313,6 @@ func (h *APIHandler) getCredential(w http.ResponseWriter, req *http.Request, ps return } util.MapStr(obj.Payload).Delete("basic_auth.password") + util.MapStr(obj.Payload).Delete("access_token.access_token") h.WriteGetOKJSON(w, id, obj) } diff --git a/plugin/managed/server/config.go b/plugin/managed/server/config.go index e872c124..02d8b912 100644 --- a/plugin/managed/server/config.go +++ b/plugin/managed/server/config.go @@ -164,6 +164,10 @@ func (h APIHandler) syncConfigs(w http.ResponseWriter, req *http.Request, ps htt h.WriteError(w, err.Error(), http.StatusInternalServerError) } + if writeTokenAuthError(h, w, validateSyncRequestAuth(req, &obj.Client)) { + return + } + if global.Env().IsDebug { log.Trace("request:", util.MustToJSON(obj)) } diff --git a/plugin/managed/server/credential.go b/plugin/managed/server/credential.go new file mode 100644 index 00000000..6093c75c --- /dev/null +++ b/plugin/managed/server/credential.go @@ -0,0 +1,298 @@ +package server + +import ( + "fmt" + "net/http" + "strings" + + "infini.sh/framework/core/credential" + "infini.sh/framework/core/model" + "infini.sh/framework/core/orm" + "infini.sh/framework/core/util" + common2 "infini.sh/framework/modules/elastic/common" + "infini.sh/framework/modules/security/access_token" +) + +const instanceAccessTokenKey = "access_token" +const agentAPICredentialIDKey = "agent_api_credential_id" +const managerAPICredentialIDKey = "manager_api_credential_id" + +// Keep reading the old key so existing managed instances continue to work +// before their next save migrates the field name. +const legacyManagerSyncCredentialIDKey = "manager_sync_credential_id" + +func clearInstanceAccessToken(instance *model.Instance) { + deleteInstanceSystemString(instance, instanceAccessTokenKey) +} + +func getInstanceCredentialName(instance *model.Instance) string { + if instance == nil { + return "agent" + } + if name := strings.TrimSpace(instance.Name); name != "" { + return name + } + if id := strings.TrimSpace(instance.ID); id != "" { + return id + } + return "agent" +} + +func getInstanceSystemString(instance *model.Instance, key string) string { + if instance == nil || instance.System == nil { + return "" + } + + value, ok := instance.GetSystemValue(key) + if !ok { + return "" + } + + text, ok := value.(string) + if !ok { + return "" + } + + return strings.TrimSpace(text) +} + +func setInstanceSystemString(instance *model.Instance, key, value string) { + if instance == nil || strings.TrimSpace(value) == "" { + return + } + instance.SetSystemValue(key, value) +} + +func deleteInstanceSystemString(instance *model.Instance, key string) { + if instance == nil || instance.System == nil { + return + } + delete(instance.System, key) + if len(instance.System) == 0 { + instance.System = nil + } +} + +func loadExistingInstance(instanceID string) (*model.Instance, error) { + if strings.TrimSpace(instanceID) == "" { + return nil, nil + } + + instance := &model.Instance{} + instance.ID = instanceID + exists, err := orm.Get(instance) + if err != nil { + return nil, err + } + if !exists { + return nil, nil + } + return instance, nil +} + +func preserveManagedCredentialIDs(instance, oldInst *model.Instance) { + if instance == nil || oldInst == nil { + return + } + + if instance.CredentialID == "" { + instance.CredentialID = oldInst.CredentialID + } + if getAgentAPICredentialID(instance) == "" { + setAgentAPICredentialID(instance, getAgentAPICredentialID(oldInst)) + } + if getManagerAPICredentialID(instance) == "" { + setManagerAPICredentialID(instance, getManagerAPICredentialID(oldInst)) + } +} + +func upsertManagedAccessTokenCredential(credentialID, name string, tags []string, accessToken string) (string, error) { + cred := credential.Credential{} + exists := false + if credentialID != "" { + cred.ID = credentialID + var err error + exists, err = orm.Get(&cred) + if err != nil { + return "", err + } + } + + cred.Name = name + cred.Type = credential.AccessToken + cred.Tags = tags + cred.Payload = map[string]interface{}{ + credential.AccessToken: map[string]interface{}{ + "access_token": accessToken, + }, + } + + if err := cred.Encode(); err != nil { + return "", err + } + + ctx := &orm.Context{Refresh: orm.WaitForRefresh} + if exists { + cred.Invalid = false + if err := orm.Update(ctx, &cred); err != nil { + return "", err + } + return cred.ID, nil + } + + cred.ID = util.GetUUID() + if err := orm.Create(ctx, &cred); err != nil { + return "", err + } + return cred.ID, nil +} + +func getAgentAPICredentialID(instance *model.Instance) string { + if instance == nil { + return "" + } + if credentialID := getInstanceSystemString(instance, agentAPICredentialIDKey); credentialID != "" { + return credentialID + } + return instance.CredentialID +} + +func setAgentAPICredentialID(instance *model.Instance, credentialID string) { + setInstanceSystemString(instance, agentAPICredentialIDKey, credentialID) +} + +func getManagerAPICredentialID(instance *model.Instance) string { + if credentialID := getInstanceSystemString(instance, managerAPICredentialIDKey); credentialID != "" { + return credentialID + } + return getInstanceSystemString(instance, legacyManagerSyncCredentialIDKey) +} + +func setManagerAPICredentialID(instance *model.Instance, credentialID string) { + setInstanceSystemString(instance, managerAPICredentialIDKey, credentialID) + deleteInstanceSystemString(instance, legacyManagerSyncCredentialIDKey) +} + +func upsertInstanceAgentAPICredential(instance *model.Instance, accessToken string) (string, error) { + if instance == nil { + return "", fmt.Errorf("instance is nil") + } + if strings.TrimSpace(accessToken) == "" { + return "", fmt.Errorf("access token is empty") + } + + return upsertManagedAccessTokenCredential( + getAgentAPICredentialID(instance), + fmt.Sprintf("%s agent api", getInstanceCredentialName(instance)), + []string{"agent", "managed", "agent_api", "access_token"}, + accessToken, + ) +} + +func upsertInstanceManagerAPICredential(instance *model.Instance, accessToken string) (string, error) { + if instance == nil { + return "", fmt.Errorf("instance is nil") + } + if strings.TrimSpace(accessToken) == "" { + return "", fmt.Errorf("access token is empty") + } + + return upsertManagedAccessTokenCredential( + getManagerAPICredentialID(instance), + fmt.Sprintf("%s manager api", getInstanceCredentialName(instance)), + []string{"agent", "managed", "manager_api", "access_token"}, + accessToken, + ) +} + +func applyCredentialRequestAuth(req *util.Request, credentialID string) error { + if req == nil || strings.TrimSpace(credentialID) == "" { + return nil + } + + cred, err := common2.GetCredential(credentialID) + if err != nil { + return err + } + + switch cred.Type { + case credential.BasicAuth: + auth, err := cred.DecodeBasicAuth() + if err != nil { + return err + } + req.SetBasicAuth(auth.Username, auth.Password.Get()) + case credential.AccessToken: + token, err := cred.DecodeAccessToken() + if err != nil { + return err + } + req.AddHeader(access_token.HeaderAPIToken, token.AccessToken.Get()) + default: + return fmt.Errorf("unsupported credential type [%s]", cred.Type) + } + + return nil +} + +func applyInstanceRequestAuth(req *util.Request, instance *model.Instance) error { + if req == nil || instance == nil { + return nil + } + + if credentialID := getAgentAPICredentialID(instance); credentialID != "" { + return applyCredentialRequestAuth(req, credentialID) + } + + if instance.BasicAuth != nil && instance.BasicAuth.Username != "" { + req.SetBasicAuth(instance.BasicAuth.Username, instance.BasicAuth.Password.Get()) + } + + return nil +} + +func getInstanceByEndpoint(endpoint string) (*model.Instance, error) { + if strings.TrimSpace(endpoint) == "" { + return nil, nil + } + + queryDSL := util.MapStr{ + "size": 1, + "query": util.MapStr{ + "bool": util.MapStr{ + "must": []util.MapStr{ + { + "term": util.MapStr{ + "endpoint": endpoint, + }, + }, + }, + }, + }, + } + + q := orm.Query{RawQuery: util.MustToJSONBytes(queryDSL)} + err, res := orm.Search(&model.Instance{}, &q) + if err != nil { + return nil, err + } + if len(res.Result) == 0 { + return nil, nil + } + + obj := &model.Instance{} + util.MustFromJSONBytes(util.MustToJSONBytes(res.Result[0]), obj) + return obj, nil +} + +func prepareProxyAgentRequest(endpoint string, req *util.Request) error { + instance, err := getInstanceByEndpoint(endpoint) + if err != nil || instance == nil { + return err + } + return applyInstanceRequestAuth(req, instance) +} + +func isAuthorizedStatus(code int) bool { + return code == http.StatusOK +} diff --git a/plugin/managed/server/instance.go b/plugin/managed/server/instance.go index 0fe130b3..343d8230 100644 --- a/plugin/managed/server/instance.go +++ b/plugin/managed/server/instance.go @@ -30,14 +30,15 @@ package server import ( "context" "fmt" - "infini.sh/framework/core/event" - "infini.sh/framework/core/global" - "infini.sh/framework/core/task" "net/http" "strconv" "strings" "time" + "infini.sh/framework/core/event" + "infini.sh/framework/core/global" + "infini.sh/framework/core/task" + log "github.com/cihub/seelog" "infini.sh/console/core/security/enum" "infini.sh/framework/core/api" @@ -57,6 +58,7 @@ var instanceSecrets = map[string][]common.Secrets{} //map instance->secrets TODO func init() { //for public usage, agent can report self to server, usually need to enroll by manager api.HandleAPIMethod(api.POST, common.REGISTER_API, handler.registerInstance) //client register self to config servers + api.HandleAPIMethod(api.POST, instanceTokenExchangeAPI, handler.exchangeInstanceToken) //for public usage, get install script api.HandleAPIMethod(api.GET, GET_INSTALL_SCRIPT_API, handler.getInstallScript) @@ -85,7 +87,6 @@ func init() { } func (h APIHandler) registerInstance(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - var obj = &model.Instance{} err := h.DecodeJSON(req, obj) if err != nil { @@ -97,12 +98,22 @@ func (h APIHandler) registerInstance(w http.ResponseWriter, req *http.Request, p return } - oldInst := &model.Instance{} - oldInst.ID = obj.ID - exists, err := orm.Get(oldInst) - if exists { + if writeTokenAuthError(h, w, validateRegisterRequestAuth(req, obj)) { + return + } + + oldInst, err := loadExistingInstance(obj.ID) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + if oldInst != nil { obj.Created = oldInst.Created + preserveManagedCredentialIDs(obj, oldInst) } + + clearInstanceAccessToken(obj) + err = orm.Save(nil, obj) if err != nil { h.WriteError(w, err.Error(), http.StatusInternalServerError) diff --git a/plugin/managed/server/managed_token.go b/plugin/managed/server/managed_token.go new file mode 100644 index 00000000..27b22efc --- /dev/null +++ b/plugin/managed/server/managed_token.go @@ -0,0 +1,131 @@ +package server + +import ( + "errors" + "fmt" + "strings" + "time" + + "infini.sh/framework/core/global" + "infini.sh/framework/core/model" + "infini.sh/framework/core/security" + "infini.sh/framework/core/util" + "infini.sh/framework/modules/security/access_token" +) + +var managedRegisterPermission = security.GetOrInitPermission("managed", "instance", "register") +var managedExchangePermission = security.GetOrInitPermission("managed", "instance", "exchange") +var managedSyncPermission = security.GetOrInitPermission("managed", "config", "sync") + +var errManagedTokenInvalid = errors.New("managed token is invalid") +var errManagedTokenExpired = errors.New("managed token is expired") + +func getBootstrapTokenPermissions() []security.PermissionKey { + return []security.PermissionKey{ + managedRegisterPermission, + managedExchangePermission, + } +} + +func getManagerTokenPermissions() []security.PermissionKey { + return []security.PermissionKey{ + managedRegisterPermission, + managedExchangePermission, + managedSyncPermission, + } +} + +func newManagedTokenUser(userID string, instance *model.Instance) *security.UserSessionInfo { + user := &security.UserSessionInfo{ + Provider: "managed_agent", + Login: userID, + } + if instance != nil && strings.TrimSpace(instance.ID) != "" { + user.Login = instance.ID + user.Set("instance_id", instance.ID) + user.Set("instance_name", instance.Name) + user.Set("endpoint", instance.Endpoint) + } + user.SetUserID(userID) + return user +} + +func issueManagedAPIToken(user *security.UserSessionInfo, name, typeName string, expiredAt int64, permissions []security.PermissionKey) (string, error) { + res, err := access_token.CreateAPIToken(user, name, typeName, expiredAt, permissions) + if err != nil { + return "", err + } + + token, ok := res["access_token"].(string) + if !ok || strings.TrimSpace(token) == "" { + return "", fmt.Errorf("failed to create managed api token") + } + return token, nil +} + +func getManagedAPIToken(token string) (*security.AccessToken, error) { + token = strings.TrimSpace(token) + if token == "" { + return nil, errManagedTokenInvalid + } + + record, err := access_token.GetToken(token) + if err != nil { + return nil, errManagedTokenInvalid + } + if record.ExpireIn > 0 && time.Now().After(time.Unix(record.ExpireIn, 0)) { + return nil, errManagedTokenExpired + } + return record, nil +} + +func getEffectiveManagedPermissions(token *security.AccessToken) []security.PermissionKey { + if token == nil { + return nil + } + + permissions := token.Permissions + if global.Env().SystemConfig.WebAppConfig.Security.Authentication.AccessToken.Native { + // In native mode, effective permissions are limited by both the token and + // the current owner's permissions, so revoked user permissions take effect + // immediately for managed tokens as well. + tokenLevel := security.ConvertPermissionKeysToHashSet(token.Permissions) + + user := security.UserSessionInfo{Provider: "native"} + user.SetUserID(token.GetOwnerID()) + + userLevel := security.ConvertPermissionKeysToHashSet(security.GetAllPermissionsForUser(&user)) + permissions = security.ConvertPermissionHashSetToKeys(security.IntersectSetsFast(tokenLevel, userLevel)) + } + + return permissions +} + +func requireManagedPermissions(token *security.AccessToken, permissions ...security.PermissionKey) error { + if len(permissions) == 0 { + return nil + } + if token == nil { + return errManagedTokenInvalid + } + + if !util.IsSuperset( + security.ConvertPermissionKeysToHashSet(getEffectiveManagedPermissions(token)), + security.ConvertPermissionKeysToHashSet(permissions), + ) { + return errManagedTokenInvalid + } + return nil +} + +func requireManagedInstance(token *security.AccessToken, instance *model.Instance) error { + if token == nil || instance == nil || strings.TrimSpace(instance.ID) == "" { + return errManagedTokenInvalid + } + + tokenInstanceID, ok := token.GetString("instance_id") + if !ok || strings.TrimSpace(tokenInstanceID) == "" || tokenInstanceID != instance.ID { + return errManagedTokenInvalid + } + return nil +} diff --git a/plugin/managed/server/manager.go b/plugin/managed/server/manager.go index 29ce6d8f..7ae7e634 100644 --- a/plugin/managed/server/manager.go +++ b/plugin/managed/server/manager.go @@ -106,6 +106,11 @@ func ProxyAgentRequest(tag, endpoint string, req *util.Request, responseObjectTo } }) + err = prepareProxyAgentRequest(endpoint, req) + if err != nil { + return nil, err + } + req.Url = endpoint + req.Path res, err = util.ExecuteRequestWithCatchFlag(mTLSClient, req, true) diff --git a/plugin/managed/server/register_token_test.go b/plugin/managed/server/register_token_test.go new file mode 100644 index 00000000..6ce37d40 --- /dev/null +++ b/plugin/managed/server/register_token_test.go @@ -0,0 +1,170 @@ +package server + +import ( + "os" + "strings" + "sync" + "testing" + "time" + + "infini.sh/framework/core/kv" + "infini.sh/framework/core/security" +) + +type memoryKVStore struct { + lock sync.RWMutex + data map[string]map[string][]byte +} + +func newMemoryKVStore() *memoryKVStore { + return &memoryKVStore{ + data: map[string]map[string][]byte{}, + } +} + +func (m *memoryKVStore) Open() error { return nil } +func (m *memoryKVStore) Close() error { return nil } + +func (m *memoryKVStore) GetValue(bucket string, key []byte) ([]byte, error) { + m.lock.RLock() + defer m.lock.RUnlock() + if m.data[bucket] == nil { + return nil, nil + } + value := m.data[bucket][string(key)] + if value == nil { + return nil, nil + } + buf := make([]byte, len(value)) + copy(buf, value) + return buf, nil +} + +func (m *memoryKVStore) GetCompressedValue(bucket string, key []byte) ([]byte, error) { + return m.GetValue(bucket, key) +} + +func (m *memoryKVStore) AddValueCompress(bucket string, key []byte, value []byte) error { + return m.AddValue(bucket, key, value) +} + +func (m *memoryKVStore) AddValue(bucket string, key []byte, value []byte) error { + m.lock.Lock() + defer m.lock.Unlock() + if m.data[bucket] == nil { + m.data[bucket] = map[string][]byte{} + } + buf := make([]byte, len(value)) + copy(buf, value) + m.data[bucket][string(key)] = buf + return nil +} + +func (m *memoryKVStore) ExistsKey(bucket string, key []byte) (bool, error) { + m.lock.RLock() + defer m.lock.RUnlock() + if m.data[bucket] == nil { + return false, nil + } + _, ok := m.data[bucket][string(key)] + return ok, nil +} + +func (m *memoryKVStore) DeleteKey(bucket string, key []byte) error { + m.lock.Lock() + defer m.lock.Unlock() + if m.data[bucket] != nil { + delete(m.data[bucket], string(key)) + } + return nil +} + +func TestMain(m *testing.M) { + kv.Register("managed-server-register-token-test", newMemoryKVStore()) + os.Exit(m.Run()) +} + +func TestIssueBootstrapTokenCanBeValidated(t *testing.T) { + token, err := issueBootstrapToken("user-1") + if err != nil { + t.Fatalf("issueBootstrapToken returned error: %v", err) + } + if token == "" { + t.Fatal("expected non-empty bootstrap token") + } + + if err := validateBootstrapToken(token); err != nil { + t.Fatalf("validateBootstrapToken returned error: %v", err) + } +} + +func TestValidateBootstrapTokenRejectsMissingOrUnknownToken(t *testing.T) { + if err := validateBootstrapToken(""); err == nil || !strings.Contains(err.Error(), "required") { + t.Fatalf("expected missing token error, got %v", err) + } + + if err := validateBootstrapToken("missing-token"); err == nil || !strings.Contains(err.Error(), "invalid") { + t.Fatalf("expected invalid token error, got %v", err) + } +} + +func TestGetBootstrapTokenUserIDReturnsOwner(t *testing.T) { + token, err := issueBootstrapToken("user-2") + if err != nil { + t.Fatalf("issueBootstrapToken returned error: %v", err) + } + + userID, err := getBootstrapTokenUserID(token) + if err != nil { + t.Fatalf("getBootstrapTokenUserID returned error: %v", err) + } + if userID != "user-2" { + t.Fatalf("expected token owner user-2, got %q", userID) + } +} + +func TestValidateBootstrapTokenRejectsExpiredToken(t *testing.T) { + user := &security.UserSessionInfo{ + Provider: "managed_agent", + Login: "user-3", + } + user.SetUserID("user-3") + + token, err := issueManagedAPIToken( + user, + "expired managed bootstrap", + "managed_agent_bootstrap", + time.Now().Add(-time.Minute).Unix(), + getBootstrapTokenPermissions(), + ) + if err != nil { + t.Fatalf("failed to create expired bootstrap token: %v", err) + } + + if err := validateBootstrapToken(token); err == nil || !strings.Contains(err.Error(), "expired") { + t.Fatalf("expected expired token error, got %v", err) + } +} + +func TestValidateBootstrapTokenRejectsTokenWithoutRegisterPermission(t *testing.T) { + user := &security.UserSessionInfo{ + Provider: "managed_agent", + Login: "user-4", + } + user.SetUserID("user-4") + + token, err := issueManagedAPIToken( + user, + "managed sync only", + "managed_agent_sync", + time.Now().Add(time.Hour).Unix(), + []security.PermissionKey{managedSyncPermission}, + ) + if err != nil { + t.Fatalf("failed to create managed sync token: %v", err) + } + + if err := validateBootstrapToken(token); err == nil || !strings.Contains(err.Error(), "invalid") { + t.Fatalf("expected invalid token error, got %v", err) + } +} diff --git a/plugin/managed/server/script.go b/plugin/managed/server/script.go index 4dbf660f..3daf3c68 100644 --- a/plugin/managed/server/script.go +++ b/plugin/managed/server/script.go @@ -28,12 +28,14 @@ package server import ( + "errors" "fmt" log "github.com/cihub/seelog" - "infini.sh/console/core/security" + rbac "infini.sh/console/core/security" "infini.sh/console/modules/agent/common" httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/core/global" + "infini.sh/framework/core/security" "infini.sh/framework/core/util" "infini.sh/framework/lib/fasttemplate" "net/url" @@ -45,18 +47,63 @@ import ( "time" ) -type Token struct { +type installScriptToken struct { CreatedAt time.Time UserID string } -const ExpiredIn = time.Millisecond * 1000 * 60 * 60 +const managedInstallTokenTTL = time.Millisecond * 1000 * 60 * 60 const GET_INSTALL_SCRIPT_API = "/instance/_get_install_script" -var expiredTokenCache = util.NewCacheWithExpireOnAdd(ExpiredIn, 100) +var expiredTokenCache = util.NewCacheWithExpireOnAdd(managedInstallTokenTTL, 100) +var errBootstrapTokenRequired = errors.New("bootstrap token is required") +var errBootstrapTokenInvalid = errors.New("bootstrap token is invalid") +var errBootstrapTokenExpired = errors.New("bootstrap token is expired") + +func issueBootstrapToken(userID string) (string, error) { + return issueManagedAPIToken( + newManagedTokenUser(userID, nil), + "managed bootstrap", + "managed_agent_bootstrap", + time.Now().Add(managedInstallTokenTTL).Unix(), + getBootstrapTokenPermissions(), + ) +} + +func getBootstrapToken(tokenStr string, permissions ...security.PermissionKey) (*security.AccessToken, error) { + if strings.TrimSpace(tokenStr) == "" { + return nil, errBootstrapTokenRequired + } + + token, err := getManagedAPIToken(tokenStr) + if err != nil { + if errors.Is(err, errManagedTokenExpired) { + return nil, errBootstrapTokenExpired + } + return nil, errBootstrapTokenInvalid + } + if err := requireManagedPermissions(token, permissions...); err != nil { + return nil, errBootstrapTokenInvalid + } + + return token, nil +} + +func validateBootstrapToken(tokenStr string) error { + _, err := getBootstrapToken(tokenStr, managedRegisterPermission) + return err +} + +func getBootstrapTokenUserID(tokenStr string) (string, error) { + token, err := getBootstrapToken(tokenStr, managedExchangePermission) + if err != nil { + return "", err + } + return strings.TrimSpace(token.GetOwnerID()), nil +} func (h *APIHandler) generateInstallCommand(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - claims, ok := req.Context().Value("user").(*security.UserClaims) + claims, ok := req.Context().Value("user").(*rbac.UserClaims) if !ok { h.WriteError(w, "user not found", http.StatusInternalServerError) return @@ -67,7 +114,7 @@ func (h *APIHandler) generateInstallCommand(w http.ResponseWriter, req *http.Req return } var ( - t *Token + t *installScriptToken tokenStr string ) @@ -75,21 +122,13 @@ func (h *APIHandler) generateInstallCommand(w http.ResponseWriter, req *http.Req location := "/opt/agent" tokenStr = util.GetUUID() - t = &Token{ + t = &installScriptToken{ CreatedAt: time.Now(), UserID: claims.UserId, } expiredTokenCache.Put(tokenStr, t) - consoleEndpoint := agCfg.Setup.ConsoleEndpoint - if consoleEndpoint == "" { - consoleEndpoint = getDefaultEndpoint(req) - } - - basePath := global.Env().SystemConfig.WebAppConfig.BasePath - if len(basePath) > 0 { - consoleEndpoint = fmt.Sprintf("%s%s", strings.TrimRight(consoleEndpoint, "/"), basePath) - } + consoleEndpoint := getConsoleEndpoint(req, agCfg.Setup.ConsoleEndpoint) endpoint, err := url.JoinPath(consoleEndpoint, GET_INSTALL_SCRIPT_API) if err != nil { @@ -100,7 +139,7 @@ func (h *APIHandler) generateInstallCommand(w http.ResponseWriter, req *http.Req "script": fmt.Sprintf(`curl -ksSL %s?token=%s |sudo bash -s -- -u %s -t %v`, endpoint, tokenStr, agCfg.Setup.DownloadURL, location), "token": tokenStr, - "expired_at": t.CreatedAt.Add(ExpiredIn), + "expired_at": t.CreatedAt.Add(managedInstallTokenTTL), }, http.StatusOK) } @@ -112,6 +151,18 @@ func getDefaultEndpoint(req *http.Request) string { return fmt.Sprintf("%s://%s", scheme, req.Host) } +func getConsoleEndpoint(req *http.Request, configured string) string { + endpoint := configured + if endpoint == "" { + endpoint = getDefaultEndpoint(req) + } + basePath := strings.TrimSpace(global.Env().SystemConfig.WebAppConfig.BasePath) + if basePath == "" || strings.HasSuffix(strings.TrimRight(endpoint, "/"), basePath) { + return endpoint + } + return fmt.Sprintf("%s%s", strings.TrimRight(endpoint, "/"), basePath) +} + func (h *APIHandler) getInstallScript(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { tokenStr := h.GetParameter(req, "token") @@ -126,8 +177,8 @@ func (h *APIHandler) getInstallScript(w http.ResponseWriter, req *http.Request, return } - t, ok := v.(*Token) - if !ok || t.CreatedAt.Add(ExpiredIn).Before(time.Now()) { + t, ok := v.(*installScriptToken) + if !ok || t.CreatedAt.Add(managedInstallTokenTTL).Before(time.Now()) { expiredTokenCache.Delete(tokenStr) h.WriteError(w, "token was expired", http.StatusUnauthorized) return @@ -160,9 +211,13 @@ func (h *APIHandler) getInstallScript(w http.ResponseWriter, req *http.Request, port = "8080" } - consoleEndpoint := agCfg.Setup.ConsoleEndpoint - if consoleEndpoint == "" { - consoleEndpoint = getDefaultEndpoint(req) + consoleEndpoint := getConsoleEndpoint(req, agCfg.Setup.ConsoleEndpoint) + + accessToken, err := issueBootstrapToken(t.UserID) + if err != nil { + log.Error(err) + h.WriteError(w, err.Error(), http.StatusInternalServerError) + return } _, err = tpl.Execute(w, map[string]interface{}{ @@ -172,6 +227,7 @@ func (h *APIHandler) getInstallScript(w http.ResponseWriter, req *http.Request, "client_key": clientKeyPEM, "ca_crt": caCert, "port": port, + "access_token": accessToken, "token": tokenStr, }) diff --git a/plugin/managed/server/token_exchange.go b/plugin/managed/server/token_exchange.go new file mode 100644 index 00000000..f1d04adf --- /dev/null +++ b/plugin/managed/server/token_exchange.go @@ -0,0 +1,243 @@ +package server + +import ( + "errors" + "fmt" + "net/http" + "strings" + + httprouter "infini.sh/framework/core/api/router" + "infini.sh/framework/core/model" + "infini.sh/framework/core/orm" + "infini.sh/framework/core/security" + "infini.sh/framework/modules/security/access_token" +) + +const instanceTokenExchangeAPI = "/instance/_exchange_token" + +// -1 means the exchanged manager api token never expires. +const managedAgentSyncTokenExpireAt int64 = -1 + +type tokenExchangeRequest struct { + InstanceID string `json:"instance_id,omitempty"` + AgentAPIToken string `json:"agent_api_token,omitempty"` +} + +type tokenExchangeResponse struct { + ManagerAPIToken string `json:"manager_api_token,omitempty"` +} + +var errManagerAPITokenRequired = errors.New("manager api token is required") +var errManagerAPITokenInvalid = errors.New("manager api token is invalid") + +func writeTokenAuthError(h APIHandler, w http.ResponseWriter, err error) bool { + if err == nil { + return false + } + + switch { + case errors.Is(err, errBootstrapTokenRequired), + errors.Is(err, errBootstrapTokenInvalid), + errors.Is(err, errBootstrapTokenExpired), + errors.Is(err, errManagerAPITokenRequired), + errors.Is(err, errManagerAPITokenInvalid): + h.WriteError(w, err.Error(), http.StatusUnauthorized) + default: + h.WriteError(w, err.Error(), http.StatusInternalServerError) + } + + return true +} + +func getManagerAPIToken(token string, instance *model.Instance, permissions ...security.PermissionKey) (*security.AccessToken, error) { + token = strings.TrimSpace(token) + if token == "" { + return nil, errManagerAPITokenRequired + } + + record, err := getManagedAPIToken(token) + if err != nil { + return nil, errManagerAPITokenInvalid + } + if err := requireManagedPermissions(record, permissions...); err != nil { + return nil, errManagerAPITokenInvalid + } + + instance, err = loadStoredInstance(instance) + if err != nil { + return nil, err + } + if instance == nil { + return nil, errManagerAPITokenInvalid + } + if err := requireManagedInstance(record, instance); err != nil { + return nil, errManagerAPITokenInvalid + } + return record, nil +} + +func validateManagerAPIToken(token string, instance *model.Instance, permissions ...security.PermissionKey) error { + _, err := getManagerAPIToken(token, instance, permissions...) + return err +} + +func authorizeExchangeToken(token string, instance *model.Instance) (string, string, error) { + _, err := getManagerAPIToken(token, instance, managedExchangePermission) + if err == nil { + return "", token, nil + } + if !errors.Is(err, errManagerAPITokenInvalid) { + return "", "", err + } + + userID, regErr := getBootstrapTokenUserID(token) + if regErr != nil { + return "", "", regErr + } + return userID, "", nil +} + +func loadStoredInstance(instance *model.Instance) (*model.Instance, error) { + if instance == nil || strings.TrimSpace(instance.ID) == "" { + return nil, nil + } + if getManagerAPICredentialID(instance) != "" { + return instance, nil + } + return loadExistingInstance(instance.ID) +} + +func validateTokenExchangeRequest(reqBody *tokenExchangeRequest) error { + if reqBody == nil { + return fmt.Errorf("empty request") + } + if strings.TrimSpace(reqBody.InstanceID) == "" { + return fmt.Errorf("empty instance id") + } + if strings.TrimSpace(reqBody.AgentAPIToken) == "" { + return fmt.Errorf("empty agent api token") + } + return nil +} + +func ensureManagerAPICredential(instance *model.Instance, managerAPIToken, userID string) (string, string, error) { + managerCredentialID := getManagerAPICredentialID(instance) + if strings.TrimSpace(managerAPIToken) == "" { + return issueManagerAPIToken(instance, userID) + } + if managerCredentialID != "" { + return managerAPIToken, managerCredentialID, nil + } + + managerCredentialID, err := upsertInstanceManagerAPICredential(instance, managerAPIToken) + if err != nil { + return "", "", err + } + return managerAPIToken, managerCredentialID, nil +} + +func persistExchangedTokens(instance *model.Instance, agentAPIToken, managerAPIToken, userID string) (string, error) { + agentCredentialID, err := upsertInstanceAgentAPICredential(instance, agentAPIToken) + if err != nil { + return "", err + } + setAgentAPICredentialID(instance, agentCredentialID) + + managerAPIToken, managerCredentialID, err := ensureManagerAPICredential(instance, managerAPIToken, userID) + if err != nil { + return "", err + } + setManagerAPICredentialID(instance, managerCredentialID) + clearInstanceAccessToken(instance) + + if err := orm.Save(nil, instance); err != nil { + return "", err + } + return managerAPIToken, nil +} + +func validateRegisterRequestAuth(req *http.Request, instance *model.Instance) error { + token := strings.TrimSpace(req.Header.Get(access_token.HeaderAPIToken)) + if token == "" { + return nil + } + + err := validateManagerAPIToken(token, instance, managedRegisterPermission) + if err == nil || !errors.Is(err, errManagerAPITokenInvalid) { + return err + } + + return validateBootstrapToken(token) +} + +func validateSyncRequestAuth(req *http.Request, instance *model.Instance) error { + managerAPIToken := strings.TrimSpace(req.Header.Get(access_token.HeaderAPIToken)) + if managerAPIToken == "" { + return nil + } + return validateManagerAPIToken(managerAPIToken, instance, managedSyncPermission) +} + +func issueManagerAPIToken(instance *model.Instance, userID string) (string, string, error) { + if instance == nil { + return "", "", fmt.Errorf("instance is nil") + } + if strings.TrimSpace(userID) == "" { + return "", "", fmt.Errorf("user id is empty") + } + + managerAPIToken, err := issueManagedAPIToken( + newManagedTokenUser(userID, instance), + fmt.Sprintf("%s manager api", getInstanceCredentialName(instance)), + "managed_agent_sync", + managedAgentSyncTokenExpireAt, + getManagerTokenPermissions(), + ) + if err != nil { + return "", "", err + } + + credentialID, err := upsertInstanceManagerAPICredential(instance, managerAPIToken) + if err != nil { + return "", "", err + } + + return managerAPIToken, credentialID, nil +} + +func (h APIHandler) exchangeInstanceToken(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + reqBody := &tokenExchangeRequest{} + if err := h.DecodeJSON(req, reqBody); err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + if err := validateTokenExchangeRequest(reqBody); err != nil { + h.WriteError(w, err.Error(), http.StatusBadRequest) + return + } + + instance, err := loadExistingInstance(reqBody.InstanceID) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + if instance == nil { + h.WriteError(w, "instance not found", http.StatusBadRequest) + return + } + obj := *instance + + userID, managerAPIToken, err := authorizeExchangeToken(strings.TrimSpace(req.Header.Get(access_token.HeaderAPIToken)), &obj) + if writeTokenAuthError(h, w, err) { + return + } + managerAPIToken, err = persistExchangedTokens(&obj, reqBody.AgentAPIToken, managerAPIToken, userID) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + + h.WriteJSON(w, tokenExchangeResponse{ + ManagerAPIToken: managerAPIToken, + }, http.StatusOK) +} diff --git a/plugin/managed/server/token_exchange_test.go b/plugin/managed/server/token_exchange_test.go new file mode 100644 index 00000000..531c9992 --- /dev/null +++ b/plugin/managed/server/token_exchange_test.go @@ -0,0 +1,29 @@ +package server + +import ( + "testing" + + "infini.sh/framework/core/model" + "infini.sh/framework/core/security" +) + +func TestRequireManagedPermissionsRejectsMissingPermission(t *testing.T) { + token := &security.AccessToken{ + Permissions: []security.PermissionKey{managedRegisterPermission}, + } + + if err := requireManagedPermissions(token, managedSyncPermission); err == nil { + t.Fatal("expected missing managed sync permission to be rejected") + } +} + +func TestRequireManagedInstanceRejectsMismatchedInstance(t *testing.T) { + token := &security.AccessToken{} + token.Set("instance_id", "instance-1") + + instance := &model.Instance{} + instance.ID = "instance-2" + if err := requireManagedInstance(token, instance); err == nil { + t.Fatal("expected mismatched instance id to be rejected") + } +} From eea573b7e8b45e10757b0b21c5fc491cb1b7b3fb Mon Sep 17 00:00:00 2001 From: medcl Date: Tue, 26 May 2026 22:15:43 +0800 Subject: [PATCH 2/7] chore: fix build --- core/security/access_token.go | 2 +- core/security/context.go | 3 +- core/security/validate.go | 2 +- go.mod | 126 +++++++ go.sum | 337 ++++++++++++++++++ main.go | 2 +- model/instance.go | 60 +++- modules/elastic/api/manage.go | 4 +- modules/elastic/api/v1/manage.go | 4 +- modules/security/credential/api/credential.go | 12 +- plugin/api/email/server.go | 6 +- plugin/managed/server/credential.go | 80 +---- plugin/setup/setup.go | 4 +- 13 files changed, 558 insertions(+), 84 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/core/security/access_token.go b/core/security/access_token.go index f23efd97..6b122dac 100644 --- a/core/security/access_token.go +++ b/core/security/access_token.go @@ -28,7 +28,7 @@ package security import ( - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v4" "infini.sh/framework/core/errors" "infini.sh/framework/core/util" "time" diff --git a/core/security/context.go b/core/security/context.go index c4334271..5dd10b45 100644 --- a/core/security/context.go +++ b/core/security/context.go @@ -30,7 +30,8 @@ package security import ( "context" "fmt" - "github.com/golang-jwt/jwt" + + "github.com/golang-jwt/jwt/v4" ) const ctxUserKey = "user" diff --git a/core/security/validate.go b/core/security/validate.go index be6d2e6f..ce7661a9 100644 --- a/core/security/validate.go +++ b/core/security/validate.go @@ -30,7 +30,7 @@ package security import ( "errors" "fmt" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v4" "infini.sh/console/core/security/enum" httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/core/radix" diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..5436cfdb --- /dev/null +++ b/go.mod @@ -0,0 +1,126 @@ +module infini.sh/console + +go 1.25.0 + +replace infini.sh/framework => ../framework + +replace github.com/cihub/seelog => ../framework/lib/seelog + +require ( + github.com/Knetic/govaluate v3.0.0+incompatible + github.com/buger/jsonparser v1.1.2 + github.com/cihub/seelog v0.0.0-00010101000000-000000000000 + github.com/crewjam/saml v0.5.1 + github.com/emirpasic/gods v1.18.1 + github.com/golang-jwt/jwt/v4 v4.5.2 + github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df + github.com/google/go-github v17.0.0+incompatible + github.com/mitchellh/mapstructure v1.5.0 + github.com/r3labs/diff/v2 v2.15.1 + github.com/segmentio/encoding v0.4.1 + github.com/stretchr/testify v1.11.1 + golang.org/x/crypto v0.50.0 + golang.org/x/oauth2 v0.29.0 + gopkg.in/yaml.v2 v2.4.0 + infini.sh/framework v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/Azure/go-ntlmssp v0.1.0 // indirect + github.com/OneOfOne/xxhash v1.2.8 // indirect + github.com/RoaringBitmap/roaring v1.9.4 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/arl/statsviz v0.6.0 // indirect + github.com/beevik/etree v1.5.0 // indirect + github.com/bits-and-blooms/bitset v1.12.0 // indirect + github.com/bkaradzic/go-lz4 v1.0.0 // indirect + github.com/caddyserver/certmagic v0.25.3 // indirect + github.com/caddyserver/zerossl v0.1.5 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgraph-io/badger/v4 v4.7.0 // indirect + github.com/dgraph-io/ristretto v0.2.0 // indirect + github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/ebitengine/purego v0.10.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect + github.com/go-ldap/ldap/v3 v3.4.13 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/flatbuffers v25.2.10+incompatible // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gookit/filter v1.2.3 // indirect + github.com/gookit/goutil v0.7.1 // indirect + github.com/gookit/validate v1.5.6 // indirect + github.com/gorilla/context v1.1.2 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.4.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e // indirect + github.com/jonboulle/clockwork v0.2.2 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect + github.com/kardianos/service v1.2.2 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/libdns/libdns v1.1.1 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mholt/acmez/v3 v3.1.6 // indirect + github.com/miekg/dns v1.1.72 // indirect + github.com/mschoch/smat v0.2.0 // indirect + github.com/onsi/gomega v1.35.1 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/rs/xid v1.6.0 // indirect + github.com/russellhaering/goxmldsig v1.4.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287 // indirect + github.com/segmentio/asm v1.1.3 // indirect + github.com/shirou/gopsutil/v4 v4.26.3 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect + github.com/twmb/franz-go v1.18.1 // indirect + github.com/twmb/franz-go/pkg/kadm v1.16.0 // indirect + github.com/twmb/franz-go/pkg/kmsg v1.11.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.1 // indirect + go.uber.org/zap/exp v0.3.0 // indirect + golang.org/x/mod v0.35.0 // indirect + golang.org/x/net v0.53.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/term v0.42.0 // indirect + golang.org/x/text v0.36.0 // indirect + golang.org/x/time v0.11.0 // indirect + golang.org/x/tools v0.44.0 // indirect + google.golang.org/appengine v1.6.6 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + infini.sh/license v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..0f35c1ca --- /dev/null +++ b/go.sum @@ -0,0 +1,337 @@ +code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE= +code.pfad.fr/check v1.1.0/go.mod h1:NiUH13DtYsb7xp5wll0U4SXx7KhXQVCtRgdC96IPfoM= +github.com/Azure/go-ntlmssp v0.1.0 h1:DjFo6YtWzNqNvQdrwEyr/e4nhU3vRiwenz5QX7sFz+A= +github.com/Azure/go-ntlmssp v0.1.0/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk= +github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv2QzDdQ= +github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= +github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI= +github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/arl/statsviz v0.6.0 h1:jbW1QJkEYQkufd//4NDYRSNBpwJNrdzPahF7ZmoGdyE= +github.com/arl/statsviz v0.6.0/go.mod h1:0toboo+YGSUXDaS4g1D5TVS4dXs7S7YYT5J/qnW2h8s= +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= +github.com/beevik/etree v1.5.0 h1:iaQZFSDS+3kYZiGoc9uKeOkUY3nYMXOKLl6KIJxiJWs= +github.com/beevik/etree v1.5.0/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs= +github.com/bits-and-blooms/bitset v1.12.0 h1:U/q1fAF7xXRhFCrhROzIfffYnu+dlS38vCZtmFVPHmA= +github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk= +github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= +github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= +github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/caddyserver/certmagic v0.25.3 h1:mGf5ba8F7xA4c5jfDZZbK2buY1VEkbnwpMDixaju94A= +github.com/caddyserver/certmagic v0.25.3/go.mod h1:YVs43D5+H/Dckt4bTga1KSO/xYfFBfVZainGDywYPAA= +github.com/caddyserver/zerossl v0.1.5 h1:dkvOjBAEEtY6LIGAHei7sw2UgqSD6TrWweXpV7lvEvE= +github.com/caddyserver/zerossl v0.1.5/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/crewjam/saml v0.5.1 h1:g+mfp0CrLuLRZCK793PgJcZeg5dS/0CDwoeAX2zcwNI= +github.com/crewjam/saml v0.5.1/go.mod h1:r0fDkmFe5URDgPrmtH0IYokva6fac3AUdstiPhyEolQ= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= +github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA= +github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= +github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= +github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= +github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-ldap/ldap/v3 v3.4.13 h1:+x1nG9h+MZN7h/lUi5Q3UZ0fJ1GyDQYbPvbuH38baDQ= +github.com/go-ldap/ldap/v3 v3.4.13/go.mod h1:LxsGZV6vbaK0sIvYfsv47rfh4ca0JXokCoKjZxsszv0= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df h1:Mwihr/o+v4L5h56rwHLOE20+hh7Okhwno5BHz3zDuao= +github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= +github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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/gookit/filter v1.2.3 h1:Zo7cBOtsVzAoa/jtf+Ury6zlsbJXqInFdUpbbnB2vMM= +github.com/gookit/filter v1.2.3/go.mod h1:nFLJcOV8dRgS1iiX23gUQgmHUhpuS40qCvAGgIvA1pM= +github.com/gookit/goutil v0.7.1 h1:AaFJPN9mrdeYBv8HOybri26EHGCC34WJVT7jUStGJsI= +github.com/gookit/goutil v0.7.1/go.mod h1:vJS9HXctYTCLtCsZot5L5xF+O1oR17cDYO9R0HxBmnU= +github.com/gookit/validate v1.5.6 h1:D6vbSZzreuKYpeeXm5FDDEJy3K5E4lcWsQE4saSMZbU= +github.com/gookit/validate v1.5.6/go.mod h1:WYEHndRNepIIkM+6CtgEX9MQ9ToIQRhXxmz5oLHF/fc= +github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= +github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= +github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e h1:ZZCvgaRDZg1gC9/1xrsgaJzQUCQgniKtw0xjWywWAOE= +github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e/go.mod h1:+rHyWac2R9oAZwFe1wGY2HBzFJJy++RHBg1cU23NkD8= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= +github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh5YzC3JVwU= +github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk= +github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U= +github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ= +github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U= +github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= +github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk= +github.com/mholt/acmez/v3 v3.1.6/go.mod h1:5nTPosTGosLxF3+LU4ygbgMRFDhbAVpqMI4+a4aHLBY= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= +github.com/nsqio/nsq v1.3.0 h1:v7NtyO844ieTIOCQEqQ7IUSSi1ImhgrTTto1rgIYGEU= +github.com/nsqio/nsq v1.3.0/go.mod h1:RxNr6UC0kSkNF44LnJrlN3U3CQnQGTXk+QKfSZLzqvc= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg= +github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= +github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287 h1:qIQ0tWF9vxGtkJa24bR+2i53WBCz1nW/Pc47oVYauC4= +github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= +github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= +github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= +github.com/segmentio/encoding v0.4.1 h1:KLGaLSW0jrmhB58Nn4+98spfvPvmo4Ci1P/WIQ9wn7w= +github.com/segmentio/encoding v0.4.1/go.mod h1:/d03Cd8PoaDeceuhUUUQWjU0KhWjrmYrWPgtJHYZSnI= +github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc= +github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/twmb/franz-go v1.18.1 h1:D75xxCDyvTqBSiImFx2lkPduE39jz1vaD7+FNc+vMkc= +github.com/twmb/franz-go v1.18.1/go.mod h1:Uzo77TarcLTUZeLuGq+9lNpSkfZI+JErv7YJhlDjs9M= +github.com/twmb/franz-go/pkg/kadm v1.16.0 h1:STMs1t5lYR5mR974PSiwNzE5TvsosByTp+rKXLOhAjE= +github.com/twmb/franz-go/pkg/kadm v1.16.0/go.mod h1:MUdcUtnf9ph4SFBLLA/XxE29rvLhWYLM9Ygb8dfSCvw= +github.com/twmb/franz-go/pkg/kmsg v1.11.2 h1:hIw75FpwcAjgeyfIGFqivAvwC5uNIOWRGvQgZhH4mhg= +github.com/twmb/franz-go/pkg/kmsg v1.11.2/go.mod h1:CFfkkLysDNmukPYhGzuUcDtf46gQSqCZHMW1T4Z+wDE= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= +github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= +github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= +github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= +go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= +golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +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/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/main.go b/main.go index 75050557..be08535e 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,7 @@ import ( elastic2 "infini.sh/framework/modules/elastic" _ "time/tzdata" - log "github.com/cihub/seelog" + "infini.sh/framework/core/log" "infini.sh/console/config" "infini.sh/console/model" "infini.sh/console/model/alerting" diff --git a/model/instance.go b/model/instance.go index ffcf01d6..b1a6f6d9 100644 --- a/model/instance.go +++ b/model/instance.go @@ -31,7 +31,11 @@ import ( "context" "errors" "fmt" + "infini.sh/framework/core/credential" + common2 "infini.sh/framework/modules/elastic/common" + "infini.sh/framework/modules/security/access_token" "net/http" + "strings" "time" "infini.sh/framework/core/model" @@ -83,7 +87,7 @@ func (inst *TaskWorker) DeletePipeline(pipelineID string) error { return inst.doRequest(req, nil) } -func (inst *TaskWorker) GetPipeline(pipelineID string) (*pipeline.PipelineStatus, error) { +func (inst *TaskWorker) GetPipeline(pipelineID string) (*pipeline.PipelineTaskStatus, error) { if pipelineID == "" { return nil, errors.New("invalid pipelineID") } @@ -94,7 +98,7 @@ func (inst *TaskWorker) GetPipeline(pipelineID string) (*pipeline.PipelineStatus Url: fmt.Sprintf("%s/pipeline/task/%s", inst.Endpoint, pipelineID), Context: ctx, } - res := pipeline.PipelineStatus{} + res := pipeline.PipelineTaskStatus{} err := inst.doRequest(req, &res) if err != nil { return nil, err @@ -102,7 +106,7 @@ func (inst *TaskWorker) GetPipeline(pipelineID string) (*pipeline.PipelineStatus return &res, nil } -func (inst *TaskWorker) GetPipelinesByIDs(pipelineIDs []string) (pipeline.GetPipelinesResponse, error) { +func (inst *TaskWorker) GetPipelinesByIDs(pipelineIDs []string) (pipeline.GetPipelineTasksResponse, error) { body := util.MustToJSONBytes(util.MapStr{ "ids": pipelineIDs, }) @@ -114,7 +118,7 @@ func (inst *TaskWorker) GetPipelinesByIDs(pipelineIDs []string) (pipeline.GetPip Body: body, Context: ctx, } - res := pipeline.GetPipelinesResponse{} + res := pipeline.GetPipelineTasksResponse{} err := inst.doRequest(req, &res) return res, err } @@ -157,9 +161,9 @@ func (inst *TaskWorker) TryConnectWithTimeout(duration time.Duration) error { } func (inst *TaskWorker) doRequest(req *util.Request, resBody interface{}) error { - if inst.BasicAuth != nil && inst.BasicAuth.Username != "" { - req.SetBasicAuth(inst.BasicAuth.Username, inst.BasicAuth.Password.Get()) - } + + _ = ApplyAuthFromInstance(&inst.Instance, req) + result, err := util.ExecuteRequest(req) if err != nil { return err @@ -172,3 +176,45 @@ func (inst *TaskWorker) doRequest(req *util.Request, resBody interface{}) error } return nil } + +func ApplyAuthFromInstance(inst *model.Instance, req *util.Request) error { + if inst.BasicAuth != nil && inst.BasicAuth.Username != "" { + req.SetBasicAuth(inst.BasicAuth.Username, inst.BasicAuth.Password.Get()) + } else if inst.AccessToken != "" { + req.AddHeader(model.API_TOKEN, inst.AccessToken) + } else if cred := inst.GetSystemString(model.CredentialIDSystemKey); cred != "" { + //try credential last + return ApplyCredentialToRequest(req, cred) + } + return nil +} + +func ApplyCredentialToRequest(req *util.Request, credentialID string) error { + if req == nil || strings.TrimSpace(credentialID) == "" { + return nil + } + + cred, err := common2.GetCredential(credentialID) + if err != nil { + return err + } + + switch cred.Type { + case credential.BasicAuth: + auth, err := cred.DecodeBasicAuth() + if err != nil { + return err + } + req.SetBasicAuth(auth.Username, auth.Password.Get()) + case credential.AccessToken: + token, err := cred.DecodeAccessToken() + if err != nil { + return err + } + req.AddHeader(access_token.HeaderAPIToken, token.AccessToken.Get()) + default: + return fmt.Errorf("unsupported credential type [%s]", cred.Type) + } + + return nil +} diff --git a/modules/elastic/api/manage.go b/modules/elastic/api/manage.go index 0928e00e..eb0a1dc6 100644 --- a/modules/elastic/api/manage.go +++ b/modules/elastic/api/manage.go @@ -139,8 +139,8 @@ func saveBasicAuthToCredential(name string, auth *model.BasicAuth) (string, erro Name: name, Type: credential.BasicAuth, Tags: []string{"ES"}, - Payload: map[string]interface{}{ - "basic_auth": map[string]interface{}{ + Payload: map[credential.CredentialType]interface{}{ + credential.BasicAuth: map[string]interface{}{ "username": auth.Username, "password": auth.Password.Get(), }, diff --git a/modules/elastic/api/v1/manage.go b/modules/elastic/api/v1/manage.go index ce2eb654..40edb9a0 100644 --- a/modules/elastic/api/v1/manage.go +++ b/modules/elastic/api/v1/manage.go @@ -113,8 +113,8 @@ func saveBasicAuthToCredential(conf *elastic.ElasticsearchConfig) (string, error Name: conf.Name, Type: credential.BasicAuth, Tags: []string{"ES"}, - Payload: map[string]interface{}{ - "basic_auth": map[string]interface{}{ + Payload: map[credential.CredentialType]interface{}{ + credential.BasicAuth: map[string]interface{}{ "username": conf.BasicAuth.Username, "password": conf.BasicAuth.Password.Get(), }, diff --git a/modules/security/credential/api/credential.go b/modules/security/credential/api/credential.go index ac26435c..b2440b92 100644 --- a/modules/security/credential/api/credential.go +++ b/modules/security/credential/api/credential.go @@ -312,7 +312,15 @@ func (h *APIHandler) getCredential(w http.ResponseWriter, req *http.Request, ps }, http.StatusNotFound) return } - util.MapStr(obj.Payload).Delete("basic_auth.password") - util.MapStr(obj.Payload).Delete("access_token.access_token") + payloadStr := make(util.MapStr, len(obj.Payload)) + for k, v := range obj.Payload { + payloadStr[string(k)] = v + } + payloadStr.Delete("basic_auth.password") + payloadStr.Delete("access_token.access_token") + obj.Payload = make(map[credential.CredentialType]interface{}, len(payloadStr)) + for k, v := range payloadStr { + obj.Payload[credential.CredentialType(k)] = v + } h.WriteGetOKJSON(w, id, obj) } diff --git a/plugin/api/email/server.go b/plugin/api/email/server.go index c9b125bf..9385d0e9 100644 --- a/plugin/api/email/server.go +++ b/plugin/api/email/server.go @@ -37,7 +37,6 @@ import ( "github.com/buger/jsonparser" log "github.com/cihub/seelog" - "github.com/gopkg.in/gomail.v2" "infini.sh/console/model" "infini.sh/console/model/alerting" "infini.sh/console/plugin/api/email/common" @@ -45,6 +44,7 @@ import ( "infini.sh/framework/core/credential" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" + "infini.sh/framework/lib/gomail" ) func (h *EmailAPI) createEmailServer(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { @@ -129,8 +129,8 @@ func saveBasicAuthToCredential(srv *model.EmailServer) (string, error) { Name: srv.Name, Type: credential.BasicAuth, Tags: []string{"Email"}, - Payload: map[string]interface{}{ - "basic_auth": map[string]interface{}{ + Payload: map[credential.CredentialType]interface{}{ + credential.BasicAuth: map[string]interface{}{ "username": srv.Auth.Username, "password": srv.Auth.Password.Get(), }, diff --git a/plugin/managed/server/credential.go b/plugin/managed/server/credential.go index 6093c75c..928b0cb0 100644 --- a/plugin/managed/server/credential.go +++ b/plugin/managed/server/credential.go @@ -2,6 +2,7 @@ package server import ( "fmt" + model2 "infini.sh/console/model" "net/http" "strings" @@ -9,12 +10,10 @@ import ( "infini.sh/framework/core/model" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" - common2 "infini.sh/framework/modules/elastic/common" - "infini.sh/framework/modules/security/access_token" ) const instanceAccessTokenKey = "access_token" -const agentAPICredentialIDKey = "agent_api_credential_id" +const agentAccessTokenKey = "agent_api_credential_id" const managerAPICredentialIDKey = "manager_api_credential_id" // Keep reading the old key so existing managed instances continue to work @@ -95,12 +94,15 @@ func preserveManagedCredentialIDs(instance, oldInst *model.Instance) { return } - if instance.CredentialID == "" { - instance.CredentialID = oldInst.CredentialID + //get previous saved credential info + if id := oldInst.GetSystemString(model.CredentialIDSystemKey); id != "" { + instance.SetSystemValue(model.CredentialIDSystemKey, id) } - if getAgentAPICredentialID(instance) == "" { - setAgentAPICredentialID(instance, getAgentAPICredentialID(oldInst)) + + if getAgentAccessToken(instance) == "" { + setAgentAPICredentialID(instance, getAgentAccessToken(oldInst)) } + if getManagerAPICredentialID(instance) == "" { setManagerAPICredentialID(instance, getManagerAPICredentialID(oldInst)) } @@ -121,7 +123,7 @@ func upsertManagedAccessTokenCredential(credentialID, name string, tags []string cred.Name = name cred.Type = credential.AccessToken cred.Tags = tags - cred.Payload = map[string]interface{}{ + cred.Payload = map[credential.CredentialType]interface{}{ credential.AccessToken: map[string]interface{}{ "access_token": accessToken, }, @@ -140,25 +142,24 @@ func upsertManagedAccessTokenCredential(credentialID, name string, tags []string return cred.ID, nil } - cred.ID = util.GetUUID() if err := orm.Create(ctx, &cred); err != nil { return "", err } return cred.ID, nil } -func getAgentAPICredentialID(instance *model.Instance) string { +func getAgentAccessToken(instance *model.Instance) string { if instance == nil { return "" } - if credentialID := getInstanceSystemString(instance, agentAPICredentialIDKey); credentialID != "" { - return credentialID + if accessToken := getInstanceSystemString(instance, agentAccessTokenKey); accessToken != "" { + return accessToken } - return instance.CredentialID + return instance.AccessToken } func setAgentAPICredentialID(instance *model.Instance, credentialID string) { - setInstanceSystemString(instance, agentAPICredentialIDKey, credentialID) + setInstanceSystemString(instance, agentAccessTokenKey, credentialID) } func getManagerAPICredentialID(instance *model.Instance) string { @@ -182,7 +183,7 @@ func upsertInstanceAgentAPICredential(instance *model.Instance, accessToken stri } return upsertManagedAccessTokenCredential( - getAgentAPICredentialID(instance), + getAgentAccessToken(instance), fmt.Sprintf("%s agent api", getInstanceCredentialName(instance)), []string{"agent", "managed", "agent_api", "access_token"}, accessToken, @@ -205,52 +206,6 @@ func upsertInstanceManagerAPICredential(instance *model.Instance, accessToken st ) } -func applyCredentialRequestAuth(req *util.Request, credentialID string) error { - if req == nil || strings.TrimSpace(credentialID) == "" { - return nil - } - - cred, err := common2.GetCredential(credentialID) - if err != nil { - return err - } - - switch cred.Type { - case credential.BasicAuth: - auth, err := cred.DecodeBasicAuth() - if err != nil { - return err - } - req.SetBasicAuth(auth.Username, auth.Password.Get()) - case credential.AccessToken: - token, err := cred.DecodeAccessToken() - if err != nil { - return err - } - req.AddHeader(access_token.HeaderAPIToken, token.AccessToken.Get()) - default: - return fmt.Errorf("unsupported credential type [%s]", cred.Type) - } - - return nil -} - -func applyInstanceRequestAuth(req *util.Request, instance *model.Instance) error { - if req == nil || instance == nil { - return nil - } - - if credentialID := getAgentAPICredentialID(instance); credentialID != "" { - return applyCredentialRequestAuth(req, credentialID) - } - - if instance.BasicAuth != nil && instance.BasicAuth.Username != "" { - req.SetBasicAuth(instance.BasicAuth.Username, instance.BasicAuth.Password.Get()) - } - - return nil -} - func getInstanceByEndpoint(endpoint string) (*model.Instance, error) { if strings.TrimSpace(endpoint) == "" { return nil, nil @@ -290,7 +245,8 @@ func prepareProxyAgentRequest(endpoint string, req *util.Request) error { if err != nil || instance == nil { return err } - return applyInstanceRequestAuth(req, instance) + + return model2.ApplyAuthFromInstance(instance, req) } func isAuthorizedStatus(code int) bool { diff --git a/plugin/setup/setup.go b/plugin/setup/setup.go index c820751a..e329c2dd 100644 --- a/plugin/setup/setup.go +++ b/plugin/setup/setup.go @@ -745,8 +745,8 @@ func createCred(name, username, password string) string { Name: name, Type: credential.BasicAuth, Tags: []string{"infini", "system"}, - Payload: map[string]interface{}{ - "basic_auth": map[string]interface{}{ + Payload: map[credential.CredentialType]interface{}{ + credential.BasicAuth: map[string]interface{}{ "username": username, "password": password, }, From 8a8a030959988e4469024534d33eb7da6d927248 Mon Sep 17 00:00:00 2001 From: medcl Date: Tue, 26 May 2026 23:09:38 +0800 Subject: [PATCH 3/7] chore: fix build, handle agent register --- main.go | 2 +- plugin/managed/server/credential.go | 66 ++++++++++++++++++++++------ plugin/managed/server/instance.go | 67 +++++++++++++++++++++++++---- 3 files changed, 113 insertions(+), 22 deletions(-) diff --git a/main.go b/main.go index be08535e..2f936f92 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,6 @@ import ( elastic2 "infini.sh/framework/modules/elastic" _ "time/tzdata" - "infini.sh/framework/core/log" "infini.sh/console/config" "infini.sh/console/model" "infini.sh/console/model/alerting" @@ -52,6 +51,7 @@ import ( "infini.sh/framework/core/elastic" "infini.sh/framework/core/env" "infini.sh/framework/core/global" + "infini.sh/framework/core/log" "infini.sh/framework/core/module" "infini.sh/framework/core/orm" task1 "infini.sh/framework/core/task" diff --git a/plugin/managed/server/credential.go b/plugin/managed/server/credential.go index 928b0cb0..93e377d7 100644 --- a/plugin/managed/server/credential.go +++ b/plugin/managed/server/credential.go @@ -108,7 +108,7 @@ func preserveManagedCredentialIDs(instance, oldInst *model.Instance) { } } -func upsertManagedAccessTokenCredential(credentialID, name string, tags []string, accessToken string) (string, error) { +func upsertAccessToken(credentialID, name string, tags []string, accessToken string) (string, error) { cred := credential.Credential{} exists := false if credentialID != "" { @@ -148,6 +148,48 @@ func upsertManagedAccessTokenCredential(credentialID, name string, tags []string return cred.ID, nil } +func upsertAccessTokenToCredential(instance *model.Instance, accessToken string) error { + cred := credential.Credential{} + exists := false + if credentialID := instance.GetSystemString(model.CredentialIDSystemKey); credentialID != "" { + cred.ID = credentialID + var err error + exists, err = orm.Get(&cred) + if err != nil { + return err + } + } + + cred.Name = fmt.Sprintf("access_token for instance: %v/%v", instance.Name, instance.ID) + cred.Type = credential.AccessToken + + cred.Payload = map[credential.CredentialType]interface{}{ + credential.AccessToken: map[string]interface{}{ + "access_token": accessToken, + }, + } + + if err := cred.Encode(); err != nil { + return err + } + + ctx := &orm.Context{Refresh: orm.WaitForRefresh} + if exists { + cred.Invalid = false + if err := orm.Update(ctx, &cred); err != nil { + return err + } + instance.SetSystemValue(model.CredentialIDSystemKey, cred.ID) + return nil + } + + if err := orm.Create(ctx, &cred); err != nil { + return err + } + instance.SetSystemValue(model.CredentialIDSystemKey, cred.ID) + return nil +} + func getAgentAccessToken(instance *model.Instance) string { if instance == nil { return "" @@ -182,12 +224,8 @@ func upsertInstanceAgentAPICredential(instance *model.Instance, accessToken stri return "", fmt.Errorf("access token is empty") } - return upsertManagedAccessTokenCredential( - getAgentAccessToken(instance), - fmt.Sprintf("%s agent api", getInstanceCredentialName(instance)), - []string{"agent", "managed", "agent_api", "access_token"}, - accessToken, - ) + e := upsertAccessTokenToCredential(instance, accessToken) + return "", e } func upsertInstanceManagerAPICredential(instance *model.Instance, accessToken string) (string, error) { @@ -198,12 +236,14 @@ func upsertInstanceManagerAPICredential(instance *model.Instance, accessToken st return "", fmt.Errorf("access token is empty") } - return upsertManagedAccessTokenCredential( - getManagerAPICredentialID(instance), - fmt.Sprintf("%s manager api", getInstanceCredentialName(instance)), - []string{"agent", "managed", "manager_api", "access_token"}, - accessToken, - ) + //return upsertAccessTokenToCredential( + // getManagerAPICredentialID(instance), + // fmt.Sprintf("%s manager api", getInstanceCredentialName(instance)), + // []string{"agent", "managed", "manager_api", "access_token"}, + // accessToken, + //) + e := upsertAccessTokenToCredential(instance, accessToken) + return "", e } func getInstanceByEndpoint(endpoint string) (*model.Instance, error) { diff --git a/plugin/managed/server/instance.go b/plugin/managed/server/instance.go index 343d8230..b9a995aa 100644 --- a/plugin/managed/server/instance.go +++ b/plugin/managed/server/instance.go @@ -30,6 +30,9 @@ package server import ( "context" "fmt" + model2 "infini.sh/console/model" + "infini.sh/framework/core/security" + "infini.sh/framework/modules/security/access_token" "net/http" "strconv" "strings" @@ -39,11 +42,11 @@ import ( "infini.sh/framework/core/global" "infini.sh/framework/core/task" - log "github.com/cihub/seelog" "infini.sh/console/core/security/enum" "infini.sh/framework/core/api" httprouter "infini.sh/framework/core/api/router" elastic2 "infini.sh/framework/core/elastic" + "infini.sh/framework/core/log" "infini.sh/framework/core/model" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" @@ -102,6 +105,10 @@ func (h APIHandler) registerInstance(w http.ResponseWriter, req *http.Request, p return } + //1. client report instance info include agent's access_token + //2. server received the instance info, save access token to credential db + //3. server generate a access_token return to client + oldInst, err := loadExistingInstance(obj.ID) if err != nil { h.WriteError(w, err.Error(), http.StatusInternalServerError) @@ -109,12 +116,29 @@ func (h APIHandler) registerInstance(w http.ResponseWriter, req *http.Request, p } if oldInst != nil { obj.Created = oldInst.Created - preserveManagedCredentialIDs(obj, oldInst) + + //get previous saved credential info + if id := oldInst.GetSystemString(model.CredentialIDSystemKey); id != "" { + obj.SetSystemValue(model.CredentialIDSystemKey, id) + } + + if obj.AccessToken != "" { + //save instance's reported agent to console's crendential + err := upsertAccessTokenToCredential(obj, obj.AccessToken) + if err != nil { + panic(err) + } + } + } + //cleanup instance's sensitive data + obj.AccessToken = "" + obj.BasicAuth = nil + clearInstanceAccessToken(obj) - err = orm.Save(nil, obj) + err = orm.Save(orm.NewContextWithParent(req.Context()), obj) if err != nil { h.WriteError(w, err.Error(), http.StatusInternalServerError) return @@ -122,7 +146,15 @@ func (h APIHandler) registerInstance(w http.ResponseWriter, req *http.Request, p log.Infof("register instance: %v[%v], %v", obj.Name, obj.ID, obj.Endpoint) - h.WriteAckOKJSON(w) + permissions := []security.PermissionKey{} + //TODO add permission keys for config client's api permissions + + res, err := access_token.CreateAPIToken(nil, fmt.Sprintf("access_token for instance: %v(%v)", obj.Name, obj.ID), "for_instance", -1, permissions) + if err != nil { + panic(err) + } + + api.WriteAckJSON(w, true, 200, res) } func (h APIHandler) enrollInstance(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { @@ -449,7 +481,7 @@ func (h *APIHandler) clearInstanceByAppName(appName string) error { // check whether the instance is still online for _, instanceID := range toRemoveIDs { if inst, ok := instsCache[instanceID]; ok { - _, err = h.getInstanceInfo(inst.Endpoint, inst.BasicAuth) + err = h.checkInstanceInfo(inst) if err == nil { // Skip online instance, do not append to filtered list continue @@ -570,9 +602,8 @@ func (h *APIHandler) proxy(w http.ResponseWriter, req *http.Request, ps httprout Context: ctx, Body: reqBody, } - if obj.BasicAuth != nil { - req1.SetBasicAuth(obj.BasicAuth.Username, obj.BasicAuth.Password.Get()) - } + + _ = model2.ApplyAuthFromInstance(obj, req1) res, err := ProxyAgentRequest("runtime", obj.GetEndpoint(), req1, nil) if err != nil { @@ -603,6 +634,26 @@ func (h *APIHandler) getInstanceInfo(endpoint string, basicAuth *model.BasicAuth } +func (h *APIHandler) checkInstanceInfo(instance *model.Instance) error { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + req1 := &util.Request{ + Method: http.MethodGet, + Path: "/_info", + Context: ctx, + } + + _ = model2.ApplyAuthFromInstance(instance, req1) + + obj := &model.Instance{} + _, err := ProxyAgentRequest("runtime", instance.Endpoint, req1, obj) + if err != nil { + return err + } + return err + +} + func (h *APIHandler) tryConnect(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { var reqBody = struct { Endpoint string `json:"endpoint"` From cd181723621d2a602dbbad9f5bf9f43582c7d852 Mon Sep 17 00:00:00 2001 From: medcl Date: Wed, 27 May 2026 14:37:09 +0800 Subject: [PATCH 4/7] chore: no silent panic in debug mode --- main.go | 3 +- plugin/setup/setup.go | 99 +++++++++++++----------- service/alerting/elasticsearch/engine.go | 8 +- 3 files changed, 60 insertions(+), 50 deletions(-) diff --git a/main.go b/main.go index 2f936f92..c9de2e34 100644 --- a/main.go +++ b/main.go @@ -178,7 +178,8 @@ func main() { elastic2.InitTemplate(false) if global.Env().SetupRequired() { - for _, v := range modules { + for k, v := range modules { + log.Debugf("start module: %v", k) v.Value.Start() } } diff --git a/plugin/setup/setup.go b/plugin/setup/setup.go index e329c2dd..4ef2177d 100644 --- a/plugin/setup/setup.go +++ b/plugin/setup/setup.go @@ -195,28 +195,30 @@ func (module *Module) validate(w http.ResponseWriter, r *http.Request, ps httpro result := util.MapStr{} result["success"] = success - if r := recover(); r != nil { - var v string - switch r.(type) { - case error: - v = r.(error).Error() - case runtime.Error: - v = r.(runtime.Error).Error() - case string: - v = r.(string) - } - if v != "" { - success = false - result["error"] = util.MapStr{ - "reason": v, - } - if errType != "" { - result["type"] = errType + if !global.Env().IsDebug { + if r := recover(); r != nil { + var v string + switch r.(type) { + case error: + v = r.(error).Error() + case runtime.Error: + v = r.(runtime.Error).Error() + case string: + v = r.(string) } - if fixTips != "" { - result["fix_tips"] = fixTips + if v != "" { + success = false + result["error"] = util.MapStr{ + "reason": v, + } + if errType != "" { + result["type"] = errType + } + if fixTips != "" { + result["fix_tips"] = fixTips + } + code = http.StatusInternalServerError } - code = http.StatusInternalServerError } } module.WriteJSON(w, result, code) @@ -427,31 +429,33 @@ func (module *Module) initialize(w http.ResponseWriter, r *http.Request, ps http "secret_mismatch": secretMismatch, } result["success"] = success - - if r := recover(); r != nil { - var v string - switch r.(type) { - case error: - v = r.(error).Error() - case runtime.Error: - v = r.(runtime.Error).Error() - case string: - v = r.(string) - } - if v != "" { - success = false - result["error"] = util.MapStr{ - "reason": v, + if !global.Env().IsDebug { + if r := recover(); r != nil { + var v string + switch r.(type) { + case error: + v = r.(error).Error() + case runtime.Error: + v = r.(runtime.Error).Error() + case string: + v = r.(string) } - if errType != "" { - result["type"] = errType + if v != "" { + success = false + result["error"] = util.MapStr{ + "reason": v, + } + if errType != "" { + result["type"] = errType + } + if fixTips != "" { + result["fix_tips"] = fixTips + } + code = http.StatusInternalServerError } - if fixTips != "" { - result["fix_tips"] = fixTips - } - code = http.StatusInternalServerError } } + module.WriteJSON(w, result, code) }() err, client := module.initTempClient(request) @@ -793,12 +797,15 @@ func (module *Module) initializeTemplate(w http.ResponseWriter, r *http.Request, // recover from panic and return error message defer func() { - if v := recover(); v != nil { - module.WriteJSON(w, util.MapStr{ - "success": false, - "log": fmt.Sprintf("%v", v), - }, http.StatusOK) + if !global.Env().IsDebug { + if v := recover(); v != nil { + module.WriteJSON(w, util.MapStr{ + "success": false, + "log": fmt.Sprintf("%v", v), + }, http.StatusOK) + } } + }() request := &SetupRequest{} diff --git a/service/alerting/elasticsearch/engine.go b/service/alerting/elasticsearch/engine.go index 0d0b4e68..d1b70d24 100644 --- a/service/alerting/elasticsearch/engine.go +++ b/service/alerting/elasticsearch/engine.go @@ -1243,9 +1243,11 @@ func performChannels(channels []alerting.Channel, ctx map[string]interface{}, ra func (engine *Engine) GenerateTask(rule alerting.Rule) func(ctx context.Context) { return func(ctx context.Context) { defer func() { - if err := recover(); err != nil { - log.Error(err) - debug.PrintStack() + if !global.Env().IsDebug { + if err := recover(); err != nil { + log.Error(err) + debug.PrintStack() + } } }() err := engine.Do(&rule) From eb93340ff38f7affd25917f0a9aec15f693808c9 Mon Sep 17 00:00:00 2001 From: medcl Date: Wed, 27 May 2026 14:37:31 +0800 Subject: [PATCH 5/7] chore: fix duplicated handler issue --- modules/security/realm/authc/native/permission.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/security/realm/authc/native/permission.json b/modules/security/realm/authc/native/permission.json index 38d1c677..a74e3087 100644 --- a/modules/security/realm/authc/native/permission.json +++ b/modules/security/realm/authc/native/permission.json @@ -591,9 +591,6 @@ {"name": "template.get", "methods": ["get"], "path": "/_template/:template_name" }, - {"name": "template.exists", "methods": ["head"], - "path": "/_template/:template_name" - }, {"name": "template.put", "methods": ["put", "post"], "path": "/_template/:template_name" }, From ccebe075e5a81c3e9b0acf2991530932fbd82ac7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 10:53:36 +0000 Subject: [PATCH 6/7] fix: preserve typed basic auth credential key --- plugin/api/email/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/api/email/server.go b/plugin/api/email/server.go index 02b942cd..8d515997 100644 --- a/plugin/api/email/server.go +++ b/plugin/api/email/server.go @@ -129,7 +129,7 @@ func saveBasicAuthToCredential(srv *model.EmailServer) (string, error) { Type: credential.BasicAuth, Tags: []string{"Email"}, Payload: map[string]interface{}{ - "basic_auth": map[string]interface{}{ + string(credential.BasicAuth): map[string]interface{}{ "username": srv.Auth.Username, "password": srv.Auth.Password.Get(), }, From 86c08793f4b4451be07135dcd0cd50a85ee91d34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 10:54:48 +0000 Subject: [PATCH 7/7] fix: preserve typed basic auth credential key --- go.mod | 80 ------------------- go.sum | 240 --------------------------------------------------------- 2 files changed, 320 deletions(-) diff --git a/go.mod b/go.mod index d8bd6fd6..e2f52e1e 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ replace github.com/cihub/seelog => ../framework/lib/seelog require ( github.com/Knetic/govaluate v3.0.0+incompatible github.com/buger/jsonparser v1.2.0 - github.com/cihub/seelog v0.0.0-00010101000000-000000000000 github.com/crewjam/saml v0.5.1 github.com/emirpasic/gods v1.18.1 github.com/golang-jwt/jwt/v4 v4.5.2 @@ -23,103 +22,24 @@ require ( golang.org/x/oauth2 v0.36.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/yaml.v2 v2.4.0 - infini.sh/framework v0.0.0-00010101000000-000000000000 ) require ( - github.com/Azure/go-ntlmssp v0.1.0 // indirect - github.com/OneOfOne/xxhash v1.2.8 // indirect - github.com/RoaringBitmap/roaring v1.9.4 // indirect - github.com/andybalholm/brotli v1.1.1 // indirect - github.com/arl/statsviz v0.6.0 // indirect github.com/beevik/etree v1.5.0 // indirect - github.com/bits-and-blooms/bitset v1.12.0 // indirect - github.com/bkaradzic/go-lz4 v1.0.0 // indirect - github.com/caddyserver/certmagic v0.25.3 // indirect - github.com/caddyserver/zerossl v0.1.5 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/dgraph-io/badger/v4 v4.7.0 // indirect - github.com/dgraph-io/ristretto v0.2.0 // indirect - github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/ebitengine/purego v0.10.0 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect - github.com/go-ldap/ldap/v3 v3.4.13 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/gookit/filter v1.2.3 // indirect - github.com/gookit/goutil v0.7.1 // indirect - github.com/gookit/validate v1.5.6 // indirect - github.com/gorilla/context v1.1.2 // indirect - github.com/gorilla/securecookie v1.1.2 // indirect - github.com/gorilla/sessions v1.4.0 // indirect - github.com/gorilla/websocket v1.5.3 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect - github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e // indirect github.com/jonboulle/clockwork v0.2.2 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect - github.com/kardianos/service v1.2.2 // indirect - github.com/klauspost/compress v1.18.0 // indirect - github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/libdns/libdns v1.1.1 // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect - github.com/mattn/go-isatty v0.0.22 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mholt/acmez/v3 v3.1.6 // indirect - github.com/miekg/dns v1.1.72 // indirect - github.com/mschoch/smat v0.2.0 // indirect - github.com/pierrec/lz4/v4 v4.1.22 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/rs/cors v1.11.1 // indirect - github.com/rs/xid v1.6.0 // indirect github.com/russellhaering/goxmldsig v1.4.0 // indirect - github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287 // indirect github.com/segmentio/asm v1.1.3 // indirect - github.com/shirou/gopsutil/v4 v4.26.3 // indirect - github.com/tklauser/go-sysconf v0.3.16 // indirect - github.com/tklauser/numcpus v0.11.0 // indirect - github.com/twmb/franz-go v1.18.1 // indirect - github.com/twmb/franz-go/pkg/kadm v1.16.0 // indirect - github.com/twmb/franz-go/pkg/kmsg v1.11.2 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect - github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zeebo/blake3 v0.2.4 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.35.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/trace v1.35.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect - go.uber.org/zap/exp v0.3.0 // indirect - golang.org/x/mod v0.35.0 // indirect golang.org/x/net v0.54.0 // indirect - golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.45.0 // indirect - golang.org/x/term v0.43.0 // indirect - golang.org/x/text v0.37.0 // indirect - golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.44.0 // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index deb03063..236a18aa 100644 --- a/go.sum +++ b/go.sum @@ -1,77 +1,18 @@ -code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE= -code.pfad.fr/check v1.1.0/go.mod h1:NiUH13DtYsb7xp5wll0U4SXx7KhXQVCtRgdC96IPfoM= -github.com/Azure/go-ntlmssp v0.1.0 h1:DjFo6YtWzNqNvQdrwEyr/e4nhU3vRiwenz5QX7sFz+A= -github.com/Azure/go-ntlmssp v0.1.0/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= -github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv2QzDdQ= -github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= -github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI= -github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= -github.com/arl/statsviz v0.6.0 h1:jbW1QJkEYQkufd//4NDYRSNBpwJNrdzPahF7ZmoGdyE= -github.com/arl/statsviz v0.6.0/go.mod h1:0toboo+YGSUXDaS4g1D5TVS4dXs7S7YYT5J/qnW2h8s= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.5.0 h1:iaQZFSDS+3kYZiGoc9uKeOkUY3nYMXOKLl6KIJxiJWs= github.com/beevik/etree v1.5.0/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs= -github.com/bits-and-blooms/bitset v1.12.0 h1:U/q1fAF7xXRhFCrhROzIfffYnu+dlS38vCZtmFVPHmA= -github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk= -github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/buger/jsonparser v1.2.0 h1:4EFcvK1kD4jyj6YqNK6skK6w+y7FHHBR+XBCtxwu/6g= github.com/buger/jsonparser v1.2.0/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/caddyserver/certmagic v0.25.3 h1:mGf5ba8F7xA4c5jfDZZbK2buY1VEkbnwpMDixaju94A= -github.com/caddyserver/certmagic v0.25.3/go.mod h1:YVs43D5+H/Dckt4bTga1KSO/xYfFBfVZainGDywYPAA= -github.com/caddyserver/zerossl v0.1.5 h1:dkvOjBAEEtY6LIGAHei7sw2UgqSD6TrWweXpV7lvEvE= -github.com/caddyserver/zerossl v0.1.5/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/crewjam/saml v0.5.1 h1:g+mfp0CrLuLRZCK793PgJcZeg5dS/0CDwoeAX2zcwNI= github.com/crewjam/saml v0.5.1/go.mod h1:r0fDkmFe5URDgPrmtH0IYokva6fac3AUdstiPhyEolQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= -github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA= -github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= -github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= -github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= -github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= -github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= -github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= -github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= -github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= -github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= -github.com/go-ldap/ldap/v3 v3.4.13 h1:+x1nG9h+MZN7h/lUi5Q3UZ0fJ1GyDQYbPvbuH38baDQ= -github.com/go-ldap/ldap/v3 v3.4.13/go.mod h1:LxsGZV6vbaK0sIvYfsv47rfh4ca0JXokCoKjZxsszv0= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -79,236 +20,60 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df h1:Mwihr/o+v4L5h56rwHLOE20+hh7Okhwno5BHz3zDuao= github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= -github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= -github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -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/gookit/filter v1.2.3 h1:Zo7cBOtsVzAoa/jtf+Ury6zlsbJXqInFdUpbbnB2vMM= -github.com/gookit/filter v1.2.3/go.mod h1:nFLJcOV8dRgS1iiX23gUQgmHUhpuS40qCvAGgIvA1pM= -github.com/gookit/goutil v0.7.1 h1:AaFJPN9mrdeYBv8HOybri26EHGCC34WJVT7jUStGJsI= -github.com/gookit/goutil v0.7.1/go.mod h1:vJS9HXctYTCLtCsZot5L5xF+O1oR17cDYO9R0HxBmnU= -github.com/gookit/validate v1.5.6 h1:D6vbSZzreuKYpeeXm5FDDEJy3K5E4lcWsQE4saSMZbU= -github.com/gookit/validate v1.5.6/go.mod h1:WYEHndRNepIIkM+6CtgEX9MQ9ToIQRhXxmz5oLHF/fc= -github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= -github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM= -github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= -github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= -github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= -github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= -github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= -github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= -github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= -github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= -github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= -github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= -github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= -github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= -github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e h1:ZZCvgaRDZg1gC9/1xrsgaJzQUCQgniKtw0xjWywWAOE= -github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e/go.mod h1:+rHyWac2R9oAZwFe1wGY2HBzFJJy++RHBg1cU23NkD8= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= -github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= -github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= -github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= -github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh5YzC3JVwU= -github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk= -github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U= -github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ= -github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U= -github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= -github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= -github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk= -github.com/mholt/acmez/v3 v3.1.6/go.mod h1:5nTPosTGosLxF3+LU4ygbgMRFDhbAVpqMI4+a4aHLBY= -github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= -github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= -github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= -github.com/nsqio/nsq v1.3.0 h1:v7NtyO844ieTIOCQEqQ7IUSSi1ImhgrTTto1rgIYGEU= -github.com/nsqio/nsq v1.3.0/go.mod h1:RxNr6UC0kSkNF44LnJrlN3U3CQnQGTXk+QKfSZLzqvc= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= -github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= -github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg= github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= -github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= -github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= -github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= -github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287 h1:qIQ0tWF9vxGtkJa24bR+2i53WBCz1nW/Pc47oVYauC4= -github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0= github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= -github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc= -github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= -github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= -github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= -github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= -github.com/twmb/franz-go v1.18.1 h1:D75xxCDyvTqBSiImFx2lkPduE39jz1vaD7+FNc+vMkc= -github.com/twmb/franz-go v1.18.1/go.mod h1:Uzo77TarcLTUZeLuGq+9lNpSkfZI+JErv7YJhlDjs9M= -github.com/twmb/franz-go/pkg/kadm v1.16.0 h1:STMs1t5lYR5mR974PSiwNzE5TvsosByTp+rKXLOhAjE= -github.com/twmb/franz-go/pkg/kadm v1.16.0/go.mod h1:MUdcUtnf9ph4SFBLLA/XxE29rvLhWYLM9Ygb8dfSCvw= -github.com/twmb/franz-go/pkg/kmsg v1.11.2 h1:hIw75FpwcAjgeyfIGFqivAvwC5uNIOWRGvQgZhH4mhg= -github.com/twmb/franz-go/pkg/kmsg v1.11.2/go.mod h1:CFfkkLysDNmukPYhGzuUcDtf46gQSqCZHMW1T4Z+wDE= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= -github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= -github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= -github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= -github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= -github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= -go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= -golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -320,13 +85,9 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= -gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -335,4 +96,3 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=