Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package minio-client for openSUSE:Factory checked in at 2025-05-26 18:36:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/minio-client (Old) and /work/SRC/openSUSE:Factory/.minio-client.new.2732 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "minio-client" Mon May 26 18:36:48 2025 rev:113 rq:1279894 version:20250521T015954Z Changes: -------- --- /work/SRC/openSUSE:Factory/minio-client/minio-client.changes 2025-04-24 17:28:10.948054273 +0200 +++ /work/SRC/openSUSE:Factory/.minio-client.new.2732/minio-client.changes 2025-05-26 18:38:24.338653992 +0200 @@ -1,0 +2,17 @@ +Sun May 25 07:51:23 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 20250521T015954Z: + * Fix deletion of previously sync'd buckets and objects during + mc-mirror (#5205) + * Add STATUS column to batch job list table output (#5202) + * fix: remove check if lock config exists before set (#5203) + * removing config cmd (#5201) + * fix: support chained mirror properly for delete propagation + #4558 (#5197) + * Change support profile defaults (#5198) + * Explicitly set file permissions for + admin-cluster-{bucket,iam}-export… (#5194) + * Add support for catalog batch job type (#5150) + * Add `idp openid accesskey` commands (#5182) + +------------------------------------------------------------------- Old: ---- minio-client-20250416T181326Z.obscpio New: ---- minio-client-20250521T015954Z.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ minio-client.spec ++++++ --- /var/tmp/diff_new_pack.1r46pu/_old 2025-05-26 18:38:25.278693454 +0200 +++ /var/tmp/diff_new_pack.1r46pu/_new 2025-05-26 18:38:25.282693622 +0200 @@ -17,7 +17,7 @@ Name: minio-client -Version: 20250416T181326Z +Version: 20250521T015954Z Release: 0 Summary: Client for MinIO License: AGPL-3.0-only ++++++ _service ++++++ --- /var/tmp/diff_new_pack.1r46pu/_old 2025-05-26 18:38:25.322695302 +0200 +++ /var/tmp/diff_new_pack.1r46pu/_new 2025-05-26 18:38:25.326695469 +0200 @@ -5,7 +5,7 @@ <param name="exclude">.git</param> <param name="changesgenerate">enable</param> <param name="versionformat">@PARENT_TAG@</param> - <param name="revision">RELEASE.2025-04-16T18-13-26Z</param> + <param name="revision">RELEASE.2025-05-21T01-59-54Z</param> <param name="match-tag">RELEASE.*</param> <param name="versionrewrite-pattern">RELEASE\.(.*)-(.*)-(.*)-(.*)-(.*)</param> <param name="versionrewrite-replacement">\1\2\3\4\5</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.1r46pu/_old 2025-05-26 18:38:25.350696477 +0200 +++ /var/tmp/diff_new_pack.1r46pu/_new 2025-05-26 18:38:25.350696477 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/minio/mc</param> - <param name="changesrevision">b00526b153a31b36767991a4f5ce2cced435ee8e</param></service></servicedata> + <param name="changesrevision">f71ad84bcf0fd4369691952af5d925347837dcec</param></service></servicedata> (No newline at EOF) ++++++ minio-client-20250416T181326Z.obscpio -> minio-client-20250521T015954Z.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/admin-accesskey-info.go new/minio-client-20250521T015954Z/cmd/admin-accesskey-info.go --- old/minio-client-20250416T181326Z/cmd/admin-accesskey-info.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/admin-accesskey-info.go 2025-05-21 03:59:54.000000000 +0200 @@ -18,7 +18,15 @@ package cmd import ( + "strings" + "time" + + "github.com/charmbracelet/lipgloss" + humanize "github.com/dustin/go-humanize" "github.com/minio/cli" + json "github.com/minio/colorjson" + "github.com/minio/madmin-go/v3" + "github.com/minio/mc/pkg/probe" ) var adminAccesskeyInfoCmd = cli.Command{ @@ -45,6 +53,150 @@ `, } +type accesskeyMessage struct { + op string + Status string `json:"status"` + AccessKey string `json:"accessKey"` + SecretKey string `json:"secretKey,omitempty"` + STS bool `json:"sts,omitempty"` + ParentUser string `json:"parentUser,omitempty"` + AccountStatus string `json:"accountStatus,omitempty"` + ImpliedPolicy bool `json:"impliedPolicy,omitempty"` + Policy json.RawMessage `json:"policy,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Expiration *time.Time `json:"expiration,omitempty"` + Provider string `json:"provider,omitempty"` + ProviderInfo providerInfo `json:"providerInfo,omitempty"` +} + +func (m accesskeyMessage) String() string { + labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) // green + o := strings.Builder{} + switch m.op { + case "info": + expirationStr := "NONE" + if m.Expiration != nil && !m.Expiration.IsZero() && !m.Expiration.Equal(timeSentinel) { + expirationStr = humanize.Time(*m.Expiration) + } + policyStr := "embedded" + if m.ImpliedPolicy { + policyStr = "implied" + } + statusStr := "enabled" + if m.AccountStatus == "off" { + statusStr = "disabled" + } + stsStr := "false" + if m.STS { + stsStr = "true" + } + 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", labelStyle.Render("Expiration:"), expirationStr)) + o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("STS:"), stsStr)) + o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Provider:"), m.Provider)) + if m.ProviderInfo != nil { + o.WriteString(iFmt(0, "%s\n", labelStyle.Render("Provider Specific Info:"))) + o.WriteString(m.ProviderInfo.String()) + } + case "create": + expirationStr := "NONE" + if m.Expiration != nil && !m.Expiration.IsZero() && !m.Expiration.Equal(timeSentinel) { + expirationStr = m.Expiration.String() + } + 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", labelStyle.Render("Description:"), m.Description)) + case "remove": + 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 o.String() +} + +func (m accesskeyMessage) JSON() string { + m.Status = "success" + jsonMessageBytes, e := json.MarshalIndent(m, "", " ") + fatalIf(probe.NewError(e), "Unable to marshal into JSON.") + + return string(jsonMessageBytes) +} + +type providerInfo interface { + String() string +} + func mainAdminAccesskeyInfo(ctx *cli.Context) error { return commonAccesskeyInfo(ctx) } + +func commonAccesskeyInfo(ctx *cli.Context) error { + if len(ctx.Args()) < 2 { + showCommandHelpAndExit(ctx, 1) // last argument is exit code + } + + args := ctx.Args() + aliasedURL := args.Get(0) + accessKeys := args.Tail() + + // Create a new MinIO Admin Client + client, err := newAdminClient(aliasedURL) + fatalIf(err, "Unable to initialize admin connection.") + + for _, accessKey := range accessKeys { + // Assume service account by default + res, e := client.InfoAccessKey(globalContext, accessKey) + fatalIf(probe.NewError(e), "Unable to get info for access key.") + m := accesskeyMessage{ + op: "info", + AccessKey: accessKey, + ParentUser: res.ParentUser, + AccountStatus: res.AccountStatus, + ImpliedPolicy: res.ImpliedPolicy, + Policy: json.RawMessage(res.Policy), + Name: res.Name, + Description: res.Description, + Expiration: nilExpiry(res.Expiration), + Provider: res.UserProvider, + } + + switch res.UserProvider { + case madmin.LDAPProvider: + info := res.LDAPSpecificInfo + m.ProviderInfo = ldapAccessKeyInfo{ + Username: info.Username, + } + case madmin.OpenIDProvider: + info := res.OpenIDSpecificInfo + m.ProviderInfo = openIDAccessKeyInfo{ + ConfigName: info.ConfigName, + UserID: info.UserID, + UserIDClaim: info.UserIDClaim, + DisplayName: info.DisplayName, + DisplayNameClaim: info.DisplayNameClaim, + } + } + printMsg(m) + } + + return nil +} + +func nilExpiry(expiry *time.Time) *time.Time { + if expiry != nil && expiry.Equal(timeSentinel) { + return nil + } + return expiry +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/admin-cluster-bucket-export.go new/minio-client-20250521T015954Z/cmd/admin-cluster-bucket-export.go --- old/minio-client-20250416T181326Z/cmd/admin-cluster-bucket-export.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/admin-cluster-bucket-export.go 2025-05-21 03:59:54.000000000 +0200 @@ -119,6 +119,11 @@ } fatalIf(probe.NewError(moveFile(tmpFile.Name(), downloadPath)), "Unable to rename downloaded data, file exists at %s", tmpFile.Name()) + // Explicitly set permissions to 0o600 and override umask + // to ensure that the file is not world-readable. + e = os.Chmod(downloadPath, 0o600) + fatalIf(probe.NewError(e), "Unable to set file permissions for "+downloadPath) + if !globalJSON { console.Infof("Bucket metadata successfully downloaded as %s\n", downloadPath) return nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/admin-cluster-iam-export.go new/minio-client-20250521T015954Z/cmd/admin-cluster-iam-export.go --- old/minio-client-20250416T181326Z/cmd/admin-cluster-iam-export.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/admin-cluster-iam-export.go 2025-05-21 03:59:54.000000000 +0200 @@ -125,6 +125,11 @@ fatalIf(probe.NewError(moveFile(tmpFile.Name(), downloadPath)), "Unable to rename downloaded data, file exists at %s", tmpFile.Name()) + // Explicitly set permissions to 0o600 and override umask + // to ensure that the file is not world-readable. + e = os.Chmod(downloadPath, 0o600) + fatalIf(probe.NewError(e), "Unable to set file permissions for "+downloadPath) + if !globalJSON { console.Infof("IAM info successfully downloaded as %s\n", downloadPath) return nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/auto-complete.go new/minio-client-20250521T015954Z/cmd/auto-complete.go --- old/minio-client-20250416T181326Z/cmd/auto-complete.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/auto-complete.go 2025-05-21 03:59:54.000000000 +0200 @@ -369,6 +369,15 @@ "/idp/openid/enable": aliasCompleter, "/idp/openid/disable": aliasCompleter, + "/idp/openid/accesskey/list": aliasCompleter, + "/idp/openid/accesskey/ls": aliasCompleter, + "/idp/openid/accesskey/info": aliasCompleter, + "/idp/openid/accesskey/remove": aliasCompleter, + "/idp/openid/accesskey/rm": aliasCompleter, + "/idp/openid/accesskey/edit": aliasCompleter, + "/idp/openid/accesskey/enable": aliasCompleter, + "/idp/openid/accesskey/disable": aliasCompleter, + "/idp/ldap/add": aliasCompleter, "/idp/ldap/update": aliasCompleter, "/idp/ldap/remove": aliasCompleter, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/batch-list.go new/minio-client-20250521T015954Z/cmd/batch-list.go --- old/minio-client-20250416T181326Z/cmd/batch-list.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/batch-list.go 2025-05-21 03:59:54.000000000 +0200 @@ -66,6 +66,7 @@ type batchListMessage struct { Status string `json:"status"` Jobs []madmin.BatchJobResult `json:"jobs"` + Admin *madmin.AdminClient `json:"-"` // Add AdminClient to fetch job status } // String colorized batchList message @@ -90,15 +91,35 @@ table.SetTablePadding("\t") // pad with tabs table.SetNoWhiteSpace(true) - table.SetHeader([]string{"ID", "TYPE", "USER", "STARTED"}) - data := make([][]string, 0, 4) + // Add a new "STATUS" column to the table header + table.SetHeader([]string{"ID", "TYPE", "USER", "STARTED", "STATUS"}) + data := make([][]string, 0, 5) + // Fetch the status for the batch job using BatchJobStatus API for _, job := range c.Jobs { + jobStatus := "unknown" + jobMetric, err := c.Admin.BatchJobStatus(context.Background(), job.ID) + + // Output error if the API call fails, but continue processing remaining jobs + if err != nil { + println("Failed to fetch job status for Job ID:", job.ID, "Error:", err.Error()) + } else { + if jobMetric.LastMetric.Complete && !jobMetric.LastMetric.Failed { + jobStatus = "completed" + } else if !jobMetric.LastMetric.Complete && !jobMetric.LastMetric.Failed { + jobStatus = "in-progress" + } else if jobMetric.LastMetric.Failed { + jobStatus = "failed" + } + } + + // Add jobStatus details to the data table data = append(data, []string{ job.ID, string(job.Type), job.User, humanize.Time(job.Started), + jobStatus, }) } @@ -111,7 +132,43 @@ // JSON jsonified batchList message func (c batchListMessage) JSON() string { c.Status = "success" - batchListMessageBytes, e := json.MarshalIndent(c, "", " ") + + // Create a temporary slice to hold jobs with derived statuses + jobsWithStatus := make([]map[string]interface{}, len(c.Jobs)) + + // Fetch the status for the batch job using BatchJobStatus API + for i, job := range c.Jobs { + jobStatus := "unknown" + jobMetric, err := c.Admin.BatchJobStatus(context.Background(), job.ID) + + // Output error if the API call fails, but continue processing remaining jobs + if err != nil { + println("Failed to fetch job status for Job ID:", job.ID, "Error:", err.Error()) + } else { + if jobMetric.LastMetric.Complete && !jobMetric.LastMetric.Failed { + jobStatus = "completed" + } else if !jobMetric.LastMetric.Complete && !jobMetric.LastMetric.Failed { + jobStatus = "in-progress" + } else if jobMetric.LastMetric.Failed { + jobStatus = "failed" + } + } + + // Add the job details along with the derived status + jobsWithStatus[i] = map[string]interface{}{ + "id": job.ID, + "type": job.Type, + "user": job.User, + "started": job.Started, + "status": jobStatus, + } + } + + // Marshal the updated jobs into JSON + batchListMessageBytes, e := json.MarshalIndent(map[string]interface{}{ + "status": c.Status, + "jobs": jobsWithStatus, + }, "", " ") fatalIf(probe.NewError(e), "Unable to marshal into JSON.") return string(batchListMessageBytes) @@ -147,6 +204,7 @@ printMsg(batchListMessage{ Status: "success", Jobs: res.Jobs, + Admin: adminClient, // Pass the adminClient for status lookups }) return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/batch-status.go new/minio-client-20250521T015954Z/cmd/batch-status.go --- old/minio-client-20250416T181326Z/cmd/batch-status.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/batch-status.go 2025-05-21 03:59:54.000000000 +0200 @@ -281,7 +281,22 @@ accElapsedTime := m.metric.LastUpdate.Sub(m.metric.StartTime) addLine("Elapsed: ", accElapsedTime.String()) } - + case string(madmin.BatchJobCatalog): + addLine("JobType: ", m.metric.JobType) + addLine("ObjectsScannedCount: ", m.metric.Catalog.ObjectsScannedCount) + addLine("ObjectsMatchedCount: ", m.metric.Catalog.ObjectsMatchedCount) + lastScanned := fmt.Sprintf("%s/%s", m.metric.Catalog.LastBucketScanned, m.metric.Catalog.LastObjectScanned) + addLine("LastScanned: ", lastScanned) + lastMatched := fmt.Sprintf("%s/%s", m.metric.Catalog.LastBucketMatched, m.metric.Catalog.LastObjectMatched) + addLine("LastMatched: ", lastMatched) + accElapsedTime := m.metric.LastUpdate.Sub(m.metric.StartTime) + addLine("RecordsWrittenCount: ", m.metric.Catalog.RecordsWrittenCount) + addLine("OutputObjectsCount: ", m.metric.Catalog.OutputObjectsCount) + addLine("Elapsed: ", accElapsedTime.Round(time.Second).String()) + addLine("Scan Speed: ", fmt.Sprintf("%f objects/s", float64(m.metric.Catalog.ObjectsScannedCount)/accElapsedTime.Seconds())) + if m.metric.Catalog.ErrorMsg != "" { + addLine("Error: ", m.metric.Catalog.ErrorMsg) + } } table.AppendBulk(data) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/config-deprecated.go new/minio-client-20250521T015954Z/cmd/config-deprecated.go --- old/minio-client-20250416T181326Z/cmd/config-deprecated.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/config-deprecated.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,101 +0,0 @@ -// Copyright (c) 2015-2022 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 <http://www.gnu.org/licenses/>. - -package cmd - -import "github.com/minio/cli" - -var configCmd = cli.Command{ - Name: "config", - Usage: "configure MinIO client", - Action: func(ctx *cli.Context) error { - cli.ShowCommandHelp(ctx, ctx.Args().First()) - return nil - }, - Hidden: true, - Before: setGlobalsFromContext, - HideHelpCommand: true, - Flags: globalFlags, - Subcommands: []cli.Command{ - configHostCmd, - }, -} - -var configHostCmd = cli.Command{ - Name: "host", - Usage: "add, remove and list hosts in configuration file", - Action: func(ctx *cli.Context) error { - cli.ShowCommandHelp(ctx, ctx.Args().First()) - return nil - }, - Before: setGlobalsFromContext, - Flags: globalFlags, - Subcommands: []cli.Command{ - configHostAddCmd, - configHostRemoveCmd, - configHostListCmd, - }, - HideHelpCommand: true, -} - -var configHostAddFlags = []cli.Flag{ - cli.StringFlag{ - Name: "lookup", - Value: "auto", - Usage: "bucket lookup supported by the server. Valid options are '[dns, path, auto]'", - }, - cli.StringFlag{ - Name: "api", - Usage: "API signature. Valid options are '[S3v4, S3v2]'", - }, -} - -var configHostAddCmd = cli.Command{ - Name: "add", - ShortName: "a", - Usage: "add a new host to configuration file", - Action: func(cli *cli.Context) error { - return mainAliasSet(cli, true) - }, - Before: setGlobalsFromContext, - Flags: append(configHostAddFlags, globalFlags...), - HideHelpCommand: true, -} - -var configHostListCmd = cli.Command{ - Name: "list", - ShortName: "ls", - Usage: "list hosts in configuration file", - Action: func(cli *cli.Context) error { - return mainAliasList(cli, true) - }, - Before: setGlobalsFromContext, - Flags: globalFlags, - HideHelpCommand: true, -} - -var configHostRemoveCmd = cli.Command{ - Name: "remove", - ShortName: "rm", - Usage: "remove a host from configuration file", - Action: func(cli *cli.Context) error { - return mainAliasRemove(cli) - }, - Before: setGlobalsFromContext, - Flags: globalFlags, - HideHelpCommand: true, -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-create-with-login.go new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-create-with-login.go --- old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-create-with-login.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-create-with-login.go 2025-05-21 03:59:54.000000000 +0200 @@ -74,7 +74,7 @@ res, e := client.AddServiceAccountLDAP(globalContext, opts) fatalIf(probe.NewError(e), "unable to add service account") - m := ldapAccesskeyMessage{ + m := accesskeyMessage{ op: "create", Status: "success", AccessKey: res.AccessKey, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-create.go new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-create.go --- old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-create.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-create.go 2025-05-21 03:59:54.000000000 +0200 @@ -127,7 +127,7 @@ } fatalIf(probe.NewError(e), "Unable to add service account.") - m := ldapAccesskeyMessage{ + m := accesskeyMessage{ op: "create", Status: "success", AccessKey: res.AccessKey, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-edit.go new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-edit.go --- old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-edit.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-edit.go 2025-05-21 03:59:54.000000000 +0200 @@ -101,7 +101,7 @@ e := client.UpdateServiceAccount(globalContext, accessKey, opts) fatalIf(probe.NewError(e), "Unable to edit service account.") - m := ldapAccesskeyMessage{ + m := accesskeyMessage{ op: "edit", Status: "success", AccessKey: accessKey, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-enable.go new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-enable.go --- old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-enable.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-enable.go 2025-05-21 03:59:54.000000000 +0200 @@ -73,7 +73,7 @@ }) fatalIf(probe.NewError(e), "Unable to add service account.") - m := ldapAccesskeyMessage{ + m := accesskeyMessage{ op: op, Status: "success", AccessKey: accessKey, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-info.go new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-info.go --- old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-info.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-info.go 2025-05-21 03:59:54.000000000 +0200 @@ -19,13 +19,9 @@ import ( "strings" - "time" "github.com/charmbracelet/lipgloss" - humanize "github.com/dustin/go-humanize" "github.com/minio/cli" - json "github.com/minio/colorjson" - "github.com/minio/mc/pkg/probe" ) var idpLdapAccesskeyInfoCmd = cli.Command{ @@ -52,137 +48,18 @@ `, } -type ldapAccesskeyMessage struct { - op string - Status string `json:"status"` - AccessKey string `json:"accessKey"` - SecretKey string `json:"secretKey,omitempty"` - ParentUser string `json:"parentUser,omitempty"` - AccountStatus string `json:"accountStatus,omitempty"` - ImpliedPolicy bool `json:"impliedPolicy,omitempty"` - Policy json.RawMessage `json:"policy,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - Expiration *time.Time `json:"expiration,omitempty"` +type ldapAccessKeyInfo struct { + Username string `json:"username,omitempty"` } -func (m ldapAccesskeyMessage) String() string { +func (l ldapAccessKeyInfo) String() string { labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) // green o := strings.Builder{} - switch m.op { - case "info": - expirationStr := "NONE" - if m.Expiration != nil && !m.Expiration.IsZero() && !m.Expiration.Equal(timeSentinel) { - expirationStr = humanize.Time(*m.Expiration) - } - policyStr := "embedded" - if m.ImpliedPolicy { - policyStr = "implied" - } - 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", labelStyle.Render("Expiration:"), expirationStr)) - case "create": - expirationStr := "NONE" - if m.Expiration != nil && !m.Expiration.IsZero() && !m.Expiration.Equal(timeSentinel) { - expirationStr = m.Expiration.String() - } - 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", labelStyle.Render("Description:"), m.Description)) - case "remove": - 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))) - } + o.WriteString(labelStyle.Render("Username: ")) + o.WriteString(l.Username) return o.String() } -func (m ldapAccesskeyMessage) JSON() string { - jsonMessageBytes, e := json.MarshalIndent(m, "", " ") - fatalIf(probe.NewError(e), "Unable to marshal into JSON.") - - return string(jsonMessageBytes) -} - func mainIDPLdapAccesskeyInfo(ctx *cli.Context) error { return commonAccesskeyInfo(ctx) } - -// currently no difference between ldap and builtin accesskey info -func commonAccesskeyInfo(ctx *cli.Context) error { - if len(ctx.Args()) < 2 { - showCommandHelpAndExit(ctx, 1) // last argument is exit code - } - - args := ctx.Args() - aliasedURL := args.Get(0) - accessKeys := args.Tail() - - // Create a new MinIO Admin Client - client, err := newAdminClient(aliasedURL) - fatalIf(err, "Unable to initialize admin connection.") - - for _, accessKey := range accessKeys { - // Assume service account by default - res, e := client.InfoServiceAccount(globalContext, accessKey) - if e != nil { - // If not a service account must be sts - tempRes, e := client.TemporaryAccountInfo(globalContext, accessKey) - if e != nil { - errorIf(probe.NewError(e), "Unable to retrieve access key %s info.", accessKey) - } else { - m := ldapAccesskeyMessage{ - op: "info", - AccessKey: accessKey, - Status: "success", - ParentUser: tempRes.ParentUser, - AccountStatus: tempRes.AccountStatus, - ImpliedPolicy: tempRes.ImpliedPolicy, - Policy: json.RawMessage(tempRes.Policy), - Name: tempRes.Name, - Description: tempRes.Description, - Expiration: nilExpiry(tempRes.Expiration), - } - printMsg(m) - } - } else { - m := ldapAccesskeyMessage{ - op: "info", - AccessKey: accessKey, - Status: "success", - ParentUser: res.ParentUser, - AccountStatus: res.AccountStatus, - ImpliedPolicy: res.ImpliedPolicy, - Policy: json.RawMessage(res.Policy), - Name: res.Name, - Description: res.Description, - Expiration: nilExpiry(res.Expiration), - } - printMsg(m) - } - } - - return nil -} - -func nilExpiry(expiry *time.Time) *time.Time { - if expiry != nil && expiry.Equal(timeSentinel) { - return nil - } - return expiry -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-list.go new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-list.go --- old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-list.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-list.go 2025-05-21 03:59:54.000000000 +0200 @@ -19,6 +19,7 @@ import ( "errors" + "strings" "github.com/minio/cli" "github.com/minio/madmin-go/v3" @@ -129,18 +130,24 @@ svcaccOnly := ctx.Bool("svcacc-only") selfFlag := ctx.Bool("self") opts.All = ctx.Bool("all") + opts.AllConfigs = ctx.Bool("all-configs") args := ctx.Args() aliasedURL = args.Get(0) users = args.Tail() + aliasedURL, cfgName, _ := strings.Cut(aliasedURL, ":") + if cfgName != "" { + opts.ConfigName = cfgName + } + var e error if (usersOnly && svcaccOnly) || (usersOnly && stsOnly) || (svcaccOnly && stsOnly) { e = errors.New("only one of --users-only, --temp-only, or --permanent-only can be specified") } else if selfFlag && opts.All { e = errors.New("only one of --self or --all can be specified") } else if (selfFlag || opts.All) && len(users) > 0 { - e = errors.New("user DNs cannot be specified with --self or --all") + e = errors.New("users cannot be specified with --self or --all") } fatalIf(probe.NewError(e), "Invalid flags.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-remove.go new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-remove.go --- old/minio-client-20250416T181326Z/cmd/idp-ldap-accesskey-remove.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/idp-ldap-accesskey-remove.go 2025-05-21 03:59:54.000000000 +0200 @@ -66,7 +66,7 @@ e := client.DeleteServiceAccount(globalContext, accessKey) fatalIf(probe.NewError(e), "Unable to remove service account.") - m := ldapAccesskeyMessage{ + m := accesskeyMessage{ op: "remove", Status: "success", AccessKey: accessKey, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-disable.go new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-disable.go --- old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-disable.go 1970-01-01 01:00:00.000000000 +0100 +++ new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-disable.go 2025-05-21 03:59:54.000000000 +0200 @@ -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 <http://www.gnu.org/licenses/>. + +package cmd + +import ( + "github.com/minio/cli" +) + +var idpOpenidAccesskeyDisableCmd = cli.Command{ + Name: "disable", + Usage: "disable an access key", + Action: mainIDPOpenIDAccesskeyDisable, + 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 mainIDPOpenIDAccesskeyDisable(ctx *cli.Context) error { + return enableDisableAccesskey(ctx, false) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-edit.go new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-edit.go --- old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-edit.go 1970-01-01 01:00:00.000000000 +0100 +++ new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-edit.go 2025-05-21 03:59:54.000000000 +0200 @@ -0,0 +1,77 @@ +// 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 <http://www.gnu.org/licenses/>. + +package cmd + +import ( + "github.com/minio/cli" +) + +var idpOpenIDAccesskeyEditFlags = []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 idpOpenidAccesskeyEditCmd = cli.Command{ + Name: "edit", + Usage: "edit existing access keys for OpenID", + Action: mainIDPOpenIDAccesskeyEdit, + Before: setGlobalsFromContext, + Flags: append(idpOpenIDAccesskeyEditFlags, 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 mainIDPOpenIDAccesskeyEdit(ctx *cli.Context) error { + return commonAccesskeyEdit(ctx) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-enable.go new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-enable.go --- old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-enable.go 1970-01-01 01:00:00.000000000 +0100 +++ new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-enable.go 2025-05-21 03:59:54.000000000 +0200 @@ -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 <http://www.gnu.org/licenses/>. + +package cmd + +import ( + "github.com/minio/cli" +) + +var idpOpenidAccesskeyEnableCmd = cli.Command{ + Name: "enable", + Usage: "enable an access key", + Action: mainIDPOpenIDAccesskeyEnable, + 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 mainIDPOpenIDAccesskeyEnable(ctx *cli.Context) error { + return enableDisableAccesskey(ctx, true) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-info.go new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-info.go --- old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-info.go 1970-01-01 01:00:00.000000000 +0100 +++ new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-info.go 2025-05-21 03:59:54.000000000 +0200 @@ -0,0 +1,78 @@ +// Copyright (c) 2015-2023 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 <http://www.gnu.org/licenses/>. + +package cmd + +import ( + "fmt" + "strings" + + "github.com/charmbracelet/lipgloss" + "github.com/minio/cli" +) + +var idpOpenidAccesskeyInfoCmd = cli.Command{ + Name: "info", + Usage: "info about given access key pairs for OpenID", + Action: mainIDPOpenIDAccesskeyInfo, + Before: setGlobalsFromContext, + Flags: globalFlags, + OnUsageError: onUsageError, + CustomHelpTemplate: `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{.HelpName}} [FLAGS] TARGET ACCESSKEY [ACCESSKEY...] + +FLAGS: + {{range .VisibleFlags}}{{.}} + {{end}} +EXAMPLES: + 1. Get info for the access key "testkey" + {{.Prompt}} {{.HelpName}} local/ testkey + 2. Get info for the access keys "testkey" and "testkey2" + {{.Prompt}} {{.HelpName}} local/ testkey testkey2 + `, +} + +type openIDAccessKeyInfo struct { + ConfigName string `json:"configName"` + UserID string `json:"userID"` + UserIDClaim string `json:"userIDClaim"` + DisplayName string `json:"displayName,omitempty"` + DisplayNameClaim string `json:"displayNameClaim,omitempty"` +} + +func (l openIDAccessKeyInfo) String() string { + labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) // green + o := strings.Builder{} + if l.ConfigName == "_" { + l.ConfigName = "_ (default)" + } + o.WriteString(iFmt(2, "%s %s\n", labelStyle.Render("Config:"), l.ConfigName)) + if l.DisplayNameClaim != "" { + dispNameLabel := fmt.Sprintf("Display Name (%s):", l.DisplayNameClaim) + o.WriteString(iFmt(2, "%s %s\n", labelStyle.Render(dispNameLabel), l.DisplayName)) + } + uidLabel := fmt.Sprintf("User ID (%s):", l.UserIDClaim) + o.WriteString(iFmt(2, "%s %s\n", labelStyle.Render(uidLabel), l.UserID)) + return o.String() +} + +func mainIDPOpenIDAccesskeyInfo(ctx *cli.Context) error { + return commonAccesskeyInfo(ctx) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-list.go new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-list.go --- old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-list.go 1970-01-01 01:00:00.000000000 +0100 +++ new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-list.go 2025-05-21 03:59:54.000000000 +0200 @@ -0,0 +1,169 @@ +// Copyright (c) 2015-2025 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 <http://www.gnu.org/licenses/>. + +package cmd + +import ( + "strings" + + "github.com/charmbracelet/lipgloss" + humanize "github.com/dustin/go-humanize" + "github.com/minio/cli" + json "github.com/minio/colorjson" + "github.com/minio/madmin-go/v3" + "github.com/minio/mc/pkg/probe" +) + +var idpOpenIDAccesskeyListFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "users-only", + Usage: "only list user DNs", + }, + cli.BoolFlag{ + Name: "temp-only", + Usage: "only list temporary access keys", + }, + cli.BoolFlag{ + Name: "svcacc-only", + Usage: "only list service account access keys", + }, + cli.BoolFlag{ + Name: "self", + Usage: "list access keys for the authenticated user", + }, + cli.BoolFlag{ + Name: "all", + Usage: "list all access keys for all OpenID users", + }, + cli.BoolFlag{ + Name: "all-configs", + Usage: "list access keys for all OpenID configurations", + }, +} + +var idpOpenidAccesskeyListCmd = cli.Command{ + Name: "list", + ShortName: "ls", + Usage: "list access key pairs for OpenID", + Action: mainIDPOpenIDAccesskeyList, + Before: setGlobalsFromContext, + Flags: append(idpOpenIDAccesskeyListFlags, globalFlags...), + OnUsageError: onUsageError, + CustomHelpTemplate: `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{.HelpName}} [FLAGS] TARGET[:CFGNAME] [USER/ID...] + +FLAGS: + {{range .VisibleFlags}}{{.}} + {{end}} +EXAMPLES: + 1. Get list of all OpenID users and associated access keys in local server (if admin) + {{.Prompt}} {{.HelpName}} local/ + + 2. Get list of OpenID users in local server (if admin) + {{.Prompt}} {{.HelpName}} local/ --users-only + + 3. Get list of all users and associated temporary access keys in play server (if admin) + {{.Prompt}} {{.HelpName}} play/ --temp-only + + 4. Get list of access keys associated with internal name 'openidinternalname' + {{.Prompt}} {{.HelpName}} play/ openidinternalname + + 5. Get list of access keys associated with ID claim 'openidsub' (default claim is sub) + {{.Prompt}} {{.HelpName}} play/ openidsub + + 7. Get authenticated user and associated access keys in local server (if not admin) + {{.Prompt}} {{.HelpName}} local/ +`, +} + +type openIDAccesskeyList struct { + Status string `json:"status"` + ConfigName string `json:"configName"` + Users []madmin.OpenIDUserAccessKeys `json:"users"` +} + +func (m openIDAccesskeyList) String() string { + labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) + o := strings.Builder{} + + o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("Config Name:"), m.ConfigName)) + userStr := "User ID" + for _, user := range m.Users { + o.WriteString(iFmt(2, "%s %s\n", labelStyle.Render(userStr+":"), user.MinioAccessKey)) + o.WriteString(iFmt(2, "%s %s\n", labelStyle.Render("ID:"), user.ID)) + if user.ReadableName != "" { + o.WriteString(iFmt(2, "%s %s\n", labelStyle.Render("Readable Name:"), user.ReadableName)) + } + if len(user.STSKeys) > 0 || len(user.ServiceAccounts) > 0 { + o.WriteString(iFmt(4, "%s\n", labelStyle.Render("Access Keys:"))) + } + for _, k := range user.STSKeys { + expiration := "never" + if nilExpiry(k.Expiration) != nil { + expiration = humanize.Time(*k.Expiration) + } + o.WriteString(iFmt(6, "%s, expires: %s, sts: true\n", k.AccessKey, expiration)) + } + for _, k := range user.ServiceAccounts { + expiration := "never" + if nilExpiry(k.Expiration) != nil { + expiration = humanize.Time(*k.Expiration) + } + o.WriteString(iFmt(6, "%s, expires: %s, sts: false\n", k.AccessKey, expiration)) + } + } + + return o.String() +} + +func (m openIDAccesskeyList) JSON() string { + jsonMessageBytes, e := json.MarshalIndent(m, "", " ") + fatalIf(probe.NewError(e), "Unable to marshal into JSON.") + + return string(jsonMessageBytes) +} + +func mainIDPOpenIDAccesskeyList(ctx *cli.Context) error { + aliasedURL, tentativeAll, users, opts := commonAccesskeyList(ctx) + + // Create a new MinIO Admin Client + client, err := newAdminClient(aliasedURL) + fatalIf(err, "Unable to initialize admin connection.") + + accessKeys, e := client.ListAccessKeysOpenIDBulk(globalContext, users, opts) + if e != nil { + if e.Error() == "Access Denied." && tentativeAll { + // retry with self + opts.All = false + accessKeys, e = client.ListAccessKeysOpenIDBulk(globalContext, users, opts) + } + fatalIf(probe.NewError(e), "Unable to list access keys.") + } + + for _, cfg := range accessKeys { + m := openIDAccesskeyList{ + Status: "success", + ConfigName: cfg.ConfigName, + Users: cfg.Users, + } + printMsg(m) + } + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-remove.go new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-remove.go --- old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey-remove.go 1970-01-01 01:00:00.000000000 +0100 +++ new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey-remove.go 2025-05-21 03:59:54.000000000 +0200 @@ -0,0 +1,49 @@ +// Copyright (c) 2015-2023 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 <http://www.gnu.org/licenses/>. + +package cmd + +import ( + "github.com/minio/cli" +) + +var idpOpenidAccesskeyRemoveCmd = cli.Command{ + Name: "remove", + ShortName: "rm", + Usage: "delete access key pairs for OpenID", + Action: mainIDPOpenIDAccesskeyRemove, + Before: setGlobalsFromContext, + Flags: globalFlags, + OnUsageError: onUsageError, + CustomHelpTemplate: `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{.HelpName}} [FLAGS] TARGET ACCESSKEY + +FLAGS: + {{range .VisibleFlags}}{{.}} + {{end}} +EXAMPLES: + 1. Remove the access key "testkey" from local server + {{.Prompt}} {{.HelpName}} local/ testkey + `, +} + +func mainIDPOpenIDAccesskeyRemove(ctx *cli.Context) error { + return commonAccesskeyRemove(ctx) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey.go new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey.go --- old/minio-client-20250416T181326Z/cmd/idp-openid-accesskey.go 1970-01-01 01:00:00.000000000 +0100 +++ new/minio-client-20250521T015954Z/cmd/idp-openid-accesskey.go 2025-05-21 03:59:54.000000000 +0200 @@ -0,0 +1,44 @@ +// Copyright (c) 2015-2023 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 <http://www.gnu.org/licenses/>. + +package cmd + +import "github.com/minio/cli" + +var idpOpenidAccesskeySubcommands = []cli.Command{ + idpOpenidAccesskeyListCmd, + idpOpenidAccesskeyRemoveCmd, + idpOpenidAccesskeyInfoCmd, + idpOpenidAccesskeyEditCmd, + idpOpenidAccesskeyEnableCmd, + idpOpenidAccesskeyDisableCmd, +} + +var idpOpenIDAccesskeyCmd = cli.Command{ + Name: "accesskey", + Usage: "manage OpenID access key pairs", + Action: mainIDPOpenIDAccesskey, + Before: setGlobalsFromContext, + Flags: globalFlags, + Subcommands: idpOpenidAccesskeySubcommands, + HideHelpCommand: true, +} + +func mainIDPOpenIDAccesskey(ctx *cli.Context) error { + commandNotFound(ctx, idpOpenidAccesskeySubcommands) + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/idp-openid.go new/minio-client-20250521T015954Z/cmd/idp-openid.go --- old/minio-client-20250416T181326Z/cmd/idp-openid.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/idp-openid.go 2025-05-21 03:59:54.000000000 +0200 @@ -28,6 +28,7 @@ idpOpenidInfoCmd, idpOpenidEnableCmd, idpOpenidDisableCmd, + idpOpenIDAccesskeyCmd, // TODO: idpOpenidPolicyCmd, } idpOpenidCmd = cli.Command{ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/main.go new/minio-client-20250521T015954Z/cmd/main.go --- old/minio-client-20250416T181326Z/cmd/main.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/main.go 2025-05-21 03:59:54.000000000 +0200 @@ -421,7 +421,6 @@ batchCmd, cpCmd, catCmd, - configCmd, corsCmd, diffCmd, duCmd, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/mirror-main.go new/minio-client-20250521T015954Z/cmd/mirror-main.go --- old/minio-client-20250416T181326Z/cmd/mirror-main.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/mirror-main.go 2025-05-21 03:59:54.000000000 +0200 @@ -747,7 +747,7 @@ } mirrorURL.TotalCount = mj.status.GetCounts() mirrorURL.TotalSize = mj.status.Get() - if mirrorURL.TargetContent != nil && (mj.opts.isRemove || mj.opts.activeActive) { + if mirrorURL.TargetContent != nil && (mj.opts.isRemove || mj.opts.activeActive || mj.opts.isWatch) { mj.parallel.queueTask(func() URLs { return mj.doRemove(ctx, mirrorURL, event) }, 0) @@ -995,7 +995,8 @@ isOverwrite = cli.Bool("overwrite") } - isWatch := cli.Bool("watch") || cli.Bool("multi-master") || cli.Bool("active-active") + isWatch := cli.Bool("watch") || cli.Bool("multi-master") + isActiveActive := cli.Bool("active-active") isRemove := cli.Bool("remove") md5, checksum := parseChecksum(cli) @@ -1023,7 +1024,7 @@ storageClass: cli.String("storage-class"), userMetadata: userMetadata, encKeyDB: encKeyDB, - activeActive: isWatch, + activeActive: isActiveActive, } // If we are not using active/active and we are not removing @@ -1055,7 +1056,7 @@ if d.Diff == differInSecond { diffBucket := strings.TrimPrefix(d.SecondURL, dstClt.GetURL().String()) - if !isFake && isRemove { + if !isFake && isRemove && createDstBuckets { aliasedDstBucket := path.Join(dstURL, diffBucket) err := deleteBucket(ctx, aliasedDstBucket, false) mj.status.fatalIf(err, "Failed to start mirroring.") @@ -1072,6 +1073,15 @@ newDstClt, _ := newClient(newTgtURL) if d.Diff == differInFirst { + // This loop is responsible solely for bringing target on par with source at the bucket level. + // createDstBuckets == false implies that the target itself represents a bucket. + // So we don't want to perform MakeBucket (and in turn delete and recreate already existing buckets and objects) if it already exists. + // Any differences at the object level between source and target's bucket will be synced as part of objectDifference() that gets + // called later. + if !createDstBuckets { + continue + } + var ( withLock bool mode minio.RetentionMode diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/retention-set.go new/minio-client-20250521T015954Z/cmd/retention-set.go --- old/minio-client-20250416T181326Z/cmd/retention-set.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/retention-set.go 2025-05-21 03:59:54.000000000 +0200 @@ -148,11 +148,10 @@ target, versionID, recursive, rewind, withVersions, mode, validity, unit, bypass, bucketMode := parseSetRetentionArgs(cliCtx) - fatalIfBucketLockNotSupported(ctx, target) - if bucketMode { return setBucketLock(target, mode, validity, unit) } + fatalIfBucketLockNotSupported(ctx, target) if withVersions && rewind.IsZero() { rewind = time.Now().UTC() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/minio-client-20250416T181326Z/cmd/support-profile.go new/minio-client-20250521T015954Z/cmd/support-profile.go --- old/minio-client-20250416T181326Z/cmd/support-profile.go 2025-04-16 20:13:26.000000000 +0200 +++ new/minio-client-20250521T015954Z/cmd/support-profile.go 2025-05-21 03:59:54.000000000 +0200 @@ -37,12 +37,12 @@ cli.IntFlag{ Name: "duration", Usage: "profile for the specified duration in seconds", - Value: 10, + Value: 15, }, cli.StringFlag{ Name: "type", - Usage: "profiler type, possible values are 'cpu', 'cpuio', 'mem', 'block', 'mutex', 'trace', 'threads' and 'goroutines'", - Value: "cpu,mem,block,mutex,goroutines", + Usage: "profiler type, possible values are 'cpu', 'cpuio', 'mem', 'block', 'mutex', 'trace', 'threads', 'goroutines' and 'runtime'", + Value: "cpu,mem,goroutines,runtime", }, }, subnetCommonFlags...) ) ++++++ minio-client.obsinfo ++++++ --- /var/tmp/diff_new_pack.1r46pu/_old 2025-05-26 18:38:25.606707224 +0200 +++ /var/tmp/diff_new_pack.1r46pu/_new 2025-05-26 18:38:25.610707392 +0200 @@ -1,5 +1,5 @@ name: minio-client -version: 20250416T181326Z -mtime: 1744827206 -commit: b00526b153a31b36767991a4f5ce2cced435ee8e +version: 20250521T015954Z +mtime: 1747792794 +commit: f71ad84bcf0fd4369691952af5d925347837dcec ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/minio-client/vendor.tar.gz /work/SRC/openSUSE:Factory/.minio-client.new.2732/vendor.tar.gz differ: char 128, line 1