diff --git a/.github/scripts/commit_prefix_check.py b/.github/scripts/commit_prefix_check.py
index b8c14c2e3c5..a345a60eced 100644
--- a/.github/scripts/commit_prefix_check.py
+++ b/.github/scripts/commit_prefix_check.py
@@ -62,18 +62,28 @@ def infer_prefix_from_paths(paths):
component_prefixes.add(f"{parts[1]}:")
# ----- src/ → flb_xxx.* → xxx: OR src/
/ → : -----
- # ----- src/fluent-bit.c → bin: -----
+ # ----- src/ handling -----
if p.startswith("src/"):
+ parts = p.split("/")
filename = os.path.basename(p)
- if filename.startswith("flb_"):
+
+ # src/fluent-bit.c → bin:
+ if filename == "fluent-bit.c":
+ component_prefixes.add("bin:")
+ continue
+
+ # src/flb_xxx.c → xxx:
+ if len(parts) == 2 and filename.startswith("flb_"):
core = filename[4:].split(".")[0]
component_prefixes.add(f"{core}:")
- elif filename == "fluent-bit.c":
- component_prefixes.add("bin:")
- else:
- parts = p.split("/")
- if len(parts) > 1:
- component_prefixes.add(f"{parts[1]}:")
+ continue
+
+ # src//... → :
+ if len(parts) > 2:
+ src_dir = parts[1]
+ component_prefixes.add(f"{src_dir}:")
+ continue
+
# prefixes = component prefixes + build: if needed
prefixes |= component_prefixes
@@ -170,6 +180,23 @@ def validate_commit(commit):
expected_lower = {p.lower() for p in expected}
subj_lower = subject_prefix.lower()
+
+ # ------------------------------------------------
+ # config_format conditional umbrella rule
+ # ------------------------------------------------
+ if "config_format:" in expected_lower:
+ non_build = {
+ p for p in expected_lower
+ if p not in ("build:", "cmakelists.txt:")
+ }
+
+ # Allow ONLY if all non-build prefixes are config_format:
+ if non_build != {"config_format:"}:
+ return False, (
+ f"Subject prefix '{subject_prefix}' does not match files changed.\n"
+ f"config_format commits must not include other components."
+ )
+
# ------------------------------------------------
# Multiple-component detection
# ------------------------------------------------
diff --git a/.github/scripts/tests/test_commit_lint.py b/.github/scripts/tests/test_commit_lint.py
index ec6b9982a03..0496e3ed641 100644
--- a/.github/scripts/tests/test_commit_lint.py
+++ b/.github/scripts/tests/test_commit_lint.py
@@ -622,6 +622,75 @@ def test_valid_config_file_changes():
ok, _ = validate_commit(commit)
assert ok is True
+# -----------------------------------------------------------
+# config_format strict rules
+# -----------------------------------------------------------
+
+def test_valid_config_format_commit():
+ """
+ When files under src/config_format are modified, the subject MUST use
+ the umbrella prefix 'config_format:'.
+
+ This ensures config_format is treated as a logical subsystem rather than
+ exposing internal implementation names (cf_yaml, cf_fluentbit, etc.)
+ in commit subjects.
+ """
+ commit = make_commit(
+ "config_format: cf_yaml: fix include resolution\n\nSigned-off-by: User",
+ ["src/config_format/flb_cf_yaml.c"]
+ )
+ ok, _ = validate_commit(commit)
+ assert ok is True
+
+
+def test_error_cf_yaml_prefix_not_allowed():
+ """
+ Internal implementation prefixes like 'cf_yaml:' must NOT be allowed
+ as commit subjects when modifying src/config_format.
+
+ The umbrella prefix 'config_format:' must be used instead.
+ """
+ commit = make_commit(
+ "cf_yaml: fix include resolution\n\nSigned-off-by: User",
+ ["src/config_format/flb_cf_yaml.c"]
+ )
+ ok, msg = validate_commit(commit)
+ assert ok is False
+ assert "config_format:" in msg
+
+
+def test_error_yaml_prefix_not_allowed():
+ """
+ Generic implementation prefixes like 'yaml:' must NOT be allowed
+ for src/config_format changes.
+
+ This prevents leaking format-specific implementation details into
+ commit history.
+ """
+ commit = make_commit(
+ "yaml: fix include resolution\n\nSigned-off-by: User",
+ ["src/config_format/flb_cf_yaml.c"]
+ )
+ ok, msg = validate_commit(commit)
+ assert ok is False
+ assert "config_format:" in msg
+
+
+def test_valid_config_format_multiple_files():
+ """
+ Modifying multiple files under src/config_format should still require
+ the 'config_format:' umbrella prefix.
+ """
+ commit = make_commit(
+ "config_format: refactor include handling\n\nSigned-off-by: User",
+ [
+ "src/config_format/flb_cf_yaml.c",
+ "src/config_format/flb_cf_fluentbit.c",
+ ]
+ )
+ ok, _ = validate_commit(commit)
+ assert ok is True
+
# -----------------------------------------------------------
# Additional Tests: validate_commit Complex Scenarios