"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkoutRepo = void 0; const fs_1 = require("fs"); const path_1 = require("path"); const simple_git_1 = require("simple-git"); const context_1 = require("./context"); const pino_1 = __importDefault(require("pino")); const logger = (0, pino_1.default)({ level: process.env.LOG_LEVEL || 'info' }); const checkoutRepo = async (tempDir, options = {}) => { const ctx = (0, context_1.getCurrentContext)(); if (!ctx) throw new Error('No context available for checkout'); // Verify git is available const git = (0, simple_git_1.simpleGit)(); try { await git.raw(['--version']); } catch (e) { throw new Error('git command not found in PATH. Please install git.'); } const { owner, repo } = ctx.repo; const installationId = ctx.probotContext.payload.installation?.id; if (!installationId) { throw new Error('Installation ID not found in payload'); } const { token } = (await ctx.probotContext.octokit.auth({ type: 'installation' })); if (!token) { throw new Error('Failed to create installation access token: token is undefined'); } // Ensure gh CLI is authenticated for subsequent contexts process.env.GH_TOKEN = token; process.env.GITHUB_TOKEN = token; // SECURITY: Use token via environment variable, NOT in URL // This prevents token exposure in process listings and logs const cloneUrl = `https://github.com/${owner}/${repo}.git`; const isPullRequest = !!ctx.probotContext.payload.pull_request; const headBranch = isPullRequest ? ctx.probotContext.payload.pull_request.head.ref : (ctx.probotContext.payload.ref?.replace('refs/heads/', '') || ctx.probotContext.payload.repository?.default_branch || 'main'); const headSha = isPullRequest ? ctx.probotContext.payload.pull_request.head.sha : (options.ref || ctx.probotContext.payload.after); // Set up git credential helper for secure token authentication process.env.GIT_ASKPASS = 'echo'; process.env.GIT_USERNAME = 'x-access-token'; process.env.GIT_PASSWORD = token; if ((0, fs_1.existsSync)(tempDir)) { (0, fs_1.rmSync)(tempDir, { recursive: true, force: true }); } (0, fs_1.mkdirSync)(tempDir, { recursive: true }); logger.info({ owner, repo, tempDir }, 'Cloning repository'); const repoGit = (0, simple_git_1.simpleGit)(tempDir, { timeout: { block: 120000 } // 2 minute timeout for all git operations }); try { if (options.sparse && options.files && options.files.length > 0) { logger.info({ fileCount: options.files.length }, 'Using sparse checkout'); // Initialize empty repo and configure sparse checkout await repoGit.init(['--bare']); await repoGit.addRemote('origin', cloneUrl); // Configure sparse checkout await repoGit.raw(['config', 'core.sparseCheckout', 'true']); (0, fs_1.writeFileSync)((0, path_1.join)(tempDir, '.git/info/sparse-checkout'), options.files.join('\n')); // Fetch and checkout specific commit await repoGit.fetch(['origin', headSha, '--depth', '1']); await repoGit.checkout(['FETCH_HEAD']); } else { logger.info('Performing full shallow clone'); // Clone with depth 1 for efficiency await repoGit.clone(cloneUrl, '.', [ '--depth', '1', '--single-branch', '--branch', headBranch, '--no-checkout' ]); // Fetch and checkout specific SHA await repoGit.fetch(['origin', headSha, '--depth', '1']); await repoGit.checkout([headSha]); } // Configure git identity await repoGit.addConfig('user.name', 'PRIX AI Auditor'); await repoGit.addConfig('user.email', 'bot@prix.ai'); logger.info({ owner, repo, headSha }, 'Repository cloned successfully'); } catch (error) { logger.error({ error, owner, repo }, 'Git operation failed'); throw new Error(`Failed to clone repository: ${error}`); } return tempDir; }; exports.checkoutRepo = checkoutRepo; //# sourceMappingURL=checkout.js.map