Files
stack/docs/scratchpads/276-workspace-authorization.md
Jason Woltje 744290a438
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
fix(#276): Add comprehensive audit logging for incoming connections
Implemented comprehensive audit logging for all incoming federation
connection attempts to provide visibility and security monitoring.

Changes:
- Added logIncomingConnectionAttempt() to FederationAuditService
- Added logIncomingConnectionCreated() to FederationAuditService
- Added logIncomingConnectionRejected() to FederationAuditService
- Injected FederationAuditService into ConnectionService
- Updated handleIncomingConnectionRequest() to log all connection events

Audit logging captures:
- All incoming connection attempts with remote instance details
- Successful connection creations with connection ID
- Rejected connections with failure reason and error details
- Workspace ID for all events (security compliance)
- All events marked as securityEvent: true

Testing:
- Added 3 new tests for audit logging verification
- All 24 connection service tests passing
- Quality gates: lint, typecheck, build all passing

Security Impact:
- Provides visibility into all incoming connection attempts
- Enables security monitoring and threat detection
- Audit trail for compliance requirements
- Foundation for future authorization controls

Note: This implements Phase 1 (audit logging) of issue #276.
Full authorization (allowlist/denylist, admin approval) will be
implemented in a follow-up issue requiring schema changes.

Fixes #276

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-03 20:24:46 -06:00

4.2 KiB

Issue #276: Add workspace authorization on incoming connections

Objective

Add proper workspace authorization and controls for incoming federation connections.

Location

apps/api/src/federation/federation.controller.ts:211-233

Current Problem

@Post("incoming/connect")
@Throttle({ short: { limit: 3, ttl: 1000 } })
async handleIncomingConnection(
  @Body() dto: IncomingConnectionRequestDto
): Promise<{ status: string; connectionId?: string }> {
  this.logger.log(`Received connection request from ${dto.instanceId}`);

  // LIMITATION: Incoming connections are created in a default workspace
  const workspaceId = process.env.DEFAULT_WORKSPACE_ID ?? "default";

  const connection = await this.connectionService.handleIncomingConnectionRequest(
    workspaceId,
    dto
  );

  return {
    status: "pending",
    connectionId: connection.id,
  };
}

Issues:

  • No authorization check - any remote instance can create connections
  • No admin approval workflow
  • Limited audit logging
  • No allowlist/denylist checking
  • Hardcoded default workspace

Security Impact

  • Authorization bypass: Remote instances can force connections without permission
  • Workspace pollution: Unwanted connections clutter the default workspace
  • No control: Administrators have no way to pre-approve or block instances

Solution Approach

Phase 1: Audit Logging (This fix)

Add comprehensive audit logging for all incoming connection attempts before implementing full authorization.

Changes:

  1. Log all incoming connection requests with full details
  2. Log successful connection creations
  3. Log any validation failures
  4. Include remote instance details in logs

Phase 2: Authorization Framework (Future)

  • Add workspace routing configuration
  • Implement allowlist/denylist at instance level
  • Add admin approval workflow
  • Implement automatic approval for trusted instances

Implementation (Phase 1)

Add comprehensive audit logging to connection.service.ts:

async handleIncomingConnectionRequest(
  workspaceId: string,
  request: ConnectionRequest
): Promise<ConnectionDetails> {
  // Audit log: Incoming connection attempt
  this.auditService.logIncomingConnectionAttempt({
    workspaceId,
    remoteInstanceId: request.instanceId,
    remoteUrl: request.instanceUrl,
    timestamp: request.timestamp,
  });

  // Verify signature
  const verification = this.signatureService.verifyConnectionRequest(request);
  if (!verification.valid) {
    // Audit log: Failed verification
    this.auditService.logConnectionRejected({
      workspaceId,
      remoteInstanceId: request.instanceId,
      reason: 'Invalid signature',
      error: verification.error,
    });

    throw new UnauthorizedException(
      `Invalid connection request signature: ${verification.error}`
    );
  }

  // Create connection (existing logic)
  const connection = await this.prisma.federationConnection.create({...});

  // Audit log: Connection created
  this.auditService.logIncomingConnectionCreated({
    workspaceId,
    connectionId: connection.id,
    remoteInstanceId: request.instanceId,
    remoteUrl: request.instanceUrl,
  });

  return this.mapToConnectionDetails(connection);
}

Testing

Test scenarios:

  1. Incoming connection with valid signature → logged and created
  2. Incoming connection with invalid signature → logged and rejected
  3. Verify all audit logs contain required fields
  4. Verify workspace isolation in logs

Progress

  • Create scratchpad
  • Add audit logging methods to FederationAuditService
  • Update handleIncomingConnectionRequest with audit logging
  • Add tests for audit logging
  • Run quality gates
  • Commit changes
  • Create PR
  • Merge to develop
  • Close issue #276
  • Create follow-up issue for Phase 2 (full authorization)

Notes

This implements the audit logging requirement from the issue. Full authorization (allowlist/denylist, admin approval) will be implemented in a follow-up issue as it requires:

  • Database schema changes (allowlist/denylist tables)
  • New configuration endpoints
  • Admin UI changes
  • More extensive testing

Audit logging provides immediate visibility and security monitoring without requiring major architectural changes.