From 0828861bd06ace675370625ac7c345e2a7220432 Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Sun, 25 Oct 2026 03:32:53 +0800 Subject: [PATCH 1/7] iam: restore native policy immediately after resetting overrides Signed-off-by: Feng Ruohang (cherry picked from commit 1e3ab56b064bf4d56eee636fb77ac5af229f92ef) --- cmd/iam-credential-retention_test.go | 10 +- cmd/iam-policy-reset_test.go | 305 +++++++++++++++++++++++++++ cmd/iam-store.go | 133 +++++++----- 3 files changed, 389 insertions(+), 59 deletions(-) create mode 100644 cmd/iam-policy-reset_test.go diff --git a/cmd/iam-credential-retention_test.go b/cmd/iam-credential-retention_test.go index 09392e86e..063601120 100644 --- a/cmd/iam-credential-retention_test.go +++ b/cmd/iam-credential-retention_test.go @@ -85,15 +85,21 @@ func TestIAMPolicyDeletionRemainsExplicit(t *testing.T) { } p, err := sys.store.GetPolicy("readwrite") mustIAM(t, err) + native, err := sys.InfoPolicy("readwrite") + mustIAM(t, err) if err := sys.DeletePolicy(ctx, "readwrite", true); err == nil { t.Fatal("local pristine builtin policy became deletable") } _, err = sys.SetPolicy(ctx, "readwrite", p) mustIAM(t, err) mustIAM(t, sys.DeletePolicy(ctx, "readwrite", true)) + assertIAMPolicyResetInfo(t, sys, "readwrite", native) mustIAM(t, sys.store.LoadIAMCache(ctx, false)) - if _, err := sys.store.GetPolicy("readwrite"); !errors.Is(err, errNoSuchPolicy) { - t.Fatalf("reload restored an explicitly deleted override: %v", err) + assertIAMPolicyResetInfo(t, sys, "readwrite", native) + r, err = loadIAMRevision(ctx, sys.store, getPolicyDocPath("readwrite")) + mustIAM(t, err) + if !r.Deleted { + t.Fatal("native policy restoration removed the override tombstone") } _, err = sys.SetPolicy(ctx, "readwrite", p) mustIAM(t, err) diff --git a/cmd/iam-policy-reset_test.go b/cmd/iam-policy-reset_test.go new file mode 100644 index 000000000..e69fa89fb --- /dev/null +++ b/cmd/iam-policy-reset_test.go @@ -0,0 +1,305 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// 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 ( + "context" + "encoding/json" + "errors" + "fmt" + "reflect" + "sync" + "testing" + "time" + + "github.com/minio/madmin-go/v3" + "github.com/minio/minio/internal/grid" + "github.com/pgsty/silo-pkg/v3/policy" +) + +func newIAMPolicyResetSibling(ctx context.Context, t *testing.T, source *IAMSys, obj ObjectLayer) *IAMSys { + t.Helper() + store := &IAMStoreSys{IAMStorageAPI: newIAMObjectStore(obj, MinIOUsersSysType)} + if original, ok := source.store.IAMStorageAPI.(*IAMEtcdStore); ok { + store.IAMStorageAPI = newIAMEtcdStore(original.client, MinIOUsersSysType) + } + mustIAM(t, store.LoadIAMCache(ctx, true)) + return &IAMSys{store: store, usersSysType: MinIOUsersSysType} +} + +func assertIAMPolicyResetInfo(t *testing.T, sys *IAMSys, name string, want *madmin.PolicyInfo) { + t.Helper() + got, err := sys.InfoPolicy(name) + mustIAM(t, err) + var gotPolicy, wantPolicy policy.Policy + mustIAM(t, json.Unmarshal(got.Policy, &gotPolicy)) + mustIAM(t, json.Unmarshal(want.Policy, &wantPolicy)) + // Actions and resources are sets, whose JSON array order is not stable. + // Compare their exact contents while retaining all native metadata checks. + gotMetadata, wantMetadata := *got, *want + gotMetadata.Policy, wantMetadata.Policy = nil, nil + if !gotPolicy.Equals(wantPolicy) || !reflect.DeepEqual(gotMetadata, wantMetadata) { + t.Fatalf("policy definition or native metadata changed: got %+v, want %+v", got, want) + } +} + +// The first InfoPolicy call after Reset must work without any inventory read, +// refresh, or retry. The durable tombstone belongs to the removed override; +// it must still reject stale overrides without suppressing the native policy. +func TestIAMBuiltinPolicyResetRestoresNativePolicy(t *testing.T) { + for _, backend := range []string{"object", "etcd"} { + t.Run(backend, func(t *testing.T) { + ctx, sys, obj := prepareIAMRevisionFixture(t, backend) + for _, builtin := range policy.DefaultPolicies { + t.Run(builtin.Name, func(t *testing.T) { + name := builtin.Name + native, err := sys.InfoPolicy(name) + mustIAM(t, err) + override := builtin.Definition + override.ID = "reset-override" + written, err := sys.SetPolicy(ctx, name, override) + mustIAM(t, err) + mustIAM(t, sys.DeletePolicy(ctx, name, true)) + assertIAMPolicyResetInfo(t, sys, name, native) + + path := getPolicyDocPath(name) + deleted, err := loadIAMRevision(ctx, sys.store, path) + mustIAM(t, err) + if !deleted.Deleted || !deleted.timestamp().After(written) { + t.Fatalf("Reset lost the override deletion revision: %+v", deleted) + } + for _, at := range []time.Time{written, deleted.timestamp()} { + _, err = sys.SetPolicy(withIAMReplicationTime(ctx, at), name, override) + if !errors.Is(err, errIAMStaleUpdate) { + t.Fatalf("Reset accepted a stale override at %s: %v", at, err) + } + assertIAMPolicyResetInfo(t, sys, name, native) + } + mustIAM(t, sys.store.LoadIAMCache(ctx, false)) + assertIAMPolicyResetInfo(t, sys, name, native) + fresh := newIAMPolicyResetSibling(ctx, t, sys, obj) + assertIAMPolicyResetInfo(t, fresh, name, native) + for _, docs := range []bool{false, true} { + mustIAM(t, iamPolicyReloadCall(ctx, fresh.store, docs)) + assertIAMPolicyResetInfo(t, fresh, name, native) + } + after, err := loadIAMRevision(ctx, fresh.store, path) + mustIAM(t, err) + if !reflect.DeepEqual(after, deleted) || !fresh.store.revisionIndex().get(path).Deleted { + t.Fatal("default restoration changed the durable deletion or revision index") + } + // A deliberate new edit remains possible after Reset. + _, err = sys.SetPolicy(ctx, name, override) + mustIAM(t, err) + current, err := sys.store.GetPolicyDoc(name) + mustIAM(t, err) + if current.Policy.ID != override.ID || current.UpdateDate.IsZero() { + t.Fatal("Reset prevented a subsequent explicit override") + } + mustIAM(t, sys.DeletePolicy(ctx, name, true)) + }) + } + }) + } +} + +// Peer and watch notifications carry a name, not a version. Reload committed +// storage so delayed deletion events cannot erase a recreated policy. Built-in +// defaults retain mappings; a genuinely deleted custom policy does not. +func TestIAMPolicyResetNotificationLoadsCommittedState(t *testing.T) { + for _, backend := range []string{"object", "etcd"} { + for _, delivery := range []string{"peer", "watch"} { + for _, recreate := range []bool{false, true} { + for _, name := range []string{"writeonly", "reset-custom"} { + t.Run(fmt.Sprintf("%s/%s/recreate=%t/%s", backend, delivery, recreate, name), func(t *testing.T) { + ctx, source, obj := prepareIAMRevisionFixture(t, backend) + globalObjLayerMutex.Lock() + globalObjectAPI = obj + globalObjLayerMutex.Unlock() + builtin := name == "writeonly" + var want *madmin.PolicyInfo + if builtin { + var err error + want, err = source.InfoPolicy(name) + mustIAM(t, err) + } + p, err := source.store.GetPolicy("readwrite") + mustIAM(t, err) + p.ID = "reset-original-override" + _, err = source.SetPolicy(ctx, name, p) + mustIAM(t, err) + _, err = source.CreateUser(ctx, "reset-user", madmin.AddOrUpdateUserReq{SecretKey: "synthetic-reset-password", Status: madmin.AccountEnabled}) + mustIAM(t, err) + _, err = source.AddUsersToGroup(ctx, "reset-group", []string{"reset-user"}) + mustIAM(t, err) + for _, group := range []bool{false, true} { + entity := "reset-user" + if group { + entity = "reset-group" + } + _, err = source.PolicyDBSet(ctx, entity, "readonly,"+name, regUser, group) + mustIAM(t, err) + } + if err := source.DeletePolicy(ctx, name, true); !errors.Is(err, errPolicyInUse) { + t.Fatalf("Reset bypassed policy-in-use protection: %v", err) + } + sibling := newIAMPolicyResetSibling(ctx, t, source, obj) + mappings := make(map[bool]MappedPolicy) + mappings[false], _ = sibling.store.GetMappedPolicy("reset-user", false) + mappings[true], _ = sibling.store.GetMappedPolicy("reset-group", true) + // A remote site may delete before this node has received the + // corresponding mapping changes. Local deletion stays guarded. + mustIAM(t, source.DeletePolicy(withIAMReplicationTime(ctx, UTCNow()), name, true)) + if recreate { + p.ID = "reset-recreated-override" + _, err = source.SetPolicy(ctx, name, p) + mustIAM(t, err) + want, err = source.InfoPolicy(name) + mustIAM(t, err) + } + before, err := loadIAMRevision(ctx, source.store, getPolicyDocPath(name)) + mustIAM(t, err) + globalIAMSys = sibling + defer func() { globalIAMSys = source }() + for range 2 { + if delivery == "peer" { + _, remoteErr := (&peerRESTServer{}).DeletePolicyHandler(grid.NewMSSWith(map[string]string{peerRESTPolicy: name})) + if remoteErr != nil { + t.Fatal(remoteErr) + } + } else { + mustIAM(t, sibling.loadWatchedEvent(ctx, iamWatchEvent{keyPath: getPolicyDocPath(name)})) + } + if builtin || recreate { + assertIAMPolicyResetInfo(t, sibling, name, want) + } else if _, err := sibling.InfoPolicy(name); !errors.Is(err, errNoSuchPolicy) { + t.Fatalf("deleted custom policy returned: %v", err) + } + for group, original := range mappings { + entity := "reset-user" + if group { + entity = "reset-group" + } + got, _ := sibling.store.GetMappedPolicy(entity, group) + if builtin || recreate { + if !reflect.DeepEqual(got, original) { + t.Fatalf("notification changed surviving mappings: %+v", got) + } + } else if got.Policies != "readonly" { + t.Fatalf("custom deletion did not retain only the unrelated mapping: %+v", got) + } + } + } + after, err := loadIAMRevision(ctx, source.store, getPolicyDocPath(name)) + mustIAM(t, err) + if !reflect.DeepEqual(after, before) { + t.Fatal("notification changed durable policy storage") + } + }) + } + } + } + } +} + +func TestIAMPolicyResetNotificationSurvivesOlderRefresh(t *testing.T) { + ctx, source, obj := prepareIAMRevisionFixture(t) + p, err := source.store.GetPolicy("readwrite") + mustIAM(t, err) + p.ID = "old-override" + _, err = source.SetPolicy(ctx, "writeonly", p) + mustIAM(t, err) + sibling := newIAMPolicyResetSibling(ctx, t, source, obj) + original := sibling.store.IAMStorageAPI + loading, release := make(chan struct{}), make(chan struct{}) + unblock := sync.OnceFunc(func() { close(release) }) + var wg sync.WaitGroup + t.Cleanup(func() { unblock(); wg.Wait() }) + sibling.store.IAMStorageAPI = &iamPolicyReloadStore{ + IAMStorageAPI: original, + policies: original.loadPolicyDocs, + users: func(ctx context.Context, typ IAMUserType, m map[string]UserIdentity) error { + if typ == regUser { + close(loading) + <-release + } + return original.loadUsers(ctx, typ, m) + }, + } + done := make(chan error, 1) + wg.Go(func() { done <- sibling.store.LoadIAMCache(ctx, false) }) + awaitIAMPolicyReload(t, loading) + mustIAM(t, source.DeletePolicy(ctx, "writeonly", true)) + p.ID = "newer-override" + _, err = source.SetPolicy(ctx, "writeonly", p) + mustIAM(t, err) + want, err := source.InfoPolicy("writeonly") + mustIAM(t, err) + // The delayed deletion notification must observe the newer edit, and + // prevent a refresh that captured the old override from replacing it. + mustIAM(t, sibling.DeletePolicy(ctx, "writeonly", false)) + unblock() + mustIAM(t, <-done) + assertIAMPolicyResetInfo(t, sibling, "writeonly", want) +} + +type iamPolicyResetFailureStore struct { + IAMStorageAPI + err error +} + +func (s *iamPolicyResetFailureStore) saveIAMConfig(context.Context, any, string, ...options) error { + return s.err +} + +func (s *iamPolicyResetFailureStore) loadPolicyDoc(context.Context, string, map[string]PolicyDoc) error { + return s.err +} + +func TestIAMBuiltinPolicyResetStorageFailurePreservesOverride(t *testing.T) { + for _, backend := range []string{"object", "etcd"} { + t.Run(backend, func(t *testing.T) { + ctx, sys, _ := prepareIAMRevisionFixture(t, backend) + p, err := sys.store.GetPolicy("readonly") + mustIAM(t, err) + _, err = sys.SetPolicy(ctx, "writeonly", p) + mustIAM(t, err) + before, err := sys.InfoPolicy("writeonly") + mustIAM(t, err) + stored, err := loadIAMRevision(ctx, sys.store, getPolicyDocPath("writeonly")) + mustIAM(t, err) + original := sys.store.IAMStorageAPI + injected := errors.New("injected policy storage failure") + sys.store.IAMStorageAPI = &iamPolicyResetFailureStore{IAMStorageAPI: original, err: injected} + for _, notify := range []bool{true, false} { + if err := sys.DeletePolicy(ctx, "writeonly", notify); !errors.Is(err, injected) { + t.Fatalf("storage failure became a successful Reset, notify=%t: %v", notify, err) + } + assertIAMPolicyResetInfo(t, sys, "writeonly", before) + } + if err := sys.loadWatchedEvent(ctx, iamWatchEvent{keyPath: getPolicyDocPath("writeonly")}); !errors.Is(err, injected) { + t.Fatalf("watch storage failure became a default policy: %v", err) + } + assertIAMPolicyResetInfo(t, sys, "writeonly", before) + after, err := loadIAMRevision(ctx, original, getPolicyDocPath("writeonly")) + mustIAM(t, err) + if !reflect.DeepEqual(after, stored) { + t.Fatal("failed Reset changed the durable override") + } + }) + } +} diff --git a/cmd/iam-store.go b/cmd/iam-store.go index 89f78284a..677ab33f6 100644 --- a/cmd/iam-store.go +++ b/cmd/iam-store.go @@ -647,6 +647,20 @@ func setDefaultCannedPolicies(policies map[string]PolicyDoc) { } } +// Remove a stored policy from cache. A built-in policy's deletion removes its +// override, so its native definition remains available with native metadata. +// The durable tombstone is retained separately to reject stale overrides. +func removePolicyFromCache(name string, policies map[string]PolicyDoc) (restoredDefault bool) { + delete(policies, name) + for _, p := range policy.DefaultPolicies { + if p.Name == name { + policies[name] = defaultPolicyDoc(p.Definition) + return true + } + } + return false +} + // LoadIAMCache reads all IAM items and populates a new iamCache object and // replaces the in-memory cache object. func (store *IAMStoreSys) LoadIAMCache(ctx context.Context, firstTime bool) error { @@ -722,7 +736,7 @@ func (store *IAMStoreSys) LoadIAMCache(ctx context.Context, firstTime bool) erro for name := range newCache.iamPolicyDocsMap { if store.revisionIndex().get(getPolicyDocPath(name)).Deleted { - delete(newCache.iamPolicyDocsMap, name) + removePolicyFromCache(name, newCache.iamPolicyDocsMap) } } @@ -1376,9 +1390,9 @@ func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string, } // PolicyNotificationHandler - loads given policy from storage. If not present, -// deletes from cache. This notification only reads from storage, and updates -// cache. When the notification is for a policy deletion, it updates the -// user-policy and group-policy maps as well. +// removes its override from cache. This notification only reads from storage, +// and updates cache. A deleted built-in override restores its native policy; +// a deleted custom policy is removed from user-policy and group-policy maps. func (store *IAMStoreSys) PolicyNotificationHandler(ctx context.Context, policy string) error { if policy == "" { return errInvalidArgument @@ -1389,8 +1403,10 @@ func (store *IAMStoreSys) PolicyNotificationHandler(ctx context.Context, policy err := store.loadPolicyDoc(ctx, policy, cache.iamPolicyDocsMap) if errors.Is(err, errNoSuchPolicy) { - // policy was deleted, update cache. - delete(cache.iamPolicyDocsMap, policy) + if removePolicyFromCache(policy, cache.iamPolicyDocsMap) { + cache.updatedAt = time.Now() + return nil + } // update user policy map cache.iamUserPolicyMap.Range(func(u string, mp MappedPolicy) bool { @@ -1426,74 +1442,77 @@ func (store *IAMStoreSys) PolicyNotificationHandler(ctx context.Context, policy cache.updatedAt = time.Now() return nil } + if err == nil { + cache.updatedAt = time.Now() + } return err } -// DeletePolicy - deletes policy from storage and cache. When this called in -// response to a notification (i.e. isFromNotification = true), it skips the -// validation of policy usage and the attempt to delete in the backend as well -// (as this is already done by the notifying node). +// DeletePolicy - deletes a stored policy and restores the native definition +// when it was a built-in override. Notifications reload committed storage, so +// a delayed deletion event cannot remove a subsequently recreated policy. func (store *IAMStoreSys) DeletePolicy(ctx context.Context, policy string, isFromNotification bool) error { if policy == "" { return errInvalidArgument } + if isFromNotification { + return store.PolicyNotificationHandler(ctx, policy) + } cache := store.lock() defer store.unlock() - if !isFromNotification { - if err := store.checkIAMRevision(ctx, getPolicyDocPath(policy), true); err != nil { - return err + if err := store.checkIAMRevision(ctx, getPolicyDocPath(policy), true); err != nil { + return err + } + if _, replicated := iamReplicationTime(ctx); !replicated { + if _, exists := cache.iamPolicyDocsMap[policy]; !exists { + // Preserve idempotent local deletion without creating a durable + // revocation for a misspelled/nonexistent policy name. + return nil } - if _, replicated := iamReplicationTime(ctx); !replicated { - if _, exists := cache.iamPolicyDocsMap[policy]; !exists { - // Preserve idempotent local deletion without creating a durable - // revocation for a misspelled/nonexistent policy name. - return nil + // Check if policy is mapped to any existing user or group. If so, we do not + // allow deletion of the policy. If the policy is mapped to an STS account, + // we do allow deletion. + users := []string{} + groups := []string{} + cache.iamUserPolicyMap.Range(func(u string, mp MappedPolicy) bool { + pset := mp.policySet() + if store.getUsersSysType() == MinIOUsersSysType { + if _, ok := cache.iamUsersMap[u]; !ok { + // This case can happen when a temporary account is + // deleted or expired - remove it from userPolicyMap. + cache.iamUserPolicyMap.Delete(u) + return true + } } - // Check if policy is mapped to any existing user or group. If so, we do not - // allow deletion of the policy. If the policy is mapped to an STS account, - // we do allow deletion. - users := []string{} - groups := []string{} - cache.iamUserPolicyMap.Range(func(u string, mp MappedPolicy) bool { - pset := mp.policySet() - if store.getUsersSysType() == MinIOUsersSysType { - if _, ok := cache.iamUsersMap[u]; !ok { - // This case can happen when a temporary account is - // deleted or expired - remove it from userPolicyMap. - cache.iamUserPolicyMap.Delete(u) - return true - } - } - if pset.Contains(policy) { - users = append(users, u) - } - return true - }) - cache.iamGroupPolicyMap.Range(func(g string, mp MappedPolicy) bool { - pset := mp.policySet() - if pset.Contains(policy) { - groups = append(groups, g) - } - return true - }) - if len(users) != 0 || len(groups) != 0 { - return errPolicyInUse + if pset.Contains(policy) { + users = append(users, u) } - } - - err := store.deletePolicyDoc(ctx, policy) - if errors.Is(err, errNoSuchPolicy) { - // Ignore error if policy is already deleted. - err = nil - } - if err != nil { - return err + return true + }) + cache.iamGroupPolicyMap.Range(func(g string, mp MappedPolicy) bool { + pset := mp.policySet() + if pset.Contains(policy) { + groups = append(groups, g) + } + return true + }) + if len(users) != 0 || len(groups) != 0 { + return errPolicyInUse } } - delete(cache.iamPolicyDocsMap, policy) + err := store.deletePolicyDoc(ctx, policy) + if errors.Is(err, errNoSuchPolicy) { + // Ignore error if policy is already deleted. + err = nil + } + if err != nil { + return err + } + + removePolicyFromCache(policy, cache.iamPolicyDocsMap) cache.updatedAt = time.Now() return nil From 5f1f4178aed31ad5523e7383096be9d1df70e21d Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Sun, 25 Oct 2026 21:01:01 +0800 Subject: [PATCH 2/7] fix: return current bucket inventory from account info Signed-off-by: Feng Ruohang (cherry picked from commit 6921f8c18693d6426a188624ffc9205f8986761a) --- cmd/admin-account-buckets_test.go | 80 +++++++++++++++++++++++++++++++ cmd/admin-handlers-users.go | 5 +- 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 cmd/admin-account-buckets_test.go diff --git a/cmd/admin-account-buckets_test.go b/cmd/admin-account-buckets_test.go new file mode 100644 index 000000000..ffe7bea6b --- /dev/null +++ b/cmd/admin-account-buckets_test.go @@ -0,0 +1,80 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later + +package cmd + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/minio/madmin-go/v3" + "github.com/minio/minio/internal/cachevalue" +) + +func TestAccountInfoReflectsBucketMutations(t *testing.T) { + ctx := t.Context() + bed, err := prepareAdminErasureTestBed(ctx) + if err != nil { + t.Fatal(err) + } + defer bed.TearDown() + previousCache := listBucketsCache + defer func() { listBucketsCache = previousCache }() + + // Hold a real pre-mutation snapshot past the assertions so the regression + // cannot disappear merely because a slow test outlasted the cache TTL. + freezeListing := func() { + t.Helper() + buckets, err := bed.objLayer.ListBuckets(ctx, BucketOptions{}) + if err != nil { + t.Fatal(err) + } + listBucketsCache = cachevalue.NewFromFunc(time.Hour, cachevalue.Opts{}, func(context.Context) ([]BucketInfo, error) { + return buckets, nil + }) + if _, err := listBucketsCache.GetWithCtx(ctx); err != nil { + t.Fatal(err) + } + } + const bucket = "account-info-freshness" + assertPresent := func(want bool) { + t.Helper() + req, err := buildAdminRequest(nil, http.MethodGet, "/accountinfo", 0, nil) + if err != nil { + t.Fatal(err) + } + rec := httptest.NewRecorder() + bed.router.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("account info: %d %s", rec.Code, rec.Body.String()) + } + var info madmin.AccountInfo + if err := json.Unmarshal(rec.Body.Bytes(), &info); err != nil { + t.Fatal(err) + } + found := false + for _, item := range info.Buckets { + if item.Name == bucket { + found = true + } + } + if found != want { + t.Errorf("account info bucket present = %v, want %v", found, want) + } + } + + freezeListing() + if err := bed.objLayer.MakeBucket(ctx, bucket, MakeBucketOptions{}); err != nil { + t.Fatal(err) + } + assertPresent(true) + freezeListing() + if err := bed.objLayer.DeleteBucket(ctx, bucket, DeleteBucketOptions{}); err != nil { + t.Fatal(err) + } + assertPresent(false) +} diff --git a/cmd/admin-handlers-users.go b/cmd/admin-handlers-users.go index 590788b37..29a240f41 100644 --- a/cmd/admin-handlers-users.go +++ b/cmd/admin-handlers-users.go @@ -1447,7 +1447,10 @@ func (a adminAPIHandlers) AccountInfoHandler(w http.ResponseWriter, r *http.Requ return buckets[i].Name < buckets[j].Name }) } else { - buckets, err = objectAPI.ListBuckets(ctx, BucketOptions{Cached: true}) + // Console refreshes this inventory immediately after bucket mutations. + // A stale cached list can otherwise hide a creation or retain a deletion + // indefinitely in the client's snapshot. + buckets, err = objectAPI.ListBuckets(ctx, BucketOptions{}) if err != nil { writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) return From 030c6d740e9fc9d9f3e1d3fcce52d49721704dbf Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Sun, 25 Oct 2026 21:01:22 +0800 Subject: [PATCH 3/7] deps: integrate pkg 3.15.1 and Console 2.5.0 candidate for acceptance Signed-off-by: Feng Ruohang --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 8160c0e58..da5d02fa2 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,9 @@ go 1.27.3 // Console and MC retain their historical module paths for best-effort upstream // compatibility. Pin the maintained PGSTY implementations used by SILO. -replace github.com/minio/console => github.com/pgsty/silo-console v0.0.0-20261017112417-ef2dd2c41d21 +replace github.com/minio/console => github.com/pgsty/silo-console v0.0.0-20261025123227-c19b4257fc7d -replace github.com/minio/mc => github.com/pgsty/mc v0.0.0-20261017101407-fa3b8bf72458 +replace github.com/minio/mc => github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94 // v22.7.0 does not compile on NetBSD because its unix implementation uses // CLOCK_MONOTONIC, which is unavailable there. Keep the last portable release @@ -68,7 +68,7 @@ require ( github.com/minio/kms-go/kes v0.3.1 github.com/minio/kms-go/kms v0.7.0 github.com/minio/madmin-go/v3 v3.0.110 - github.com/minio/minio-go/v7 v7.4.1 + github.com/minio/minio-go/v7 v7.4.2-0.20261020194015-ab93db7ba435 github.com/minio/mux v1.10.1 github.com/minio/selfupdate v0.6.0 github.com/minio/simdjson-go v0.4.5 @@ -81,7 +81,7 @@ require ( github.com/nats-io/stan.go v0.10.4 github.com/ncw/directio v1.0.5 github.com/nsqio/go-nsq v1.1.0 - github.com/pgsty/silo-pkg/v3 v3.14.3 + github.com/pgsty/silo-pkg/v3 v3.15.1 github.com/philhofer/fwd v1.2.1 github.com/pierrec/lz4/v4 v4.1.33 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index be51e599c..66ceb9615 100644 --- a/go.sum +++ b/go.sum @@ -442,8 +442,8 @@ github.com/minio/madmin-go/v3 v3.0.110 h1:FIYekj7YPc430ffpXFWiUtyut3qBt/unIAcDzJ github.com/minio/madmin-go/v3 v3.0.110/go.mod h1:WOe2kYmYl1OIlY2DSRHVQ8j1v4OItARQ6jGyQqcCud8= 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.4.1 h1:PtU/zIOfQRWZ+QydXAZysc+xZYHdG+BBR4Z6TUvy73w= -github.com/minio/minio-go/v7 v7.4.1/go.mod h1:nQnQi7zTfXR4lREtYXZQWqo5aw0Rqv+ZqCGrTORygRk= +github.com/minio/minio-go/v7 v7.4.2-0.20261020194015-ab93db7ba435 h1:BIn1BJi2zZ+z5BIMsr02USFB+Wmipc4SrIAA8nksNH0= +github.com/minio/minio-go/v7 v7.4.2-0.20261020194015-ab93db7ba435/go.mod h1:nQnQi7zTfXR4lREtYXZQWqo5aw0Rqv+ZqCGrTORygRk= github.com/minio/mux v1.10.1 h1:grrK8SwRKbkNFE6qG7WAvFGH09bB46d5teOOtKfQ14s= github.com/minio/mux v1.10.1/go.mod h1:INYT4sMSTJy0QWUEA/E2DZNxJ5sAxIwbnyZjkzNFRfE= github.com/minio/pkg/v3 v3.11.0 h1:WjzWGP7lyuupJgUSRim1RDtNujHtESyMQF7qSR4r5Dg= @@ -506,12 +506,12 @@ github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6 github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pgsty/mc v0.0.0-20261017101407-fa3b8bf72458 h1:f3kbkjtjj6D7PXmsIeKrv8phXncq1OVrxKM2e4I6rVk= -github.com/pgsty/mc v0.0.0-20261017101407-fa3b8bf72458/go.mod h1:n8NDi0J3hPUGCIM9tOxlhYXkYS9xiTVIxlxa3Rwx1cw= -github.com/pgsty/silo-console v0.0.0-20261017112417-ef2dd2c41d21 h1:PHxPswGiEwU9MVisu0/Ab7AcNX4IveiX1thQzUXOsM4= -github.com/pgsty/silo-console v0.0.0-20261017112417-ef2dd2c41d21/go.mod h1:HFNaafu5iCO9bWS86PIyTbgF+yPD4phFt+gxML/1jJU= -github.com/pgsty/silo-pkg/v3 v3.14.3 h1:hMDxOo36F1whGRkYScrUGGwn98FvsmJ8hVM6pE4i8Bs= -github.com/pgsty/silo-pkg/v3 v3.14.3/go.mod h1:zqIm3FMETmwPHRKuUExCDGfYkCNXt+vpfBnPM821RdI= +github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94 h1:M5n0rCPOTyo3RiQBeSCQW/klx08efFpiVYmPq6eoM3w= +github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94/go.mod h1:H3Uwlm1Qj3kPsbmojhNnv3aj5a+QdjdTKwv4w4gMSF8= +github.com/pgsty/silo-console v0.0.0-20261025123227-c19b4257fc7d h1:hoC+8oNkEF6MbIql7pYxUzkhvhMj1ok1DlP304OL7yk= +github.com/pgsty/silo-console v0.0.0-20261025123227-c19b4257fc7d/go.mod h1:fMxNcVxan3mu9mc7HCRiczSyQoFrbZEGumEmpatxtds= +github.com/pgsty/silo-pkg/v3 v3.15.1 h1:T5rqY3HR1WGybcjnx/ghBvliEgo7yNCA7JAC3f1LpTk= +github.com/pgsty/silo-pkg/v3 v3.15.1/go.mod h1:GmTF6fIEkTrzgM+ysWWfDZIlVRD2DYAJkKjA5bjiWpQ= github.com/philhofer/fwd v1.2.1 h1:UtpS73q8bFgy/yH3gCq8LSNvj5gv/FowNOiWZa7uKwQ= github.com/philhofer/fwd v1.2.1/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pierrec/lz4/v4 v4.1.33 h1:GjG1TJ1V4IzKP8L96muuuDNpTwd7D+l2ccXrjAbe014= From 62124c779c1524cd6569d63ccc0c9a60a460f7db Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Sun, 25 Oct 2026 21:06:21 +0800 Subject: [PATCH 4/7] docs: include coordinated Console dependency attributions Signed-off-by: Feng Ruohang --- CREDITS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CREDITS b/CREDITS index ea7129b5e..37e996c5b 100644 --- a/CREDITS +++ b/CREDITS @@ -18146,6 +18146,18 @@ The licenses and notices of every third-party component linked into the binary or bundled into the web application are collected in the CREDITS file next to this notice (`console credits`, or /legal/CREDITS on a running server). +The in-tree MinIO Design System (MDS) in web-app/packages/mds is derived from +https://github.com/georgmangold/mds, revision +b66d0b06272ae88e3975248691799a1cb0b4d6de (v1.1.5.9), and is licensed under +AGPL-3.0-or-later. Copyright remains with MinIO, Inc. and its contributors. +Its unchanged LICENSE and vendoring history are in web-app/packages/mds; +local modifications are documented in UPSTREAM.md there. + +The surface/shadow token recipes adapt Fluid Functionalism by Micka Touillaud, +https://github.com/mickadesign/fluid-functionalism, under the MIT License. +Copyright (c) 2026 Micka Touillaud. The full MIT notice is retained in +web-app/licenses/fluid-functionalism-MIT.txt and generated into CREDITS. + ================================================================ github.com/minio/crc64nvme From 475640e7e152230ca9158c41a5d612cbcc8f6ddb Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Sun, 25 Oct 2026 21:33:34 +0800 Subject: [PATCH 5/7] deps: embed the repaired Console 2.5.0 candidate Signed-off-by: Feng Ruohang --- CHANGELOG.md | 14 +++++++++++++- README.md | 6 ++++++ README_ZH.md | 5 +++++ go.mod | 2 +- go.sum | 4 ++-- 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5ad5bf9b..184d44394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,19 @@ Thanks to [@910patin](https://github.com/910patin) for the original fix and reproduction in [#250](https://github.com/pgsty/silo/pull/250). - Build the server and standalone debugging tools with Go 1.27.3 and refresh - Go dependencies. Keep the published Console, mcli and silo-pkg references. + Go dependencies, including silo-pkg v3.15.1, the published mcli 20261025 + source and upstream minio-go `ab93db7ba435` for multipart, read/seek and + batch-delete fixes. Retain output-format and NetBSD compatibility selections. +- Embed the unreleased Console 2.5.0 candidate `abc1729b5a23`, including its + GUI update, diagnostic WebSocket closing handshake and complete health-report + decoding. This selects a source commit, not a new Console release. +- Read current bucket inventory in account-info responses so Console refreshes + immediately reflect successful creation and deletion. This management endpoint + now performs a live list instead of returning a cached inventory. +- Restore the native built-in policy immediately after resetting an override. + Peer and etcd notifications reload committed state, so delayed delete events + preserve subsequent edits. Keep deletion revisions, policy-in-use checks and + custom-policy deletion behavior; storage failures retain the previous policy. - Preserve Kafka's default broker protocol 2.1 and terminal-width behavior; fix legacy DARE v1 key unsealing and verify DARE v1/v2 and MinKMS TLS compatibility. - Update bundled curl to 8.23.0 and require patched static libraries. Apply diff --git a/README.md b/README.md index a38d661ac..38c9d3677 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,12 @@ This release strengthens Object Lock and IAM authorization, makes scoped STS rev Read the [release notes](https://github.com/pgsty/silo/releases/tag/RELEASE.2026-10-18T00-00-00Z) before upgrading, especially the removal of strict multipart listing, coordinated server upgrades, and measured performance costs. See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the people behind the code, reports, and documentation. +Current source is unreleased: Go 1.27.3, silo-pkg v3.15.1, mcli 20261025, +upstream minio-go `ab93db7ba435`, and the Console 2.5.0 candidate `abc1729b5a23`. +It includes the Server IAM cache repair needed by Console's **Reset to default** +action. See [CHANGELOG.md](CHANGELOG.md#unreleased); the published artifacts above +retain their original component versions. + ## Overview PGSTY SILO keeps one maintained release line of the open-source MinIO server alive after upstream ended community distribution: builds, packages, multi-arch images, security fixes, and the full web console. Pigsty runs it in production as its PostgreSQL backup repository. diff --git a/README_ZH.md b/README_ZH.md index c6377785c..f3f7839cd 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -43,6 +43,11 @@ 升级前请阅读[发行说明](https://github.com/pgsty/silo/releases/tag/RELEASE.2026-10-18T00-00-00Z),特别是 strict 分片列表的移除、服务端协调升级要求与实测性能成本。代码、问题报告和文档贡献者见 [CONTRIBUTORS.md](CONTRIBUTORS.md)。 +当前源码尚未发布:使用 Go 1.27.3、silo-pkg v3.15.1、mcli 20261025、上游 +minio-go `ab93db7ba435`,并内嵌 Console 2.5.0 候选提交 `abc1729b5a23`。 +其中包含 Console **Reset to default(恢复默认)** 所需的 Server IAM 缓存修复。 +详见 [CHANGELOG.md](CHANGELOG.md#unreleased);上述已发布制品仍保留原有组件版本。 + ## 概述 上游停止社区发行后,Silo 为开源 MinIO 服务端维护一条持续可用的版本线:构建、软件包、多架构镜像、安全修复与完整 Web 控制台。Pigsty 在生产环境中用它承载 PostgreSQL 备份存储。 diff --git a/go.mod b/go.mod index da5d02fa2..00417d09f 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.27.3 // Console and MC retain their historical module paths for best-effort upstream // compatibility. Pin the maintained PGSTY implementations used by SILO. -replace github.com/minio/console => github.com/pgsty/silo-console v0.0.0-20261025123227-c19b4257fc7d +replace github.com/minio/console => github.com/pgsty/silo-console v0.0.0-20261025133048-abc1729b5a23 replace github.com/minio/mc => github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94 diff --git a/go.sum b/go.sum index 66ceb9615..61f6ff306 100644 --- a/go.sum +++ b/go.sum @@ -508,8 +508,8 @@ github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwp github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94 h1:M5n0rCPOTyo3RiQBeSCQW/klx08efFpiVYmPq6eoM3w= github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94/go.mod h1:H3Uwlm1Qj3kPsbmojhNnv3aj5a+QdjdTKwv4w4gMSF8= -github.com/pgsty/silo-console v0.0.0-20261025123227-c19b4257fc7d h1:hoC+8oNkEF6MbIql7pYxUzkhvhMj1ok1DlP304OL7yk= -github.com/pgsty/silo-console v0.0.0-20261025123227-c19b4257fc7d/go.mod h1:fMxNcVxan3mu9mc7HCRiczSyQoFrbZEGumEmpatxtds= +github.com/pgsty/silo-console v0.0.0-20261025133048-abc1729b5a23 h1:VwIfjyv4L3YgOSu9loimfUhV3mm3D3iQibJZpzTaD8o= +github.com/pgsty/silo-console v0.0.0-20261025133048-abc1729b5a23/go.mod h1:fMxNcVxan3mu9mc7HCRiczSyQoFrbZEGumEmpatxtds= github.com/pgsty/silo-pkg/v3 v3.15.1 h1:T5rqY3HR1WGybcjnx/ghBvliEgo7yNCA7JAC3f1LpTk= github.com/pgsty/silo-pkg/v3 v3.15.1/go.mod h1:GmTF6fIEkTrzgM+ysWWfDZIlVRD2DYAJkKjA5bjiWpQ= github.com/philhofer/fwd v1.2.1 h1:UtpS73q8bFgy/yH3gCq8LSNvj5gv/FowNOiWZa7uKwQ= From 79eca5e92043f3d53e9dcd27b2c9a051f408949e Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Sun, 25 Oct 2026 21:50:10 +0800 Subject: [PATCH 6/7] deps: select the Console candidate with native keyboard regression coverage Signed-off-by: Feng Ruohang --- CHANGELOG.md | 2 +- README.md | 2 +- README_ZH.md | 2 +- go.mod | 2 +- go.sum | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 184d44394..4cb925004 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ Go dependencies, including silo-pkg v3.15.1, the published mcli 20261025 source and upstream minio-go `ab93db7ba435` for multipart, read/seek and batch-delete fixes. Retain output-format and NetBSD compatibility selections. -- Embed the unreleased Console 2.5.0 candidate `abc1729b5a23`, including its +- Embed the unreleased Console 2.5.0 candidate `ab4309ffb54d`, including its GUI update, diagnostic WebSocket closing handshake and complete health-report decoding. This selects a source commit, not a new Console release. - Read current bucket inventory in account-info responses so Console refreshes diff --git a/README.md b/README.md index 38c9d3677..f9a5b2791 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ This release strengthens Object Lock and IAM authorization, makes scoped STS rev Read the [release notes](https://github.com/pgsty/silo/releases/tag/RELEASE.2026-10-18T00-00-00Z) before upgrading, especially the removal of strict multipart listing, coordinated server upgrades, and measured performance costs. See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the people behind the code, reports, and documentation. Current source is unreleased: Go 1.27.3, silo-pkg v3.15.1, mcli 20261025, -upstream minio-go `ab93db7ba435`, and the Console 2.5.0 candidate `abc1729b5a23`. +upstream minio-go `ab93db7ba435`, and the Console 2.5.0 candidate `ab4309ffb54d`. It includes the Server IAM cache repair needed by Console's **Reset to default** action. See [CHANGELOG.md](CHANGELOG.md#unreleased); the published artifacts above retain their original component versions. diff --git a/README_ZH.md b/README_ZH.md index f3f7839cd..2869ccd95 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -44,7 +44,7 @@ 升级前请阅读[发行说明](https://github.com/pgsty/silo/releases/tag/RELEASE.2026-10-18T00-00-00Z),特别是 strict 分片列表的移除、服务端协调升级要求与实测性能成本。代码、问题报告和文档贡献者见 [CONTRIBUTORS.md](CONTRIBUTORS.md)。 当前源码尚未发布:使用 Go 1.27.3、silo-pkg v3.15.1、mcli 20261025、上游 -minio-go `ab93db7ba435`,并内嵌 Console 2.5.0 候选提交 `abc1729b5a23`。 +minio-go `ab93db7ba435`,并内嵌 Console 2.5.0 候选提交 `ab4309ffb54d`。 其中包含 Console **Reset to default(恢复默认)** 所需的 Server IAM 缓存修复。 详见 [CHANGELOG.md](CHANGELOG.md#unreleased);上述已发布制品仍保留原有组件版本。 diff --git a/go.mod b/go.mod index 00417d09f..c1f55dcfb 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.27.3 // Console and MC retain their historical module paths for best-effort upstream // compatibility. Pin the maintained PGSTY implementations used by SILO. -replace github.com/minio/console => github.com/pgsty/silo-console v0.0.0-20261025133048-abc1729b5a23 +replace github.com/minio/console => github.com/pgsty/silo-console v0.0.0-20261025134801-ab4309ffb54d replace github.com/minio/mc => github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94 diff --git a/go.sum b/go.sum index 61f6ff306..a457fa418 100644 --- a/go.sum +++ b/go.sum @@ -508,8 +508,8 @@ github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwp github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94 h1:M5n0rCPOTyo3RiQBeSCQW/klx08efFpiVYmPq6eoM3w= github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94/go.mod h1:H3Uwlm1Qj3kPsbmojhNnv3aj5a+QdjdTKwv4w4gMSF8= -github.com/pgsty/silo-console v0.0.0-20261025133048-abc1729b5a23 h1:VwIfjyv4L3YgOSu9loimfUhV3mm3D3iQibJZpzTaD8o= -github.com/pgsty/silo-console v0.0.0-20261025133048-abc1729b5a23/go.mod h1:fMxNcVxan3mu9mc7HCRiczSyQoFrbZEGumEmpatxtds= +github.com/pgsty/silo-console v0.0.0-20261025134801-ab4309ffb54d h1:kRQD9mfus1t5D86PaK1oO0FqwGrzsZdcieaof0GROvI= +github.com/pgsty/silo-console v0.0.0-20261025134801-ab4309ffb54d/go.mod h1:fMxNcVxan3mu9mc7HCRiczSyQoFrbZEGumEmpatxtds= github.com/pgsty/silo-pkg/v3 v3.15.1 h1:T5rqY3HR1WGybcjnx/ghBvliEgo7yNCA7JAC3f1LpTk= github.com/pgsty/silo-pkg/v3 v3.15.1/go.mod h1:GmTF6fIEkTrzgM+ysWWfDZIlVRD2DYAJkKjA5bjiWpQ= github.com/philhofer/fwd v1.2.1 h1:UtpS73q8bFgy/yH3gCq8LSNvj5gv/FowNOiWZa7uKwQ= From 41822710e4dc70a20d8b80c2b095beb76532dee2 Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Sun, 25 Oct 2026 22:13:27 +0800 Subject: [PATCH 7/7] deps: embed the Console bucket-search navigation repair Signed-off-by: Feng Ruohang --- CHANGELOG.md | 2 +- README.md | 2 +- README_ZH.md | 2 +- go.mod | 2 +- go.sum | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb925004..efd5623bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ Go dependencies, including silo-pkg v3.15.1, the published mcli 20261025 source and upstream minio-go `ab93db7ba435` for multipart, read/seek and batch-delete fixes. Retain output-format and NetBSD compatibility selections. -- Embed the unreleased Console 2.5.0 candidate `ab4309ffb54d`, including its +- Embed the unreleased Console 2.5.0 candidate `258717be077b`, including its GUI update, diagnostic WebSocket closing handshake and complete health-report decoding. This selects a source commit, not a new Console release. - Read current bucket inventory in account-info responses so Console refreshes diff --git a/README.md b/README.md index f9a5b2791..24c710875 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ This release strengthens Object Lock and IAM authorization, makes scoped STS rev Read the [release notes](https://github.com/pgsty/silo/releases/tag/RELEASE.2026-10-18T00-00-00Z) before upgrading, especially the removal of strict multipart listing, coordinated server upgrades, and measured performance costs. See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the people behind the code, reports, and documentation. Current source is unreleased: Go 1.27.3, silo-pkg v3.15.1, mcli 20261025, -upstream minio-go `ab93db7ba435`, and the Console 2.5.0 candidate `ab4309ffb54d`. +upstream minio-go `ab93db7ba435`, and the Console 2.5.0 candidate `258717be077b`. It includes the Server IAM cache repair needed by Console's **Reset to default** action. See [CHANGELOG.md](CHANGELOG.md#unreleased); the published artifacts above retain their original component versions. diff --git a/README_ZH.md b/README_ZH.md index 2869ccd95..525bbf8aa 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -44,7 +44,7 @@ 升级前请阅读[发行说明](https://github.com/pgsty/silo/releases/tag/RELEASE.2026-10-18T00-00-00Z),特别是 strict 分片列表的移除、服务端协调升级要求与实测性能成本。代码、问题报告和文档贡献者见 [CONTRIBUTORS.md](CONTRIBUTORS.md)。 当前源码尚未发布:使用 Go 1.27.3、silo-pkg v3.15.1、mcli 20261025、上游 -minio-go `ab93db7ba435`,并内嵌 Console 2.5.0 候选提交 `ab4309ffb54d`。 +minio-go `ab93db7ba435`,并内嵌 Console 2.5.0 候选提交 `258717be077b`。 其中包含 Console **Reset to default(恢复默认)** 所需的 Server IAM 缓存修复。 详见 [CHANGELOG.md](CHANGELOG.md#unreleased);上述已发布制品仍保留原有组件版本。 diff --git a/go.mod b/go.mod index c1f55dcfb..ca92e0fe9 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.27.3 // Console and MC retain their historical module paths for best-effort upstream // compatibility. Pin the maintained PGSTY implementations used by SILO. -replace github.com/minio/console => github.com/pgsty/silo-console v0.0.0-20261025134801-ab4309ffb54d +replace github.com/minio/console => github.com/pgsty/silo-console v0.0.0-20261025140954-258717be077b replace github.com/minio/mc => github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94 diff --git a/go.sum b/go.sum index a457fa418..994ee5543 100644 --- a/go.sum +++ b/go.sum @@ -508,8 +508,8 @@ github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwp github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94 h1:M5n0rCPOTyo3RiQBeSCQW/klx08efFpiVYmPq6eoM3w= github.com/pgsty/mc v0.0.0-20261025104502-dcc78d506f94/go.mod h1:H3Uwlm1Qj3kPsbmojhNnv3aj5a+QdjdTKwv4w4gMSF8= -github.com/pgsty/silo-console v0.0.0-20261025134801-ab4309ffb54d h1:kRQD9mfus1t5D86PaK1oO0FqwGrzsZdcieaof0GROvI= -github.com/pgsty/silo-console v0.0.0-20261025134801-ab4309ffb54d/go.mod h1:fMxNcVxan3mu9mc7HCRiczSyQoFrbZEGumEmpatxtds= +github.com/pgsty/silo-console v0.0.0-20261025140954-258717be077b h1:/RQ+D5TRP8/GGZaY5cbwIixd1RFE0eQjEVLBpIl3+8k= +github.com/pgsty/silo-console v0.0.0-20261025140954-258717be077b/go.mod h1:fMxNcVxan3mu9mc7HCRiczSyQoFrbZEGumEmpatxtds= github.com/pgsty/silo-pkg/v3 v3.15.1 h1:T5rqY3HR1WGybcjnx/ghBvliEgo7yNCA7JAC3f1LpTk= github.com/pgsty/silo-pkg/v3 v3.15.1/go.mod h1:GmTF6fIEkTrzgM+ysWWfDZIlVRD2DYAJkKjA5bjiWpQ= github.com/philhofer/fwd v1.2.1 h1:UtpS73q8bFgy/yH3gCq8LSNvj5gv/FowNOiWZa7uKwQ=