feat(#84): implement instance identity model for federation

Implemented the foundation of federation architecture with instance
identity and connection management:

Database Schema:
- Added Instance model for instance identity with keypair generation
- Added FederationConnection model for workspace-scoped connections
- Added FederationConnectionStatus enum (PENDING, ACTIVE, SUSPENDED, DISCONNECTED)

Service Layer:
- FederationService with instance identity management
- RSA 2048-bit keypair generation for signing
- Public identity endpoint (excludes private key)
- Keypair regeneration capability

API Endpoints:
- GET /api/v1/federation/instance - Returns public instance identity
- POST /api/v1/federation/instance/regenerate-keys - Admin keypair regeneration

Tests:
- 11 tests passing (7 service, 4 controller)
- 100% statement coverage, 100% function coverage
- Follows TDD principles (Red-Green-Refactor)

Configuration:
- Added INSTANCE_NAME and INSTANCE_URL environment variables
- Integrated FederationModule into AppModule

Refs #84

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-03 10:58:50 -06:00
parent 6e63508f97
commit 7989c089ef
10 changed files with 853 additions and 22 deletions

View File

@@ -0,0 +1,38 @@
/**
* Federation Controller
*
* API endpoints for instance identity and federation management.
*/
import { Controller, Get, Post, UseGuards, Logger } from "@nestjs/common";
import { FederationService } from "./federation.service";
import { AuthGuard } from "../auth/guards/auth.guard";
import { PublicInstanceIdentity, InstanceIdentity } from "./types/instance.types";
@Controller("api/v1/federation")
export class FederationController {
private readonly logger = new Logger(FederationController.name);
constructor(private readonly federationService: FederationService) {}
/**
* Get this instance's public identity
* No authentication required - this is public information for federation
*/
@Get("instance")
async getInstance(): Promise<PublicInstanceIdentity> {
this.logger.debug("GET /api/v1/federation/instance");
return this.federationService.getPublicIdentity();
}
/**
* Regenerate instance keypair
* Requires authentication - this is an admin operation
*/
@Post("instance/regenerate-keys")
@UseGuards(AuthGuard)
async regenerateKeys(): Promise<InstanceIdentity> {
this.logger.log("POST /api/v1/federation/instance/regenerate-keys");
return this.federationService.regenerateKeypair();
}
}