generated from coulomb/repo-seed
Implement WP-0011 hub service, CLI, and deployment artifacts
Some checks failed
ci / validate-registry (push) Has been cancelled
Some checks failed
ci / validate-registry (push) Has been cancelled
Add FederationHubAPI spec, hub registration schema, FastAPI hub with SQLite persistence, reuse-surface hub CLI client, Dockerfile, and hub tests. Activate workplan; T05 deploy and T06 ops docs remain open pending railiance01 cutover.
This commit is contained in:
261
specs/FederationHubAPI.md
Normal file
261
specs/FederationHubAPI.md
Normal file
@@ -0,0 +1,261 @@
|
||||
# Federation Hub API
|
||||
|
||||
**Repository:** `reuse-surface`
|
||||
**Artifact:** `specs/FederationHubAPI.md`
|
||||
**Status:** Draft 0.1 (REUSE-WP-0011-T01)
|
||||
**Schema:** `schemas/hub-registration.schema.yaml`
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
The federation hub is a hosted coordination service that records which
|
||||
repositories publish capability indexes and serves a composed federated index
|
||||
for agent discovery. It does **not** store capability entry Markdown bodies.
|
||||
|
||||
Companion deployment workplan: `railiance-apps` **RAILIANCE-WP-0007**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Base URL and formats
|
||||
|
||||
| Item | Value |
|
||||
|---|---|
|
||||
| Default production URL | `https://reuse-hub.whywhynot.de` (confirm at deploy) |
|
||||
| API prefix | `/v1` |
|
||||
| Read formats | JSON (default), YAML via `Accept: application/yaml` or `?format=yaml` |
|
||||
| Write content type | `application/json` |
|
||||
|
||||
Environment variables for clients:
|
||||
|
||||
| Variable | Purpose |
|
||||
|---|---|
|
||||
| `REUSE_SURFACE_HUB_URL` | Hub base URL (no trailing slash) |
|
||||
| `REUSE_SURFACE_HUB_TOKEN` | Bearer token for write operations |
|
||||
|
||||
---
|
||||
|
||||
## 3. Authentication
|
||||
|
||||
| Endpoint class | Auth |
|
||||
|---|---|
|
||||
| `GET /health`, `GET /v1/repos`, `GET /v1/repos/{repo}`, `GET /v1/federated` | Public (read) |
|
||||
| `POST /v1/repos`, `PATCH /v1/repos/{repo}`, `DELETE /v1/repos/{repo}`, `POST /v1/federated/compose` | Bearer token required |
|
||||
|
||||
Write requests must include:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <REUSE_SURFACE_HUB_TOKEN>
|
||||
```
|
||||
|
||||
Missing or invalid token → `401 Unauthorized`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Registration model
|
||||
|
||||
A registration mirrors federation `url` sources from
|
||||
`schemas/federation.schema.yaml`, plus hub metadata:
|
||||
|
||||
| Field | Required | Notes |
|
||||
|---|---|---|
|
||||
| `repo` | yes | Slug `[a-z][a-z0-9-]*`; primary key |
|
||||
| `url` | yes | HTTP(S) URL to `capabilities.yaml` |
|
||||
| `enabled` | yes | Include in federated compose when true |
|
||||
| `domain` | yes | e.g. `helix_forge` |
|
||||
| `required` | no | Fail compose if fetch fails and no cache |
|
||||
| `description` | no | Human-readable note |
|
||||
| `cache_ttl_seconds` | no | Default `86400` |
|
||||
| `auth_env` | no | Hub container env var for fetch auth (never returned in GET) |
|
||||
| `auth_header` | no | Default `Authorization` |
|
||||
| `registered_at` | hub | ISO-8601 UTC |
|
||||
| `updated_at` | hub | ISO-8601 UTC |
|
||||
| `registered_by` | no | Optional client-supplied actor label |
|
||||
|
||||
Local filesystem `index` paths are **not** accepted — registrations must use
|
||||
published raw URLs.
|
||||
|
||||
---
|
||||
|
||||
## 5. Endpoints
|
||||
|
||||
### 5.1 `GET /health`
|
||||
|
||||
Liveness/readiness probe.
|
||||
|
||||
**Response `200`:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"service": "reuse-surface-hub",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 `GET /v1/repos`
|
||||
|
||||
List all registrations (including disabled).
|
||||
|
||||
**Response `200`:**
|
||||
|
||||
```json
|
||||
{
|
||||
"count": 2,
|
||||
"repos": [
|
||||
{
|
||||
"repo": "reuse-surface",
|
||||
"url": "https://gitea.coulomb.social/coulomb/reuse-surface/raw/main/registry/indexes/capabilities.yaml",
|
||||
"enabled": true,
|
||||
"required": true,
|
||||
"domain": "helix_forge",
|
||||
"description": "Primary registry",
|
||||
"cache_ttl_seconds": 86400,
|
||||
"registered_at": "2026-06-15T12:00:00Z",
|
||||
"updated_at": "2026-06-15T12:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`auth_env` is omitted from responses.
|
||||
|
||||
### 5.3 `POST /v1/repos`
|
||||
|
||||
Register a new repository. **Auth required.**
|
||||
|
||||
**Request body:** `registration_request` from schema.
|
||||
|
||||
**Response `201`:** Full registration object.
|
||||
|
||||
**Errors:**
|
||||
|
||||
| Code | Condition |
|
||||
|---|---|
|
||||
| `400` | Schema validation failure |
|
||||
| `401` | Missing/invalid token |
|
||||
| `409` | `repo` already registered |
|
||||
|
||||
### 5.4 `GET /v1/repos/{repo}`
|
||||
|
||||
Fetch one registration.
|
||||
|
||||
**Response `200`:** Registration object.
|
||||
**Response `404`:** Unknown repo.
|
||||
|
||||
### 5.5 `PATCH /v1/repos/{repo}`
|
||||
|
||||
Update fields on an existing registration. **Auth required.**
|
||||
|
||||
**Request body:** `registration_update` from schema (at least one field).
|
||||
|
||||
**Response `200`:** Updated registration.
|
||||
|
||||
**Errors:** `400`, `401`, `404`.
|
||||
|
||||
### 5.6 `DELETE /v1/repos/{repo}`
|
||||
|
||||
Remove a registration. **Auth required.**
|
||||
|
||||
**Response `204`:** No content.
|
||||
**Response `404`:** Unknown repo.
|
||||
|
||||
### 5.7 `GET /v1/federated`
|
||||
|
||||
Return the composed federated index from all **enabled** registrations.
|
||||
|
||||
Reuses WP-0010 remote fetch/cache logic server-side. Output shape matches
|
||||
`registry/indexes/federated.yaml`:
|
||||
|
||||
```yaml
|
||||
version: 1
|
||||
updated: "2026-06-15"
|
||||
domain: helix_forge
|
||||
collision_policy: warn
|
||||
sources:
|
||||
- repo: reuse-surface
|
||||
url: https://...
|
||||
count: 12
|
||||
capabilities:
|
||||
- id: capability.registry.register
|
||||
source_repo: reuse-surface
|
||||
source_url: https://...
|
||||
# ... index fields ...
|
||||
```
|
||||
|
||||
Query parameters:
|
||||
|
||||
| Param | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `format` | `json` | `json` or `yaml` |
|
||||
| `refresh` | `false` | Bypass remote cache when `true` |
|
||||
|
||||
Warnings from compose (duplicate IDs, fetch fallbacks) are returned in response
|
||||
header `X-Federation-Warnings` (semicolon-separated) for MVP; JSON envelope
|
||||
extension is a future option.
|
||||
|
||||
**Response `200`:** Federated index document.
|
||||
**Response `502`:** Required source unavailable with no cache.
|
||||
|
||||
### 5.8 `POST /v1/federated/compose`
|
||||
|
||||
Trigger federated index refresh (same as `GET /v1/federated?refresh=true`).
|
||||
**Auth required.** Useful for operators after bulk registration changes.
|
||||
|
||||
**Response `200`:** Federated index document.
|
||||
|
||||
---
|
||||
|
||||
## 6. Error envelope
|
||||
|
||||
Non-2xx responses use:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "validation_error",
|
||||
"message": "Human-readable summary",
|
||||
"details": ["optional field-level messages"]
|
||||
}
|
||||
```
|
||||
|
||||
| `error` code | HTTP |
|
||||
|---|---|
|
||||
| `validation_error` | 400 |
|
||||
| `unauthorized` | 401 |
|
||||
| `not_found` | 404 |
|
||||
| `conflict` | 409 |
|
||||
| `compose_error` | 502 |
|
||||
|
||||
---
|
||||
|
||||
## 7. Hub service configuration
|
||||
|
||||
| Env var | Required | Purpose |
|
||||
|---|---|---|
|
||||
| `REUSE_SURFACE_HUB_TOKEN` | yes | Write API bearer token |
|
||||
| `REUSE_SURFACE_HUB_DB` | no | SQLite path (default `/data/hub.db`) |
|
||||
| `REUSE_SURFACE_HUB_CACHE_DIR` | no | Remote index cache (default `/data/cache`) |
|
||||
| `REUSE_SURFACE_HUB_DOMAIN` | no | Default federated `domain` (default `helix_forge`) |
|
||||
|
||||
---
|
||||
|
||||
## 8. CLI mapping
|
||||
|
||||
| CLI command | API call |
|
||||
|---|---|
|
||||
| `reuse-surface hub status` | `GET /health` |
|
||||
| `reuse-surface hub list` | `GET /v1/repos` |
|
||||
| `reuse-surface hub show --repo X` | `GET /v1/repos/X` |
|
||||
| `reuse-surface hub register ...` | `POST /v1/repos` |
|
||||
| `reuse-surface hub update ...` | `PATCH /v1/repos/{repo}` |
|
||||
|
||||
Global flags: `--hub-url`, env `REUSE_SURFACE_HUB_URL`, `REUSE_SURFACE_HUB_TOKEN`.
|
||||
|
||||
---
|
||||
|
||||
## 9. Deployment reference
|
||||
|
||||
- Image: `gitea.coulomb.social/coulomb/reuse-surface-hub:<tag>`
|
||||
- Probe path: `/health`
|
||||
- Persistence: PVC at `/data` (SQLite + fetch cache)
|
||||
- Helm release: `railiance-apps` RAILIANCE-WP-0007
|
||||
Reference in New Issue
Block a user