import { CommandBus, QueryBus } from '@nestjs/cqrs'; import { ForbiddenError } from '@task-stream/api/shared/domain'; import { createHmac } from 'node:crypto'; import { RecordGitMentionsCommand } from './git/git'; import { GitService } from './git.service'; import { FindProjectsRepository } from './ports/find-projects.repository'; import { GitIntegrationsRepository } from './ports/git-integrations.repository'; const push = { ref: 'refs/heads/main', repository: { html_url: 'https://git.example.org/acme/api' }, commits: [ { id: 'abc1234', message: 'WEB-7: pay by card', url: 'https://git.example.org/acme/api/commit/abc1234', timestamp: '2026-10-09T10:00:00Z', author: { name: 'Ana', username: 'ana' }, }, ], }; describe('GitService', () => { const executed: object[] = []; const git = new GitService( { execute: async (command: object) => { executed.push(command); return 1; }, } as unknown as CommandBus, {} as QueryBus, { findById: async (id: string) => (id === 'p1' ? { id: 'p1' } : null), findByKey: async (key: string) => (key === 'WEB' ? { id: 'p1' } : null), } as unknown as FindProjectsRepository, { repositoriesOf: async () => [ { id: 'r1', name: 'web', secret: 'web-secret', createdAt: '' }, { id: 'r2', name: 'api', secret: 'api-secret', createdAt: '' }, ], saveAll: async () => undefined, } as GitIntegrationsRepository, ); /** A Gitea delivery signed with `secret`. */ const delivery = (secret: string, project = 'WEB') => { const rawBody = Buffer.from(JSON.stringify(push)); return { project, rawBody, body: push, headers: { 'x-gitea-event': 'push', 'x-gitea-signature': createHmac('sha256', secret) .update(rawBody) .digest('hex'), }, }; }; beforeEach(() => (executed.length = 0)); it('tells the repository by the secret its webhook was signed with', async () => { expect(await git.receive(delivery('api-secret'))).toEqual({ recorded: 1 }); expect(executed).toEqual([ expect.objectContaining({ projectId: 'p1', repository: 'api' }), ]); expect(executed[0]).toBeInstanceOf(RecordGitMentionsCommand); }); it('refuses a secret no repository of the project has, or another project', async () => { await expect(git.receive(delivery('stolen'))).rejects.toThrow( ForbiddenError, ); await expect(git.receive(delivery('api-secret', 'NOPE'))).rejects.toThrow( ForbiddenError, ); expect(executed).toEqual([]); }); });