Skip to content
Merged
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ Plexara MCP exposes two gateway capabilities:
`api-test` is the upstream HTTP fixture the API gateway calls. Endpoints
are deliberately simple and deterministic; their job is not to compute
anything useful, it's to make the gateway's behavior observable. Every
request will (M2+) be recorded in a Postgres-backed audit log so you can
request will be recorded in a Postgres-backed audit log so you can
compare what a client sent through Plexara, what reached this server, and
what came back.

## Endpoint groups (M1)
## Endpoint groups

- **identity** — `GET /v1/whoami`, `GET /v1/headers`. Verify the gateway
forwards identity, args, and HTTP headers (with redaction).
Expand Down Expand Up @@ -61,7 +61,7 @@ make test # alias: go test -race -count=1 ./...
make verify # CI-equivalent: fmt, vet, test, lint, security, coverage gate
```

Integration tests requiring testcontainers Postgres land in M2.
Integration tests requiring testcontainers Postgres land in.

## Layout

Expand Down
12 changes: 5 additions & 7 deletions configs/api-test.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@ endpoints:
data: { enabled: true }
failure: { enabled: true }
echo: { enabled: true }
# The groups below land in M3/M4; toggles are accepted now but the
# underlying groups aren't registered until those milestones.
streaming: { enabled: false }
pagination: { enabled: false }
methods: { enabled: false }
security: { enabled: false }
export: { enabled: false }
streaming: { enabled: true }
pagination: { enabled: true }
methods: { enabled: true }
security: { enabled: true }
export: { enabled: true }
10 changes: 5 additions & 5 deletions configs/api-test.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ endpoints:
data: { enabled: true }
failure: { enabled: true }
echo: { enabled: true }
streaming: { enabled: true } # M3+
pagination: { enabled: true } # M4+
methods: { enabled: true } # M4+
security: { enabled: true } # M4+
export: { enabled: true } # M4+
streaming: { enabled: true }
pagination: { enabled: true }
methods: { enabled: true }
security: { enabled: true }
export: { enabled: true }

# Optional: POST a connection definition to a Plexara admin URL on boot
# so api-test self-registers in dev. Default off; keep fixture decoupled.
Expand Down
10 changes: 5 additions & 5 deletions configs/api-test.live.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ endpoints:
data: { enabled: true }
failure: { enabled: true }
echo: { enabled: true }
streaming: { enabled: false }
pagination: { enabled: false }
methods: { enabled: false }
security: { enabled: false }
export: { enabled: false }
streaming: { enabled: true }
pagination: { enabled: true }
methods: { enabled: true }
security: { enabled: true }
export: { enabled: true }
10 changes: 5 additions & 5 deletions docs/configuration/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ gateway forwards from its caller. The chain is:
if enabled, the bcrypt-hashed Postgres store.
2. **Static bearer** — `Authorization: Bearer <token>` matched against
the `bearer.tokens` static list.
3. **OIDC JWT** (M3+) — `Authorization: Bearer <jwt>` validated against
3. **OIDC JWT** — `Authorization: Bearer <jwt>` validated against
the configured IdP's JWKS.
4. **Anonymous fallback** — when `auth.allow_anonymous: true` and no
credential matched, requests proceed with an anonymous identity.
Expand Down Expand Up @@ -59,7 +59,7 @@ database:
```

The bcrypt store layers under the file store: file keys win, DB keys
are consulted on miss. To create a key, use the portal (M3+) or call
are consulted on miss. To create a key, use the portal or call
the admin API directly:

```bash
Expand Down Expand Up @@ -87,7 +87,7 @@ bearer:
Used when a Plexara connection is configured with `auth_mode: bearer`
and `credential: <token>`.

## OIDC JWT (M3+)
## OIDC JWT

When the Plexara gateway uses `oauth2_client_credentials` or
`oauth2_authorization_code`, it exchanges with the IdP and forwards the
Expand All @@ -112,7 +112,7 @@ JWKS is cached in-process for `jwks_cache_ttl`. Validation checks:
- `azp` (or `client_id` claim, depending on IdP) is in `allowed_clients`.
- `exp` and `nbf` allow a `clock_skew_seconds` tolerance.

The Keycloak realm `dev/keycloak/api-test-realm.json` (M3) pre-seeds
The Keycloak realm `dev/keycloak/api-test-realm.json` pre-seeds
two confidential clients (`plexara-cc` for client-credentials,
`plexara-ac` for auth-code) and a portal user (`dev` / `dev`).

Expand Down Expand Up @@ -153,7 +153,7 @@ safe to run with anonymous + a few static keys: clients that send a
valid key get their identity, clients that send nothing get anonymous,
clients that send a bad key get 401.

## Portal browser login (M3+)
## Portal browser login

The portal uses a standard OIDC PKCE flow: hit `/portal/`, redirect to
the IdP, callback at `portal.oidc_redirect_path`, set a session cookie.
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ first run. Subsequent runs reuse the file so sessions persist.

`source ./.env.dev` to load them into the current shell.

## OIDC (M3+)
## OIDC

| Variable | Used in | Description |
| --- | --- | --- |
Expand Down
26 changes: 13 additions & 13 deletions docs/configuration/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Static bearer-token authentication for `auth_mode: bearer` connections.

External OIDC IdP for JWT validation (`oauth2_client_credentials` and
`oauth2_authorization_code` Plexara connections; also the portal browser
login). Lands in M3 alongside Keycloak.
login)..

| Key | Default | Description |
| --- | --- | --- |
Expand Down Expand Up @@ -120,7 +120,7 @@ Default `redact_keys`:

## `portal`

The embedded React SPA + portal API. Lands in M3.
The embedded React SPA + portal API..

| Key | Default | Description |
| --- | --- | --- |
Expand All @@ -135,17 +135,17 @@ The embedded React SPA + portal API. Lands in M3.
Per-group toggles. Disabling a group removes its routes from the mux
and from the published OpenAPI doc.

| Key | Default | Status |
| --- | --- | --- |
| `identity.enabled` | `false` | M1 |
| `data.enabled` | `false` | M1 |
| `failure.enabled` | `false` | M1 |
| `echo.enabled` | `false` | M1 |
| `streaming.enabled` | `false` | M3+ |
| `pagination.enabled` | `false` | M4+ |
| `methods.enabled` | `false` | M4+ |
| `security.enabled` | `false` | M4+ |
| `export.enabled` | `false` | M4+ |
| Key | Default |
| --- | --- |
| `identity.enabled` | `false` |
| `data.enabled` | `false` |
| `failure.enabled` | `false` |
| `echo.enabled` | `false` |
| `streaming.enabled` | `false` |
| `pagination.enabled` | `false` |
| `methods.enabled` | `false` |
| `security.enabled` | `false` |
| `export.enabled` | `false` |

## `plexara.register`

Expand Down
2 changes: 1 addition & 1 deletion docs/endpoints/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Response (200):
Bounds:

- `0 <= bytes <= 32 MiB` (32×1024×1024). Larger sizes belong on the
export endpoint group (M4+), which streams to the asset store
export endpoint group, which streams to the asset store
instead of allocating in memory.
- `bytes < 0` or non-integer → 400.

Expand Down
2 changes: 1 addition & 1 deletion docs/endpoints/echo.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,4 @@ curl -s -I http://localhost:8080/v1/echo -H "X-API-Key: $KEY"
The handler reads up to 1 MiB of inbound body. Larger bodies are
truncated; `body_size` reports the captured prefix length. For
testing the gateway's handling of >1 MiB bodies, use the export
endpoint group (M4+).
endpoint group.
68 changes: 68 additions & 0 deletions docs/endpoints/export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
title: Export
description: Large/long-running endpoints intended as targets for the Plexara API gateway's api_export tool. Exercise the gateway's body-size and slow-first-byte handling.
---

# Export

Three endpoints designed to stress the gateway differently:

| Method | Path | What it stresses |
| --- | --- | --- |
| `GET` | `/v1/export/big-body?size_kb=N&seed=S` | Large response body forwarding. |
| `GET` | `/v1/export/csv?rows=N&seed=S` | Non-JSON content type, large text. |
| `GET` | `/v1/export/long-running?duration_ms=N` | Slow first-byte. |

## Determinism

`big-body` and `csv` both fill their rows with
`hex(sha256(seed:index))[:16]`. Same `(seed, index)` produces the same
value across runs, across endpoints, and across builds. The same
fixture data shows up in the `pagination` group too, by design.

## Bounds

| Parameter | Default | Max |
| --- | --- | --- |
| `size_kb` | 64 | 10240 (10 MiB) |
| `rows` | 1000 | 250000 |
| `duration_ms` | 1000 | 60000 (60 s) |

Values outside the bounds return `400`. The caps are fixture-side
defense against runaway test invocations, not a contract — real
`api_export` traffic moves well above these in production.

## Context cancellation

Both `/v1/export/big-body` and `/v1/export/csv` check
`r.Context().Done()` between rows and stop writing when the client
disconnects. `/v1/export/long-running` uses a `select` on a timer
plus the context, so a 60-second wait aborts instantly on disconnect
instead of pinning a goroutine.

## Examples

```bash
# 64 KiB JSON array (default size, with a fixed seed).
curl -s 'http://localhost:8080/v1/export/big-body?seed=fixed' | wc -c

# 1000-row CSV.
curl -s 'http://localhost:8080/v1/export/csv?rows=1000&seed=fixed' | head -3
# index,value
# 0,<hex>
# 1,<hex>

# 5-second slow-first-byte. Useful for gateway request-timeout testing.
curl -s 'http://localhost:8080/v1/export/long-running?duration_ms=5000'
# {"slept_ms":5000}
```

## Why this exists

The Plexara gateway's `api_export` tool streams large upstream responses
to an asset store rather than buffering them in memory. A misconfigured
gateway can break this in two ways: by truncating the body when its
in-memory cap fires (`big-body` exposes this), or by timing out the
upstream call before the first byte arrives (`long-running` exposes
this). The `csv` endpoint stresses the content-type code path that
`api_export` clients use when they ask for non-JSON exports.
46 changes: 46 additions & 0 deletions docs/endpoints/methods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: Methods
description: Method-matrix endpoint that accepts every common HTTP verb at a single path and echoes the verb the server observed.
---

# Methods

A single path, every common verb. Lets a gateway test assert that the
HTTP method survives the proxy hop unchanged.

| Method | Path | Returns |
| --- | --- | --- |
| `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS` | `/v1/method/echo` | `{ "method": "POST", "path": "/v1/method/echo", "query": {...} }` |

`HEAD` returns headers only (per RFC 7231). `OPTIONS` returns the body
plus an `Allow` header listing every supported verb.

`CONNECT` and `TRACE` are not registered; Go's `http.ServeMux` answers
them with `405 Method Not Allowed` because other verbs are registered
for the same path.

## Examples

```bash
curl -s -X PATCH http://localhost:8080/v1/method/echo
# {"method":"PATCH","path":"/v1/method/echo"}

curl -is -X HEAD http://localhost:8080/v1/method/echo | head -1
# HTTP/1.1 200 OK

curl -is -X OPTIONS http://localhost:8080/v1/method/echo
# HTTP/1.1 200 OK
# Allow: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS

curl -s -X CONNECT http://localhost:8080/v1/method/echo
# (405 Method Not Allowed)
```

## Why this exists

Gateway proxies sometimes break verbs in subtle ways: rewriting `PATCH`
to `POST` to fit a stricter client library, swallowing `OPTIONS`
pre-flight responses inside a CORS layer, or refusing `HEAD` because
the upstream handler doesn't register it explicitly. This endpoint
exposes every verb at one path so a tester can spot any of those
rewrites with a single curl loop.
24 changes: 12 additions & 12 deletions docs/endpoints/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ call, the body it got back is bit-for-bit predictable.

## Groups

| Group | Status | Purpose |
| --- | --- | --- |
| [Identity](identity.md) | M1 | Verify identity / header pass-through. |
| [Data](data.md) | M1 | Deterministic bodies for caching / dedup / size handling. |
| [Failure](failure.md) | M1 | Controlled error codes, latency, seeded flake. |
| [Echo](echo.md) | M1 | Generic catch-all that returns the request verbatim. |
| Streaming | M3+ | Chunked, SSE, NDJSON responses. |
| Pagination | M4+ | One endpoint per cursor style the gateway recognizes. |
| Methods | M4+ | Method matrix on `/v1/method/echo`. |
| Security | M4+ | Probe targets the gateway should refuse to forward. |
| Export | M4+ | Large/long-running targets exercising `api_export`. |
| Group | Purpose |
| --- | --- |
| [Identity](identity.md) | Verify identity / header pass-through. |
| [Data](data.md) | Deterministic bodies for caching / dedup / size handling. |
| [Failure](failure.md) | Controlled error codes, latency, seeded flake. |
| [Echo](echo.md) | Generic catch-all that returns the request verbatim. |
| Streaming | Chunked, SSE, NDJSON responses. |
| Pagination | One endpoint per cursor style the gateway recognizes. |
| Methods | Method matrix on `/v1/method/echo`. |
| Security | Probe targets the gateway should refuse to forward. |
| Export | Large/long-running targets exercising `api_export`. |

## Toggling groups

Expand All @@ -60,7 +60,7 @@ chaos testing) and one with only `data` (for stable cache fixtures).
## OpenAPI exposure

Every enabled route is published in `/openapi.json` and `/openapi.yaml`
(M4+). The Plexara gateway's `api_list_endpoints` tool reads this
. The Plexara gateway's `api_list_endpoints` tool reads this
document, so registering api-test with its OpenAPI spec inline gives
gateway callers a discoverable catalog.

Expand Down
Loading
Loading