Files
PaperClipAI/server/src/__tests__/project-skill-setup-identity.test.ts
T
DottaandPaperclip 473c80d13f Automatically import and update project repository skills (#16066)
Automatically import skills from new GitHub project repositories and update enabled sources in the background. Preserve project-derived access, saved selections, immutable execution versions and explicit pins; add legacy adoption, refresh and connection repair in Sources.

Include durable scheduling and bounded work credits, production Storybook journeys, real GitHub-to-routine acceptance receipts and final-head CI/security/Greptile qualification.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-13 16:11:43 -05:00

26 lines
2.0 KiB
TypeScript

import { beforeEach, expect, it, vi } from 'vitest';
import type { Db } from '@paperclipai/db';
import { projectSkillSetupIdentity } from '../services/project-skill-source-bindings.js';
const { capture } = vi.hoisted(() => ({ capture: vi.fn() }));
vi.mock('../services/run-identity.js', () => ({ captureRunIdentity: capture }));
const db = {} as Db;
const actor = { type: 'agent' as const, source: 'agent_jwt' as const, companyId: 'company', agentId: 'agent', runId: 'run', onBehalfOfUserId: 'forged' };
beforeEach(() => capture.mockReset());
it('keeps responsibility without searching personal GitHub grants when the run has no selected credential', async () => {
capture.mockResolvedValue({ run: { responsibleUserId: 'person' }, context: { github: null } });
expect(await projectSkillSetupIdentity(db, 'company', actor)).toMatchObject({ refreshUserId: 'person', connectionId: null, refreshGrantId: null });
});
it('pins only the connection and grant already authorized for the active run', async () => {
capture.mockResolvedValue({ run: { responsibleUserId: 'person' }, context: { github: { status: 'available', connectionId: 'selected', grantId: 'grant' } } });
expect(await projectSkillSetupIdentity(db, 'company', actor)).toMatchObject({ refreshUserId: 'person', connectionId: 'selected', refreshGrantId: 'grant' });
expect(capture).toHaveBeenCalledWith(db, { companyId: 'company', agentId: 'agent', runId: 'run' });
});
it('does not reuse an unavailable run credential', async () => {
capture.mockResolvedValue({ run: { responsibleUserId: 'person' }, context: { github: { status: 'unavailable', connectionId: 'old', grantId: 'old' } } });
expect(await projectSkillSetupIdentity(db, 'company', actor)).toMatchObject({ connectionId: null, refreshGrantId: null });
});
it('API keys do not obtain responsibility or a run credential', async () => {
expect(await projectSkillSetupIdentity(db, 'company', { ...actor, source: 'agent_key' })).toMatchObject({ refreshUserId: null, connectionId: null, refreshGrantId: null });
expect(capture).not.toHaveBeenCalled();
});