chore: upgrade Node.js runtime to v24 across codebase #419

Merged
jason.woltje merged 438 commits from fix/auth-frontend-remediation into main 2026-02-17 01:04:47 +00:00
4 changed files with 143 additions and 3 deletions
Showing only changes of commit 43681ca1b1 - Show all commits

View File

@@ -0,0 +1,80 @@
/**
* Capabilities DTO Tests
*
* Tests for FederationCapabilities validation.
*/
import { describe, it, expect } from "vitest";
import { validate } from "class-validator";
import { plainToInstance } from "class-transformer";
import { FederationCapabilitiesDto } from "./capabilities.dto";
describe("FederationCapabilitiesDto", () => {
it("should accept valid capabilities", async () => {
const plain = {
supportsQuery: true,
supportsCommand: false,
supportsEvent: true,
supportsAgentSpawn: false,
protocolVersion: "1.0",
};
const dto = plainToInstance(FederationCapabilitiesDto, plain);
const errors = await validate(dto);
expect(errors).toHaveLength(0);
});
it("should accept minimal valid capabilities", async () => {
const plain = {};
const dto = plainToInstance(FederationCapabilitiesDto, plain);
const errors = await validate(dto);
expect(errors).toHaveLength(0);
});
it("should reject invalid boolean for supportsQuery", async () => {
const plain = {
supportsQuery: "yes", // Should be boolean
};
const dto = plainToInstance(FederationCapabilitiesDto, plain);
const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
expect(errors[0].property).toBe("supportsQuery");
});
it("should reject invalid type for protocolVersion", async () => {
const plain = {
protocolVersion: 1.0, // Should be string
};
const dto = plainToInstance(FederationCapabilitiesDto, plain);
const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
expect(errors[0].property).toBe("protocolVersion");
});
it("should accept only specified fields", async () => {
const plain = {
supportsQuery: true,
supportsCommand: true,
supportsEvent: false,
supportsAgentSpawn: true,
protocolVersion: "1.0",
};
const dto = plainToInstance(FederationCapabilitiesDto, plain);
const errors = await validate(dto);
expect(errors).toHaveLength(0);
expect(dto.supportsQuery).toBe(true);
expect(dto.supportsCommand).toBe(true);
expect(dto.supportsEvent).toBe(false);
expect(dto.supportsAgentSpawn).toBe(true);
expect(dto.protocolVersion).toBe("1.0");
});
});

View File

@@ -0,0 +1,32 @@
/**
* Capabilities DTO
*
* Data Transfer Object for federation capabilities validation.
*/
import { IsBoolean, IsOptional, IsString } from "class-validator";
/**
* DTO for validating FederationCapabilities structure
*/
export class FederationCapabilitiesDto {
@IsOptional()
@IsBoolean()
supportsQuery?: boolean;
@IsOptional()
@IsBoolean()
supportsCommand?: boolean;
@IsOptional()
@IsBoolean()
supportsEvent?: boolean;
@IsOptional()
@IsBoolean()
supportsAgentSpawn?: boolean;
@IsOptional()
@IsString()
protocolVersion?: string;
}

View File

@@ -4,8 +4,10 @@
* Data Transfer Objects for federation connection API.
*/
import { IsString, IsUrl, IsOptional, IsObject, IsNumber } from "class-validator";
import { IsString, IsUrl, IsOptional, IsObject, IsNumber, ValidateNested } from "class-validator";
import { Type } from "class-transformer";
import { Sanitize, SanitizeObject } from "../../common/decorators/sanitize.decorator";
import { FederationCapabilitiesDto } from "./capabilities.dto";
/**
* DTO for initiating a connection
@@ -57,8 +59,9 @@ export class IncomingConnectionRequestDto {
@IsString()
publicKey!: string;
@IsObject()
capabilities!: Record<string, unknown>;
@ValidateNested()
@Type(() => FederationCapabilitiesDto)
capabilities!: FederationCapabilitiesDto;
@IsNumber()
timestamp!: number;

View File

@@ -339,5 +339,30 @@ describe("FederationController", () => {
});
expect(connectionService.handleIncomingConnectionRequest).toHaveBeenCalled();
});
it("should validate capabilities structure with valid data", async () => {
const dto = {
instanceId: "remote-instance-456",
instanceUrl: "https://remote.example.com",
publicKey: "PUBLIC_KEY",
capabilities: {
supportsQuery: true,
supportsCommand: false,
supportsEvent: true,
supportsAgentSpawn: false,
protocolVersion: "1.0",
},
timestamp: Date.now(),
signature: "valid-signature",
};
vi.spyOn(connectionService, "handleIncomingConnectionRequest").mockResolvedValue(
mockConnection
);
const result = await controller.handleIncomingConnection(dto);
expect(result.status).toBe("pending");
expect(connectionService.handleIncomingConnectionRequest).toHaveBeenCalled();
});
});
});