Skip to content

Latest commit

 

History

History
234 lines (183 loc) · 9.43 KB

File metadata and controls

234 lines (183 loc) · 9.43 KB
title RADAR REST API
description Read-only JSON over the latest stored inventory report and assessment report. Base URL in local dev: http://127.0.0.1:8080. No authentication (cluster-internal service; expose via Sunbeam Proxy if...

RADAR REST API

Read-only JSON over the latest stored inventory report and assessment report. Base URL in local dev: http://127.0.0.1:8080. No authentication (cluster-internal service; expose via Sunbeam Proxy if needed — see docs/KUBERNETES.md).

Dashboard

GET /

When RADAR_DASHBOARD_ENABLED is true (the default), the API serves a human-readable landing page at the root path. It renders each tracked component, its current and latest versions, risk assessment, dry-run status, and an emoji status indicator, styled with the Beam dark theme. The page fetches /api/v1/components, /api/v1/assessments, and /api/v1/dryruns client-side.

Each table header has a dropdown menu for sorting. The default sort is assessment severity (most-urgent first), then component name; select ascending/descending order or a specific value from the dropdown. Components with a dry-run status show a show output button that opens a modal preview of the namespace's dry-run output; the preview includes a link to the full /output?namespace=<ns> page.

If RADAR_GRAFANA_URL is set, a Grafana icon appears in the page header and links to that URL.

When the dashboard is disabled, GET / returns 404 {"error":"not found"} like any unknown path.

Probes

Endpoint Purpose Success Failure
GET /__lbheartbeat__ Liveness (cluster contract) 200 ok (text)
GET /__heartbeat__ Readiness — checks store reachability 200 ok (text) 503 unavailable
GET /health JSON health summary 200 {"status":"ok",…} 503 {"status":"error",…}
GET /metrics Prometheus text metrics 200 (text/plain)

Inventory

GET /api/v1/inventory

The full latest report.

{
  "generated_at": "2026-08-22 01:00:38 UTC",
  "components": [{ "name": "Gateway API CRDs", "…": "" }]
}

404 {"error":"no inventory yet — run the radar job first"} before the first run.

GET /api/v1/components

The latest report's component records as a flat array (record shape: docs/SCHEMA.md).

GET /api/v1/components/{name}

One component record. name is URL-encoded and matched exactly (e.g. /api/v1/components/Scaleway%20cert-manager%20webhook).

{
  "name": "Cert-manager",
  "namespace": "cert-manager",
  "current": "1.19.4",
  "latest": "v1.21.1",
  "source": "helm_chart",
  "upstream": "https://charts.jetstack.io::cert-manager",
  "link_template": "https://github.com/cert-manager/cert-manager/releases/tag/{app_version}",
  "notes": "Helm chart 1.19.4",
  "update_available": true,
  "chart_version": "1.19.4",
  "track_app_version": true
}

404 {"error":"component not found: {name}"} when absent.

Assessments

The assess job (pipeline step 2 — see docs/ARCHITECTURE.md) attaches one assessment report to the latest inventory run; these endpoints serve it (record shape: docs/SCHEMA.md).

GET /api/v1/assessments

The full latest assessment report. Optional ?risk_level= narrows assessments to one risk level.

{
  "generated_at": "2026-08-22 01:30:12 UTC",
  "inventory_generated_at": "2026-08-22 01:00:38 UTC",
  "assessments": [{ "name": "Cert-manager", "risk_level": "breaking", "…": "" }]
}

inventory_generated_at is the generated_at of the inventory run the assessments were computed from. 404 {"error":"no assessments yet — run the radar assess job first"} before the first assess run; 400 {"error":"invalid risk_level: … (expected one of …)"} when the filter value isn't a known risk level.

Risk levels: breaking, deprecated, eol_warning, false_positive, floating_tag, custom_fork, review, unknown, likely_safe, non_applicable. Assessments are sorted most-urgent-first in exactly that order.

GET /api/v1/assessments/{name}

One assessment record. name is URL-encoded and matched exactly, like the component endpoints.

{
  "name": "Cert-manager",
  "current": "v1.19.4",
  "latest": "v2.0.0",
  "risk_level": "breaking",
  "reason": "Major version bump: 1.19.4 → 2.0.0",
  "action": "Read migration guide before upgrading",
  "layer": "layer_0_precheck",
  "details": { "from": "v1.19.4", "to": "v2.0.0" }
}

layer names the analysis layer that produced the verdict; details carries layer-specific evidence. 404 {"error":"assessment not found: {name}"} when absent.

Dry-runs

The dry-run job (pipeline step 3 — see docs/ARCHITECTURE.md) attaches one dry-run report to the latest assessed inventory run; these endpoints serve it.

Dry-runs are grouped by Kubernetes namespace: all drifted likely_safe Helm components in a namespace are bumped to latest together, the namespace is rendered once, and kubectl apply --dry-run=server is run once. The resulting record covers every component whose chart was mutated in that namespace, and all of them share the same status, stdout, and stderr.

GET /api/v1/dryruns

The full latest dry-run report. Optional ?status= narrows dry_runs to one status, and optional ?namespace= returns only the dry-run for that namespace (404 when not found).

{
  "generated_at": "2026-08-22 02:00:15 UTC",
  "inventory_generated_at": "2026-08-22 01:00:38 UTC",
  "assessment_generated_at": "2026-08-22 01:30:12 UTC",
  "dry_runs": [
    {
      "namespace": "longhorn-system",
      "components": ["Longhorn"],
      "status": "success",
      "stdout": "namespace/longhorn-system created (dry-run)",
      "stderr": "",
      "duration_ms": 1234,
      "details": {
        "work_dir": "/tmp/radar-dryrun-xxx",
        "namespace_base": "/tmp/radar-base-xxx/base/longhorn",
        "component_count": 1,
        "mutated_versions": { "Longhorn": "1.12.0" },
        "kubectl_exit_code": 0,
        "sunbeam_exit_code": 0
      }
    }
  ]
}

Statuses: success, build_failed, dryrun_failed, skipped_no_mapping, skipped_unsupported_source. 404 {"error":"no dry-runs yet — run the radar dry-run job first"} before the first dry-run job; 400 {"error":"invalid status: … (expected one of …)"} when the filter value isn't a known status.

GET /api/v1/dryruns/{namespace}

One dry-run result, looked up by Kubernetes namespace (URL-encoded).

{
  "namespace": "longhorn-system",
  "components": ["Longhorn"],
  "status": "success",
  "stdout": "namespace/longhorn-system created (dry-run)",
  "stderr": "",
  "duration_ms": 1234,
  "details": {
    "work_dir": "/tmp/radar-dryrun-xxx",
    "namespace_base": "/tmp/radar-base-xxx/base/longhorn",
    "component_count": 1,
    "mutated_versions": { "Longhorn": "1.12.0" },
    "kubectl_exit_code": 0,
    "sunbeam_exit_code": 0
  }
}

404 {"error":"dry-run not found: {namespace}"} when absent.

Dry-run output viewer

GET /output?namespace=<ns>

When the dashboard is enabled, this returns a human-readable HTML page for a single namespace's dry-run output. It shows the namespace, status badge, and collapsible sections for kubectl stdout, kubectl stderr, Sunbeam logs, and the raw details JSON.

400 {"error":"namespace query param required"} if namespace is missing. 404 {"error":"dry-run not found: {namespace}"} when the namespace has no dry-run record.

Errors

Status Body When
400 {"error":"invalid risk_level: … (expected one of …)"} Bad ?risk_level= filter
404 {"error":"not found"} Unknown path
404 {"error":"no inventory yet — run the radar job first"} Store empty
404 {"error":"no assessments yet — run the radar assess job first"} No assessment run yet
404 {"error":"no dry-runs yet — run the radar dry-run job first"} No dry-run job yet
404 {"error":"component not found: …"} Unknown component name
404 {"error":"assessment not found: …"} Unknown component name
404 {"error":"dry-run not found: …"} Unknown component name
400 {"error":"invalid status: … (expected one of …)"} Bad ?status= filter
405 {"error":"method not allowed"} Non-GET on data endpoints
503 probe bodies above Store unreachable

Notes

  • There are no write endpoints by design. Refresh happens by running the job (Kubernetes Job/CronJob, later wfe); the API always serves the latest stored run.
  • Responses are pretty-printed JSON with content-type: application/json; charset=utf-8.
  • Component names are not unique across runs but are unique within one report (postgres enforces PRIMARY KEY (run_id, name)).