UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

171 lines (170 loc) 5.13 kB
import { i as registerSecretValueForRedaction } from "./secret-redaction-registry-BOLC6DkF.js"; import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js"; import { o as sha256HexPrefixCore } from "./crypto-digest-C4hqTb_e.js"; import { r as runCommandWithTimeout } from "./exec-BIE-3oLG.js"; import { a as inspectPathPermissions } from "./permissions-BhjKuixU.js"; import { a as managedGitHubIdentityEnvironment, v as writeManagedGitHubProfileFiles } from "./github-tool-identity-CsNyDjEx.js"; import path from "node:path"; import fs from "node:fs/promises"; //#region src/worker/github-binding.runtime.ts const log = createSubsystemLogger("worker/github"); async function bindWorkerGitHubCheckout(cwd, binding, baseEnv, signal) { const git = (args, timeoutMs = 5e3) => runCommandWithTimeout([ "git", "-C", cwd, ...args ], { baseEnv, timeoutMs, maxOutputBytes: { stdout: 1048576, stderr: 2048 }, ...signal ? { signal } : {} }); const requireGit = async (args) => { const result = await git(args); if (result.code !== 0 || result.stdoutTruncatedBytes) throw new Error(`git ${args[0]} failed or output was truncated (exit ${result.code})`); return result.stdout; }; try { if ((await git(["rev-parse", "--git-dir"])).code !== 0) return; if (binding.remoteUrl) { const origin = await git([ "remote", "get-url", "origin" ]); if (origin.code !== 0) await requireGit([ "remote", "add", "origin", binding.remoteUrl ]); else if (origin.stdout.trim() !== binding.remoteUrl) await requireGit([ "remote", "set-url", "origin", binding.remoteUrl ]); } const head = await git([ "symbolic-ref", "--quiet", "HEAD" ]); const branch = `refs/heads/${binding.branch}`; if (head.code !== 0 || head.stdout.trim() !== branch) { await requireGit([ "update-ref", branch, "HEAD" ]); await requireGit([ "symbolic-ref", "HEAD", branch ]); } if (!binding.remoteUrl || signal?.aborted) return; const fetched = await git([ "fetch", "--quiet", "origin", binding.branch ], 6e4); if (fetched.code !== 0) { if (fetched.stderr.includes("couldn't find remote ref")) return; throw new Error(`git fetch failed (exit ${fetched.code})`); } await requireGit([ "update-ref", `refs/remotes/origin/${binding.branch}`, "FETCH_HEAD" ]); await requireGit([ "branch", `--set-upstream-to=origin/${binding.branch}`, binding.branch ]); const local = (await requireGit(["rev-parse", "HEAD"])).trim(); const remote = (await requireGit(["rev-parse", "FETCH_HEAD"])).trim(); if (local === remote) return; if ((await git([ "merge-base", "--is-ancestor", "HEAD", "FETCH_HEAD" ])).code !== 0) { log.warn(`GitHub checkout fast-forward skipped: ${binding.branch} HEAD=${local.slice(0, 7)} origin=${remote.slice(0, 7)}`); return; } if (signal?.aborted) return; const listDeleted = async () => (await requireGit([ "ls-files", "--deleted", "-z" ])).split("\0").filter(Boolean); const deletedBefore = new Set(await listDeleted()); await requireGit([ "reset", "--mixed", "FETCH_HEAD" ]); const missing = (await listDeleted()).filter((file) => !deletedBefore.has(file)); if (missing.length > 0) await requireGit([ "--literal-pathspecs", "checkout", "--", ...missing ]); } catch (error) { log.warn(`GitHub checkout binding failed: ${String(error).slice(0, 2048)}`); } } async function prepareWorkerGitHubEnvironment(params) { const { binding, stateDir, runId, cwd, signal } = params; registerSecretValueForRedaction(binding.token); const profilesRoot = path.join(stateDir, "github-profiles"); const profileDir = path.join(profilesRoot, sha256HexPrefixCore(runId, 16)); try { await fs.rm(profilesRoot, { recursive: true, force: true }); await writeManagedGitHubProfileFiles(profileDir, binding); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Worker GitHub identity profile could not be written: ${message}`, { cause: error }); } const localIdentityEnv = managedGitHubIdentityEnvironment({ profileDir, gitAuthor: binding.gitAuthor, gitConfig: [["credential.helper", ""], ["credential.helper", "!gh auth git-credential"]] }); if (process.platform === "win32") { const permissions = await inspectPathPermissions(profileDir); if (!permissions.ok || permissions.source !== "windows-acl" || permissions.ownerTrusted !== true || permissions.groupReadable || permissions.worldReadable || permissions.groupWritable || permissions.worldWritable) { log.warn(`GitHub binding skipped: profile is not owner-only: ${profileDir}`); return; } } await bindWorkerGitHubCheckout(cwd, binding, { ...process.env, ...localIdentityEnv, GH_TOKEN: binding.token, GITHUB_TOKEN: "" }, signal); return { managedLocalIdentity: true, excludedStoreNames: [], credentialScrubEnv: { GH_TOKEN: "", GITHUB_TOKEN: "" }, localIdentityEnv }; } //#endregion export { prepareWorkerGitHubEnvironment };