Skip to content

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
jest.mock('@db', () => ({
db: {
integrationCheckRun: {
groupBy: jest.fn(),
findMany: jest.fn(),
},
},
}));

import { db } from '@db';
import { CheckRunRepository } from './check-run.repository';

// Grab through the module reference to avoid the `unbound-method` lint rule
// that fires when extracting an instance method from an object literal.
const mockedCheckRun = db.integrationCheckRun as unknown as {
groupBy: jest.Mock;
findMany: jest.Mock;
};
const mockGroupBy = mockedCheckRun.groupBy;
const mockFindMany = mockedCheckRun.findMany;

function makeRun(opts: {
id: string;
connectionId: string;
checkId?: string;
createdAt: string;
}) {
return {
id: opts.id,
connectionId: opts.connectionId,
checkId: opts.checkId ?? 'aws-s3-encryption',
createdAt: new Date(opts.createdAt),
results: [],
connection: {
id: opts.connectionId,
metadata: {},
provider: { slug: 'aws' },
},
};
}

describe('CheckRunRepository.findLatestPerConnectionAndCheckByTask', () => {
const repo = new CheckRunRepository();

beforeEach(() => {
jest.clearAllMocks();
});

it('returns nothing when the task has no runs', async () => {
mockGroupBy.mockResolvedValue([]);
const result = await repo.findLatestPerConnectionAndCheckByTask('task_1');
expect(result).toEqual([]);
expect(mockFindMany).not.toHaveBeenCalled();
});

it('GUARANTEES every account’s latest run even when one account dominates the recent window', async () => {
// 3 accounts (A, B, C) each ran the same check once; A was then re-run many
// times most recently. A flat "newest N rows" limit would bury B and C.
mockGroupBy.mockResolvedValue([
{
connectionId: 'A',
checkId: 'aws-s3-encryption',
_max: { createdAt: new Date('2026-06-09T15:00:00Z') },
},
{
connectionId: 'B',
checkId: 'aws-s3-encryption',
_max: { createdAt: new Date('2026-06-01T09:00:00Z') },
},
{
connectionId: 'C',
checkId: 'aws-s3-encryption',
_max: { createdAt: new Date('2026-06-01T08:00:00Z') },
},
]);

const latestPerGroup = [
makeRun({
id: 'rA',
connectionId: 'A',
createdAt: '2026-06-09T15:00:00Z',
}),
makeRun({
id: 'rB',
connectionId: 'B',
createdAt: '2026-06-01T09:00:00Z',
}),
makeRun({
id: 'rC',
connectionId: 'C',
createdAt: '2026-06-01T08:00:00Z',
}),
];
// Recent window is dominated by account A's burst of re-runs.
const recentWindow = [
makeRun({
id: 'rA',
connectionId: 'A',
createdAt: '2026-06-09T15:00:00Z',
}),
makeRun({
id: 'rA2',
connectionId: 'A',
createdAt: '2026-06-09T14:00:00Z',
}),
makeRun({
id: 'rA3',
connectionId: 'A',
createdAt: '2026-06-09T13:00:00Z',
}),
makeRun({
id: 'rA4',
connectionId: 'A',
createdAt: '2026-06-09T12:00:00Z',
}),
makeRun({
id: 'rA5',
connectionId: 'A',
createdAt: '2026-06-09T11:00:00Z',
}),
];

// First findMany = OR-of-tuples (latest per group); second = recent window.
mockFindMany.mockImplementation((args: { where?: { OR?: unknown } }) =>
Promise.resolve(args.where?.OR ? latestPerGroup : recentWindow),
);

const result = await repo.findLatestPerConnectionAndCheckByTask('task_1');
const connectionIds = new Set(result.map((r) => r.connectionId));

expect(connectionIds.has('A')).toBe(true);
expect(connectionIds.has('B')).toBe(true);
expect(connectionIds.has('C')).toBe(true);
// Newest-first ordering preserved.
expect(result[0].id).toBe('rA');
// Deduped by id (rA appears in both the latest set and the recent window).
expect(result.filter((r) => r.id === 'rA')).toHaveLength(1);
});

it('excludes disconnected connections in both queries', async () => {
mockGroupBy.mockResolvedValue([
{
connectionId: 'A',
checkId: 'c',
_max: { createdAt: new Date('2026-06-09T15:00:00Z') },
},
]);
mockFindMany.mockResolvedValue([
makeRun({
id: 'rA',
connectionId: 'A',
createdAt: '2026-06-09T15:00:00Z',
}),
]);

await repo.findLatestPerConnectionAndCheckByTask('task_1');

for (const call of mockFindMany.mock.calls) {
expect(call[0].where.connection).toEqual({
status: { not: 'disconnected' },
});
}
});

it('clamps an oversized historyPerGroup to the cap (no unbounded read)', async () => {
mockGroupBy.mockResolvedValue([
{
connectionId: 'A',
checkId: 'c',
_max: { createdAt: new Date('2026-06-09T15:00:00Z') },
},
]);
mockFindMany.mockResolvedValue([]);

await repo.findLatestPerConnectionAndCheckByTask('task_1', {
historyPerGroup: 100000,
});

// recent-window query = the findMany WITHOUT an OR clause.
const recentCall = mockFindMany.mock.calls.find((c) => !c[0].where.OR);
expect(recentCall?.[0].take).toBe(1 * 50); // groups.length(1) * MAX(50)
});

it('falls back to the default for an invalid historyPerGroup (NaN/negative)', async () => {
mockGroupBy.mockResolvedValue([
{
connectionId: 'A',
checkId: 'c',
_max: { createdAt: new Date('2026-06-09T15:00:00Z') },
},
]);
mockFindMany.mockResolvedValue([]);

await repo.findLatestPerConnectionAndCheckByTask('task_1', {
historyPerGroup: Number.NaN,
});
let recentCall = mockFindMany.mock.calls.find((c) => !c[0].where.OR);
expect(recentCall?.[0].take).toBe(1 * 5); // default 5

mockFindMany.mockClear();
await repo.findLatestPerConnectionAndCheckByTask('task_1', {
historyPerGroup: -10,
});
recentCall = mockFindMany.mock.calls.find((c) => !c[0].where.OR);
expect(recentCall?.[0].take).toBe(1 * 5); // default 5
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Injectable } from '@nestjs/common';
import { db } from '@db';
import type { IntegrationRunStatus, Prisma } from '@db';
import type { Prisma } from '@db';

/** Default / hard cap for run-history depth per (connection, check) group. */
const DEFAULT_HISTORY_PER_GROUP = 5;
const MAX_HISTORY_PER_GROUP = 50;

export interface CreateCheckRunDto {
connectionId: string;
Expand Down Expand Up @@ -149,6 +153,89 @@ export class CheckRunRepository {
});
}

/**
* Get check runs for a task, GUARANTEEING every (connection, check) group's
* most recent run is included (plus a bounded history tail).
*
* Why not just `findByTask` with a row limit: checks run once per connected
* account, so a customer with multiple AWS accounts has one run per account.
* A flat "newest N rows" limit can silently drop an account whose latest run
* predates a burst of re-runs on a busier account — that account then
* vanishes from the task UI. Here we first establish the per-group maxima via
* `groupBy`, fetch each group's latest run explicitly (completeness), then add
* a recent window for history. Used by the task UI so manual and scheduled
* runs both surface every account.
*/
async findLatestPerConnectionAndCheckByTask(
taskId: string,
{
historyPerGroup = DEFAULT_HISTORY_PER_GROUP,
}: { historyPerGroup?: number } = {},
) {
// `historyPerGroup` can originate from a user-supplied `?limit=` query param
// (parsed with parseInt → possibly NaN/negative/huge). Clamp it so it never
// produces an invalid `take` (500) or an unbounded, expensive read.
const perGroup =
Number.isInteger(historyPerGroup) && historyPerGroup > 0
? Math.min(historyPerGroup, MAX_HISTORY_PER_GROUP)
: DEFAULT_HISTORY_PER_GROUP;

const include = {
results: true,
connection: { include: { provider: true } },
} as const;

const where = {
taskId,
connection: { status: { not: 'disconnected' } },
} satisfies Prisma.IntegrationCheckRunWhereInput;

// Every (connection, check) group that has runs for this task, with its
// most recent run timestamp.
const groups = await db.integrationCheckRun.groupBy({
by: ['connectionId', 'checkId'],
where,
_max: { createdAt: true },
});
if (groups.length === 0) return [];

// Completeness guarantee: explicitly fetch each group's latest run.
const tuples = groups.flatMap((g) =>
g._max.createdAt
? [
{
connectionId: g.connectionId,
checkId: g.checkId,
createdAt: g._max.createdAt,
},
]
: [],
);
const latest = tuples.length
? await db.integrationCheckRun.findMany({
where: { ...where, OR: tuples },
include,
})
: [];

// History tail: a bounded recent window. Combined with the guaranteed
// latest set, every account shows its current result and recently-active
// accounts also show past runs.
const recent = await db.integrationCheckRun.findMany({
where,
include,
orderBy: { createdAt: 'desc' },
take: groups.length * perGroup,
});

// Merge + dedupe by id, newest-first (preserves the /runs ordering contract).
const byId = new Map<string, (typeof recent)[number]>();
for (const run of [...latest, ...recent]) byId.set(run.id, run);
return Array.from(byId.values()).sort(
(a, b) => b.createdAt.getTime() - a.createdAt.getTime(),
);
}

/**
* Get the latest check run for a specific check on a task
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,28 @@ export class ConnectionRepository {
});
}

/**
* All active connections for a single provider in an org. Used to run a
* check against every connected account (e.g. each AWS account a customer
* has connected) rather than only the first one.
*/
async findActiveByProviderAndOrg(
providerId: string,
organizationId: string,
): Promise<IntegrationConnection[]> {
return db.integrationConnection.findMany({
where: {
providerId,
organizationId,
status: 'active',
},
include: {
provider: true,
},
orderBy: { createdAt: 'asc' },
});
}

async create(data: CreateConnectionDto): Promise<IntegrationConnection> {
return db.integrationConnection.create({
data: {
Expand Down
Loading
Loading