feat(#93): implement agent spawn via federation
Implements FED-010: Agent Spawn via Federation feature that enables spawning and managing Claude agents on remote federated Mosaic Stack instances via COMMAND message type. Features: - Federation agent command types (spawn, status, kill) - FederationAgentService for handling agent operations - Integration with orchestrator's agent spawner/lifecycle services - API endpoints for spawning, querying status, and killing agents - Full command routing through federation COMMAND infrastructure - Comprehensive test coverage (12/12 tests passing) Architecture: - Hub → Spoke: Spawn agents on remote instances - Command flow: FederationController → FederationAgentService → CommandService → Remote Orchestrator - Response handling: Remote orchestrator returns agent status/results - Security: Connection validation, signature verification Files created: - apps/api/src/federation/types/federation-agent.types.ts - apps/api/src/federation/federation-agent.service.ts - apps/api/src/federation/federation-agent.service.spec.ts Files modified: - apps/api/src/federation/command.service.ts (agent command routing) - apps/api/src/federation/federation.controller.ts (agent endpoints) - apps/api/src/federation/federation.module.ts (service registration) - apps/orchestrator/src/api/agents/agents.controller.ts (status endpoint) - apps/orchestrator/src/api/agents/agents.module.ts (lifecycle integration) Testing: - 12/12 tests passing for FederationAgentService - All command service tests passing - TypeScript compilation successful - Linting passed Refs #93 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ POST /auth/sign-up
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
@@ -30,6 +31,7 @@ POST /auth/sign-up
|
||||
```
|
||||
|
||||
**Response (201):**
|
||||
|
||||
```json
|
||||
{
|
||||
"user": {
|
||||
@@ -47,6 +49,7 @@ POST /auth/sign-up
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
|
||||
- `409 Conflict` — Email already exists
|
||||
- `422 Validation Error` — Invalid input
|
||||
|
||||
@@ -61,6 +64,7 @@ POST /auth/sign-in
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
@@ -69,6 +73,7 @@ POST /auth/sign-in
|
||||
```
|
||||
|
||||
**Response (200):**
|
||||
|
||||
```json
|
||||
{
|
||||
"user": {
|
||||
@@ -85,6 +90,7 @@ POST /auth/sign-in
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
|
||||
- `401 Unauthorized` — Invalid credentials
|
||||
|
||||
---
|
||||
@@ -98,11 +104,13 @@ POST /auth/sign-out
|
||||
```
|
||||
|
||||
**Headers:**
|
||||
|
||||
```http
|
||||
Authorization: Bearer {session_token}
|
||||
```
|
||||
|
||||
**Response (200):**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true
|
||||
@@ -120,11 +128,13 @@ GET /auth/session
|
||||
```
|
||||
|
||||
**Headers:**
|
||||
|
||||
```http
|
||||
Authorization: Bearer {session_token}
|
||||
```
|
||||
|
||||
**Response (200):**
|
||||
|
||||
```json
|
||||
{
|
||||
"user": {
|
||||
@@ -140,6 +150,7 @@ Authorization: Bearer {session_token}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
|
||||
- `401 Unauthorized` — Invalid or expired session
|
||||
|
||||
---
|
||||
@@ -153,11 +164,13 @@ GET /auth/profile
|
||||
```
|
||||
|
||||
**Headers:**
|
||||
|
||||
```http
|
||||
Authorization: Bearer {session_token}
|
||||
```
|
||||
|
||||
**Response (200):**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "user-uuid",
|
||||
@@ -168,6 +181,7 @@ Authorization: Bearer {session_token}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
|
||||
- `401 Unauthorized` — Not authenticated
|
||||
|
||||
---
|
||||
@@ -181,12 +195,14 @@ GET /auth/callback/authentik
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
- `code` — Authorization code from provider
|
||||
- `state` — CSRF protection token
|
||||
|
||||
This endpoint is called by the OIDC provider after successful authentication.
|
||||
|
||||
**Response:**
|
||||
|
||||
- Redirects to frontend with session token
|
||||
|
||||
---
|
||||
@@ -229,10 +245,12 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
|
||||
### Token Storage
|
||||
|
||||
**Frontend (Browser):**
|
||||
|
||||
- Store in `httpOnly` cookie (most secure)
|
||||
- Or `localStorage` (less secure, XSS vulnerable)
|
||||
|
||||
**Mobile/Desktop:**
|
||||
|
||||
- Secure storage (Keychain on iOS, KeyStore on Android)
|
||||
|
||||
### Token Expiration
|
||||
@@ -240,8 +258,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
|
||||
Tokens expire after 24 hours (configurable via `JWT_EXPIRATION`).
|
||||
|
||||
**Check expiration:**
|
||||
|
||||
```typescript
|
||||
import { AuthSession } from '@mosaic/shared';
|
||||
import { AuthSession } from "@mosaic/shared";
|
||||
|
||||
const isExpired = (session: AuthSession) => {
|
||||
return new Date(session.session.expiresAt) < new Date();
|
||||
@@ -249,6 +268,7 @@ const isExpired = (session: AuthSession) => {
|
||||
```
|
||||
|
||||
**Refresh flow** (future implementation):
|
||||
|
||||
```http
|
||||
POST /auth/refresh
|
||||
```
|
||||
@@ -307,6 +327,7 @@ curl -X POST http://localhost:3001/auth/sign-in \
|
||||
```
|
||||
|
||||
**Save the token from response:**
|
||||
|
||||
```bash
|
||||
TOKEN=$(curl -X POST http://localhost:3001/auth/sign-in \
|
||||
-H "Content-Type: application/json" \
|
||||
|
||||
Reference in New Issue
Block a user