diff --git a/cmd/admin-cluster-iam-import.go b/cmd/admin-cluster-iam-import.go index 0289913969..d7332ae4c2 100644 --- a/cmd/admin-cluster-iam-import.go +++ b/cmd/admin-cluster-iam-import.go @@ -23,11 +23,13 @@ import ( "io" "os" "path/filepath" + "strings" "github.com/klauspost/compress/zip" "github.com/minio/cli" + json "github.com/minio/colorjson" + "github.com/minio/madmin-go/v3" "github.com/minio/mc/pkg/probe" - "github.com/minio/pkg/v3/console" ) var adminClusterIAMImportCmd = cli.Command{ @@ -54,6 +56,123 @@ EXAMPLES: `, } +type iamImportInfo madmin.ImportIAMResult + +func (i iamImportInfo) JSON() string { + bs, e := json.MarshalIndent(madmin.ImportIAMResult(i), "", " ") + fatalIf(probe.NewError(e), "Unable to marshal into JSON.") + return string(bs) +} + +func (i iamImportInfo) String() string { + var messages []string + info := madmin.ImportIAMResult(i) + messages = append(messages, processIAMEntities(info.Skipped, "Skipped")...) + messages = append(messages, processIAMEntities(info.Removed, "Removed")...) + messages = append(messages, processIAMEntities(info.Added, "Added")...) + messages = append(messages, processErrIAMEntities(info.Failed)...) + return strings.Join(messages, "\n") +} + +func processIAMEntities(entities madmin.IAMEntities, action string) []string { + var messages []string + if len(entities.Policies) > 0 { + messages = append(messages, fmt.Sprintf("%s policies: %v", action, strings.Join(entities.Policies, ", "))) + } + if len(entities.Users) > 0 { + messages = append(messages, fmt.Sprintf("%s users: %v", action, strings.Join(entities.Users, ", "))) + } + if len(entities.Groups) > 0 { + messages = append(messages, fmt.Sprintf("%s groups: %v", action, strings.Join(entities.Groups, ", "))) + } + if len(entities.ServiceAccounts) > 0 { + messages = append(messages, fmt.Sprintf("%s service accounts: %v", action, strings.Join(entities.ServiceAccounts, ", "))) + } + var users []string + for _, pol := range entities.UserPolicies { + for name := range pol { + users = append(users, name) + } + } + if len(users) > 0 { + messages = append(messages, fmt.Sprintf("%s policies for users: %v", action, strings.Join(users, ", "))) + } + var groups []string + for _, pol := range entities.GroupPolicies { + for name := range pol { + groups = append(groups, name) + } + } + if len(groups) > 0 { + messages = append(messages, fmt.Sprintf("%s policies for groups: %v", action, strings.Join(groups, ", "))) + } + var stsarr []string + for _, pol := range entities.STSPolicies { + for name := range pol { + stsarr = append(stsarr, name) + } + } + if len(stsarr) > 0 { + messages = append(messages, fmt.Sprintf("%s policies for sts: %v", action, strings.Join(stsarr, ", "))) + } + return messages +} + +func processErrIAMEntities(entities madmin.IAMErrEntities) []string { + var messages []string + + var policies []string + for _, entry := range entities.Policies { + policies = append(policies, entry.Name) + } + if len(policies) > 0 { + messages = append(messages, fmt.Sprintf("Failed to add policies: %v", strings.Join(policies, ", "))) + } + var users []string + for _, entry := range entities.Users { + users = append(users, entry.Name) + } + if len(users) > 0 { + messages = append(messages, fmt.Sprintf("Failed to add users: %v", strings.Join(users, ", "))) + } + var groups []string + for _, entry := range entities.Groups { + groups = append(groups, entry.Name) + } + if len(groups) > 0 { + messages = append(messages, fmt.Sprintf("Failed to add groups: %v", strings.Join(groups, ", "))) + } + var sas []string + for _, entry := range entities.ServiceAccounts { + sas = append(sas, entry.Name) + } + if len(sas) > 0 { + messages = append(messages, fmt.Sprintf("Failed to add service accounts: %v", strings.Join(sas, ", "))) + } + var polusers []string + for _, pol := range entities.UserPolicies { + polusers = append(polusers, pol.Name) + } + if len(polusers) > 0 { + messages = append(messages, fmt.Sprintf("Failed to add policies for users: %v", strings.Join(polusers, ", "))) + } + var polgroups []string + for _, pol := range entities.GroupPolicies { + polgroups = append(polgroups, pol.Name) + } + if len(polgroups) > 0 { + messages = append(messages, fmt.Sprintf("Failed to add policies for groups: %v", strings.Join(polgroups, ", "))) + } + var polsts []string + for _, pol := range entities.STSPolicies { + polsts = append(polsts, pol.Name) + } + if len(polsts) > 0 { + messages = append(messages, fmt.Sprintf("Failed to add policies for sts: %v", strings.Join(polsts, ", "))) + } + return messages +} + func checkIAMImportSyntax(ctx *cli.Context) { if len(ctx.Args()) != 2 { showCommandHelpAndExit(ctx, 1) // last argument is exit code @@ -95,11 +214,13 @@ func mainClusterIAMImport(ctx *cli.Context) error { return nil } - e = client.ImportIAM(context.Background(), f) - fatalIf(probe.NewError(e).Trace(aliasedURL), "Unable to import IAM info.") - - if !globalJSON { - console.Infof("IAM info imported to %s from %s\n", aliasedURL, args.Get(1)) + iamr, e := client.ImportIAMV2(context.Background(), f) + if e != nil { + e = client.ImportIAM(context.Background(), f) + fatalIf(probe.NewError(e).Trace(aliasedURL), "Unable to import IAM info.") + } else { + printMsg(iamImportInfo(iamr)) } + return nil } diff --git a/cmd/auto-complete.go b/cmd/auto-complete.go index b05a6c585e..3d54a01f73 100644 --- a/cmd/auto-complete.go +++ b/cmd/auto-complete.go @@ -388,6 +388,9 @@ var completeCmds = map[string]complete.Predictor{ "/idp/ldap/accesskey/remove": aliasCompleter, "/idp/ldap/accesskey/rm": aliasCompleter, "/idp/ldap/accesskey/info": aliasCompleter, + "/idp/ldap/accesskey/edit": aliasCompleter, + "/idp/ldap/accesskey/enable": aliasCompleter, + "/idp/ldap/accesskey/disable": aliasCompleter, "/admin/policy/info": aliasCompleter, "/admin/policy/update": aliasCompleter, diff --git a/cmd/idp-ldap-accesskey-disable.go b/cmd/idp-ldap-accesskey-disable.go new file mode 100644 index 0000000000..511da3afaf --- /dev/null +++ b/cmd/idp-ldap-accesskey-disable.go @@ -0,0 +1,48 @@ +// Copyright (c) 2015-2024 MinIO, Inc. +// +// This file is part of MinIO Object Storage stack +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import ( + "github.com/minio/cli" +) + +var idpLdapAccesskeyDisableCmd = cli.Command{ + Name: "disable", + Usage: "disable an access key", + Action: mainIDPLdapAccesskeyDisable, + Before: setGlobalsFromContext, + Flags: globalFlags, + OnUsageError: onUsageError, + CustomHelpTemplate: `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{.HelpName}} [FLAGS] [TARGET] + +FLAGS: + {{range .VisibleFlags}}{{.}} + {{end}} +EXAMPLES: + 1. Disable LDAP access key + {{.Prompt}} {{.HelpName}} myminio myaccesskey +`, +} + +func mainIDPLdapAccesskeyDisable(ctx *cli.Context) error { + return enableDisableAccesskey(ctx, false) +} diff --git a/cmd/idp-ldap-accesskey-edit.go b/cmd/idp-ldap-accesskey-edit.go new file mode 100644 index 0000000000..2a8680a3e5 --- /dev/null +++ b/cmd/idp-ldap-accesskey-edit.go @@ -0,0 +1,167 @@ +// Copyright (c) 2015-2024 MinIO, Inc. +// +// This file is part of MinIO Object Storage stack +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import ( + "bytes" + "errors" + "fmt" + "os" + "time" + + "github.com/minio/cli" + "github.com/minio/madmin-go/v3" + "github.com/minio/mc/pkg/probe" + "github.com/minio/pkg/v3/policy" +) + +var idpLdapAccesskeyEditFlags = []cli.Flag{ + cli.StringFlag{ + Name: "secret-key", + Usage: "set a secret key for the account", + }, + cli.StringFlag{ + Name: "policy", + Usage: "path to a JSON policy file", + }, + cli.StringFlag{ + Name: "name", + Usage: "friendly name for the account", + }, + cli.StringFlag{ + Name: "description", + Usage: "description for the account", + }, + cli.StringFlag{ + Name: "expiry-duration", + Usage: "duration before the access key expires", + }, + cli.StringFlag{ + Name: "expiry", + Usage: "expiry date for the access key", + }, +} + +var idpLdapAccesskeyEditCmd = cli.Command{ + Name: "edit", + Usage: "edit existing access keys for LDAP", + Action: mainIDPLdapAccesskeyEdit, + Before: setGlobalsFromContext, + Flags: append(idpLdapAccesskeyEditFlags, globalFlags...), + OnUsageError: onUsageError, + CustomHelpTemplate: `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{.HelpName}} [FLAGS] [TARGET] + +FLAGS: + {{range .VisibleFlags}}{{.}} + {{end}} +EXAMPLES: + 1. Change the secret key for the access key "testkey" + {{.Prompt}} {{.HelpName}} myminio/ testkey --secret-key 'xxxxxxx' + 2. Change the expiry duration for the access key "testkey" + {{.Prompt}} {{.HelpName}} myminio/ testkey ---expiry-duration 24h +`, +} + +func mainIDPLdapAccesskeyEdit(ctx *cli.Context) error { + if len(ctx.Args()) == 0 || len(ctx.Args()) > 2 { + showCommandHelpAndExit(ctx, 1) // last argument is exit code + } + + args := ctx.Args() + aliasedURL := args.Get(0) + accessKey := args.Get(1) + + opts := accessKeyEditOpts(ctx) + client, err := newAdminClient(aliasedURL) + fatalIf(err, "Unable to initialize admin connection.") + + e := client.UpdateServiceAccount(globalContext, accessKey, opts) + fatalIf(probe.NewError(e), "Unable to edit service account.") + + m := ldapAccesskeyMessage{ + op: "edit", + Status: "success", + AccessKey: accessKey, + } + printMsg(m) + + return nil +} + +func accessKeyEditOpts(ctx *cli.Context) madmin.UpdateServiceAccountReq { + name := ctx.String("name") + expVal := ctx.String("expiry") + policyPath := ctx.String("policy") + secretKey := ctx.String("secret-key") + description := ctx.String("description") + expDurVal := ctx.Duration("expiry-duration") + + if expVal != "" && expDurVal != 0 { + fatalIf(probe.NewError(errors.New("Only one of --expiry or --expiry-duration can be specified")), "invalid flags") + } + + opts := madmin.UpdateServiceAccountReq{ + NewName: name, + NewSecretKey: secretKey, + NewDescription: description, + } + + if policyPath != "" { + // Validate the policy document and ensure it has at least one statement + policyBytes, e := os.ReadFile(policyPath) + fatalIf(probe.NewError(e), "unable to read the policy document") + + p, e := policy.ParseConfig(bytes.NewReader(policyBytes)) + fatalIf(probe.NewError(e), "unable to parse the policy document") + + if p.IsEmpty() { + fatalIf(errInvalidArgument(), "empty policies are not allowed") + } + + opts.NewPolicy = policyBytes + } + + switch { + case expVal != "": + location, e := time.LoadLocation("Local") + fatalIf(probe.NewError(e), "unable to load local location. verify your local TZ= settings") + + var found bool + for _, format := range supportedTimeFormats { + t, e := time.ParseInLocation(format, expVal, location) + if e == nil { + found = true + opts.NewExpiration = &t + break + } + } + + if !found { + fatalIf(probe.NewError(fmt.Errorf("invalid expiry date format '%s'", expVal)), "unable to parse the expiry argument") + } + case expDurVal != 0: + t := time.Now().Add(expDurVal) + opts.NewExpiration = &t + } + + return opts +} diff --git a/cmd/idp-ldap-accesskey-enable.go b/cmd/idp-ldap-accesskey-enable.go new file mode 100644 index 0000000000..b32016f639 --- /dev/null +++ b/cmd/idp-ldap-accesskey-enable.go @@ -0,0 +1,84 @@ +// Copyright (c) 2015-2024 MinIO, Inc. +// +// This file is part of MinIO Object Storage stack +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import ( + "github.com/minio/cli" + "github.com/minio/madmin-go/v3" + "github.com/minio/mc/pkg/probe" +) + +var idpLdapAccesskeyEnableCmd = cli.Command{ + Name: "enable", + Usage: "enable an access key", + Action: mainIDPLdapAccesskeyEnable, + Before: setGlobalsFromContext, + Flags: globalFlags, + OnUsageError: onUsageError, + CustomHelpTemplate: `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{.HelpName}} [FLAGS] [TARGET] + +FLAGS: + {{range .VisibleFlags}}{{.}} + {{end}} +EXAMPLES: + 1. Enable LDAP access key + {{.Prompt}} {{.HelpName}} myminio myaccesskey +`, +} + +func mainIDPLdapAccesskeyEnable(ctx *cli.Context) error { + return enableDisableAccesskey(ctx, true) +} + +func enableDisableAccesskey(ctx *cli.Context, enable bool) error { + if len(ctx.Args()) == 0 || len(ctx.Args()) > 2 { + showCommandHelpAndExit(ctx, 1) // last argument is exit code + } + + args := ctx.Args() + aliasedURL := args.Get(0) + accessKey := args.Get(1) + + client, err := newAdminClient(aliasedURL) + fatalIf(err, "Unable to initialize admin connection.") + + op := "disable" + status := "off" + if enable { + op = "enable" + status = "on" + } + + e := client.UpdateServiceAccount(globalContext, accessKey, madmin.UpdateServiceAccountReq{ + NewStatus: status, + }) + fatalIf(probe.NewError(e), "Unable to add service account.") + + m := ldapAccesskeyMessage{ + op: op, + Status: "success", + AccessKey: accessKey, + } + printMsg(m) + + return nil +} diff --git a/cmd/idp-ldap-accesskey-info.go b/cmd/idp-ldap-accesskey-info.go index ae0b3146fe..67f42e873a 100644 --- a/cmd/idp-ldap-accesskey-info.go +++ b/cmd/idp-ldap-accesskey-info.go @@ -26,7 +26,6 @@ import ( "github.com/minio/cli" json "github.com/minio/colorjson" "github.com/minio/mc/pkg/probe" - "github.com/minio/pkg/v3/console" ) var idpLdapAccesskeyInfoCmd = cli.Command{ @@ -68,6 +67,8 @@ type ldapAccesskeyMessage struct { } func (m ldapAccesskeyMessage) String() string { + labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) // green + o := strings.Builder{} switch m.op { case "info": expirationStr := "NONE" @@ -78,39 +79,37 @@ func (m ldapAccesskeyMessage) String() string { if m.ImpliedPolicy { policyStr = "implied" } - - labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) // green - o := strings.Builder{} - + statusStr := "enabled" + if m.AccountStatus == "off" { + statusStr = "disabled" + } o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Access Key:"), m.AccessKey)) o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Parent User:"), m.ParentUser)) + o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Status:"), statusStr)) o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Policy:"), policyStr)) o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Name:"), m.Name)) o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Description:"), m.Description)) - o.WriteString(iFmt(0, "%s %s\n\n", labelStyle.Render("Expiration:"), expirationStr)) - - return o.String() - + o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Expiration:"), expirationStr)) case "create": expirationStr := "NONE" if m.Expiration != nil && !m.Expiration.IsZero() && !m.Expiration.Equal(timeSentinel) { expirationStr = m.Expiration.String() } - - labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) // green - o := strings.Builder{} - o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Access Key:"), m.AccessKey)) o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Secret Key:"), m.SecretKey)) o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Expiration:"), expirationStr)) o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Name:"), m.Name)) - o.WriteString(iFmt(0, "%s %s\n\n", labelStyle.Render("Description:"), m.Description)) - - return o.String() + o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Description:"), m.Description)) case "remove": - return console.Colorize("RemoveAccessKey", "Successfully removed access key `"+m.AccessKey+"`.") + o.WriteString(labelStyle.Render(iFmt(0, "Successfully removed access key `%s`.", m.AccessKey))) + case "edit": + o.WriteString(labelStyle.Render(iFmt(0, "Successfully edited access key `%s`.", m.AccessKey))) + case "enable": + o.WriteString(labelStyle.Render(iFmt(0, "Successfully enabled access key `%s`.", m.AccessKey))) + case "disable": + o.WriteString(labelStyle.Render(iFmt(0, "Successfully disabled access key `%s`.", m.AccessKey))) } - return "" + return o.String() } func (m ldapAccesskeyMessage) JSON() string { diff --git a/cmd/idp-ldap-accesskey-remove.go b/cmd/idp-ldap-accesskey-remove.go index d2069625a1..8f4d57b667 100644 --- a/cmd/idp-ldap-accesskey-remove.go +++ b/cmd/idp-ldap-accesskey-remove.go @@ -18,10 +18,8 @@ package cmd import ( - "github.com/fatih/color" "github.com/minio/cli" "github.com/minio/mc/pkg/probe" - "github.com/minio/pkg/v3/console" ) var idpLdapAccesskeyRemoveCmd = cli.Command{ @@ -52,8 +50,6 @@ func mainIDPLdapAccesskeyRemove(ctx *cli.Context) error { showCommandHelpAndExit(ctx, 1) // last argument is exit code } - console.SetColor("RemoveAccessKey", color.New(color.FgGreen)) - args := ctx.Args() aliasedURL := args.Get(0) accessKey := args.Get(1) diff --git a/cmd/idp-ldap-accesskey.go b/cmd/idp-ldap-accesskey.go index 392be7c731..a0f1751670 100644 --- a/cmd/idp-ldap-accesskey.go +++ b/cmd/idp-ldap-accesskey.go @@ -25,6 +25,9 @@ var idpLdapAccesskeySubcommands = []cli.Command{ idpLdapAccesskeyInfoCmd, idpLdapAccesskeyCreateCmd, idpLdapAccesskeyCreateWithLoginCmd, + idpLdapAccesskeyEditCmd, + idpLdapAccesskeyEnableCmd, + idpLdapAccesskeyDisableCmd, } var idpLdapAccesskeyCmd = cli.Command{ diff --git a/cmd/ilm-tier-remove.go b/cmd/ilm-tier-remove.go index e645734d89..5a26dae8f4 100644 --- a/cmd/ilm-tier-remove.go +++ b/cmd/ilm-tier-remove.go @@ -19,9 +19,23 @@ package cmd import ( "github.com/minio/cli" + "github.com/minio/madmin-go/v3" "github.com/minio/mc/pkg/probe" ) +var adminTierRmFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "force", + Usage: "forcefully remove the specified tier", + Hidden: true, + }, + cli.BoolFlag{ + Name: "dangerous", + Usage: "additional flag to be required in addition to force flag", + Hidden: true, + }, +} + var adminTierRmCmd = cli.Command{ Name: "remove", ShortName: "rm", @@ -29,7 +43,7 @@ var adminTierRmCmd = cli.Command{ Action: mainAdminTierRm, OnUsageError: onUsageError, Before: setGlobalsFromContext, - Flags: globalFlags, + Flags: append(globalFlags, adminTierRmFlags...), CustomHelpTemplate: `NAME: {{.HelpName}} - {{.Usage}} @@ -65,11 +79,15 @@ func mainAdminTierRm(ctx *cli.Context) error { fatalIf(errInvalidArgument(), "Tier name can't be empty") } + if ctx.Bool("force") && !ctx.Bool("dangerous") { + fatalIf(errInvalidArgument(), "This operation results in an irreversible disconnection from the specified remote tier. If you are really sure, retry this command with ‘--force’ and ‘--dangerous’ flags.") + } + // Create a new MinIO Admin Client client, cerr := newAdminClient(aliasedURL) fatalIf(cerr, "Unable to initialize admin connection.") - e := client.RemoveTier(globalContext, tierName) + e := client.RemoveTierV2(globalContext, tierName, madmin.RemoveTierOpts{Force: ctx.Bool("force")}) fatalIf(probe.NewError(e).Trace(args...), "Unable to remove remote tier target") printMsg(&tierMessage{ diff --git a/go.mod b/go.mod index 21f397af1b..0c7fc242c9 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/minio/cli v1.24.2 github.com/minio/colorjson v1.0.8 github.com/minio/filepath v1.0.0 - github.com/minio/madmin-go/v3 v3.0.65 + github.com/minio/madmin-go/v3 v3.0.66 github.com/minio/minio-go/v7 v7.0.76 github.com/minio/pkg/v3 v3.0.13 github.com/minio/selfupdate v0.6.0 diff --git a/go.sum b/go.sum index 3f785c719e..4d42f8f7b7 100644 --- a/go.sum +++ b/go.sum @@ -138,8 +138,8 @@ github.com/minio/colorjson v1.0.8 h1:AS6gEQ1dTRYHmC4xuoodPDRILHP/9Wz5wYUGDQfPLpg github.com/minio/colorjson v1.0.8/go.mod h1:wrs39G/4kqNlGjwqHvPlAnXuc2tlPszo6JKdSBCLN8w= github.com/minio/filepath v1.0.0 h1:fvkJu1+6X+ECRA6G3+JJETj4QeAYO9sV43I79H8ubDY= github.com/minio/filepath v1.0.0/go.mod h1:/nRZA2ldl5z6jT9/KQuvZcQlxZIMQoFFQPvEXx9T/Bw= -github.com/minio/madmin-go/v3 v3.0.65 h1:5Vp04vyI39xLe+aAAvMm8XGjNvHWIFWTl1isFdCZcoE= -github.com/minio/madmin-go/v3 v3.0.65/go.mod h1:IFAwr0XMrdsLovxAdCcuq/eoL4nRuMVQQv0iubJANQw= +github.com/minio/madmin-go/v3 v3.0.66 h1:O4w7L3vTxhORqTeyegFdbuO4kKVbAUarJfcmsDXQMTs= +github.com/minio/madmin-go/v3 v3.0.66/go.mod h1:IFAwr0XMrdsLovxAdCcuq/eoL4nRuMVQQv0iubJANQw= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.76 h1:9nxHH2XDai61cT/EFhyIw/wW4vJfpPNvl7lSFpRt+Ng=