This is an automated email from the ASF dual-hosted git repository.

deardeng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new c3c7af57fa4 [fix](be) Remove heartbeat tokens from logs and errors 
(#69532)
c3c7af57fa4 is described below

commit c3c7af57fa4e018a2f4319bf60ce5f83ef503ad7
Author: deardeng <[email protected]>
AuthorDate: Mon Oct 26 11:59:16 2026 +0800

    [fix](be) Remove heartbeat tokens from logs and errors (#69532)
    
    Problem Summary: When a BE receives its cluster token or a new
    authentication token, heartbeat INFO logs include the credential values.
    A cluster-token mismatch also includes both tokens in the error
    response, which can propagate to FE logs. Keep the heartbeat event
    messages and invalid-token error while removing credential values. Add a
    unit test covering initialization, repeated heartbeats, successive
    authentication-token updates, and token mismatch, including checks that
    logs and error responses do not contain the credentials.
---
 be/src/agent/heartbeat_server.cpp       | 10 ++--
 be/test/agent/heartbeat_server_test.cpp | 91 +++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/be/src/agent/heartbeat_server.cpp 
b/be/src/agent/heartbeat_server.cpp
index a3ee995020e..dd9ed4358a2 100644
--- a/be/src/agent/heartbeat_server.cpp
+++ b/be/src/agent/heartbeat_server.cpp
@@ -227,10 +227,9 @@ Status HeartbeatServer::_heartbeat(const TMasterInfo& 
master_info) {
     if (master_info.__isset.token) {
         if (_cluster_info->token == "") {
             _cluster_info->token = master_info.token;
-            LOG(INFO) << "get token. token: " << _cluster_info->token;
+            LOG(INFO) << "get token";
         } else if (_cluster_info->token != master_info.token) {
-            return Status::InternalError("invalid token. local: {}, master: 
{}",
-                                         _cluster_info->token, 
master_info.token);
+            return Status::InternalError("invalid token");
         }
     }
 
@@ -330,10 +329,9 @@ Status HeartbeatServer::_heartbeat(const TMasterInfo& 
master_info) {
     if (master_info.__isset.auth_token) {
         if (_cluster_info->curr_auth_token == "") {
             _cluster_info->curr_auth_token = master_info.auth_token;
-            LOG(INFO) << "set new auth token: " << master_info.auth_token;
+            LOG(INFO) << "set new auth token";
         } else if (_cluster_info->curr_auth_token != master_info.auth_token) {
-            LOG(INFO) << "last auth token: " << _cluster_info->last_auth_token
-                      << "set new auth token: " << master_info.auth_token;
+            LOG(INFO) << "update auth token";
             _cluster_info->last_auth_token = _cluster_info->curr_auth_token;
             _cluster_info->curr_auth_token = master_info.auth_token;
         }
diff --git a/be/test/agent/heartbeat_server_test.cpp 
b/be/test/agent/heartbeat_server_test.cpp
new file mode 100644
index 00000000000..f71e5341f65
--- /dev/null
+++ b/be/test/agent/heartbeat_server_test.cpp
@@ -0,0 +1,91 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "agent/heartbeat_server.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+#include <string>
+
+#include "runtime/cluster_info.h"
+#include "runtime/exec_env.h"
+#include "storage/storage_engine.h"
+#include "util/defer_op.h"
+
+namespace doris {
+
+class HeartbeatLogSink : public google::LogSink {
+public:
+    void send(google::LogSeverity /*severity*/, const char* /*full_filename*/,
+              const char* /*base_filename*/, int /*line*/, const 
google::LogMessageTime& /*time*/,
+              const char* message, std::size_t message_len) override {
+        messages.append(message, message_len);
+    }
+
+    std::string messages;
+};
+
+TEST(HeartbeatServerTest, DoesNotExposeTokens) {
+    
ExecEnv::GetInstance()->set_storage_engine(std::make_unique<StorageEngine>(EngineOptions
 {}));
+    Defer reset_engine([] { 
ExecEnv::GetInstance()->set_storage_engine(nullptr); });
+    ClusterInfo cluster;
+    cluster.cluster_id = 7;
+    HeartbeatServer server(&cluster);
+    TMasterInfo master;
+    master.__set_cluster_id(7);
+    master.__set_epoch(10);
+    TNetworkAddress address;
+    address.__set_hostname("master-a");
+    address.__set_port(9020);
+    master.__set_network_address(address);
+    master.__set_token("heartbeat_cluster_secret");
+
+    HeartbeatLogSink log_sink;
+    google::AddLogSink(&log_sink);
+    Defer remove_log_sink([&] { google::RemoveLogSink(&log_sink); });
+
+    THeartbeatResult result;
+    for (const auto* token :
+         {"heartbeat_auth_secret_a", "heartbeat_auth_secret_b", 
"heartbeat_auth_secret_c"}) {
+        master.__set_auth_token(token);
+        server.heartbeat(result, master);
+        ASSERT_EQ(TStatusCode::OK, result.status.status_code);
+    }
+
+    server.heartbeat(result, master);
+    ASSERT_EQ(TStatusCode::OK, result.status.status_code);
+    EXPECT_EQ("heartbeat_auth_secret_c", cluster.curr_auth_token);
+    EXPECT_EQ("heartbeat_auth_secret_b", cluster.last_auth_token);
+
+    master.__set_token("heartbeat_mismatched_secret");
+    server.heartbeat(result, master);
+    ASSERT_EQ(TStatusCode::INTERNAL_ERROR, result.status.status_code);
+    ASSERT_EQ(1, result.status.error_msgs.size());
+    EXPECT_NE(std::string::npos, 
result.status.error_msgs.front().find("invalid token"));
+    EXPECT_EQ("heartbeat_cluster_secret", cluster.token);
+
+    for (const auto* secret :
+         {"heartbeat_cluster_secret", "heartbeat_mismatched_secret", 
"heartbeat_auth_secret_a",
+          "heartbeat_auth_secret_b", "heartbeat_auth_secret_c"}) {
+        EXPECT_EQ(std::string::npos, log_sink.messages.find(secret));
+        EXPECT_EQ(std::string::npos, 
result.status.error_msgs.front().find(secret));
+    }
+}
+
+} // namespace doris


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to