(
_req: IncomingMessage,
res: ServerResponse,
body: LocalOpCloneRequest,
)
| 8449 | preBodyGate: (req, res) => checkLocalOpSecurity(req, res, { handler: HANDLE_LOCAL_OP_CLONE }), |
| 8450 | }); |
| 8451 | async function handleLocalOpCloneInner( |
| 8452 | _req: IncomingMessage, |
| 8453 | res: ServerResponse, |
| 8454 | body: LocalOpCloneRequest, |
| 8455 | ): Promise<void> { |
| 8456 | const { url, dir, branch } = body; |
| 8457 | |
| 8458 | if (!isAllowedGitUrl(url)) { |
| 8459 | errorResponse( |
| 8460 | res, |
| 8461 | 400, |
| 8462 | 'urn:ok:error:url-not-allowed', |
| 8463 | 'URL protocol is not allowed for clone.', |
| 8464 | { handler: HANDLE_LOCAL_OP_CLONE, cause: new Error(`url=${url}`) }, |
| 8465 | ); |
| 8466 | return; |
| 8467 | } |
| 8468 | if (!isSafeLocalPath(dir)) { |
| 8469 | errorResponse( |
| 8470 | res, |
| 8471 | 400, |
| 8472 | 'urn:ok:error:dir-outside-home', |
| 8473 | 'Clone destination must be within the user home directory.', |
| 8474 | { handler: HANDLE_LOCAL_OP_CLONE, cause: new Error(`dir=${dir}`) }, |
| 8475 | ); |
| 8476 | return; |
| 8477 | } |
| 8478 | |
| 8479 | if (!localOpGuard.tryAcquire(LOCAL_OP_CLONE_KEY)) { |
| 8480 | errorResponse( |
| 8481 | res, |
| 8482 | 429, |
| 8483 | 'urn:ok:error:concurrent-operation', |
| 8484 | 'A clone operation is already in progress.', |
| 8485 | { handler: HANDLE_LOCAL_OP_CLONE, extraHeaders: { 'Retry-After': '30' } }, |
| 8486 | ); |
| 8487 | return; |
| 8488 | } |
| 8489 | |
| 8490 | res.writeHead(200, { |
| 8491 | 'Content-Type': 'application/x-ndjson', |
| 8492 | 'Transfer-Encoding': 'chunked', |
| 8493 | 'X-Content-Type-Options': 'nosniff', |
| 8494 | 'Cache-Control': 'no-cache', |
| 8495 | }); |
| 8496 | |
| 8497 | const writeStreamError = createStreamingErrorWriter(res, HANDLE_LOCAL_OP_CLONE); |
| 8498 | |
| 8499 | let cloneCompleteDir: string | null = null; |
| 8500 | |
| 8501 | const flow = runCloneSubprocess({ |
| 8502 | cliArgs: localOpCliArgs, |
| 8503 | url, |
| 8504 | dir, |
| 8505 | branch, |
| 8506 | timeoutMs: LOCAL_OP_TIMEOUT_MS, |
| 8507 | onEvent: (event) => { |
| 8508 | if (event.type === 'complete') { |
nothing calls this directly
no test coverage detected