Skip to Content
FeaturesK8s API Auto-Discovery

K8s API Auto-Discovery

Eliminate manual API registration by discovering APIs from Kubernetes services. The discovery agent scans customer clusters, probes OpenAPI endpoints, and registers runtime records that users can map to their API catalog.

Status

In Progress P0

Completion: ~40% — Backend and agent deployed. Bulk import UI and manual mapping dialog are in progress.


The Dual Discovery Model

This is the central design decision for the feature. Every API entity can have two distinct records:

Api (1) ──── (1) SpecRecord ← REQUIRED. The intended API (design-time) Api (1) ──── (0..1) RuntimeRecord ← OPTIONAL. The observed API (runtime)
SpecRecordRuntimeRecord
SourceManual upload, GitHub, or bulk import from K8sK8s discovery agent
Required?Yes — every API must have oneNo — can be absent
Used forOperations parsing, RAG indexing, mock serverService endpoint info, cluster location
Authoritative?Yes — drives catalog and AI featuresNo — observational only

See PDR-001 and PDR-002 for the design rationale.


Data Model

RuntimeRecordResponse (frontend type)

type RuntimeRecordResponse = { id: string; // UUID apiId?: string; // null = orphaned (not yet linked to an API) k8sServiceName: string; k8sNamespace: string; k8sClusterId: string; metadataHash: string; // SHA-256 fingerprint (see below) status: string; // ACTIVE, INACTIVE, ORPHANED };

SpecRecordEntity (backend)

// Key fields on SpecRecordEntity UUID id UUID apiId // always set — required String openApiSpec // raw OpenAPI spec (JSON or YAML string) String specSourceType // MANUAL_UPLOAD, GITHUB, BULK_IMPORT String githubRepo // optional String gitSha // V49 migration — for GitHub-sourced specs

RuntimeRecordEntity (backend)

UUID id UUID apiId // FK to Api — null means orphaned String k8sServiceName String k8sNamespace String k8sClusterId String metadataHash // SHA-256 duplicate prevention key RuntimeRecordStatus status // ACTIVE, INACTIVE, ORPHANED

Metadata Hash (Duplicate Detection)

The hash is a SHA-256 fingerprint of the identifying fields of a runtime record:

String hash = DigestUtils.sha256Hex( k8sServiceName + ":" + k8sNamespace + ":" + apiName + ":" + apiVersion );

When a new runtime record arrives from the discovery agent:

  1. Compute the hash
  2. Check if a record with that hash already exists
  3. If yes → reject (duplicate), return the existing record ID
  4. If no → create the record

The hash is also used to auto-link runtime records to existing catalog APIs on bulk import. If an existing API’s name and version match the hash, the apiId is set automatically.


Discovery Agent

winspect-api-discovery-agent is a lightweight Spring Boot pod deployed in customer Kubernetes clusters via Helm.

Discovery loop

1. List services in configured namespaces 2. For each service: a. Probe well-known OpenAPI paths: - /v3/api-docs - /openapi.json - /openapi.yaml - /swagger.json b. If spec found → extract name, version, paths c. Compute metadata hash d. POST to central Winspect API: POST /discovery/runtime-records 3. Sleep for configured scan interval 4. Repeat

Deployment (Helm)

# values.yaml (key settings) winspect: apiBaseUrl: https://api.winspect.io # Central Winspect API apiKey: <org-api-key> # Org-level API key for authentication scanIntervalSeconds: 300 # How often to scan namespaces: ["default", "production"] # Which namespaces to scan clusterId: "prod-cluster-1" # Unique identifier for this cluster

Registration endpoint

POST /api-management/discovery/runtime-records Content-Type: application/json X-API-Key: <org-api-key> { "k8sServiceName": "cart-service", "k8sNamespace": "default", "k8sClusterId": "prod-cluster-1", "openApiSpec": "<spec content>", "apiName": "Cart Service API", "apiVersion": "1.0.0" }

User Flows

Bulk Import

When an organization has no APIs yet, all orphaned runtime records can be imported at once. Each orphaned record creates a new API + SpecRecord in the catalog.

UI location: Discovery dashboard → “Import All” button (shown when catalog is empty)

Frontend client: services/discoveryClient.ts

// Bulk import all orphaned runtime records await bulkImportRuntimeRecords(authToken, orgId);

Backend: POST /api-management/discovery/runtime-records/bulk-import

Flow:

  1. Find all orphaned runtime records for the org (where apiId IS NULL)
  2. For each: create Api + SpecRecord (spec from the discovered OpenAPI spec)
  3. Set apiId on the runtime record
  4. Return created API IDs

Manual Mapping

Link an individual orphaned runtime record to an existing API.

UI location: Discovery dashboard → orphaned record → “Map to API” dialog

Frontend client: services/discoveryClient.ts

await mapRuntimeRecordToApi(authToken, runtimeRecordId, apiId);

Backend: PATCH /api-management/discovery/runtime-records/{id}/map


Frontend Service Client

All discovery operations go through services/discoveryClient.ts.

Key functions (to implement or extend as needed):

// Get all runtime records for org (orphaned and mapped) getRuntimeRecords(authToken: string, orgId: string): Promise<RuntimeRecordResponse[]> // Bulk import all orphaned records bulkImportRuntimeRecords(authToken: string, orgId: string): Promise<{ createdApis: string[] }> // Map single orphaned record to an existing API mapRuntimeRecordToApi(authToken: string, runtimeRecordId: string, apiId: string): Promise<void> // Get orphaned records (not yet linked) getOrphanedRuntimeRecords(authToken: string, orgId: string): Promise<RuntimeRecordResponse[]>

Backend Endpoints

All under platform-backend-core (port 8080), in k8s_discovery/controller/RuntimeRecordController.java.

MethodPathOperation
POST/api-management/discovery/runtime-recordsRegister runtime record (agent)
GET/api-management/discovery/runtime-recordsList all runtime records for org
GET/api-management/discovery/runtime-records/orphanedList orphaned records
POST/api-management/discovery/runtime-records/bulk-importBulk import orphaned → APIs
PATCH/api-management/discovery/runtime-records/{id}/mapMap orphaned record to existing API

Implementation State

ComponentStatus
RuntimeRecord entity + migrationDone
SpecRecord entity + migrationDone
Git SHA field on SpecRecord (V49)Done
RuntimeRecordController — register endpointDone
ApiRegistryServiceImpl — spec/runtime record linkingDone
ApiSpecSyncService — sync logicDone
Discovery agent — K8s scannerDone
Discovery agent — Helm chartDone
Bulk import backendDone
Manual mapping backendDone
Bulk import UI (discovery dashboard)In progress (bl-002)
Manual mapping dialogIn progress (bl-003)

Repositories

  • platform-backend-service — Discovery API, RuntimeRecord and SpecRecord entities, bulk import, manual mapping, ApiSpecSyncService
  • winspect-api-discovery-agent — K8s scanner, Helm chart (client-facing; shared with customers for installation)
  • api-management-ui — Discovery dashboard, bulk import UI, manual mapping dialog
Last updated on