Skip to content

Commit 8d95ff6

Browse files
mizchiclaude
andcommitted
fix: allow git requests without session_token
Clone clients don't have the session_token (only the serve side gets it from register). Git routes now only check that the session is active, while poll/respond/info still require session_token. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4b7e95b commit 8d95ff6

3 files changed

Lines changed: 23 additions & 18 deletions

File tree

src/git_serve_session.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,12 @@ export function createGitServeSession(): {
153153
}
154154

155155
async function handleGitRequest(request: Request, gitPath: string): Promise<Response> {
156-
const denied = validateToken(request);
157-
if (denied) return denied;
156+
if (!state.active) {
157+
return Response.json(
158+
{ ok: false, error: 'session not active' },
159+
{ status: 404 },
160+
);
161+
}
158162

159163
const requestId = generateRequestId();
160164
let bodyBase64: string | null = null;

tests/e2e_multi_node_test.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -250,14 +250,7 @@ Deno.test('e2e: session tokens are isolated - cross-node access denied', async (
250250
assertEquals(infoRes.status, 403, `node-${attacker} should not access node-${target} info`);
251251
await infoRes.json();
252252

253-
// git request
254-
const gitRes = await fetch(
255-
`${relay.baseUrl}/git/${
256-
nodes[target].sessionId
257-
}/info/refs?service=git-upload-pack&session_token=${nodes[attacker].sessionToken}`,
258-
);
259-
assertEquals(gitRes.status, 403, `node-${attacker} should not access node-${target} git`);
260-
await gitRes.json();
253+
// git requests are open (clone clients don't have session_token)
261254
}
262255
}
263256
} finally {
@@ -478,21 +471,21 @@ Deno.test('e2e: broadcast triggers cross-node fetch (5 nodes)', async () => {
478471
}
479472
});
480473

481-
Deno.test('e2e: no token → git request returns 403', async () => {
474+
Deno.test('e2e: no token → poll/respond returns 403, git request allowed', async () => {
482475
const relay = startRelay();
483476
try {
484477
const node = await registerNode(relay.baseUrl, 'server');
485478

486-
// Request without token
479+
// Poll without token → 403
487480
const res1 = await fetch(
488-
`${relay.baseUrl}/git/${node.sessionId}/info/refs?service=git-upload-pack`,
481+
`${relay.baseUrl}/api/v1/serve/poll?session=${node.sessionId}&timeout=1`,
489482
);
490483
assertEquals(res1.status, 403);
491484
await res1.json();
492485

493-
// Request with wrong token
486+
// Poll with wrong token → 403
494487
const res2 = await fetch(
495-
`${relay.baseUrl}/git/${node.sessionId}/info/refs?service=git-upload-pack&session_token=bad`,
488+
`${relay.baseUrl}/api/v1/serve/poll?session=${node.sessionId}&timeout=1&session_token=bad`,
496489
);
497490
assertEquals(res2.status, 403);
498491
await res2.json();

tests/git_serve_session_test.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,14 +361,22 @@ Deno.test('session_token via x-session-token header works', async () => {
361361
}
362362
});
363363

364-
Deno.test('git request without session_token returns 403', async () => {
364+
Deno.test('git request without session_token is allowed', async () => {
365365
const session = createGitServeSession();
366366
try {
367-
await registerSession(session);
367+
const token = await registerSession(session);
368+
// git requests don't require session_token (clone clients don't have it)
369+
// Start a poll to consume the request
370+
const pollP = session.fetch(
371+
new Request(`http://do/poll?timeout=2&session_token=${token}`),
372+
);
368373
const res = await session.fetch(
369374
new Request('http://do/git/info/refs?service=git-upload-pack'),
370375
);
371-
assertEquals(res.status, 403);
376+
// The request should be accepted (pending response from serve side)
377+
// We don't need to fully complete the flow, just verify it's not 403
378+
assertEquals(res.status !== 403, true);
379+
await pollP;
372380
} finally {
373381
session.cleanup();
374382
}

0 commit comments

Comments
 (0)