Implements the final piece of M7-Federation - the spoke configuration UI that allows administrators to configure their local instance's federation capabilities and settings. Backend Changes: - Add UpdateInstanceDto with validation for name, capabilities, and metadata - Implement FederationService.updateInstanceConfiguration() method - Add PATCH /api/v1/federation/instance endpoint to FederationController - Add audit logging for configuration updates - Add tests for updateInstanceConfiguration (5 new tests, all passing) Frontend Changes: - Create SpokeConfigurationForm component with PDA-friendly design - Create /federation/settings page with configuration management - Add regenerate keypair functionality with confirmation dialog - Extend federation API client with updateInstanceConfiguration and regenerateInstanceKeys - Add comprehensive tests (10 tests, all passing) Design Decisions: - Admin-only access via AdminGuard - Never expose private key in API responses (security) - PDA-friendly language throughout (no demanding terms) - Clear visual hierarchy with read-only and editable fields - Truncated public key with copy button for usability - Confirmation dialog for destructive key regeneration All tests passing: - Backend: 13/13 federation service tests passing - Frontend: 10/10 SpokeConfigurationForm tests passing - TypeScript compilation: passing - Linting: passing - PDA-friendliness: verified This completes M7-Federation. All federation features are now implemented. Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
127 lines
3.1 KiB
TypeScript
127 lines
3.1 KiB
TypeScript
/**
|
|
* Federation Audit Service
|
|
*
|
|
* Logs security-sensitive operations for compliance and monitoring.
|
|
* Uses application logger since ActivityLog requires workspace context.
|
|
*/
|
|
|
|
import { Injectable, Logger } from "@nestjs/common";
|
|
|
|
@Injectable()
|
|
export class FederationAuditService {
|
|
private readonly logger = new Logger(FederationAuditService.name);
|
|
|
|
/**
|
|
* Log instance keypair regeneration (system-level operation)
|
|
* Logged to application logs for security audit trail
|
|
*/
|
|
logKeypairRegeneration(userId: string, instanceId: string): void {
|
|
this.logger.warn({
|
|
event: "FEDERATION_KEYPAIR_REGENERATED",
|
|
userId,
|
|
instanceId,
|
|
timestamp: new Date().toISOString(),
|
|
securityEvent: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log instance configuration update (system-level operation)
|
|
* Logged to application logs for security audit trail
|
|
*/
|
|
logInstanceConfigurationUpdate(
|
|
userId: string,
|
|
instanceId: string,
|
|
updates: Record<string, unknown>
|
|
): void {
|
|
this.logger.log({
|
|
event: "FEDERATION_INSTANCE_CONFIG_UPDATED",
|
|
userId,
|
|
instanceId,
|
|
updates,
|
|
timestamp: new Date().toISOString(),
|
|
securityEvent: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log federated authentication initiation
|
|
*/
|
|
logFederatedAuthInitiation(userId: string, remoteInstanceId: string): void {
|
|
this.logger.log({
|
|
event: "FEDERATION_AUTH_INITIATED",
|
|
userId,
|
|
remoteInstanceId,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log federated identity linking
|
|
*/
|
|
logFederatedIdentityLinked(userId: string, remoteInstanceId: string): void {
|
|
this.logger.log({
|
|
event: "FEDERATION_IDENTITY_LINKED",
|
|
userId,
|
|
remoteInstanceId,
|
|
timestamp: new Date().toISOString(),
|
|
securityEvent: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log federated identity revocation
|
|
*/
|
|
logFederatedIdentityRevoked(userId: string, remoteInstanceId: string): void {
|
|
this.logger.warn({
|
|
event: "FEDERATION_IDENTITY_REVOKED",
|
|
userId,
|
|
remoteInstanceId,
|
|
timestamp: new Date().toISOString(),
|
|
securityEvent: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log identity verification attempt
|
|
*/
|
|
logIdentityVerification(userId: string, remoteInstanceId: string, success: boolean): void {
|
|
const level = success ? "log" : "warn";
|
|
this.logger[level]({
|
|
event: "FEDERATION_IDENTITY_VERIFIED",
|
|
userId,
|
|
remoteInstanceId,
|
|
success,
|
|
timestamp: new Date().toISOString(),
|
|
securityEvent: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log identity linking (create mapping)
|
|
*/
|
|
logIdentityLinking(localUserId: string, remoteInstanceId: string, remoteUserId: string): void {
|
|
this.logger.log({
|
|
event: "FEDERATION_IDENTITY_LINKED",
|
|
localUserId,
|
|
remoteUserId,
|
|
remoteInstanceId,
|
|
timestamp: new Date().toISOString(),
|
|
securityEvent: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log identity revocation (remove mapping)
|
|
*/
|
|
logIdentityRevocation(localUserId: string, remoteInstanceId: string): void {
|
|
this.logger.warn({
|
|
event: "FEDERATION_IDENTITY_REVOKED",
|
|
localUserId,
|
|
remoteInstanceId,
|
|
timestamp: new Date().toISOString(),
|
|
securityEvent: true,
|
|
});
|
|
}
|
|
}
|