Files
stack/apps/api/src/federation/audit.service.ts
Jason Woltje 004f7828fb
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/pr/woodpecker Pipeline failed
feat(#273): Implement capability-based authorization for federation
Add CapabilityGuard infrastructure to enforce capability-based authorization
on federation endpoints. Implements fail-closed security model.

Security properties:
- Deny by default (no capability = deny)
- Only explicit true values grant access
- Connection must exist and be ACTIVE
- All denials logged for audit trail

Implementation:
- Created CapabilityGuard with fail-closed authorization logic
- Added @RequireCapability decorator for marking endpoints
- Added getConnectionById() to ConnectionService
- Added logCapabilityDenied() to AuditService
- 12 comprehensive tests covering all security scenarios

Quality gates:
-  Tests: 12/12 passing
-  Lint: 0 new errors (33 pre-existing)
-  TypeScript: 0 new errors (8 pre-existing)

Refs #273

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-03 19:53:09 -06:00

146 lines
3.6 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,
});
}
/**
* Log capability denial (security event)
* Logged when remote instance attempts operation without required capability
*/
logCapabilityDenied(
remoteInstanceId: string,
requiredCapability: string,
requestedUrl: string
): void {
this.logger.warn({
event: "FEDERATION_CAPABILITY_DENIED",
remoteInstanceId,
requiredCapability,
requestedUrl,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
}