This is an automated email from the ASF dual-hosted git repository.
PragmaTwice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 47e08935c fix(replication): require admin for transfer commands (#3484)
47e08935c is described below
commit 47e08935c6fb4ec604d4d650860abca546b83c51
Author: hulk <[email protected]>
AuthorDate: Mon May 11 12:22:55 2026 +0800
fix(replication): require admin for transfer commands (#3484)
Mark PSYNC, _FETCH_META, and _FETCH_FILE as admin-only commands so
namespace users cannot invoke replication transfer internals.
Move the regression coverage into the integration replication suite,
where the command behavior is exercised against a running server.
Assisted-by: Codex/GPT 5.5 xhigh
---
src/commands/cmd_replication.cc | 6 ++---
.../integration/replication/replication_test.go | 30 ++++++++++++++++++++++
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/src/commands/cmd_replication.cc b/src/commands/cmd_replication.cc
index 73fbca830..9f15ed1e4 100644
--- a/src/commands/cmd_replication.cc
+++ b/src/commands/cmd_replication.cc
@@ -483,9 +483,9 @@ class CommandWait : public Commander,
};
REDIS_REGISTER_COMMANDS(Replication, MakeCmdAttr<CommandReplConf>("replconf",
-3, "read-only no-script", NO_KEY),
- MakeCmdAttr<CommandPSync>("psync", -2, "read-only
no-multi no-script", NO_KEY),
- MakeCmdAttr<CommandFetchMeta>("_fetch_meta", 1,
"read-only no-multi no-script", NO_KEY),
- MakeCmdAttr<CommandFetchFile>("_fetch_file", 2,
"read-only no-multi no-script", NO_KEY),
+ MakeCmdAttr<CommandPSync>("psync", -2, "read-only
no-multi no-script admin", NO_KEY),
+ MakeCmdAttr<CommandFetchMeta>("_fetch_meta", 1,
"read-only no-multi no-script admin", NO_KEY),
+ MakeCmdAttr<CommandFetchFile>("_fetch_file", 2,
"read-only no-multi no-script admin", NO_KEY),
MakeCmdAttr<CommandDBName>("_db_name", 1, "read-only
no-multi", NO_KEY),
MakeCmdAttr<CommandWait>("wait", 3, "read-only
no-multi no-script blocking", NO_KEY), )
diff --git a/tests/gocase/integration/replication/replication_test.go
b/tests/gocase/integration/replication/replication_test.go
index 6e291ecc5..23ccabd10 100644
--- a/tests/gocase/integration/replication/replication_test.go
+++ b/tests/gocase/integration/replication/replication_test.go
@@ -117,6 +117,36 @@ func TestReplicationWithHostname(t *testing.T) {
})
}
+func TestReplicationTransferCommandsRequireAdminPermission(t *testing.T) {
+ srv := util.StartServer(t, map[string]string{
+ "requirepass": "admin",
+ })
+ defer srv.Close()
+
+ ctx := context.Background()
+ adminClient := srv.NewClientWithOption(&redis.Options{Password:
"admin"})
+ defer func() { require.NoError(t, adminClient.Close()) }()
+
+ require.NoError(t, adminClient.Do(ctx, "NAMESPACE", "ADD", "test_ns",
"test_token").Err())
+
+ userClient := srv.NewClientWithOption(&redis.Options{Password:
"test_token"})
+ defer func() { require.NoError(t, userClient.Close()) }()
+
+ for _, cmd := range []struct {
+ name string
+ args []interface{}
+ }{
+ {name: "PSYNC", args: []interface{}{"1"}},
+ {name: "_FETCH_META"},
+ {name: "_FETCH_FILE", args: []interface{}{"MANIFEST-000001"}},
+ } {
+ t.Run(cmd.name, func(t *testing.T) {
+ args := append([]interface{}{cmd.name}, cmd.args...)
+ require.ErrorContains(t, userClient.Do(ctx,
args...).Err(), "admin permission required to perform the command")
+ })
+ }
+}
+
func TestReplicationLoading(t *testing.T) {
t.Parallel()
srvA := util.StartServer(t, map[string]string{})