Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
"""Tests for shared-metrics send configuration resolution."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from hermes_cli.config import DEFAULT_CONFIG
|
||||
from hermes_cli.observability.shared_metrics_send_config import (
|
||||
DEFAULT_ENDPOINT,
|
||||
resolve_send_config,
|
||||
reset_warning_latch_for_tests,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset_latch():
|
||||
reset_warning_latch_for_tests()
|
||||
yield
|
||||
reset_warning_latch_for_tests()
|
||||
|
||||
|
||||
def _config(**shared):
|
||||
return {"telemetry": {"shared_metrics": shared}}
|
||||
|
||||
|
||||
class TestDefaults:
|
||||
def test_send_is_registered_disabled_by_default(self):
|
||||
shared = DEFAULT_CONFIG["telemetry"]["shared_metrics"]
|
||||
assert shared["enabled"] is False
|
||||
assert shared["send"] is False
|
||||
|
||||
def test_default_endpoint_is_production(self):
|
||||
shared = DEFAULT_CONFIG["telemetry"]["shared_metrics"]
|
||||
assert shared["endpoint"] == DEFAULT_ENDPOINT
|
||||
assert DEFAULT_ENDPOINT.startswith("https://")
|
||||
|
||||
def test_empty_config_sends_nothing(self):
|
||||
resolved = resolve_send_config({})
|
||||
assert resolved.enabled is False
|
||||
assert resolved.send is False
|
||||
|
||||
def test_none_config_is_tolerated(self):
|
||||
assert resolve_send_config(None).send is False
|
||||
|
||||
|
||||
class TestSendRequiresCollection:
|
||||
def test_collection_alone_does_not_send(self):
|
||||
resolved = resolve_send_config(_config(enabled=True))
|
||||
assert resolved.enabled is True
|
||||
assert resolved.send is False
|
||||
|
||||
def test_send_with_collection_sends(self):
|
||||
resolved = resolve_send_config(_config(enabled=True, send=True))
|
||||
assert resolved.send is True
|
||||
|
||||
def test_send_without_collection_is_refused(self):
|
||||
resolved = resolve_send_config(_config(enabled=False, send=True))
|
||||
assert resolved.send is False
|
||||
# send must never imply enabled
|
||||
assert resolved.enabled is False
|
||||
|
||||
def test_send_without_collection_logs_an_error(self, caplog):
|
||||
with caplog.at_level(logging.ERROR):
|
||||
resolve_send_config(_config(enabled=False, send=True))
|
||||
errors = [r for r in caplog.records if r.levelno >= logging.ERROR]
|
||||
assert len(errors) == 1
|
||||
assert "enabled is false" in errors[0].getMessage()
|
||||
|
||||
def test_the_error_is_logged_once_per_process(self, caplog):
|
||||
with caplog.at_level(logging.ERROR):
|
||||
for _ in range(5):
|
||||
resolve_send_config(_config(enabled=False, send=True))
|
||||
errors = [r for r in caplog.records if r.levelno >= logging.ERROR]
|
||||
assert len(errors) == 1, "misconfiguration must not spam every hook fire"
|
||||
|
||||
|
||||
class TestEndpointPrecedence:
|
||||
def test_config_endpoint_overrides_default(self):
|
||||
resolved = resolve_send_config(
|
||||
_config(enabled=True, send=True, endpoint="https://example.test/v1")
|
||||
)
|
||||
assert resolved.endpoint == "https://example.test/v1"
|
||||
|
||||
def test_no_environment_variable_can_redirect_telemetry(self, monkeypatch):
|
||||
"""A consent hazard: an inherited env var must not silently retarget.
|
||||
|
||||
AGENTS.md also reserves HERMES_* for secrets, not behaviour.
|
||||
"""
|
||||
for name in (
|
||||
"HERMES_TELEMETRY_ENDPOINT",
|
||||
"TELEMETRY_ENDPOINT",
|
||||
"HERMES_SHARED_METRICS_ENDPOINT",
|
||||
):
|
||||
monkeypatch.setenv(name, "https://attacker.test/v1")
|
||||
resolved = resolve_send_config(_config(enabled=True, send=True))
|
||||
assert resolved.endpoint == DEFAULT_ENDPOINT
|
||||
|
||||
def test_blank_endpoint_falls_back_to_production(self):
|
||||
resolved = resolve_send_config(_config(enabled=True, send=True, endpoint=" "))
|
||||
assert resolved.endpoint == DEFAULT_ENDPOINT
|
||||
|
||||
def test_endpoint_is_stripped(self):
|
||||
resolved = resolve_send_config(
|
||||
_config(enabled=True, send=True, endpoint=" https://staging.test/v1 ")
|
||||
)
|
||||
assert resolved.endpoint == "https://staging.test/v1"
|
||||
|
||||
|
||||
class TestTransportSafety:
|
||||
def test_plaintext_endpoint_is_refused(self, caplog):
|
||||
with caplog.at_level(logging.ERROR):
|
||||
resolved = resolve_send_config(
|
||||
_config(enabled=True, send=True, endpoint="http://example.test/v1")
|
||||
)
|
||||
assert resolved.send is False, "telemetry must not go out in clear text"
|
||||
assert any("https" in r.getMessage() for r in caplog.records)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"endpoint",
|
||||
[
|
||||
"http://localhost:8099/v1/telemetry",
|
||||
"http://127.0.0.1:8099/v1/telemetry",
|
||||
],
|
||||
)
|
||||
def test_loopback_http_is_allowed_for_testing(self, endpoint):
|
||||
resolved = resolve_send_config(
|
||||
_config(enabled=True, send=True, endpoint=endpoint)
|
||||
)
|
||||
assert resolved.send is True
|
||||
|
||||
def test_nonsense_scheme_is_refused(self):
|
||||
resolved = resolve_send_config(
|
||||
_config(enabled=True, send=True, endpoint="ftp://example.test/v1")
|
||||
)
|
||||
assert resolved.send is False
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"endpoint",
|
||||
[
|
||||
"ftp://localhost/v1/telemetry",
|
||||
"gopher://localhost/v1/telemetry",
|
||||
"ws://127.0.0.1/v1/telemetry",
|
||||
],
|
||||
)
|
||||
def test_a_non_http_scheme_on_loopback_is_still_refused(self, endpoint):
|
||||
"""The scheme is allowlisted, not merely checked for plaintext http.
|
||||
|
||||
Gap found by mutation testing: replacing the `http` scheme test with
|
||||
`if True` survived the whole suite, because every non-http scheme case
|
||||
pointed at a REMOTE host, where the loopback branch rejects it anyway.
|
||||
Only a non-http scheme aimed at loopback distinguishes an allowlist
|
||||
from a plaintext-only check.
|
||||
"""
|
||||
resolved = resolve_send_config(
|
||||
_config(enabled=True, send=True, endpoint=endpoint)
|
||||
)
|
||||
assert resolved.send is False
|
||||
|
||||
def test_unsafe_endpoint_does_not_block_collection(self):
|
||||
resolved = resolve_send_config(
|
||||
_config(enabled=True, send=True, endpoint="http://example.test/v1")
|
||||
)
|
||||
assert resolved.enabled is True
|
||||
Reference in New Issue
Block a user