Skip to content

Commit 76bd893

Browse files
author
Shaurya Singh
committed
fix: use GitHub App installation token instead of encrypted PAT for analysis jobs
1 parent 4c57c6a commit 76bd893

File tree

4 files changed

+15
-18
lines changed

4 files changed

+15
-18
lines changed

src/analysis/pipeline.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Job } from 'bullmq';
22
import { AnalysisJobData } from '../queue/jobs';
3-
import { createGitHubClient } from '../github/client';
3+
import { getInstallationOctokit } from '../github/app-client';
44
import { fetchRepoSnapshot } from '../github/fetchers';
55
import { generateAllOutputs } from '../ai/generator';
66
import { decrypt } from '../utils/encryption';
@@ -11,7 +11,7 @@ import db from '../db/client';
1111
* Main analysis pipeline processor
1212
*/
1313
export async function processAnalysisJob(job: Job<AnalysisJobData>): Promise<void> {
14-
const { jobId, repoId, userId, owner, repo, branch, depth, tone, ignorePaths, accessToken } = job.data;
14+
const { jobId, repoId, userId, owner, repo, branch, depth, tone, ignorePaths, installationId } = job.data;
1515

1616
try {
1717
// Update job status to running
@@ -20,8 +20,8 @@ export async function processAnalysisJob(job: Job<AnalysisJobData>): Promise<voi
2020

2121
// Step 1: Fetch GitHub data (0-25%)
2222
await job.updateProgress(5);
23-
const decryptedToken = decrypt(accessToken);
24-
const octokit = createGitHubClient(decryptedToken);
23+
console.log(`📡 Getting GitHub App installation token for installation: ${installationId}`);
24+
const octokit = await getInstallationOctokit(installationId);
2525

2626
await updateJobStatus(jobId, 'running', 25, 'Fetching repository data...');
2727
const snapshot = await fetchRepoSnapshot(octokit, owner, repo, branch, depth, ignorePaths);

src/queue/jobs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface AnalysisJobData {
1111
depth: 'fast' | 'deep';
1212
tone: 'concise' | 'detailed';
1313
ignorePaths: string[];
14-
accessToken: string;
14+
installationId: number;
1515
}
1616

1717
export interface ExportJobData {

src/routes/jobs.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AuthenticatedRequest, requireAuth } from '../auth/middleware';
33
import { resolveRepoId, verifyJobOwnership } from '../auth/ownership';
44
import { enqueueAnalysisJob } from '../queue/jobs';
55
import { generateSnapshotHash, findRecentJob, createAnalysisJob } from '../analysis/idempotency';
6+
import { getUserInstallationId } from '../github/app-client';
67
import db from '../db/client';
78

89
export default async function jobsRoutes(fastify: FastifyInstance) {
@@ -39,17 +40,12 @@ export default async function jobsRoutes(fastify: FastifyInstance) {
3940
const repo = repoResult.rows[0];
4041
const [owner, repoName] = repo.full_name.split('/');
4142

42-
// Get GitHub access token
43-
const tokenResult = await db.query(
44-
'SELECT access_token_encrypted FROM github_accounts WHERE user_id = $1 LIMIT 1',
45-
[req.userId]
46-
);
43+
// Get GitHub App installation ID
44+
const installationId = await getUserInstallationId(req.userId, db);
4745

48-
if (tokenResult.rows.length === 0) {
49-
return reply.status(404).send({ error: 'No GitHub account connected' });
46+
if (!installationId) {
47+
return reply.status(404).send({ error: 'No GitHub App installed. Please install the GitHub App.' });
5048
}
51-
52-
const accessToken = tokenResult.rows[0].access_token_encrypted;
5349

5450
// For idempotency, using current timestamp as part of hash
5551
// In production, would fetch latest commit SHA
@@ -84,7 +80,7 @@ export default async function jobsRoutes(fastify: FastifyInstance) {
8480
depth: repo.analysis_depth,
8581
tone: repo.output_tone,
8682
ignorePaths: repo.ignore_paths || [],
87-
accessToken,
83+
installationId,
8884
});
8985

9086
return reply.status(202).send({

src/scheduler/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ async function checkScheduledRepos() {
4444
rs.output_tone,
4545
rs.ignore_paths,
4646
rs.schedule,
47-
ga.access_token_encrypted,
47+
ga.installation_id,
4848
(SELECT created_at FROM analysis_jobs
4949
WHERE repo_id = r.id
5050
ORDER BY created_at DESC
@@ -53,7 +53,8 @@ async function checkScheduledRepos() {
5353
JOIN repo_settings rs ON rs.repo_id = r.id
5454
JOIN github_accounts ga ON ga.user_id = r.user_id
5555
WHERE r.status = 'active'
56-
AND rs.schedule != 'manual'`
56+
AND rs.schedule != 'manual'
57+
AND ga.installation_id IS NOT NULL`
5758
);
5859

5960
for (const repo of result.rows) {
@@ -150,7 +151,7 @@ async function scheduleRepoAnalysis(repo: any) {
150151
depth: repo.analysis_depth,
151152
tone: repo.output_tone,
152153
ignorePaths: repo.ignore_paths || [],
153-
accessToken: repo.access_token_encrypted,
154+
installationId: repo.installation_id,
154155
});
155156

156157
console.log(`✅ Scheduled analysis for ${repo.full_name} (Job ID: ${jobId})`);

0 commit comments

Comments
 (0)