Files
han-app/VM2_services/codebase/services/tests/test_observability_infrastructure.py

122 lines
4.3 KiB
Python

from __future__ import annotations
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def read(relative: str) -> str:
return (ROOT / relative).read_text(encoding="utf-8")
def service_block(compose: str, name: str) -> str:
match = re.search(
rf"^ {re.escape(name)}:\n(?P<body>(?:^(?: |\s*$).*\n?)*)",
compose,
re.MULTILINE,
)
assert match, f"missing Compose service {name}"
return match.group("body")
def test_collector_has_only_approved_prometheus_targets() -> None:
config = read("observability/otel-collector.yaml")
targets = re.findall(r'targets: \["([^"]+)"\]', config)
assert targets == [
"127.0.0.1:8888",
"redis-exporter:9121",
"nginx-exporter:9113",
]
assert "service_name: otel-collector" in config
assert "service_name: redis" in config
assert "service_name: nginx" in config
assert "hostmetrics:" in config
assert "service.namespace, value: han-chat" in config
assert "filter/noise:" in config
assert "tail_sampling:" in config
def test_logs_are_direct_otlp_without_filelog() -> None:
config = read("observability/otel-collector.yaml")
logs = config.split(" logs:\n", 1)[1]
assert "receivers: [otlp]" in logs
assert "otlp/remote" in logs
assert "filelog" not in config
def test_apps_receive_release_and_logging_context() -> None:
compose = read("docker-compose.yml")
assert compose.count("RELEASE_VERSION: ${RELEASE_VERSION:?set RELEASE_VERSION}") >= 3
assert compose.count("LOG_LEVEL: ${LOG_LEVEL:-INFO}") == 2
def test_collector_exposes_health_and_self_metrics_and_validates_config() -> None:
compose = read("docker-compose.yml")
collector = service_block(compose, "otel-collector")
assert 'expose: ["4317", "4318", "13133", "8888"]' in collector
assert '"/otelcol-contrib", "validate"' in collector
def test_exporters_are_internal_only_and_digest_pinned() -> None:
compose = read("docker-compose.yml")
for name, port in (("redis-exporter", "9121"), ("nginx-exporter", "9113")):
block = service_block(compose, name)
assert f'expose: ["{port}"]' in block
assert "\n ports:" not in block
assert "observability" in block
assert "${REDIS_EXPORTER_IMAGE:?set immutable Redis exporter image digest}" in compose
assert "${NGINX_EXPORTER_IMAGE:?set immutable nginx exporter image digest}" in compose
def test_nginx_status_is_internal_and_query_free() -> None:
template = read("nginx/templates/10-vm2.conf.template")
status = template.split("location = /stub_status", 1)[1].split("}", 1)[0]
assert "stub_status;" in status
assert "access_log off;" in status
assert "listen 8081;" in template
assert ":8081:8081" not in read("docker-compose.yml")
def test_redis_exporter_uses_restricted_acl_and_secret_file() -> None:
acl = read("redis/redis-safety.acl.template")
compose = read("docker-compose.yml")
secret_config = json.loads(read("deployment/secrets/config.example.json"))
exporter_line = next(line for line in acl.splitlines() if line.startswith("user exporter "))
assert "-@all +ping +info" in exporter_line
assert "~*" not in exporter_line
assert "REDIS_PASSWORD_FILE: /run/secrets/redis_exporter_password" in compose
assert secret_config["secrets"]["REDIS_EXPORTER_PASSWORD"]["consumers"] == [
"redis-exporter"
]
def test_self_hosted_signoz_does_not_require_fake_auth() -> None:
collector = read("observability/otel-collector.yaml")
env_example = read(".env.example")
assert "OTEL_REMOTE_AUTH" not in collector
assert "OTEL_REMOTE_AUTH" not in env_example
assert "headers:" not in collector
def test_preflight_covers_observability_images_and_acl_pair() -> None:
preflight = read("deployment/preflight.sh")
assert "REDIS_EXPORTER_IMAGE NGINX_EXPORTER_IMAGE" in preflight
assert "REDIS_EXPORTER_PASSWORD" in preflight
assert 'target = "redis://redis-safety:6379"' in preflight
assert "Redis exporter password map does not match REDIS_SAFETY_ACL" in preflight
assert "Collector must enforce service.namespace=han-chat" in preflight
assert "Collector direct OTLP logs pipeline is missing" in preflight
assert "Collector filelog receiver is forbidden" in preflight