fix(config): allow underscore-prefixed internal/test keys past schema validation

The schema validation added in this PR (#34250) rejected underscore-
prefixed config keys like '_test.shim_marker', breaking the Docker
privilege-drop test suite (tests/docker/test_docker_exec_privilege_drop.py)
which writes such markers via 'hermes config set _test.<marker> 1' to
probe config.yaml file ownership after the UID-drop shim runs.

Ten Docker tests failed in build-amd64 CI for this reason:
  test_shim_drops_root_to_hermes_uid       (_test.shim_marker)
  test_shim_short_circuits_for_non_root    (_test.shim_short_circuit)
  test_shim_opt_out_keeps_root             (_test.opt_out)
  test_shim_opt_out_strict_truthiness[*]   (_test.falsy)  x6
  test_e2e_login_then_supervised_gateway   (_test.e2e_marker)

Fix: treat a leading underscore on the TOP-LEVEL segment as an
internal/test marker that bypasses schema validation. Mirrors Python's
own '_private' convention. The escape is narrow:

  - Only the first segment is checked, so a genuine typo in a sub-key
    under a known top-level key (e.g. 'agent._max_turns') is still
    flagged.
  - Real typos ('agent.max_turn' -> 'agent.max_turns') still caught.
  - The headline #34067 bug ('gateway.discord.gateway_restart_notification')
    still caught.

Tests (5 new in TestValidateConfigKey):
  - 4 parametrized cases for accepted underscore-prefixed keys
    (_test.shim_marker, _internal, _test.nested.deep.marker, _x)
  - test_underscore_only_first_segment_escapes: confirms agent._max_turns
    (underscore in a SUB-key, not the top) is still rejected.

All 58 tests in test_set_config_value.py pass.

Refs: #34067 #34250

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Bartok9 2026-05-29 01:13:04 -04:00 committed by Teknium
parent fd19e8bb48
commit 477274f1d9
2 changed files with 36 additions and 0 deletions

View file

@ -8645,6 +8645,20 @@ def _validate_config_key(key: str) -> tuple[bool, Optional[str]]:
segments = key.split(".")
top = segments[0]
# ── Underscore-prefixed keys are internal/test markers ───────────
# A leading underscore on the top-level segment (e.g. ``_test.shim_marker``)
# signals an intentionally non-schema, internal key. Test harnesses and
# tooling use these to write a deterministic marker into config.yaml
# without polluting the user-facing schema (see the Docker privilege-drop
# shim test, which writes ``_test.shim_marker`` to probe file ownership).
# Python's own convention treats a leading underscore as "private"; we
# honour that here so schema validation never blocks deliberately-internal
# keys. This is narrow: only the FIRST segment is checked, so a real typo
# like ``agent._max_turns`` still gets caught at the sub-key level.
if top.startswith("_"):
return True, None
known = _known_top_level_keys()
# ── First-segment validation ─────────────────────────────────────

View file

@ -587,3 +587,25 @@ class TestValidateConfigKey:
if expected_in_suggestion is not None:
assert suggestion is not None and expected_in_suggestion in suggestion, \
f"Expected suggestion to contain {expected_in_suggestion!r}, got {suggestion!r}"
@pytest.mark.parametrize("key", [
"_test.shim_marker",
"_internal",
"_test.nested.deep.marker",
"_x",
])
def test_underscore_prefixed_keys_are_accepted(self, key):
"""Underscore-prefixed top-level keys are internal/test markers and
bypass schema validation. The Docker privilege-drop shim test writes
``_test.shim_marker`` to probe config.yaml ownership; that must not
be rejected. (Regression: #34250 schema validation broke this.)"""
from hermes_cli.config import _validate_config_key
is_known, _ = _validate_config_key(key)
assert is_known, f"Expected underscore-prefixed {key!r} to be accepted"
def test_underscore_only_first_segment_escapes(self):
"""The underscore escape only applies to the FIRST segment. A real
typo in a sub-key (e.g. agent._max_turns) is still caught."""
from hermes_cli.config import _validate_config_key
is_known, suggestion = _validate_config_key("agent._max_turns")
assert not is_known, "Sub-key typo under a known top-level key must still be flagged"