Skip to content

Commit 5a3f867

Browse files
authored
Add fallback RCC user for roomote and pass job id consistently (#216)
Use Matt as the fallback user for now.
1 parent 17ce731 commit 5a3f867

File tree

12 files changed

+134
-26
lines changed

12 files changed

+134
-26
lines changed

.env.development

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ FLY_ACCESS_TOKEN="encrypted:BDm2qpf85nXBtq7KENGMiwcsFg3Ln/gRcZoUm5busQ8tRgEDXhlX
2424

2525
JOB_AUTH_PRIVATE_KEY="encrypted:BM7xBs73k3nh0isBhVELr4LFt2iMiP7XD7knKtEnm7uudQ9DclnL+Hulun8SFFsGzkIp+FyYK47JAMHqyK3NqGHE/93efpACNRNH/YVv0OfUvVw58trPdvdY60hnUrW17z/ae16LlvkBd6roCZxn0GvhgMKPRxlL1B4ZxxtfHfz+yazl0tSsr2t/iMzIhRCtQZ1638PrZJ7ugmsK1lK5g+cQDV91Onth+eVNy6cDX9NAC77iotnzXyOWPyzcxECCSje2jYysAugTTRV2pR/Lnzi506yrWumSv5SpNcDqZjek89CK29nfUJv+UIxxW2dIMIB19ZqjmSU84nIYymVzkwl7kOaDqTIEIMRSzYs/npTWDOGbtB2x49vaD5YeysFiamLlaSzvS46N+uiSrH+8VCujs7HLirOJhtkindVRiV4qfl/eycf9OG2A4jNWhS/uJYcF2QC8KZL1SwKcn7u+FDov1NAYUw25BmeYVvb+KPujsaH1DniqucaxtcGqior1ZjKU5RutbzV5QWknpNAtBD2aVv0HOB7/5bHJpwFl2vaR"
2626
JOB_AUTH_PUBLIC_KEY="encrypted:BOU3vH2HFJjRuORyr3psrDpqaXS1hXo2SxA3N2q4M2ihHgHNnbjbKAV3xYHTo9WQA6XGvRWXpo3C/soV6ukMQGkqmvjyCNPVLN3ZlJJlmbBC1qRTn83dejp4YCqV0eb3JOyOhYVpuCCIcYU3s67MRqywTxST1h1PRo3xykpgm3nY0kfZMmHvL7rTh4ik6uVebDhIY7jDrXRWlj/dia/cyEDzB88cBpmCpJx8uqFmK9889+Le4PTb7hLBIv7KvkzMb4TaB4yqpUFd/bawA0fOX5WC85t2DZ+7+Ddqp7s4x6nsNWjh51t0uYGICdF1ReWI1jZ4nKGjxpXcjfmgcXPnOT6PdjOWfMWfMGq+sE7o1GUdu5GKVwATYe4+NXrcMVsTQKdbtRrl4k1lz46jgAegUemGuBxR4Ro6qxK5xhsKeyaMnbrH8f/X0BZHAGOx"
27+
28+
ROOMOTE_FALLBACK_USER_ID="user_2wbhXyFa2AKzjh5GEqyPz3wGlN3"

.env.preview

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ FLY_ACCESS_TOKEN="encrypted:BCoSnp5DqB0Td27HYtDwIS/dZfZkyvjsgUz+0XcKdovFMr3/ZRZk
2424

2525
JOB_AUTH_PRIVATE_KEY="encrypted:BFm76/By4KHU3bILl4tYJOwwHN8xR49C/wcSrh8/0+QAhYgetocntzJ90fYS3+ER2e/Mdh1awOynhbsZ/gpLJC6PmqX+MKzkpv/xJC5AJZTAeyWAKwaL1NhUijAU8mS88/87EvKZCH9Rw/tBGy/7CFrOwipjKQxvuRZjgxmypkV8t6eIEmfGgIbzrjvSyZ6O31FpYliAABeefRpNQo3zd7tV3dX9xtVDt1Hc68vzak0Aw+EJwi+Q7YWvghpcLJxXXo+PYs15Cj9LS8Ww2Ijz/EXO98UIDMN1e947O7hrmTWPC/JVZlGJOctMyNyaX/+rSJP+XepJxkVYeG9jglOLOsIFS+KKiYfnlT3TC5pt9USaAQAsdWvcfT09TN4qYR/eeSfj7mZYNCU4LtIqrFVT65ehntTOokqN7uNSLmSQnzPIO9lhIVcarFz1C9Bx/xE4FaBVKm9agszVcUumJcfktuV/WTxRxgTmhJYbJ08shhrTubWDCxOGdr5NFR+NFN5oMe9KXCOcUjtuHQ8UUSjYwXvZzJOvRAMP0QAv5xzGTlQI"
2626
JOB_AUTH_PUBLIC_KEY="encrypted:BPcQ3GgxlCm77QmmsLm5jzFLzCVRuDJzPC7t3jfMbPYNGMBveYIJvrmnpHCNSJIGCrHi0MtFUypvyjjHgQADNN8GaWpyvifk8jTBtp1ptQq736ilxq/Z76KY96uHf59TQCvPR2pjsu7GK0AqL3wg1MV+30+wZzGNo2JYZYczMdYgrMj72d2qsOPydUgPAkXcwRMigNyPhF8JdOT9G5l1w+qRKjRSFynFIXcP61J9kykeYz3BmCIeKw2QopSYz3ie98o+PTmnyQ3KGgEdJ7IVTmV3AglWMJx6Gj6qo8hMW+pUJU790nj9FMkMHHnAIRvhEX9MmInNu+ysVuowKWfxB3IC8A9ktgk3TOZ4/Ub1EZ3rWGVyR9xVFLSYPUlW2s/PfPA8b+KdSd/QDRpGhJ0rd6pl8r33/HOErwu6Mta/4NHIBR9SRj8SrjCNTPG0"
27+
28+
ROOMOTE_FALLBACK_USER_ID="user_2wbhXyFa2AKzjh5GEqyPz3wGlN3"

.env.production

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ FLY_ACCESS_TOKEN="encrypted:BFcS7pt6Evj8OG1khLFJkqzg2MI/pP4g4tP1l85vbsiTL1x1Ovjs
2424

2525
JOB_AUTH_PRIVATE_KEY="encrypted:BNv2gXyx2FICPfSCJxDJX0ELwt35/Ie/WR0xUai/k9OqEM8p2rhLkRkde45dioGlEPbETZgWa6PDD9mXCR8qBWh4iZziDEwYd8x1uFTx26BBs1MyWk8WhRhjhQMXi0h8V7inVELiPtMcq40aSJ/2S2yTR/qyNlW0YrhQJO1FeU13n5Eelp5PSvmCVDMu+f5m4m5haiJIzvnXbnETOGqatWWNn3qXY/neyfTLlv21E95ulu2bUP1/4iRw4tf0e5LIf4TLeo3M2tSuUc/s7sELb6hNkBtBZCPkQG1+dHci/6MLrer0LiMF3Pv3fUP9ZRfRu8AnOjHuk6xBq3EshbTE+NQoWSf/47F23lHnY+pU+1cT2W+3L21RvZiVoENWC00/udbyNx5GglZmRY8+pZHUwS0l7FFVFtjXJxQigLtMsCijmmZhfz+JAlOouOUoh26HzvB7dcyHnwsXhGwEiG8wmUi8lFCmFosdMp210SRpfrJ/NywObBHYSUXDyELEpS6+GTeZQDmUs44vQ7v58waDHRQvJXGxIw4zK+s+WGlbHTnF"
2626
JOB_AUTH_PUBLIC_KEY="encrypted:BAWhQhxInT33caEIc2QQ16wSjJ7SqJ2nYc0FEwQboBfajqh9mp2SVwH/A9CbbM+JrVbqYjNamVCf+BdIJVKn4rTrrV64HVMI5T++EfxPmN59sQWgqb4Ig3DXnoo9UanXGccn23dB/k4ZtweoHSPeVXn8XbZ867TPO3QLI1Xr6fLfgxHZXcyvH6lEZlClJjM+SLRLtixkvKb5c2y1JG6cVQ+dHrvxuh10FdCFzfhkEvPHdv09dWpw6OrPfxBEk+dHpjXWO54p/4WThjJ+41Rpqne0pupLwkILaa/xMj364Q/duTKORUDdnDc+Mk9TMgHuj2M5kQGSSXXuNO4shGxupoA2y5HRI9IhjNKQIq2qikUjzzxjvfHs5ESj6DfJsDq5AwiqU6vD7XcQFbJLaUZc8FioN+gEiHnNvCoi6ZSKjvrCggt5afN+lGVNyROe"
27+
28+
ROOMOTE_FALLBACK_USER_ID="user_2xjmYpL6p3dfIFLaxJl2WNOSS7X"

.env.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ FLY_ACCESS_TOKEN="encrypted:BIobJarcf4MpmWDkSjVGjXUH87dNj5rbMqow0/7QNpa1s3eMZeRN
2323

2424
JOB_AUTH_PRIVATE_KEY="encrypted:BB5ohcsYq19krr7Rw4CVtS6GcxEbpWPeobkByt0ppr6oU92AgbbdgMdEEyA8IRFpK6H87ud6DdfV4iRnkwART3HhdJJZe06R8MfV6SCxUioz6uwRmagmeJ5/cmnViUihhFiq/NC7qSD/zfRREuhyKXA/Tr1KTllaoQn89PzpfVM42duSRZcSRQ3/vHV62v+MIRFvm2gWqL2mwgr7RtRDpijyzFvSzgerrorHMOPQTYL5uYAcS20lnFEnWzJfDU/hZmqFvyCnxG3u80IlPu+RWN7xLs/WtXZr+5UFP8sgVFRi18+xrNtam3auA163HbC8u0mk3MeYHfKihN35j+2U24oEg+sflFPSm1EfXS+da1wd7GsVfOv/9jRhSrXju1Vg1DI3PSBygiQXpTD23KtOFy5v96RtAGGUeq94Fxti1jTzngaUNxBSCO69L7PL2fo2g2ZML2GlSfSq7R8Q/T7zsjpirbecOLermJnMP0hgrkCTDaqD008iXYte01wVOqgNRuXIXtIqGrsUSf+eGLLP669TqIbNPOSq1tccOtNnPVAH"
2525
JOB_AUTH_PUBLIC_KEY="encrypted:BI7/E85qpiZMVZ79gLNRMETFCBoja4wq1Gw03BAWTct3GoCypOsgm2tYvbPOVpe/XKqFot7WVzGhaWrvx9blzrp1+LPAHcChNoa61CeUMtrNAL5VQETZ/9SJU1zLFWpHlCJuviu8G+DlC0UwfAQBdutcwhlcwP8fQSGGXgSaCcnshlhsX/tuqSnyCOrQ2kERXEFK4QT0ngETFdOzVqO0/QHbk6tL/86iv4XQ7Iz2g9XLCdAWXxcLzRn7RE9BXna4eCPahJI8NZx50E3gtD6IsQj7msL1p20PWauOJsm4futPdPNZe2k8plR48PAxTYRHgRHwHJukEqQcNjL5LdXBW0fMNQRBJLYjgxJfAs0cm6ioYXqj0cliDharBGQ71YMjsihsCPZAsozibddiKT02lEtLQOiHOp27wfDNkSOXvspkaaxjHoB4j6cTSQWb"
26+
27+
ROOMOTE_FALLBACK_USER_ID="test-user-123"

apps/roomote/src/app/api/webhooks/github/handlers/__tests__/utils.test.ts

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import { createHmac } from 'crypto';
55
vi.mock('@roo-code-cloud/db/server', () => ({
66
db: {
77
insert: vi.fn(),
8+
select: vi.fn(),
89
},
910
cloudJobs: {},
11+
orgs: {},
1012
}));
1113

1214
vi.mock('@/lib', () => ({
@@ -17,17 +19,35 @@ describe('GitHub Webhook Utils', () => {
1719
let verifySignature: typeof import('../utils').verifySignature;
1820
let createAndEnqueueJob: typeof import('../utils').createAndEnqueueJob;
1921
let isRoomoteMention: typeof import('../utils').isRoomoteMention;
20-
let mockDb: { insert: ReturnType<typeof vi.fn> };
22+
let mockDb: {
23+
insert: ReturnType<typeof vi.fn>;
24+
select: ReturnType<typeof vi.fn>;
25+
};
2126
let mockEnqueue: ReturnType<typeof vi.fn>;
2227

2328
beforeEach(async () => {
2429
vi.clearAllMocks();
2530

31+
// Set default environment variable for tests
32+
process.env.ROOMOTE_FALLBACK_USER_ID = 'test-user-123';
33+
2634
const dbModule = await import('@roo-code-cloud/db/server');
2735
const libModule = await import('@/lib');
28-
mockDb = dbModule.db as unknown as { insert: ReturnType<typeof vi.fn> };
36+
mockDb = dbModule.db as unknown as {
37+
insert: ReturnType<typeof vi.fn>;
38+
select: ReturnType<typeof vi.fn>;
39+
};
2940
mockEnqueue = libModule.enqueue as unknown as ReturnType<typeof vi.fn>;
3041

42+
// Mock the select chain for organization lookup
43+
mockDb.select.mockReturnValue({
44+
from: vi.fn().mockReturnValue({
45+
where: vi.fn().mockReturnValue({
46+
limit: vi.fn().mockResolvedValue([{ id: 'default-org-id' }]),
47+
}),
48+
}),
49+
});
50+
3151
const utilsModule = await import('../utils');
3252
verifySignature = utilsModule.verifySignature;
3353
createAndEnqueueJob = utilsModule.createAndEnqueueJob;
@@ -205,7 +225,7 @@ describe('GitHub Webhook Utils', () => {
205225
});
206226
});
207227

208-
it('should log the enqueued job', async () => {
228+
it('should log the enqueued job with user ID', async () => {
209229
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
210230

211231
const type = 'github.issue.fix';
@@ -259,6 +279,57 @@ describe('GitHub Webhook Utils', () => {
259279
createAndEnqueueJob(type, payload, testOrgId),
260280
).rejects.toThrow('Queue service unavailable');
261281
});
282+
283+
it('should always include fallback user ID in job creation', async () => {
284+
const type = 'github.issue.fix';
285+
const payload = {
286+
repo: 'test/repo',
287+
issue: 123,
288+
title: 'Test issue',
289+
body: 'Test body',
290+
};
291+
292+
const mockValuesCall = vi.fn().mockReturnValue({
293+
returning: vi.fn().mockResolvedValue([mockJob]),
294+
});
295+
mockDb.insert.mockReturnValue({
296+
values: mockValuesCall,
297+
});
298+
299+
await createAndEnqueueJob(type, payload, testOrgId);
300+
301+
expect(mockValuesCall).toHaveBeenCalledWith({
302+
type,
303+
payload,
304+
status: 'pending',
305+
orgId: testOrgId,
306+
userId: 'test-user-123',
307+
});
308+
});
309+
310+
it('should throw error when ROOMOTE_FALLBACK_USER_ID is not set', async () => {
311+
const originalEnv = process.env.ROOMOTE_FALLBACK_USER_ID;
312+
delete process.env.ROOMOTE_FALLBACK_USER_ID;
313+
314+
const type = 'github.issue.fix';
315+
const payload = {
316+
repo: 'test/repo',
317+
issue: 123,
318+
title: 'Test issue',
319+
body: 'Test body',
320+
};
321+
322+
await expect(
323+
createAndEnqueueJob(type, payload, testOrgId),
324+
).rejects.toThrow(
325+
'ROOMOTE_FALLBACK_USER_ID environment variable is required but not set',
326+
);
327+
328+
// Restore original environment
329+
if (originalEnv !== undefined) {
330+
process.env.ROOMOTE_FALLBACK_USER_ID = originalEnv;
331+
}
332+
});
262333
});
263334

264335
describe('isRoomoteMention', () => {

apps/roomote/src/app/api/webhooks/github/handlers/utils.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,24 @@ export async function createAndEnqueueJob<T extends JobType>(
4444
throw new Error('Organization ID is required for job creation.');
4545
}
4646

47+
// Require fallback user ID from environment variable
48+
const fallbackUserId = process.env.ROOMOTE_FALLBACK_USER_ID;
49+
50+
if (!fallbackUserId) {
51+
throw new Error(
52+
'ROOMOTE_FALLBACK_USER_ID environment variable is required but not set',
53+
);
54+
}
55+
4756
const [job] = await db
4857
.insert(cloudJobs)
49-
.values({ type, payload, status: 'pending', orgId: organizationId })
58+
.values({
59+
type,
60+
payload,
61+
status: 'pending',
62+
orgId: organizationId,
63+
userId: fallbackUserId,
64+
})
5065
.returning();
5166

5267
if (!job) {

apps/roomote/src/lib/job.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export async function processJob<T extends JobType>({
4444
case 'github.issue.fix':
4545
result = await fixGitHubIssue(
4646
payload as JobPayload<'github.issue.fix'>,
47+
jobId,
4748
{ onTaskStarted },
4849
mode,
4950
);
@@ -52,6 +53,7 @@ export async function processJob<T extends JobType>({
5253
case 'github.issue.comment.respond':
5354
result = await processIssueComment(
5455
payload as JobPayload<'github.issue.comment.respond'>,
56+
jobId,
5557
{ onTaskStarted },
5658
mode,
5759
);
@@ -60,6 +62,7 @@ export async function processJob<T extends JobType>({
6062
case 'github.pr.comment.respond':
6163
result = await processPullRequestComment(
6264
payload as JobPayload<'github.pr.comment.respond'>,
65+
jobId,
6366
{ onTaskStarted },
6467
mode,
6568
);
@@ -69,7 +72,7 @@ export async function processJob<T extends JobType>({
6972
const jobPayload = payload as JobPayload<'slack.app.mention'>;
7073
const { channel, thread_ts } = jobPayload;
7174

72-
result = await processSlackMention(jobPayload, {
75+
result = await processSlackMention(jobPayload, jobId, {
7376
onTaskStarted,
7477
onTaskMessage: async (message: ClineMessage) => {
7578
console.log(`onTaskMessage (${channel}, ${thread_ts}) ->`, message);

apps/roomote/src/lib/jobs/fixGitHubIssue.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88

99
export async function fixGitHubIssue(
1010
jobPayload: JobPayload<'github.issue.fix'>,
11+
jobId?: number,
1112
callbacks?: RunTaskCallbacks,
1213
mode?: string,
1314
) {
@@ -27,6 +28,7 @@ ${MAIN_BRANCH_PROTECTION}
2728
const result = await runTask({
2829
jobType: 'github.issue.fix',
2930
jobPayload,
31+
jobId,
3032
prompt,
3133
callbacks,
3234
mode,

apps/roomote/src/lib/jobs/processIssueComment.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88

99
export async function processIssueComment(
1010
jobPayload: JobPayload<'github.issue.comment.respond'>,
11+
jobId?: number,
1112
callbacks?: RunTaskCallbacks,
1213
mode?: string,
1314
) {
@@ -53,6 +54,7 @@ gh api repos/${jobPayload.repo}/issues/${jobPayload.issueNumber}/comments --meth
5354
const result = await runTask({
5455
jobType: 'github.issue.comment.respond',
5556
jobPayload,
57+
jobId,
5658
prompt,
5759
callbacks,
5860
mode,

apps/roomote/src/lib/jobs/processPullRequestComment.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88

99
export async function processPullRequestComment(
1010
jobPayload: JobPayload<'github.pr.comment.respond'>,
11+
jobId?: number,
1112
callbacks?: RunTaskCallbacks,
1213
mode?: string,
1314
) {
@@ -66,6 +67,7 @@ Do not create a new pull request - work directly on the existing PR branch.
6667
const result = await runTask({
6768
jobType: 'github.pr.comment.respond',
6869
jobPayload,
70+
jobId,
6971
prompt,
7072
callbacks,
7173
mode,

0 commit comments

Comments
 (0)