Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
248 changes: 248 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
# CLAUDE.md - AI Agent Guide for WSO2 API Platform

## Project Overview

WSO2 API Platform is a cloud-native API management platform with a policy-first gateway built on Envoy Proxy. The codebase is a Go-heavy monorepo with Node.js portals, managed via a Go workspace (`go.work`).

**License:** Apache 2.0
**Go Version:** 1.26.1
**Docker Registry:** `ghcr.io/wso2/api-platform`

## Gateway Architecture

```
┌──────────────────────────────────┐
│ Gateway-Controller (Go, Gin) │
│ REST :9090 | xDS :18000 │
│ Storage: SQLite / PostgreSQL │
└──────────────┬───────────────────┘
│ xDS protocol
┌──────────────┴───────────────────┐
▼ ▼
┌──────────────────┐ ┌───────────────────┐
│ Router (Envoy) │──ext_proc──▶│ Policy Engine │
│ HTTP :8080 │ gRPC │ Admin :9002 │
│ HTTPS :8443 │ │ CEL evaluation │
│ Admin :9901 │ │ Go policy plugins │
└──────────────────┘ └───────────────────┘
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## Build & Run Commands

### Prerequisites

- Docker + Docker Compose
- Go 1.26.1+
- Make

### Gateway

```bash
# Build all gateway images
cd gateway && make build

# Run the full gateway stack
cd gateway && docker compose up -d

# Verify health
curl http://localhost:9090/health

# Debug mode (dlv on :2345 controller, :2346 runtime)
make build-debug
docker compose -f docker-compose.debug.yaml up

# Individual builds
make build-controller
make build-gateway-runtime
make build-gateway-builder

# Multi-arch build and push
make build-and-push-multiarch
```

### Platform API

```bash
cd platform-api
make build # Docker image
make test # Run tests
make generate # OpenAPI code generation (oapi-codegen)
make build-and-push-multiarch
```

### CLI

```bash
cd cli/src
make build # Platform-specific binary
make build-all # Cross-platform builds
make test
```

### Full Platform (All-in-One)

```bash
cd distribution/all-in-one
docker compose up
```

### Root-Level Targets

```bash
make version # Show all component versions
make build-gateway # Build all gateway images
make test-gateway # Run gateway tests
make test-platform-api # Run platform-api tests
make test-cli # Run CLI tests
make push-gateway # Push gateway images to registry
make validate-versions # Validate version consistency
make clean-gateway # Clean gateway build artifacts
```

## Testing

### Unit Tests

```bash
# Gateway components
cd gateway && make test-controller
cd gateway && make test-gateway-builder
cd gateway && make test-policy-engine

# All gateway tests
cd gateway && make test
```

### Integration Tests (BDD with Godog)

Integration tests are in `gateway/it/` using Gherkin feature files.

```bash
cd gateway
make test-integration # Run integration tests (requires running images)
make test-integration-all # Build coverage images + run tests (30m timeout)
make test-postgres # Run with PostgreSQL backend

# Run a specific feature file
cd gateway/it
IT_FEATURE_PATHS=features/health.feature make test

# Multiple feature files (comma-separated)
IT_FEATURE_PATHS=features/health.feature,features/metrics.feature make test

# Filter by Godog tag (add @wip tag to your scenario in the .feature file)
go test -v ./... -godog.tags="@wip"
```

**Test artifacts:**
- `reports/integration-test-results.json`
- `coverage/integration-test-coverage.txt`
- `coverage/integration-test-coverage.html`

### Test Infrastructure

Mock servers in `/tests/mock-servers/`:
- JWKS server (JWT key validation)
- Embedding providers
- Analytics collectors
- Azure Content Safety mock
- AWS Bedrock Guardrails mock
- Mock platform API

## Configuration

Environment variables use the `APIP_GW_` prefix:

```bash
APIP_GW_CONTROLLER_STORAGE_TYPE=sqlite
APIP_GW_CONTROLLER_STORAGE_SQLITE_PATH=./data/gateway.db
APIP_GW_CONTROLLER_LOGGING_LEVEL=info
APIP_GW_DEVELOPMENT_MODE=true
APIP_GW_POLICY_ENGINE_METRICS_PORT=9002
GATEWAY_CONTROLLER_HOST=gateway-controller # Used by runtime to find controller
```

Config files: `gateway/configs/config.toml`

## Code Patterns

- **API Design:** OpenAPI specs + oapi-codegen for Go server/client generation
- **Error Handling:** Custom error types in `common/errors/` with field-level validation
- **Storage:** Interface-based storage layer supporting SQLite (dev) and PostgreSQL (prod)
- **Testing:** Table-driven unit tests, BDD integration tests (Godog/Gherkin)
- **Config:** koanf + mapstructure for config management
- **Logging:** Leveled logging (debug, info, warn, error)
- **Policies:** Go plugins compiled via gateway-builder, evaluated with CEL expressions
- **Communication:** xDS (controller-to-router), gRPC ext_proc (router-to-policy-engine), REST + WebSocket (platform-api-to-controller)

## Gateway Controller REST API Usage

The gateway controller REST API is served on port **9090** with **no base path prefix** — routes are registered at the root (e.g., `/llm-providers`, `/rest-apis`, not `/api/v1/...`).

Comment on lines +180 to +181

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use /apis instead of /rest-apis in docs.

The generated handlers register API resources at /apis; /rest-apis is inconsistent with actual routes.

Proposed fix
-The gateway controller REST API is served on port **9090** with **no base path prefix** — routes are registered at the root (e.g., `/llm-providers`, `/rest-apis`, not `/api/v1/...`).
+The gateway controller REST API is served on port **9090** with **no base path prefix** — routes are registered at the root (e.g., `/llm-providers`, `/apis`, not `/api/v1/...`).
...
-GET    /rest-apis                      # List REST APIs
-POST   /rest-apis                      # Create REST API
+GET    /apis                           # List APIs
+POST   /apis                           # Create API

Also applies to: 266-268

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.md` around lines 236 - 237, Update the documentation to use the actual
route path: replace instances of the string "/rest-apis" with "/apis" (e.g., in
the sentence describing registered routes and the example route listing) so the
docs match the generated handlers that register API resources at "/apis"; apply
the same replacement at the other mentioned occurrence.

### Authentication

Dev mode uses basic auth configured in `gateway/configs/config.toml`:

```bash
# Default dev credentials
curl -u admin:admin http://localhost:9090/llm-providers
```

There is no `/health` endpoint on the management API. A request without credentials returning `{"error":"no valid authentication credentials provided"}` confirms the server is running.

Comment on lines +191 to +192

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Correct the /health endpoint statement.

Line 247 says /health does not exist, but gateway route registration includes GET /health. This will mislead agent workflows and troubleshooting steps.

Proposed fix
-There is no `/health` endpoint on the management API. A request without credentials returning `{"error":"no valid authentication credentials provided"}` confirms the server is running.
+`/health` is available on the management API (`GET /health`). In dev mode, protected endpoints without credentials should return an authentication error, which also confirms the server is running.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
There is no `/health` endpoint on the management API. A request without credentials returning `{"error":"no valid authentication credentials provided"}` confirms the server is running.
`/health` is available on the management API (`GET /health`). In dev mode, protected endpoints without credentials should return an authentication error, which also confirms the server is running.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.md` around lines 247 - 248, Documentation incorrectly states that a
/health endpoint does not exist; update the CLAUDE.md text around the current
statement to reflect that the gateway registers a GET /health route (see the
gateway route registration/GET /health), and clarify the observed behavior
(unauthenticated request returns {"error":"no valid authentication credentials
provided"} rather than a 404). Modify the sentence to state that GET /health is
present and will respond with an authentication error when credentials are
missing, so agent workflows and troubleshooting are not misled.

### Key API Endpoints

```
GET /llm-providers # List LLM providers
POST /llm-providers # Create LLM provider
GET /llm-providers/:id # Get LLM provider by handle
PUT /llm-providers/:id # Update LLM provider
DELETE /llm-providers/:id # Delete LLM provider

GET /llm-proxies # List LLM proxies
POST /llm-proxies # Create LLM proxy
GET /llm-proxies/:id # Get LLM proxy by handle
PUT /llm-proxies/:id # Update LLM proxy
DELETE /llm-proxies/:id # Delete LLM proxy

GET /llm-provider-templates # List provider templates
POST /llm-provider-templates # Create template
GET /rest-apis # List REST APIs
POST /rest-apis # Create REST API
```
Comment on lines +195 to +212

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Label the endpoint list fenced block.

Line 251 also has an unlabeled fence. Add a language tag (e.g., text) for markdownlint MD040 compliance.

Proposed fix
-```
+```text
 GET    /llm-providers                  # List LLM providers
...
 POST   /rest-apis                      # Create REST API
-```
+```
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 251-251: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.md` around lines 251 - 268, The fenced code block containing the
endpoint list (the block starting with "GET    /llm-providers ... POST  
/rest-apis                      # Create REST API") is missing a language tag;
update that fence to include a language identifier (e.g., change ``` to ```text)
to satisfy markdownlint MD040 and close the fence normally, ensuring the opening
triple backticks are followed by the language token and the closing triple
backticks remain unchanged.


### Content Types

The API accepts both YAML (`Content-Type: application/yaml`) and JSON (`Content-Type: application/json`).

### Example: Deploy an LLM Provider

```bash
curl -u admin:admin -X POST http://localhost:9090/llm-providers \
-H "Content-Type: application/yaml" \
-d '
apiVersion: gateway.api-platform.wso2.com/v1alpha1
kind: LlmProvider
metadata:
name: my-openai-provider
spec:
displayName: My OpenAI Provider
version: v1.0
template: openai
vhost: api.openai.local
upstream:
url: "https://api.openai.com/v1"
accessControl:
mode: allow_all
'
```

Note: `spec.accessControl.mode` (`allow_all` or `deny_all`) is a **required field** for LLM providers.

### Stale Database on Startup

If the controller fails on startup with errors like `no such column: m.gateway_id`, the SQLite database schema is outdated. Fix by removing the Docker volume:

```bash
cd gateway && docker compose down -v && docker compose up -d
```