This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new e3cb203d37 [fix] restore dropped rbac rule for single monitor deletion
(#4269)
e3cb203d37 is described below
commit e3cb203d3789670d36dc9a7c1ccc2a20cea2a5ce
Author: Duansg <[email protected]>
AuthorDate: Fri Aug 7 22:07:34 2026 +0800
[fix] restore dropped rbac rule for single monitor deletion (#4269)
---
.../src/test/resources/sureness.yml | 2 +-
hertzbeat-manager/src/test/resources/sureness.yml | 2 +-
hertzbeat-startup/src/main/resources/sureness.yml | 2 +-
.../startup/security/SurenessResourceRuleTest.java | 165 +++++++++++++++++++++
.../hertzbeat-mysql-iotdb/conf/sureness.yml | 2 +-
.../hertzbeat-mysql-tdengine/conf/sureness.yml | 2 +-
.../conf/sureness.yml | 2 +-
.../conf/sureness.yml | 2 +-
.../conf/sureness.yml | 2 +-
9 files changed, 173 insertions(+), 8 deletions(-)
diff --git a/hertzbeat-e2e/hertzbeat-log-e2e/src/test/resources/sureness.yml
b/hertzbeat-e2e/hertzbeat-log-e2e/src/test/resources/sureness.yml
index 862160a289..6f2a7dbb36 100644
--- a/hertzbeat-e2e/hertzbeat-log-e2e/src/test/resources/sureness.yml
+++ b/hertzbeat-e2e/hertzbeat-log-e2e/src/test/resources/sureness.yml
@@ -25,7 +25,7 @@ resourceRole:
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- - /api/monitor/**===delete==[admin]
+ - /api/monitor/**===delete===[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
diff --git a/hertzbeat-manager/src/test/resources/sureness.yml
b/hertzbeat-manager/src/test/resources/sureness.yml
index 862160a289..6f2a7dbb36 100644
--- a/hertzbeat-manager/src/test/resources/sureness.yml
+++ b/hertzbeat-manager/src/test/resources/sureness.yml
@@ -25,7 +25,7 @@ resourceRole:
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- - /api/monitor/**===delete==[admin]
+ - /api/monitor/**===delete===[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
diff --git a/hertzbeat-startup/src/main/resources/sureness.yml
b/hertzbeat-startup/src/main/resources/sureness.yml
index a3198da74b..04c9b3b739 100644
--- a/hertzbeat-startup/src/main/resources/sureness.yml
+++ b/hertzbeat-startup/src/main/resources/sureness.yml
@@ -25,7 +25,7 @@ resourceRole:
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- - /api/monitor/**===delete==[admin]
+ - /api/monitor/**===delete===[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
diff --git
a/hertzbeat-startup/src/test/java/org/apache/hertzbeat/startup/security/SurenessResourceRuleTest.java
b/hertzbeat-startup/src/test/java/org/apache/hertzbeat/startup/security/SurenessResourceRuleTest.java
new file mode 100644
index 0000000000..40fba97784
--- /dev/null
+++
b/hertzbeat-startup/src/test/java/org/apache/hertzbeat/startup/security/SurenessResourceRuleTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+package org.apache.hertzbeat.startup.security;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import com.usthe.sureness.matcher.util.TirePathTree;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Guards the rbac rules shipped in {@code sureness.yml}.
+ *
+ * <p>Sureness splits every rule on {@code ===} and silently drops any line
that does not
+ * yield exactly three segments, so a rule with a mistyped separator
disappears from the
+ * match tree instead of failing loudly. A dropped rule leaves its endpoint
with no role
+ * requirement at all, which sureness treats as "no restriction" for an
authenticated
+ * caller. These tests assert both that every rule is well formed and that the
rules
+ * protecting destructive endpoints really resolve to the intended roles.
+ */
+class SurenessResourceRuleTest {
+
+ private static final String SEPARATOR = "===";
+
+ private static final int RESOURCE_ROLE_SEGMENTS = 3;
+
+ private static final int EXCLUDED_RESOURCE_SEGMENTS = 2;
+
+ private static List<String> resourceRole;
+
+ private static List<String> excludedResource;
+
+ private static TirePathTree roleTree;
+
+ @BeforeAll
+ @SuppressWarnings("unchecked")
+ static void loadSurenessConfig() throws IOException {
+ try (InputStream in =
SurenessResourceRuleTest.class.getResourceAsStream("/sureness.yml")) {
+ assertNotNull(in, "sureness.yml must be on the classpath");
+ Map<String, Object> document = new Yaml().load(in);
+ resourceRole = (List<String>) document.get("resourceRole");
+ excludedResource = (List<String>) document.get("excludedResource");
+ }
+ assertNotNull(resourceRole, "resourceRole must be present");
+ assertNotNull(excludedResource, "excludedResource must be present");
+
+ roleTree = new TirePathTree();
+ roleTree.buildTree(new LinkedHashSet<>(resourceRole));
+ }
+
+ @Test
+ void everyResourceRoleRuleIsWellFormed() {
+ for (String rule : resourceRole) {
+ assertEquals(RESOURCE_ROLE_SEGMENTS, rule.split(SEPARATOR,
-1).length,
+ "resourceRole rule is silently dropped by sureness, it
needs exactly two '"
+ + SEPARATOR + "' separators: " + rule);
+ }
+ }
+
+ @Test
+ void everyExcludedResourceRuleIsWellFormed() {
+ for (String rule : excludedResource) {
+ assertEquals(EXCLUDED_RESOURCE_SEGMENTS, rule.split(SEPARATOR,
-1).length,
+ "excludedResource rule is silently dropped by sureness, it
needs exactly one '"
+ + SEPARATOR + "' separator: " + rule);
+ }
+ }
+
+ @Test
+ void everyRuleReachesTheMatchTree() {
+ assertEquals(resourceRole.size(), roleTree.getResourceNum(),
+ "a rule was dropped while building the match tree, leaving its
endpoint unprotected");
+ }
+
+ @Test
+ void deletingOneMonitorIsRestrictedToAdmin() {
+ assertEquals("[admin]",
roleTree.searchPathFilterRoles("/api/monitor/1" + SEPARATOR + "delete"));
+ }
+
+ @Test
+ void deletingMonitorsIsRestrictedToAdmin() {
+ assertEquals("[admin]",
roleTree.searchPathFilterRoles("/api/monitors/1" + SEPARATOR + "delete"));
+ }
+
+ @Test
+ void readingMonitorsStaysOpenToEveryRole() {
+ assertEquals("[admin,user,guest]",
roleTree.searchPathFilterRoles("/api/monitors" + SEPARATOR + "get"));
+ }
+
+ /**
+ * The deployment scripts ship their own copies of {@code sureness.yml}; a
rule fixed only
+ * in the packaged file would still leave every container deployment
exposed.
+ *
+ * <p>Each section is checked against its own shape rather than against
"either shape".
+ * The two sections are not interchangeable: {@code resourceRole} takes
+ * {@code api===method===roles} and {@code excludedResource} takes {@code
api===method},
+ * and sureness consults the exclusion tree before it authenticates. A
rule carrying
+ * roles that lands under {@code excludedResource} therefore matches
nothing and quietly
+ * leaves its endpoint unruled, which a check accepting either shape
anywhere would
+ * wave through.
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ void deploymentCopiesCarryWellFormedRules() throws IOException {
+ Path scriptDir = Path.of("..", "script");
+ if (!Files.isDirectory(scriptDir)) {
+ // running outside the source tree, the packaged file asserted
above is all we can see
+ return;
+ }
+ Set<Path> copies;
+ try (Stream<Path> paths = Files.walk(scriptDir)) {
+ copies = paths.filter(path ->
path.getFileName().toString().equals("sureness.yml"))
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+ }
+ assertFalse(copies.isEmpty(), "expected the deployment scripts to ship
sureness.yml copies");
+ for (Path copy : copies) {
+ Map<String, Object> document;
+ try (InputStream in = Files.newInputStream(copy)) {
+ document = new Yaml().load(in);
+ }
+ List<String> copyResourceRole = (List<String>)
document.get("resourceRole");
+ List<String> copyExcludedResource = (List<String>)
document.get("excludedResource");
+ assertNotNull(copyResourceRole, "resourceRole must be present in "
+ copy);
+ assertNotNull(copyExcludedResource, "excludedResource must be
present in " + copy);
+
+ for (String rule : copyResourceRole) {
+ assertEquals(RESOURCE_ROLE_SEGMENTS, rule.split(SEPARATOR,
-1).length,
+ "resourceRole rule is silently dropped by sureness in
" + copy
+ + ", it needs exactly two '" + SEPARATOR + "'
separators: " + rule);
+ }
+ for (String rule : copyExcludedResource) {
+ assertEquals(EXCLUDED_RESOURCE_SEGMENTS, rule.split(SEPARATOR,
-1).length,
+ "excludedResource rule is silently dropped by sureness
in " + copy
+ + ", it needs exactly one '" + SEPARATOR + "'
separator: " + rule);
+ }
+ }
+ }
+}
diff --git a/script/docker-compose/hertzbeat-mysql-iotdb/conf/sureness.yml
b/script/docker-compose/hertzbeat-mysql-iotdb/conf/sureness.yml
index 28936362c9..fe6f8938f9 100644
--- a/script/docker-compose/hertzbeat-mysql-iotdb/conf/sureness.yml
+++ b/script/docker-compose/hertzbeat-mysql-iotdb/conf/sureness.yml
@@ -25,7 +25,7 @@ resourceRole:
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- - /api/monitor/**===delete==[admin]
+ - /api/monitor/**===delete===[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
diff --git a/script/docker-compose/hertzbeat-mysql-tdengine/conf/sureness.yml
b/script/docker-compose/hertzbeat-mysql-tdengine/conf/sureness.yml
index 28936362c9..fe6f8938f9 100644
--- a/script/docker-compose/hertzbeat-mysql-tdengine/conf/sureness.yml
+++ b/script/docker-compose/hertzbeat-mysql-tdengine/conf/sureness.yml
@@ -25,7 +25,7 @@ resourceRole:
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- - /api/monitor/**===delete==[admin]
+ - /api/monitor/**===delete===[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
diff --git
a/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/sureness.yml
b/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/sureness.yml
index 28936362c9..fe6f8938f9 100644
--- a/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/sureness.yml
+++ b/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/sureness.yml
@@ -25,7 +25,7 @@ resourceRole:
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- - /api/monitor/**===delete==[admin]
+ - /api/monitor/**===delete===[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
diff --git
a/script/docker-compose/hertzbeat-postgresql-greptimedb/conf/sureness.yml
b/script/docker-compose/hertzbeat-postgresql-greptimedb/conf/sureness.yml
index ee2e532df0..2d6b4441ee 100644
--- a/script/docker-compose/hertzbeat-postgresql-greptimedb/conf/sureness.yml
+++ b/script/docker-compose/hertzbeat-postgresql-greptimedb/conf/sureness.yml
@@ -25,7 +25,7 @@ resourceRole:
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- - /api/monitor/**===delete==[admin]
+ - /api/monitor/**===delete===[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
diff --git
a/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/sureness.yml
b/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/sureness.yml
index 28936362c9..fe6f8938f9 100644
---
a/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/sureness.yml
+++
b/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/sureness.yml
@@ -25,7 +25,7 @@ resourceRole:
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- - /api/monitor/**===delete==[admin]
+ - /api/monitor/**===delete===[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]