Files
TREK/server/tests/unit/nest/integrations/airtrailTestConnection.test.ts
Maurice 724c88c201 style: format server and shared with prettier
A mechanical prettier --write over server/src, server/tests, server/scripts
and shared/src with the workspaces' .prettierrc; nothing but layout and
import order changes, and every file keeps the same set of imports. shared
is formatted throughout and its format baseline is empty. The server
baseline keeps the 35 files that Prettier would grow past their lint:size
limit (they need a split first, which is not a formatting change), and the
generated entity files stay as their generator writes them.
2026-10-10 21:23:37 +02:00

98 lines
4.0 KiB
TypeScript

import { db } from '../../../../src/db/database';
import { AuditLog } from '../../../../src/db/entities/AuditLog.entity';
import { Users } from '../../../../src/db/entities/Users.entity';
import { UserAirtrailRepository } from '../../../../src/db/repositories/UserAirtrail.repository';
import { AuditService } from '../../../../src/nest/audit/audit.service';
import type { AirtrailClient } from '../../../../src/nest/integrations/airtrail.client';
import { AirtrailService } from '../../../../src/nest/integrations/airtrail.service';
import { createUser } from '../../../helpers/factories';
import { createTestOrm, type TestOrm } from '../../../helpers/test-orm';
import { describe, it, expect, vi, beforeAll, beforeEach, afterAll } from 'vitest';
// Avoid any real DNS/network from the SSRF guard during saveSettings and the probe.
vi.mock('../../../../src/utils/ssrfGuard', () => ({
checkSsrf: vi.fn(async () => ({ allowed: true, isPrivate: false })),
safeFetch: vi.fn(),
}));
// The probe is the only call that would leave the process, so the client is a
// stub; the credential handling around it runs against the real row.
const listFlights = vi.fn();
let svc: AirtrailService;
let t: TestOrm;
beforeAll(async () => {
t = await createTestOrm(db);
svc = new AirtrailService(new UserAirtrailRepository(t.orm.em), new AuditService(t.repo(AuditLog), t.repo(Users)), {
listFlights,
} as unknown as AirtrailClient);
});
afterAll(async () => {
await t.close();
});
const MASK = '••••••••';
beforeEach(() => {
listFlights.mockReset();
listFlights.mockResolvedValue([]);
});
describe('airtrail test connection keeps the stored key with its host', () => {
it('refuses a blank key field against a different host than the stored one before anything is sent', async () => {
// The form prefills the address and never the key, so retyping the URL and
// pressing Test is the ordinary way to move an instance. Falling back to the
// stored key here would carry it to whatever host was just typed.
const { user } = createUser(db);
await svc.saveSettings(user.id, 'https://old.example', 'stored-key', false, false, null);
const out = await svc.testConnection(user.id, 'https://someone-elses.example', undefined, false);
expect(out.connected).toBe(false);
expect(out.error).toContain('https://old.example');
expect(listFlights).not.toHaveBeenCalled();
});
it('treats the mask against a different port as a blank field, not a key', async () => {
const { user } = createUser(db);
await svc.saveSettings(user.id, 'https://old.example', 'stored-key', false, false, null);
const out = await svc.testConnection(user.id, 'https://old.example:8443', MASK, false);
expect(out.connected).toBe(false);
expect(listFlights).not.toHaveBeenCalled();
});
it('still tests a path edit on the same origin with the stored key', async () => {
// The same instance under a corrected path is where the key was issued, and
// refusing it would make every trailing-slash edit demand the key again.
const { user } = createUser(db);
await svc.saveSettings(user.id, 'https://at.example/api', 'stored-key', false, false, null);
const out = await svc.testConnection(user.id, 'https://at.example/', undefined, false);
expect(out.connected).toBe(true);
expect(listFlights).toHaveBeenCalledWith({
baseUrl: 'https://at.example/',
apiKey: 'stored-key',
allowInsecureTls: false,
});
});
it('uses a key typed for the new host as typed, so moving an instance and testing it first still works', async () => {
const { user } = createUser(db);
await svc.saveSettings(user.id, 'https://old.example', 'stored-key', false, false, null);
const out = await svc.testConnection(user.id, 'https://new.example', 'minted-for-new', false);
expect(out.connected).toBe(true);
expect(listFlights).toHaveBeenCalledWith({
baseUrl: 'https://new.example',
apiKey: 'minted-for-new',
allowInsecureTls: false,
});
});
});