towerops/test/towerops_web/controllers/health_controller_test.exs
Graham McIntire abfd44fd75 fix: 3 more high-severity bugs (H19, H20, H25)
- H19: /api/v1/mobile/auth/qr/verify no longer returns user_email. Knowing
  a QR token now only tells the caller the token is valid; the email is
  only revealed by /complete which consumes the token.
- H20: CoverageWorker max_attempts dropped from 3 to 1. The fail/2 path
  already returns :ok and writes the failure onto the coverage record,
  so the 3-attempt retry policy was never reachable and was misleading.
- H25: ChecksController.create rejects device_ids that don't belong to
  the caller's organization (via ScopedResource.fetch). Without this an
  API token could attach service checks to devices in another tenant.

Also strip bug ID references from in-code comments (per feedback that
H/M/L numbers don't survive past their bugs.md removal); commit history
keeps the audit trail.
2026-05-12 11:32:20 -05:00

78 lines
2.9 KiB
Elixir

defmodule ToweropsWeb.HealthControllerTest do
use ToweropsWeb.ConnCase, async: false
describe "GET /health" do
test "returns 200 when database is connected", %{conn: conn} do
conn = get(conn, "/health")
body = response(conn, 200)
result = Jason.decode!(body)
assert result["status"] == "ok"
assert result["database"] == "connected"
# `version` deliberately omitted: exposing the app version on a
# public health endpoint helps attackers fingerprint vulnerable builds.
refute Map.has_key?(result, "version")
end
test "reports redis status as not_configured when redis is not configured", %{conn: conn} do
previous = Application.get_env(:towerops, :redis)
Application.put_env(:towerops, :redis, [])
try do
conn = get(conn, "/health")
result = Jason.decode!(response(conn, 200))
assert result["redis"] == "not_configured"
after
if previous do
Application.put_env(:towerops, :redis, previous)
else
Application.delete_env(:towerops, :redis)
end
end
end
test "reports redis as connected when configured to a real instance", %{conn: conn} do
previous = Application.get_env(:towerops, :redis)
Application.put_env(:towerops, :redis, host: "localhost", port: 6379)
try do
conn = get(conn, "/health")
# Either 200 (redis up) or 503 (redis unreachable in CI) — both branches
# exercise the configured-redis code path. We just assert the response
# is well-formed JSON with a redis field.
body = response(conn, conn.status)
result = Jason.decode!(body)
assert result["redis"] in ["connected", "disconnected"]
after
if previous do
Application.put_env(:towerops, :redis, previous)
else
Application.delete_env(:towerops, :redis)
end
end
end
test "returns 503 when redis is configured but unreachable", %{conn: conn} do
previous = Application.get_env(:towerops, :redis)
# Point at a closed port on a routable but unreachable address.
# 198.51.100.0/24 is TEST-NET-2 (RFC 5737) — guaranteed not routable on the public internet.
Application.put_env(:towerops, :redis, host: "198.51.100.1", port: 1, timeout: 50)
try do
conn = get(conn, "/health")
# Expect 503 with redis disconnected
body = response(conn, 503)
result = Jason.decode!(body)
assert result["status"] == "error"
# Database is still connected in tests — exercises db_status_string(:ok)
assert result["database"] == "connected"
assert result["redis"] == "disconnected"
after
if previous do
Application.put_env(:towerops, :redis, previous)
else
Application.delete_env(:towerops, :redis)
end
end
end
end
end