Skip to content

Commit d33289f

Browse files
committed
lint code
1 parent 0473915 commit d33289f

File tree

3 files changed

+205
-272
lines changed

3 files changed

+205
-272
lines changed

src/integrations/github/routes.ts

Lines changed: 37 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,26 @@ import { v4 as uuid } from 'uuid';
44
import { ObjectId } from 'mongodb';
55
import { createHmac } from 'crypto';
66
import { GitHubService } from './service';
7+
import { ProjectDBScheme } from '@hawk.so/types';
78
import { ContextFactories } from '../../types/graphql';
89
import { RedisInstallStateStore } from './store/install-state.redis.store';
10+
import ProjectModel from '../../models/project';
911
import WorkspaceModel from '../../models/workspace';
1012
import { sgr, Effect } from '../../utils/ansi';
1113
import { databases } from '../../mongo';
1214

13-
/**
14-
* Create GitHub router
15-
*
16-
* @param factories - context factories for database access
17-
* @returns Express router with GitHub integration endpoints
18-
*/
1915
/**
2016
* Default task threshold for automatic task creation
2117
* Minimum totalCount required to trigger auto-task creation
2218
*/
2319
const DEFAULT_TASK_THRESHOLD_TOTAL_COUNT = 50;
2420

21+
/**
22+
* Create GitHub router
23+
*
24+
* @param factories - context factories for database access
25+
* @returns Express router with GitHub integration endpoints
26+
*/
2527
export function createGitHubRouter(factories: ContextFactories): express.Router {
2628
const router = express.Router();
2729
const githubService = new GitHubService();
@@ -61,8 +63,8 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
6163
req: express.Request,
6264
res: express.Response,
6365
projectId: string | undefined,
64-
errorMessagePrefix: string = 'perform this action'
65-
): Promise<{ project: any; workspace: any; userId: string } | null> {
66+
errorMessagePrefix = 'perform this action'
67+
): Promise<{ project: ProjectModel; workspace: WorkspaceModel; userId: string } | null> {
6668
const userId = req.context?.user?.id;
6769

6870
/**
@@ -143,14 +145,18 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
143145
return null;
144146
}
145147

146-
return { project, workspace, userId };
148+
return {
149+
project,
150+
workspace,
151+
userId,
152+
};
147153
}
148154

149155
/**
150156
* Log message with GitHub Integration prefix
151157
*
152158
* @param level - log level ('log', 'warn', 'error', 'info')
153-
* @param projectId - optional project ID to include in log prefix
159+
* @param projectIdOrFirstArg - optional project ID to include in log prefix, or first log argument if not a valid ObjectId
154160
* @param args - arguments to log
155161
*/
156162
function log(level: 'log' | 'warn' | 'error' | 'info', projectIdOrFirstArg?: string | unknown, ...args: unknown[]): void {
@@ -263,145 +269,20 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
263269
}
264270
});
265271

266-
/**
267-
* GET /integration/github/callback?state=<state>&installation_id=<installation_id>
268-
* Handle GitHub App installation callback
269-
*
270-
* @deprecated - now we use /oauth endpoint for both installation and OAuth callbacks
271-
*/
272-
// router.get('/callback', async (req, res, next) => {
273-
// try {
274-
// const { state, installation_id } = req.query;
275-
276-
// /**
277-
// * Log callback request for debugging
278-
// */
279-
// log('info', `Callback received: state=${state}, installation_id=${installation_id}, query=${JSON.stringify(req.query)}`);
280-
281-
// /**
282-
// * Validate required parameters
283-
// */
284-
// if (!state || typeof state !== 'string') {
285-
// return res.redirect(buildGarageRedirectUrl('/project/error/settings/task-manager', {
286-
// error: 'Missing or invalid state',
287-
// }));
288-
// }
289-
290-
// if (!installation_id || typeof installation_id !== 'string') {
291-
// return res.redirect(buildGarageRedirectUrl('/project/error/settings/task-manager', {
292-
// error: 'Missing or invalid installation_id parameter',
293-
// }));
294-
// }
295-
296-
// /**
297-
// * Verify state (CSRF protection)
298-
// * getState() atomically gets and deletes the state, preventing reuse
299-
// */
300-
// const stateData = await stateStore.getState(state);
301-
302-
// if (!stateData) {
303-
// log('warn', `Invalid or expired state: ${sgr(state.slice(0, 8), Effect.ForegroundGray)}...`);
304-
305-
// return res.redirect(buildGarageRedirectUrl('/project/error/settings/task-manager', {
306-
// error: 'Invalid or expired state. Please try connecting again.',
307-
// }));
308-
// }
309-
310-
// const { projectId, userId } = stateData;
311-
312-
// log('info', projectId, `Processing callback initiated by user ${sgr(userId, Effect.ForegroundCyan)}`);
313-
314-
// /**
315-
// * Verify project exists
316-
// */
317-
// const project = await factories.projectsFactory.findById(projectId);
318-
319-
// if (!project) {
320-
// log('error', projectId, 'Project not found');
321-
322-
// return res.redirect(buildGarageRedirectUrl('/project/error/settings/task-manager', {
323-
// error: `Project not found: ${projectId}`,
324-
// }));
325-
// }
326-
327-
// /**
328-
// * Get installation info from GitHub
329-
// */
330-
// let installation;
331-
332-
// try {
333-
// installation = await githubService.getInstallationForRepository(installation_id);
334-
// log('info', projectId, `Retrieved installation info for installation_id: ${sgr(installation_id, Effect.ForegroundCyan)}`);
335-
// } catch (error) {
336-
// log('error', projectId, `Failed to get installation info: ${error instanceof Error ? error.message : String(error)}`);
337-
338-
// return res.redirect(buildGarageRedirectUrl(`/project/${projectId}/settings/task-manager`, {
339-
// error: 'Failed to retrieve GitHub installation information. Please try again.',
340-
// }));
341-
// }
342-
343-
// /**
344-
// * For now, we save only installationId
345-
// * repoId and repoFullName will be set when creating the first issue or can be configured later
346-
// * GitHub App installation can include multiple repositories, so we don't know which one to use yet
347-
// */
348-
// const taskManagerConfig = {
349-
// type: 'github',
350-
// autoTaskEnabled: false,
351-
// taskThresholdTotalCount: DEFAULT_TASK_THRESHOLD_TOTAL_COUNT,
352-
// assignAgent: false,
353-
// connectedAt: new Date(),
354-
// updatedAt: new Date(),
355-
// config: {
356-
// installationId: installation_id,
357-
// repoId: '',
358-
// repoFullName: '',
359-
// },
360-
// };
361-
362-
// let successRedirectUrl = buildGarageRedirectUrl(`/project/${projectId}/settings/task-manager`, {
363-
// success: 'true',
364-
// });
365-
366-
// /**
367-
// * Save taskManager configuration to project
368-
// */
369-
// try {
370-
// await project.updateProject(({
371-
// taskManager: taskManagerConfig,
372-
// }) as any);
373-
374-
// log('info', projectId, 'Successfully connected GitHub integration. Redirecting to ' + sgr(successRedirectUrl, Effect.ForegroundGreen));
375-
// } catch (error) {
376-
// log('error', projectId, `Failed to save taskManager config: ${error instanceof Error ? error.message : String(error)}`);
377-
378-
// return res.redirect(buildGarageRedirectUrl(`/project/${projectId}/settings/task-manager`, {
379-
// error: 'Failed to save Task Manager configuration. Please try again.',
380-
// }));
381-
// }
382-
383-
// /**
384-
// * Redirect to Garage with success parameter
385-
// */
386-
// return res.redirect(successRedirectUrl);
387-
// } catch (error) {
388-
// log('error', 'Error in /callback endpoint:', error);
389-
// next(error);
390-
// }
391-
// });
392-
393272
/**
394273
* GET /integration/github/oauth?code=<code>&state=<state>&installation_id=<installation_id>
395274
* Handle GitHub OAuth callback for user-to-server token
396275
* Also handles GitHub App installation if installation_id is present
397276
*/
398277
router.get('/oauth', async (req, res, next) => {
399278
try {
279+
// eslint-disable-next-line @typescript-eslint/camelcase, camelcase
400280
const { code, state, installation_id } = req.query;
401281

402282
/**
403283
* Log OAuth callback request for debugging
404284
*/
285+
// eslint-disable-next-line @typescript-eslint/camelcase, camelcase
405286
log('info', `OAuth callback received: state=${state}, code=${code ? 'present' : 'missing'}, installation_id=${installation_id ? 'present' : 'missing'}, query=${JSON.stringify(req.query)}`);
406287

407288
/**
@@ -454,16 +335,16 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
454335
* If installation_id is present, handle GitHub App installation first
455336
* This happens when "Request user authorization (OAuth) during installation" is enabled
456337
*/
338+
// eslint-disable-next-line @typescript-eslint/camelcase, camelcase
457339
if (installation_id && typeof installation_id === 'string') {
340+
// eslint-disable-next-line @typescript-eslint/camelcase, camelcase
458341
log('info', projectId, `GitHub App installation detected (installation_id: ${installation_id}), processing installation first`);
459342

460343
/**
461-
* Get installation info from GitHub
344+
* Get installation info from GitHub (validates installation exists)
462345
*/
463-
let installation;
464-
465346
try {
466-
installation = await githubService.getInstallationForRepository(installation_id);
347+
await githubService.getInstallationForRepository(installation_id);
467348
log('info', projectId, `Retrieved installation info for installation_id: ${sgr(installation_id, Effect.ForegroundCyan)}`);
468349
} catch (error) {
469350
log('error', projectId, `Failed to get installation info: ${error instanceof Error ? error.message : String(error)}`);
@@ -484,6 +365,7 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
484365
connectedAt: new Date(),
485366
updatedAt: new Date(),
486367
config: {
368+
// eslint-disable-next-line @typescript-eslint/camelcase, camelcase
487369
installationId: installation_id,
488370
repoId: '',
489371
repoFullName: '',
@@ -497,10 +379,11 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
497379
...taskManagerConfig,
498380
config: {
499381
...project.taskManager.config,
382+
// eslint-disable-next-line @typescript-eslint/camelcase, camelcase
500383
installationId: installation_id,
501384
},
502385
} : taskManagerConfig,
503-
} as any);
386+
} as Partial<ProjectDBScheme>);
504387

505388
log('info', projectId, 'Successfully saved GitHub App installation');
506389
} catch (error) {
@@ -592,7 +475,7 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
592475
try {
593476
await project.updateProject({
594477
taskManager: updatedTaskManager,
595-
} as any);
478+
} as Partial<ProjectDBScheme>);
596479

597480
log('info', projectId, `Successfully saved delegatedUser token for user ${sgr(tokenData.user.login, Effect.ForegroundCyan)}`);
598481
} catch (error) {
@@ -654,7 +537,8 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
654537
*/
655538
const payload = req.body as Buffer;
656539
const hmac = createHmac('sha256', webhookSecret);
657-
hmac.update(payload as any);
540+
541+
hmac.update(payload.toString('binary'), 'binary');
658542
const calculatedSignature = `sha256=${hmac.digest('hex')}`;
659543

660544
/**
@@ -683,10 +567,12 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
683567
/**
684568
* Parse webhook payload
685569
*/
686-
let payloadData: any;
570+
type GitHubWebhookPayload = { installation?: { id?: number | string }; action?: string };
571+
572+
let payloadData: GitHubWebhookPayload;
687573

688574
try {
689-
payloadData = JSON.parse(payload.toString());
575+
payloadData = JSON.parse(payload.toString()) as GitHubWebhookPayload;
690576
} catch (error) {
691577
log('error', 'Failed to parse webhook payload:', error);
692578

@@ -797,7 +683,7 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
797683
/**
798684
* Check if taskManager is configured
799685
*/
800-
const taskManager = (project as any).taskManager;
686+
const taskManager = project.taskManager;
801687

802688
if (!taskManager) {
803689
res.status(400).json({ error: 'Task Manager is not configured for this project' });
@@ -825,7 +711,8 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
825711
/**
826712
* Log repository details for debugging
827713
*/
828-
const repoOwners = [...new Set(repositories.map((r) => r.fullName.split('/')[0]))];
714+
const repoOwners = [ ...new Set(repositories.map((r) => r.fullName.split('/')[0])) ];
715+
829716
log('info', projectId, `Retrieved ${repositories.length} repository(ies) for installation ${installationId}`);
830717
log('info', projectId, `Repository owners: ${repoOwners.join(', ')}`);
831718

@@ -884,7 +771,7 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
884771
/**
885772
* Check if taskManager is configured
886773
*/
887-
const taskManager = (project as any).taskManager;
774+
const taskManager = project.taskManager;
888775

889776
if (!taskManager) {
890777
res.status(400).json({ error: 'Task Manager is not configured for this project' });
@@ -908,7 +795,7 @@ export function createGitHubRouter(factories: ContextFactories): express.Router
908795
try {
909796
await project.updateProject({
910797
taskManager: updatedTaskManager,
911-
} as any);
798+
});
912799

913800
log('info', validatedProjectId, `Updated repository selection: ${repoFullName} (${repoId})`);
914801

0 commit comments

Comments
 (0)