You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SecuScan's backend exposes a /health route but it returns a minimal
response with no dependency status checks. This feature upgrades the
health endpoint to return a structured JSON response that includes
the status of all critical dependencies (database, cache, plugin
registry) with latency measurements, making it suitable for use as
a Docker/compose healthcheck, a load balancer probe, and a developer
diagnostics tool.
Problem
The current /health endpoint returns a static {"status": "ok"}
regardless of the actual state of the system. This means:
docker compose healthchecks pass even when the database is
unreachable or the plugin registry failed to initialise
Developers have no fast way to confirm all subsystems are
operational without tailing logs
There is no structured way for monitoring tools or CI pipelines
to assert that a deployed SecuScan instance is fully functional
The endpoint does not surface partial degradation — a working
API with a broken cache is indistinguishable from a fully healthy
instance
Proposed Solution
Backend (backend/secuscan/routes.py) — modify:
Upgrade GET /api/v1/health to perform active dependency probes
and return a structured response:
Store _start_time = time.time() at application startup and
expose it for the health route to compute uptime_seconds.
No frontend changes required.
Suggested Scope
Suggested files or directories:
backend/secuscan/routes.py — upgrade GET /health route
backend/secuscan/main.py — add startup timestamp
docker-compose.yml — update api healthcheck
backend/tests/test_health.py (new) — unit tests
Related route, page, component, API, or plugin:
GET /api/v1/health (existing, upgrade)
database.py — get_db() used for DB probe
cache.py — get_cache() used for cache probe
plugins.py — get_plugin_manager() for plugin probe
Acceptance Criteria
GET /api/v1/health returns structured JSON with status, version, uptime_seconds, and checks fields
Database probe executes SELECT 1 and records latency in ms
Cache probe pings the cache and records latency in ms
Plugin probe counts total and runnable plugins
All three probes run concurrently via asyncio.gather
Response is 200 when status is healthy or degraded
Response is 503 when status is unhealthy (DB probe fails)
uptime_seconds reflects actual time since application start
docker-compose.yml healthcheck uses the new endpoint
Unit tests cover: all-healthy, DB-down (unhealthy),
cache-down (degraded), plugin-error (degraded)
Test Plan
Start the full stack with docker compose up — confirm docker inspect shows the api container as healthy
Call GET /api/v1/health — confirm structured JSON response
with all checks passing and status: healthy
Stop the database container — call the endpoint again and
confirm status: unhealthy and HTTP 503
Stop only the Redis container — confirm status: degraded
and HTTP 200 with checks.cache.status: error
Run test_health.py — all unit tests pass
Alternatives Considered
Using a third-party health-check library (e.g. fastapi-health):
Adds a dependency for functionality that is straightforwardly
implementable with asyncio.gather and the existing database/cache
abstractions already in the codebase.
Separate /readiness and /liveness endpoints (Kubernetes style):
Out of scope for a local-first tool. A single /health endpoint
with a structured checks object is sufficient and simpler for
compose and developer use.
Returning 503 for degraded state: Degraded means the API is
still serving requests — returning 503 would cause load balancers
to stop routing traffic unnecessarily. Only a DB failure warrants
503 since the API cannot function without it.
The structured response is designed to be forward-compatible:
new dependency checks (e.g. vault, workflows scheduler) can
be added to the checks object without breaking existing
consumers
Summary
SecuScan's backend exposes a
/healthroute but it returns a minimalresponse with no dependency status checks. This feature upgrades the
health endpoint to return a structured JSON response that includes
the status of all critical dependencies (database, cache, plugin
registry) with latency measurements, making it suitable for use as
a Docker/compose healthcheck, a load balancer probe, and a developer
diagnostics tool.
Problem
The current
/healthendpoint returns a static{"status": "ok"}regardless of the actual state of the system. This means:
docker composehealthchecks pass even when the database isunreachable or the plugin registry failed to initialise
operational without tailing logs
to assert that a deployed SecuScan instance is fully functional
API with a broken cache is indistinguishable from a fully healthy
instance
Proposed Solution
Backend (
backend/secuscan/routes.py) — modify:Upgrade
GET /api/v1/healthto perform active dependency probesand return a structured response:
{ "status": "healthy" | "degraded" | "unhealthy", "version": "4.5.3-BETA", "uptime_seconds": 3412, "checks": { "database": { "status": "ok" | "error", "latency_ms": 2.4, "detail": null | "<error message>" }, "cache": { "status": "ok" | "error", "latency_ms": 0.8, "detail": null | "<error message>" }, "plugins": { "status": "ok" | "error", "total": 12, "runnable": 10, "detail": null | "<error message>" } } }Status rules:
healthy— all checks passdegraded— cache or plugins check fails but database is okunhealthy— database check failsHTTP status codes:
200forhealthyanddegraded503forunhealthyImplementation:
SELECT 1with a 2s timeout, measure latencycache.ping()or equivalent with a 1s timeoutplugin_manager.list_plugins()and countrunnable vs total — no timeout needed (in-memory)
asyncio.gather(return_exceptions=True)main.pyis used to computeuptime_secondsdocker-compose.yml— modify:Update the
apiservice healthcheck to use the new endpoint:backend/secuscan/main.py— modify:Store
_start_time = time.time()at application startup andexpose it for the health route to compute
uptime_seconds.No frontend changes required.
Suggested Scope
Suggested files or directories:
backend/secuscan/routes.py— upgradeGET /healthroutebackend/secuscan/main.py— add startup timestampdocker-compose.yml— update api healthcheckbackend/tests/test_health.py(new) — unit testsRelated route, page, component, API, or plugin:
GET /api/v1/health(existing, upgrade)database.py—get_db()used for DB probecache.py—get_cache()used for cache probeplugins.py—get_plugin_manager()for plugin probeAcceptance Criteria
GET /api/v1/healthreturns structured JSON withstatus,version,uptime_seconds, andchecksfieldsSELECT 1and records latency in msasyncio.gather200when status ishealthyordegraded503when status isunhealthy(DB probe fails)uptime_secondsreflects actual time since application startdocker-compose.ymlhealthcheck uses the new endpointcache-down (degraded), plugin-error (degraded)
Test Plan
docker compose up— confirmdocker inspectshows the api container as healthyGET /api/v1/health— confirm structured JSON responsewith all checks passing and
status: healthyconfirm
status: unhealthyand HTTP 503status: degradedand HTTP 200 with
checks.cache.status: errortest_health.py— all unit tests passAlternatives Considered
fastapi-health):Adds a dependency for functionality that is straightforwardly
implementable with
asyncio.gatherand the existing database/cacheabstractions already in the codebase.
/readinessand/livenessendpoints (Kubernetes style):Out of scope for a local-first tool. A single
/healthendpointwith a structured
checksobject is sufficient and simpler forcompose and developer use.
still serving requests — returning 503 would cause load balancers
to stop routing traffic unnecessarily. Only a DB failure warrants
503 since the API cannot function without it.
Additional Context
healthcheck requires a reliable health endpoint to probe
new dependency checks (e.g. vault, workflows scheduler) can
be added to the
checksobject without breaking existingconsumers
level:advanced,type:feature,type:devops,area:backend