@vercel/factory 0.0.23 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @vercel/factory
2
2
 
3
+ ## 0.0.25
4
+
5
+ ### Patch Changes
6
+
7
+ - a0e8c40: `checkoutGitHubRepository` can also fetch a pull request's head (including forks) to `origin/pr/<number>`, and Foreman's `inspect_repository` accepts a `pullRequestNumber`.
8
+
9
+ ## 0.0.24
10
+
11
+ ### Patch Changes
12
+
13
+ - 6a062c0: Authorize Vercel-managed GitHub credentials to act as the factory creator.
14
+
3
15
  ## 0.0.23
4
16
 
5
17
  ### Patch Changes
@@ -157,6 +157,8 @@ interface CheckoutGitHubRepositoryBaseInput {
157
157
  sandbox: GitTransferSandbox;
158
158
  repositorySlug: RepositorySlug;
159
159
  transport: GitHubGitTransport;
160
+ /** Also fetch this pull request's head, including forks, to `refs/remotes/origin/pr/<number>`. */
161
+ pullRequestNumber?: number;
160
162
  }
161
163
  /** Authorized repository checkout with recovery options that require a branch to resume. */
162
164
  type CheckoutGitHubRepositoryInput = CheckoutGitHubRepositoryBaseInput & ({
@@ -227,9 +227,12 @@ async function checkoutGitHubRepository(input) {
227
227
  if (existingOrigin !== "" && existingOrigin.toLowerCase() !== expectedOrigin) throw new GitHubCheckoutConflictError(existingOrigin, expectedOrigin);
228
228
  const resume = input.resumeBranch;
229
229
  if (resume !== void 0 && !isSafeGitRef(resume)) throw new Error(`refusing to resume unsafe branch name: ${resume}`);
230
+ const pullRequestNumber = input.pullRequestNumber;
231
+ if (pullRequestNumber !== void 0 && (!Number.isSafeInteger(pullRequestNumber) || pullRequestNumber < 1)) throw new Error("pullRequestNumber must be a positive integer");
232
+ const pullRequestRef = pullRequestNumber === void 0 ? void 0 : `refs/pull/${pullRequestNumber}/head`;
230
233
  await input.transport.fetch({
231
234
  repository: slug,
232
- refs: []
235
+ refs: pullRequestRef === void 0 ? [] : [pullRequestRef]
233
236
  }, async (bundle) => {
234
237
  await withSandboxGitBundle({
235
238
  sandbox: input.sandbox,
@@ -285,6 +288,14 @@ async function checkoutGitHubRepository(input) {
285
288
  "origin/HEAD"
286
289
  ]);
287
290
  }
291
+ if (pullRequestRef !== void 0) await runSandboxCommand(input.sandbox, [
292
+ "git",
293
+ "-C",
294
+ "repo",
295
+ "fetch",
296
+ path,
297
+ `+${pullRequestRef}:refs/remotes/origin/pr/${pullRequestNumber}`
298
+ ]);
288
299
  if (resume === void 0) return;
289
300
  if ((await input.sandbox.run({ command: [
290
301
  "git",
@@ -1 +1 @@
1
- {"version":3,"file":"github-publication.mjs","names":[],"sources":["../src/github-publication.ts"],"sourcesContent":["import {\n withSandboxGitBundle,\n quoteShellArgument,\n runSandboxCommand,\n type GitHubGitTransport,\n type GitTransferSandbox,\n} from \"./github-transfer\";\nimport type { TaskId } from \"./schema/id\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./schema/repository\";\nimport { agentSessionIdSchema, type AgentSessionId } from \"./schema/session\";\nimport { z } from \"zod\";\n\n/** Minimal sandbox command boundary required by Git checkout and publication helpers. */\nexport interface SandboxGit {\n run(options: SandboxGitCommandInput): PromiseLike<SandboxGitCommandResult>;\n}\n\n/** Shell command submitted through the minimal Git sandbox boundary. */\nexport interface SandboxGitCommandInput {\n command: string;\n}\n\n/** Captured output and optional exit status from a sandbox Git command. */\nexport interface SandboxGitCommandResult {\n stdout: string;\n stderr?: string;\n exitCode?: number;\n}\n\n/** Bounds applied while translating committed workspace changes into GitHub tree entries. */\nexport interface GitHubPublicationLimits {\n maxChangedFiles?: number;\n maxFileBytes?: number;\n}\n\n/** Repository-scoped credentials and transport for the GitHub publication client. */\nexport interface GitHubPublicationClientOptions {\n repository: RepositorySlug;\n token: string;\n fetch?: typeof globalThis.fetch;\n}\n\n/** Pull-request snapshot used to reconcile idempotent publication effects. */\nexport interface GitHubPublicationPullRequest {\n pullRequestNumber: number;\n pullRequestUrl: string;\n nodeId: string;\n title: string;\n body: string | null;\n state: \"open\" | \"closed\";\n draft: boolean;\n head: {\n branch: string;\n sha: string;\n repository: RepositorySlug | null;\n };\n}\n\n/** Git Data and pull-request operations needed by supplied publication workflows. */\nexport interface GitHubPublicationClient {\n commit(input: ReadGitHubCommitInput): Promise<GitHubCommit>;\n branchHead(input: ReadGitHubBranchHeadInput): Promise<string | null>;\n createTree(input: CreateGitHubTreeInput): Promise<string>;\n createCommit(input: CreateGitHubCommitInput): Promise<string>;\n createBranch(input: CreateGitHubBranchInput): Promise<void>;\n updateBranch(input: UpdateGitHubBranchInput): Promise<void>;\n createPullRequest(\n input: CreateGitHubPublicationPullRequestInput,\n ): Promise<CreatedGitHubPublicationPullRequest>;\n pullRequest(input: ReadGitHubPullRequestInput): Promise<GitHubPublicationPullRequest>;\n pullRequests(\n input: ListGitHubPublicationPullRequestsInput,\n ): Promise<readonly GitHubPublicationPullRequest[]>;\n markReady(input: MarkGitHubPullRequestReadyInput): Promise<void>;\n}\n\n/** Exact commit requested from GitHub's Git Data API. */\nexport interface ReadGitHubCommitInput {\n sha: string;\n}\n\n/** Tree and parents recorded for one GitHub commit. */\nexport interface GitHubCommit {\n treeSha: string;\n parentShas: readonly string[];\n}\n\n/** Exact branch whose current GitHub head should be read. */\nexport interface ReadGitHubBranchHeadInput {\n branch: string;\n}\n\n/** Base tree and exclusive file operations used to create a GitHub tree. */\nexport interface CreateGitHubTreeInput {\n baseTreeSha: string;\n entries: readonly GitHubTreeEntry[];\n}\n\n/** Commit content and parent identities used to create a GitHub commit. */\nexport interface CreateGitHubCommitInput {\n message: string;\n treeSha: string;\n parentShas: readonly string[];\n}\n\n/** Branch and commit identity used to create a GitHub branch. */\nexport interface CreateGitHubBranchInput {\n branch: string;\n sha: string;\n}\n\n/** Branch update and force policy used to move a GitHub branch. */\nexport interface UpdateGitHubBranchInput extends CreateGitHubBranchInput {\n force: boolean;\n}\n\n/** Provider-owned pull-request number to read. */\nexport interface ReadGitHubPullRequestInput {\n pullRequestNumber: number;\n}\n\n/** Provider GraphQL node identity of a draft pull request to mark ready. */\nexport interface MarkGitHubPullRequestReadyInput {\n nodeId: string;\n}\n\n/** Pull-request presentation and branch inputs used during GitHub publication. */\nexport interface CreateGitHubPublicationPullRequestInput {\n title: string;\n body: string;\n head: string;\n base: string;\n draft: boolean;\n}\n\n/** Provider identity and draft state returned after creating a pull request. */\nexport interface CreatedGitHubPublicationPullRequest {\n pullRequestNumber: number;\n pullRequestUrl: string;\n draft: boolean;\n}\n\n/** State and optional exact head filter used to list publication pull requests. */\nexport interface ListGitHubPublicationPullRequestsInput {\n state: \"open\" | \"all\";\n head?: string;\n}\n\n/** GitHub publication failure that preserves the provider HTTP status. */\nexport class GitHubPublicationApiError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(`GitHub API request failed (${status}): ${message}`);\n this.name = \"GitHubPublicationApiError\";\n }\n}\n\ninterface GitHubTreeEntryBase {\n path: string;\n mode: \"100644\" | \"100755\";\n type: \"blob\";\n}\n\n/** File content uploaded through GitHub's Git Data API. */\nexport interface GitHubTreeUpsert extends GitHubTreeEntryBase {\n content: string;\n sha?: never;\n}\n\n/** Existing file removed through GitHub's Git Data API. */\nexport interface GitHubTreeDeletion extends GitHubTreeEntryBase {\n sha: null;\n content?: never;\n}\n\n/** Exclusive bounded file upsert or deletion accepted by GitHub's Git Data API. */\nexport type GitHubTreeEntry = GitHubTreeUpsert | GitHubTreeDeletion;\n\n/** Committed workspace delta represented against a specific base commit. */\nexport interface CommittedGitChange {\n base: string;\n commitMessage: string;\n tree: readonly GitHubTreeEntry[];\n changedFiles: number;\n}\n\n/** Sandbox, repository, and bounds for reading a committed workspace delta. */\nexport interface ReadCommittedGitChangeInput extends GitHubPublicationLimits {\n sandbox: SandboxGit;\n repositorySlug: RepositorySlug;\n baseRef?: string;\n allowEmpty?: boolean;\n}\n\n/** Common dependencies for an authorized repository checkout. */\ninterface CheckoutGitHubRepositoryBaseInput {\n sandbox: GitTransferSandbox;\n repositorySlug: RepositorySlug;\n transport: GitHubGitTransport;\n}\n\n/** Authorized repository checkout with recovery options that require a branch to resume. */\nexport type CheckoutGitHubRepositoryInput = CheckoutGitHubRepositoryBaseInput &\n (\n | {\n resumeBranch?: never;\n rememberPublishedHead?: never;\n }\n | {\n /** Resume this remote branch when it exists after refreshing the default branch. */\n resumeBranch: string;\n /** Remember the resumed remote head for later publication reconciliation. */\n rememberPublishedHead?: true;\n }\n );\n\n/** Refusal raised when an existing sandbox checkout points at another repository. */\nexport class GitHubCheckoutConflictError extends Error {\n constructor(\n readonly existingOrigin: string,\n readonly expectedOrigin: string,\n ) {\n super(`sandbox checkout ${existingOrigin} does not match ${expectedOrigin}`);\n this.name = \"GitHubCheckoutConflictError\";\n }\n}\n\nconst safePathPattern = /^[A-Za-z0-9.][A-Za-z0-9._/-]*$/u;\nconst safeRefPattern = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/u;\nconst allowedModes = new Set([\"100644\", \"100755\"]);\nconst gitHubApiUrl = \"https://api.github.com\";\n\nconst shaSchema = z.string().min(1);\nconst pullRequestSchema = z.object({\n number: z.number().int().positive(),\n html_url: z.url(),\n node_id: z.string().min(1),\n title: z.string(),\n body: z.string().nullable(),\n state: z.enum([\"open\", \"closed\"]),\n draft: z.boolean(),\n head: z.object({\n ref: z.string().min(1),\n sha: shaSchema,\n repo: z.object({ full_name: z.string().min(1) }).nullable(),\n }),\n});\n\n/** GitHub Git Data and pull-request operations used by publication workflows. */\nexport function createGitHubPublicationClient(\n options: GitHubPublicationClientOptions,\n): GitHubPublicationClient {\n const repository = repositorySlugSchema.parse(options.repository.toLowerCase());\n const request = async (path: string, init: RequestInit = {}): Promise<unknown> => {\n let response: Response;\n try {\n response = await (options.fetch ?? globalThis.fetch)(\n `${gitHubApiUrl}/repos/${repository}${path}`,\n {\n ...init,\n headers: {\n Accept: \"application/vnd.github+json\",\n Authorization: `Bearer ${options.token}`,\n \"Content-Type\": \"application/json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...init.headers,\n },\n },\n );\n } catch (error) {\n throw new Error(\"GitHub API request failed\", { cause: error });\n }\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n const parsed = z.object({ message: z.string() }).safeParse(body);\n throw new GitHubPublicationApiError(\n response.status,\n parsed.success ? parsed.data.message : response.statusText,\n );\n }\n return body;\n };\n const graphql = async (query: string, variables: Record<string, unknown>): Promise<void> => {\n let response: Response;\n try {\n response = await (options.fetch ?? globalThis.fetch)(`${gitHubApiUrl}/graphql`, {\n method: \"POST\",\n headers: {\n Accept: \"application/vnd.github+json\",\n Authorization: `Bearer ${options.token}`,\n \"Content-Type\": \"application/json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n },\n body: JSON.stringify({ query, variables }),\n });\n } catch (error) {\n throw new Error(\"GitHub GraphQL request failed\", { cause: error });\n }\n const body: unknown = await response.json().catch(() => null);\n const parsed = z\n .object({ errors: z.array(z.object({ message: z.string() })).optional() })\n .safeParse(body);\n if (!response.ok || (parsed.success && parsed.data.errors?.length)) {\n throw new GitHubPublicationApiError(\n response.status,\n parsed.success && parsed.data.errors?.[0] !== undefined\n ? parsed.data.errors[0].message\n : response.statusText,\n );\n }\n };\n const parsePullRequest = (value: unknown): GitHubPublicationPullRequest => {\n const pull = pullRequestSchema.parse(value);\n return {\n pullRequestNumber: pull.number,\n pullRequestUrl: pull.html_url,\n nodeId: pull.node_id,\n title: pull.title,\n body: pull.body,\n state: pull.state,\n draft: pull.draft,\n head: {\n branch: pull.head.ref,\n sha: pull.head.sha,\n repository:\n pull.head.repo === null\n ? null\n : repositorySlugSchema.parse(pull.head.repo.full_name.toLowerCase()),\n },\n };\n };\n const branchPath = (branch: string): string => {\n if (!isSafeGitRef(branch)) throw new Error(`refusing to use unsafe branch name: ${branch}`);\n return branch;\n };\n\n return {\n async commit(input) {\n const commit = z\n .object({\n tree: z.object({ sha: shaSchema }),\n parents: z.array(z.object({ sha: shaSchema })),\n })\n .parse(await request(`/git/commits/${encodeURIComponent(input.sha)}`));\n return { treeSha: commit.tree.sha, parentShas: commit.parents.map((parent) => parent.sha) };\n },\n async branchHead(input) {\n try {\n const ref = z\n .object({ object: z.object({ sha: shaSchema }) })\n .parse(await request(`/git/ref/heads/${branchPath(input.branch)}`));\n return ref.object.sha;\n } catch (error) {\n if (error instanceof GitHubPublicationApiError && error.status === 404) return null;\n throw error;\n }\n },\n async createTree(input) {\n return z.object({ sha: shaSchema }).parse(\n await request(\"/git/trees\", {\n method: \"POST\",\n body: JSON.stringify({ base_tree: input.baseTreeSha, tree: input.entries }),\n }),\n ).sha;\n },\n async createCommit(input) {\n return z.object({ sha: shaSchema }).parse(\n await request(\"/git/commits\", {\n method: \"POST\",\n body: JSON.stringify({\n message: input.message,\n tree: input.treeSha,\n parents: input.parentShas,\n }),\n }),\n ).sha;\n },\n async createBranch(input) {\n await request(\"/git/refs\", {\n method: \"POST\",\n body: JSON.stringify({\n ref: `refs/heads/${branchPath(input.branch)}`,\n sha: input.sha,\n }),\n });\n },\n async updateBranch(input) {\n await request(`/git/refs/heads/${branchPath(input.branch)}`, {\n method: \"PATCH\",\n body: JSON.stringify({ sha: input.sha, force: input.force }),\n });\n },\n async createPullRequest(input) {\n const pull = z\n .object({\n number: z.number().int().positive(),\n html_url: z.url(),\n draft: z.boolean(),\n })\n .parse(\n await request(\"/pulls\", {\n method: \"POST\",\n body: JSON.stringify(input),\n }),\n );\n return {\n pullRequestNumber: pull.number,\n pullRequestUrl: pull.html_url,\n draft: pull.draft,\n };\n },\n async pullRequest(input) {\n return parsePullRequest(await request(`/pulls/${input.pullRequestNumber}`));\n },\n async pullRequests(input) {\n const query = new URLSearchParams({ state: input.state, per_page: \"100\" });\n if (input.head !== undefined) query.set(\"head\", input.head);\n return z\n .array(pullRequestSchema)\n .parse(await request(`/pulls?${query.toString()}`))\n .map(parsePullRequest);\n },\n async markReady(input) {\n await graphql(\n \"mutation($id: ID!) { markPullRequestReadyForReview(input: { pullRequestId: $id }) { clientMutationId } }\",\n { id: input.nodeId },\n );\n },\n };\n}\n\n/** Derive the deterministic publication branch owned by a durable Task. */\nexport function factoryTaskBranch(taskId: TaskId): string {\n return `factory/${taskId}`;\n}\n\n/** Derive the deterministic publication branch owned by an operator session. */\nexport function factorySessionBranch(sessionId: AgentSessionId): string {\n return `factory/${agentSessionIdSchema.parse(sessionId)}`;\n}\n\n/** Check whether a Git reference is safe to interpolate into supplied Git commands. */\nexport function isSafeGitRef(ref: string): boolean {\n return safeRefPattern.test(ref) && !ref.includes(\"..\");\n}\n\n/** Clone or refresh one authorized GitHub repository without retaining credentials. */\nexport async function checkoutGitHubRepository(\n input: CheckoutGitHubRepositoryInput,\n): Promise<void> {\n const slug = repositorySlugSchema.parse(input.repositorySlug.toLowerCase());\n const expectedOrigin = `https://github.com/${slug}.git`;\n const checkout = await input.sandbox.run({ command: \"test -d repo/.git\" });\n const existingOrigin =\n checkout.exitCode === undefined || checkout.exitCode === 0\n ? (\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"remote\",\n \"get-url\",\n \"origin\",\n ])\n ).trim()\n : \"\";\n if (existingOrigin !== \"\" && existingOrigin.toLowerCase() !== expectedOrigin) {\n throw new GitHubCheckoutConflictError(existingOrigin, expectedOrigin);\n }\n\n const resume = input.resumeBranch;\n if (resume !== undefined && !isSafeGitRef(resume)) {\n throw new Error(`refusing to resume unsafe branch name: ${resume}`);\n }\n await input.transport.fetch({ repository: slug, refs: [] }, async (bundle) => {\n await withSandboxGitBundle({\n sandbox: input.sandbox,\n bundle,\n async use(path) {\n if (existingOrigin === \"\") {\n await runSandboxCommand(input.sandbox, [\"git\", \"clone\", path, \"repo\"]);\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"remote\",\n \"set-url\",\n \"origin\",\n expectedOrigin,\n ]);\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"config\",\n \"user.name\",\n \"factory\",\n ]);\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"config\",\n \"user.email\",\n \"factory@localhost\",\n ]);\n } else {\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"fetch\",\n path,\n \"+refs/heads/*:refs/remotes/origin/*\",\n ]);\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"reset\",\n \"--hard\",\n \"origin/HEAD\",\n ]);\n }\n if (resume === undefined) return;\n const exists = await input.sandbox.run({\n command: [\n \"git\",\n \"-C\",\n \"repo\",\n \"show-ref\",\n \"--verify\",\n \"--quiet\",\n `refs/remotes/origin/${resume}`,\n ]\n .map(quoteShellArgument)\n .join(\" \"),\n });\n if (exists.exitCode !== 0) return;\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"checkout\",\n \"-B\",\n resume,\n `refs/remotes/origin/${resume}`,\n ]);\n if (input.rememberPublishedHead === true) {\n const head = (\n await runSandboxCommand(input.sandbox, [\"git\", \"-C\", \"repo\", \"rev-parse\", \"HEAD\"])\n ).trim();\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"config\",\n \"factory.publishedHead\",\n head,\n ]);\n }\n },\n });\n });\n}\n\n/** Sandbox and argument vector for one Git command in a repository checkout. */\nexport interface RunSandboxGitInput {\n sandbox: SandboxGit;\n args: readonly string[];\n repositoryPath?: string;\n}\n\n/** Run a Git argument vector in a sandbox repository and reject nonzero exits. */\nexport function runSandboxGit(input: RunSandboxGitInput): Promise<string> {\n return runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n input.repositoryPath ?? \"repo\",\n ...input.args,\n ]);\n}\n\n/** Read committed sandbox changes as a bounded GitHub Git Data API tree. */\nexport async function readCommittedGitChange(\n input: ReadCommittedGitChangeInput,\n): Promise<CommittedGitChange> {\n const repositorySlug = repositorySlugSchema.parse(input.repositorySlug.toLowerCase());\n const baseRef = input.baseRef ?? \"origin/HEAD\";\n if (!isSafeGitRef(baseRef)) {\n throw new Error(`refusing to read unsafe base ref: ${baseRef}`);\n }\n const maxChangedFiles = input.maxChangedFiles ?? 25;\n const maxFileBytes = input.maxFileBytes ?? 200_000;\n if (!Number.isSafeInteger(maxChangedFiles) || maxChangedFiles < 1) {\n throw new Error(\"maxChangedFiles must be a positive integer\");\n }\n if (!Number.isSafeInteger(maxFileBytes) || maxFileBytes < 1) {\n throw new Error(\"maxFileBytes must be a positive integer\");\n }\n const origin = (\n await runSandboxGit({ sandbox: input.sandbox, args: [\"remote\", \"get-url\", \"origin\"] })\n ).trim();\n if (origin !== `https://github.com/${repositorySlug}.git`) {\n throw new Error(`sandbox checkout does not match task repository ${repositorySlug}`);\n }\n const head = (\n await runSandboxGit({ sandbox: input.sandbox, args: [\"rev-parse\", \"HEAD\"] })\n ).trim();\n const base = (\n await runSandboxGit({ sandbox: input.sandbox, args: [\"rev-parse\", baseRef] })\n ).trim();\n if (head === base && input.allowEmpty !== true) {\n throw new Error(\"no local commits to publish; commit your changes in the repo first\");\n }\n const commitMessage = (\n await runSandboxGit({ sandbox: input.sandbox, args: [\"log\", \"-1\", \"--format=%B\", \"HEAD\"] })\n ).trimEnd();\n if (commitMessage.length === 0) throw new Error(\"the committed change has no commit message\");\n if (Buffer.byteLength(commitMessage, \"utf8\") > 65_536) {\n throw new Error(\"the committed change message exceeds the publication limit\");\n }\n\n const nameStatus = (\n await runSandboxGit({\n sandbox: input.sandbox,\n args: [\"diff\", \"--name-status\", base, head],\n })\n ).trim();\n const upserts: string[] = [];\n const deletions: string[] = [];\n for (const line of nameStatus.split(\"\\n\").filter(Boolean)) {\n const fields = line.split(\"\\t\");\n const status = fields[0] ?? \"\";\n if (status === \"A\" || status === \"M\" || status === \"T\") {\n upserts.push(requireSafePath(fields[1]));\n } else if (status === \"D\") {\n deletions.push(requireSafePath(fields[1]));\n } else if (status.startsWith(\"R\") || status.startsWith(\"C\")) {\n if (status.startsWith(\"R\")) deletions.push(requireSafePath(fields[1]));\n upserts.push(requireSafePath(fields[2]));\n } else {\n throw new Error(`unsupported change status \"${status}\" in ${line}`);\n }\n }\n const changedFiles = upserts.length + deletions.length;\n if (changedFiles === 0 && input.allowEmpty !== true) {\n throw new Error(\"the local commits contain no file changes\");\n }\n if (changedFiles > maxChangedFiles) {\n throw new Error(`too many changed files (${changedFiles} > ${maxChangedFiles})`);\n }\n\n const tree: GitHubTreeEntry[] = [];\n for (const path of upserts) {\n const mode = (\n await runSandboxGit({\n sandbox: input.sandbox,\n args: [\"ls-tree\", head, \"--\", path],\n })\n )\n .trim()\n .split(\" \")[0];\n if (mode === undefined || !allowedModes.has(mode)) {\n throw new Error(`unsupported file mode ${mode || \"(none)\"} for ${path}`);\n }\n const content = await runSandboxGit({\n sandbox: input.sandbox,\n args: [\"show\", `${head}:${path}`],\n });\n if (Buffer.byteLength(content, \"utf8\") > maxFileBytes) {\n throw new Error(`${path} exceeds the ${maxFileBytes} byte publication limit`);\n }\n tree.push({ path, mode: mode as \"100644\" | \"100755\", type: \"blob\", content });\n }\n for (const path of deletions) {\n tree.push({ path, mode: \"100644\", type: \"blob\", sha: null });\n }\n return { base, commitMessage, tree, changedFiles };\n}\n\nfunction requireSafePath(path: string | undefined): string {\n if (path === undefined || path === \"\" || !safePathPattern.test(path) || path.includes(\"..\")) {\n throw new Error(`refusing to publish unsafe path: ${path ?? \"(missing)\"}`);\n }\n return path;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"github-publication.mjs","names":[],"sources":["../src/github-publication.ts"],"sourcesContent":["import {\n withSandboxGitBundle,\n quoteShellArgument,\n runSandboxCommand,\n type GitHubGitTransport,\n type GitTransferSandbox,\n} from \"./github-transfer\";\nimport type { TaskId } from \"./schema/id\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./schema/repository\";\nimport { agentSessionIdSchema, type AgentSessionId } from \"./schema/session\";\nimport { z } from \"zod\";\n\n/** Minimal sandbox command boundary required by Git checkout and publication helpers. */\nexport interface SandboxGit {\n run(options: SandboxGitCommandInput): PromiseLike<SandboxGitCommandResult>;\n}\n\n/** Shell command submitted through the minimal Git sandbox boundary. */\nexport interface SandboxGitCommandInput {\n command: string;\n}\n\n/** Captured output and optional exit status from a sandbox Git command. */\nexport interface SandboxGitCommandResult {\n stdout: string;\n stderr?: string;\n exitCode?: number;\n}\n\n/** Bounds applied while translating committed workspace changes into GitHub tree entries. */\nexport interface GitHubPublicationLimits {\n maxChangedFiles?: number;\n maxFileBytes?: number;\n}\n\n/** Repository-scoped credentials and transport for the GitHub publication client. */\nexport interface GitHubPublicationClientOptions {\n repository: RepositorySlug;\n token: string;\n fetch?: typeof globalThis.fetch;\n}\n\n/** Pull-request snapshot used to reconcile idempotent publication effects. */\nexport interface GitHubPublicationPullRequest {\n pullRequestNumber: number;\n pullRequestUrl: string;\n nodeId: string;\n title: string;\n body: string | null;\n state: \"open\" | \"closed\";\n draft: boolean;\n head: {\n branch: string;\n sha: string;\n repository: RepositorySlug | null;\n };\n}\n\n/** Git Data and pull-request operations needed by supplied publication workflows. */\nexport interface GitHubPublicationClient {\n commit(input: ReadGitHubCommitInput): Promise<GitHubCommit>;\n branchHead(input: ReadGitHubBranchHeadInput): Promise<string | null>;\n createTree(input: CreateGitHubTreeInput): Promise<string>;\n createCommit(input: CreateGitHubCommitInput): Promise<string>;\n createBranch(input: CreateGitHubBranchInput): Promise<void>;\n updateBranch(input: UpdateGitHubBranchInput): Promise<void>;\n createPullRequest(\n input: CreateGitHubPublicationPullRequestInput,\n ): Promise<CreatedGitHubPublicationPullRequest>;\n pullRequest(input: ReadGitHubPullRequestInput): Promise<GitHubPublicationPullRequest>;\n pullRequests(\n input: ListGitHubPublicationPullRequestsInput,\n ): Promise<readonly GitHubPublicationPullRequest[]>;\n markReady(input: MarkGitHubPullRequestReadyInput): Promise<void>;\n}\n\n/** Exact commit requested from GitHub's Git Data API. */\nexport interface ReadGitHubCommitInput {\n sha: string;\n}\n\n/** Tree and parents recorded for one GitHub commit. */\nexport interface GitHubCommit {\n treeSha: string;\n parentShas: readonly string[];\n}\n\n/** Exact branch whose current GitHub head should be read. */\nexport interface ReadGitHubBranchHeadInput {\n branch: string;\n}\n\n/** Base tree and exclusive file operations used to create a GitHub tree. */\nexport interface CreateGitHubTreeInput {\n baseTreeSha: string;\n entries: readonly GitHubTreeEntry[];\n}\n\n/** Commit content and parent identities used to create a GitHub commit. */\nexport interface CreateGitHubCommitInput {\n message: string;\n treeSha: string;\n parentShas: readonly string[];\n}\n\n/** Branch and commit identity used to create a GitHub branch. */\nexport interface CreateGitHubBranchInput {\n branch: string;\n sha: string;\n}\n\n/** Branch update and force policy used to move a GitHub branch. */\nexport interface UpdateGitHubBranchInput extends CreateGitHubBranchInput {\n force: boolean;\n}\n\n/** Provider-owned pull-request number to read. */\nexport interface ReadGitHubPullRequestInput {\n pullRequestNumber: number;\n}\n\n/** Provider GraphQL node identity of a draft pull request to mark ready. */\nexport interface MarkGitHubPullRequestReadyInput {\n nodeId: string;\n}\n\n/** Pull-request presentation and branch inputs used during GitHub publication. */\nexport interface CreateGitHubPublicationPullRequestInput {\n title: string;\n body: string;\n head: string;\n base: string;\n draft: boolean;\n}\n\n/** Provider identity and draft state returned after creating a pull request. */\nexport interface CreatedGitHubPublicationPullRequest {\n pullRequestNumber: number;\n pullRequestUrl: string;\n draft: boolean;\n}\n\n/** State and optional exact head filter used to list publication pull requests. */\nexport interface ListGitHubPublicationPullRequestsInput {\n state: \"open\" | \"all\";\n head?: string;\n}\n\n/** GitHub publication failure that preserves the provider HTTP status. */\nexport class GitHubPublicationApiError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(`GitHub API request failed (${status}): ${message}`);\n this.name = \"GitHubPublicationApiError\";\n }\n}\n\ninterface GitHubTreeEntryBase {\n path: string;\n mode: \"100644\" | \"100755\";\n type: \"blob\";\n}\n\n/** File content uploaded through GitHub's Git Data API. */\nexport interface GitHubTreeUpsert extends GitHubTreeEntryBase {\n content: string;\n sha?: never;\n}\n\n/** Existing file removed through GitHub's Git Data API. */\nexport interface GitHubTreeDeletion extends GitHubTreeEntryBase {\n sha: null;\n content?: never;\n}\n\n/** Exclusive bounded file upsert or deletion accepted by GitHub's Git Data API. */\nexport type GitHubTreeEntry = GitHubTreeUpsert | GitHubTreeDeletion;\n\n/** Committed workspace delta represented against a specific base commit. */\nexport interface CommittedGitChange {\n base: string;\n commitMessage: string;\n tree: readonly GitHubTreeEntry[];\n changedFiles: number;\n}\n\n/** Sandbox, repository, and bounds for reading a committed workspace delta. */\nexport interface ReadCommittedGitChangeInput extends GitHubPublicationLimits {\n sandbox: SandboxGit;\n repositorySlug: RepositorySlug;\n baseRef?: string;\n allowEmpty?: boolean;\n}\n\n/** Common dependencies for an authorized repository checkout. */\ninterface CheckoutGitHubRepositoryBaseInput {\n sandbox: GitTransferSandbox;\n repositorySlug: RepositorySlug;\n transport: GitHubGitTransport;\n /** Also fetch this pull request's head, including forks, to `refs/remotes/origin/pr/<number>`. */\n pullRequestNumber?: number;\n}\n\n/** Authorized repository checkout with recovery options that require a branch to resume. */\nexport type CheckoutGitHubRepositoryInput = CheckoutGitHubRepositoryBaseInput &\n (\n | {\n resumeBranch?: never;\n rememberPublishedHead?: never;\n }\n | {\n /** Resume this remote branch when it exists after refreshing the default branch. */\n resumeBranch: string;\n /** Remember the resumed remote head for later publication reconciliation. */\n rememberPublishedHead?: true;\n }\n );\n\n/** Refusal raised when an existing sandbox checkout points at another repository. */\nexport class GitHubCheckoutConflictError extends Error {\n constructor(\n readonly existingOrigin: string,\n readonly expectedOrigin: string,\n ) {\n super(`sandbox checkout ${existingOrigin} does not match ${expectedOrigin}`);\n this.name = \"GitHubCheckoutConflictError\";\n }\n}\n\nconst safePathPattern = /^[A-Za-z0-9.][A-Za-z0-9._/-]*$/u;\nconst safeRefPattern = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/u;\nconst allowedModes = new Set([\"100644\", \"100755\"]);\nconst gitHubApiUrl = \"https://api.github.com\";\n\nconst shaSchema = z.string().min(1);\nconst pullRequestSchema = z.object({\n number: z.number().int().positive(),\n html_url: z.url(),\n node_id: z.string().min(1),\n title: z.string(),\n body: z.string().nullable(),\n state: z.enum([\"open\", \"closed\"]),\n draft: z.boolean(),\n head: z.object({\n ref: z.string().min(1),\n sha: shaSchema,\n repo: z.object({ full_name: z.string().min(1) }).nullable(),\n }),\n});\n\n/** GitHub Git Data and pull-request operations used by publication workflows. */\nexport function createGitHubPublicationClient(\n options: GitHubPublicationClientOptions,\n): GitHubPublicationClient {\n const repository = repositorySlugSchema.parse(options.repository.toLowerCase());\n const request = async (path: string, init: RequestInit = {}): Promise<unknown> => {\n let response: Response;\n try {\n response = await (options.fetch ?? globalThis.fetch)(\n `${gitHubApiUrl}/repos/${repository}${path}`,\n {\n ...init,\n headers: {\n Accept: \"application/vnd.github+json\",\n Authorization: `Bearer ${options.token}`,\n \"Content-Type\": \"application/json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...init.headers,\n },\n },\n );\n } catch (error) {\n throw new Error(\"GitHub API request failed\", { cause: error });\n }\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n const parsed = z.object({ message: z.string() }).safeParse(body);\n throw new GitHubPublicationApiError(\n response.status,\n parsed.success ? parsed.data.message : response.statusText,\n );\n }\n return body;\n };\n const graphql = async (query: string, variables: Record<string, unknown>): Promise<void> => {\n let response: Response;\n try {\n response = await (options.fetch ?? globalThis.fetch)(`${gitHubApiUrl}/graphql`, {\n method: \"POST\",\n headers: {\n Accept: \"application/vnd.github+json\",\n Authorization: `Bearer ${options.token}`,\n \"Content-Type\": \"application/json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n },\n body: JSON.stringify({ query, variables }),\n });\n } catch (error) {\n throw new Error(\"GitHub GraphQL request failed\", { cause: error });\n }\n const body: unknown = await response.json().catch(() => null);\n const parsed = z\n .object({ errors: z.array(z.object({ message: z.string() })).optional() })\n .safeParse(body);\n if (!response.ok || (parsed.success && parsed.data.errors?.length)) {\n throw new GitHubPublicationApiError(\n response.status,\n parsed.success && parsed.data.errors?.[0] !== undefined\n ? parsed.data.errors[0].message\n : response.statusText,\n );\n }\n };\n const parsePullRequest = (value: unknown): GitHubPublicationPullRequest => {\n const pull = pullRequestSchema.parse(value);\n return {\n pullRequestNumber: pull.number,\n pullRequestUrl: pull.html_url,\n nodeId: pull.node_id,\n title: pull.title,\n body: pull.body,\n state: pull.state,\n draft: pull.draft,\n head: {\n branch: pull.head.ref,\n sha: pull.head.sha,\n repository:\n pull.head.repo === null\n ? null\n : repositorySlugSchema.parse(pull.head.repo.full_name.toLowerCase()),\n },\n };\n };\n const branchPath = (branch: string): string => {\n if (!isSafeGitRef(branch)) throw new Error(`refusing to use unsafe branch name: ${branch}`);\n return branch;\n };\n\n return {\n async commit(input) {\n const commit = z\n .object({\n tree: z.object({ sha: shaSchema }),\n parents: z.array(z.object({ sha: shaSchema })),\n })\n .parse(await request(`/git/commits/${encodeURIComponent(input.sha)}`));\n return { treeSha: commit.tree.sha, parentShas: commit.parents.map((parent) => parent.sha) };\n },\n async branchHead(input) {\n try {\n const ref = z\n .object({ object: z.object({ sha: shaSchema }) })\n .parse(await request(`/git/ref/heads/${branchPath(input.branch)}`));\n return ref.object.sha;\n } catch (error) {\n if (error instanceof GitHubPublicationApiError && error.status === 404) return null;\n throw error;\n }\n },\n async createTree(input) {\n return z.object({ sha: shaSchema }).parse(\n await request(\"/git/trees\", {\n method: \"POST\",\n body: JSON.stringify({ base_tree: input.baseTreeSha, tree: input.entries }),\n }),\n ).sha;\n },\n async createCommit(input) {\n return z.object({ sha: shaSchema }).parse(\n await request(\"/git/commits\", {\n method: \"POST\",\n body: JSON.stringify({\n message: input.message,\n tree: input.treeSha,\n parents: input.parentShas,\n }),\n }),\n ).sha;\n },\n async createBranch(input) {\n await request(\"/git/refs\", {\n method: \"POST\",\n body: JSON.stringify({\n ref: `refs/heads/${branchPath(input.branch)}`,\n sha: input.sha,\n }),\n });\n },\n async updateBranch(input) {\n await request(`/git/refs/heads/${branchPath(input.branch)}`, {\n method: \"PATCH\",\n body: JSON.stringify({ sha: input.sha, force: input.force }),\n });\n },\n async createPullRequest(input) {\n const pull = z\n .object({\n number: z.number().int().positive(),\n html_url: z.url(),\n draft: z.boolean(),\n })\n .parse(\n await request(\"/pulls\", {\n method: \"POST\",\n body: JSON.stringify(input),\n }),\n );\n return {\n pullRequestNumber: pull.number,\n pullRequestUrl: pull.html_url,\n draft: pull.draft,\n };\n },\n async pullRequest(input) {\n return parsePullRequest(await request(`/pulls/${input.pullRequestNumber}`));\n },\n async pullRequests(input) {\n const query = new URLSearchParams({ state: input.state, per_page: \"100\" });\n if (input.head !== undefined) query.set(\"head\", input.head);\n return z\n .array(pullRequestSchema)\n .parse(await request(`/pulls?${query.toString()}`))\n .map(parsePullRequest);\n },\n async markReady(input) {\n await graphql(\n \"mutation($id: ID!) { markPullRequestReadyForReview(input: { pullRequestId: $id }) { clientMutationId } }\",\n { id: input.nodeId },\n );\n },\n };\n}\n\n/** Derive the deterministic publication branch owned by a durable Task. */\nexport function factoryTaskBranch(taskId: TaskId): string {\n return `factory/${taskId}`;\n}\n\n/** Derive the deterministic publication branch owned by an operator session. */\nexport function factorySessionBranch(sessionId: AgentSessionId): string {\n return `factory/${agentSessionIdSchema.parse(sessionId)}`;\n}\n\n/** Check whether a Git reference is safe to interpolate into supplied Git commands. */\nexport function isSafeGitRef(ref: string): boolean {\n return safeRefPattern.test(ref) && !ref.includes(\"..\");\n}\n\n/** Clone or refresh one authorized GitHub repository without retaining credentials. */\nexport async function checkoutGitHubRepository(\n input: CheckoutGitHubRepositoryInput,\n): Promise<void> {\n const slug = repositorySlugSchema.parse(input.repositorySlug.toLowerCase());\n const expectedOrigin = `https://github.com/${slug}.git`;\n const checkout = await input.sandbox.run({ command: \"test -d repo/.git\" });\n const existingOrigin =\n checkout.exitCode === undefined || checkout.exitCode === 0\n ? (\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"remote\",\n \"get-url\",\n \"origin\",\n ])\n ).trim()\n : \"\";\n if (existingOrigin !== \"\" && existingOrigin.toLowerCase() !== expectedOrigin) {\n throw new GitHubCheckoutConflictError(existingOrigin, expectedOrigin);\n }\n\n const resume = input.resumeBranch;\n if (resume !== undefined && !isSafeGitRef(resume)) {\n throw new Error(`refusing to resume unsafe branch name: ${resume}`);\n }\n const pullRequestNumber = input.pullRequestNumber;\n if (\n pullRequestNumber !== undefined &&\n (!Number.isSafeInteger(pullRequestNumber) || pullRequestNumber < 1)\n ) {\n throw new Error(\"pullRequestNumber must be a positive integer\");\n }\n const pullRequestRef =\n pullRequestNumber === undefined ? undefined : `refs/pull/${pullRequestNumber}/head`;\n await input.transport.fetch(\n { repository: slug, refs: pullRequestRef === undefined ? [] : [pullRequestRef] },\n async (bundle) => {\n await withSandboxGitBundle({\n sandbox: input.sandbox,\n bundle,\n async use(path) {\n if (existingOrigin === \"\") {\n await runSandboxCommand(input.sandbox, [\"git\", \"clone\", path, \"repo\"]);\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"remote\",\n \"set-url\",\n \"origin\",\n expectedOrigin,\n ]);\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"config\",\n \"user.name\",\n \"factory\",\n ]);\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"config\",\n \"user.email\",\n \"factory@localhost\",\n ]);\n } else {\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"fetch\",\n path,\n \"+refs/heads/*:refs/remotes/origin/*\",\n ]);\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"reset\",\n \"--hard\",\n \"origin/HEAD\",\n ]);\n }\n if (pullRequestRef !== undefined)\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"fetch\",\n path,\n `+${pullRequestRef}:refs/remotes/origin/pr/${pullRequestNumber}`,\n ]);\n if (resume === undefined) return;\n const exists = await input.sandbox.run({\n command: [\n \"git\",\n \"-C\",\n \"repo\",\n \"show-ref\",\n \"--verify\",\n \"--quiet\",\n `refs/remotes/origin/${resume}`,\n ]\n .map(quoteShellArgument)\n .join(\" \"),\n });\n if (exists.exitCode !== 0) return;\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"checkout\",\n \"-B\",\n resume,\n `refs/remotes/origin/${resume}`,\n ]);\n if (input.rememberPublishedHead === true) {\n const head = (\n await runSandboxCommand(input.sandbox, [\"git\", \"-C\", \"repo\", \"rev-parse\", \"HEAD\"])\n ).trim();\n await runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n \"repo\",\n \"config\",\n \"factory.publishedHead\",\n head,\n ]);\n }\n },\n });\n },\n );\n}\n\n/** Sandbox and argument vector for one Git command in a repository checkout. */\nexport interface RunSandboxGitInput {\n sandbox: SandboxGit;\n args: readonly string[];\n repositoryPath?: string;\n}\n\n/** Run a Git argument vector in a sandbox repository and reject nonzero exits. */\nexport function runSandboxGit(input: RunSandboxGitInput): Promise<string> {\n return runSandboxCommand(input.sandbox, [\n \"git\",\n \"-C\",\n input.repositoryPath ?? \"repo\",\n ...input.args,\n ]);\n}\n\n/** Read committed sandbox changes as a bounded GitHub Git Data API tree. */\nexport async function readCommittedGitChange(\n input: ReadCommittedGitChangeInput,\n): Promise<CommittedGitChange> {\n const repositorySlug = repositorySlugSchema.parse(input.repositorySlug.toLowerCase());\n const baseRef = input.baseRef ?? \"origin/HEAD\";\n if (!isSafeGitRef(baseRef)) {\n throw new Error(`refusing to read unsafe base ref: ${baseRef}`);\n }\n const maxChangedFiles = input.maxChangedFiles ?? 25;\n const maxFileBytes = input.maxFileBytes ?? 200_000;\n if (!Number.isSafeInteger(maxChangedFiles) || maxChangedFiles < 1) {\n throw new Error(\"maxChangedFiles must be a positive integer\");\n }\n if (!Number.isSafeInteger(maxFileBytes) || maxFileBytes < 1) {\n throw new Error(\"maxFileBytes must be a positive integer\");\n }\n const origin = (\n await runSandboxGit({ sandbox: input.sandbox, args: [\"remote\", \"get-url\", \"origin\"] })\n ).trim();\n if (origin !== `https://github.com/${repositorySlug}.git`) {\n throw new Error(`sandbox checkout does not match task repository ${repositorySlug}`);\n }\n const head = (\n await runSandboxGit({ sandbox: input.sandbox, args: [\"rev-parse\", \"HEAD\"] })\n ).trim();\n const base = (\n await runSandboxGit({ sandbox: input.sandbox, args: [\"rev-parse\", baseRef] })\n ).trim();\n if (head === base && input.allowEmpty !== true) {\n throw new Error(\"no local commits to publish; commit your changes in the repo first\");\n }\n const commitMessage = (\n await runSandboxGit({ sandbox: input.sandbox, args: [\"log\", \"-1\", \"--format=%B\", \"HEAD\"] })\n ).trimEnd();\n if (commitMessage.length === 0) throw new Error(\"the committed change has no commit message\");\n if (Buffer.byteLength(commitMessage, \"utf8\") > 65_536) {\n throw new Error(\"the committed change message exceeds the publication limit\");\n }\n\n const nameStatus = (\n await runSandboxGit({\n sandbox: input.sandbox,\n args: [\"diff\", \"--name-status\", base, head],\n })\n ).trim();\n const upserts: string[] = [];\n const deletions: string[] = [];\n for (const line of nameStatus.split(\"\\n\").filter(Boolean)) {\n const fields = line.split(\"\\t\");\n const status = fields[0] ?? \"\";\n if (status === \"A\" || status === \"M\" || status === \"T\") {\n upserts.push(requireSafePath(fields[1]));\n } else if (status === \"D\") {\n deletions.push(requireSafePath(fields[1]));\n } else if (status.startsWith(\"R\") || status.startsWith(\"C\")) {\n if (status.startsWith(\"R\")) deletions.push(requireSafePath(fields[1]));\n upserts.push(requireSafePath(fields[2]));\n } else {\n throw new Error(`unsupported change status \"${status}\" in ${line}`);\n }\n }\n const changedFiles = upserts.length + deletions.length;\n if (changedFiles === 0 && input.allowEmpty !== true) {\n throw new Error(\"the local commits contain no file changes\");\n }\n if (changedFiles > maxChangedFiles) {\n throw new Error(`too many changed files (${changedFiles} > ${maxChangedFiles})`);\n }\n\n const tree: GitHubTreeEntry[] = [];\n for (const path of upserts) {\n const mode = (\n await runSandboxGit({\n sandbox: input.sandbox,\n args: [\"ls-tree\", head, \"--\", path],\n })\n )\n .trim()\n .split(\" \")[0];\n if (mode === undefined || !allowedModes.has(mode)) {\n throw new Error(`unsupported file mode ${mode || \"(none)\"} for ${path}`);\n }\n const content = await runSandboxGit({\n sandbox: input.sandbox,\n args: [\"show\", `${head}:${path}`],\n });\n if (Buffer.byteLength(content, \"utf8\") > maxFileBytes) {\n throw new Error(`${path} exceeds the ${maxFileBytes} byte publication limit`);\n }\n tree.push({ path, mode: mode as \"100644\" | \"100755\", type: \"blob\", content });\n }\n for (const path of deletions) {\n tree.push({ path, mode: \"100644\", type: \"blob\", sha: null });\n }\n return { base, commitMessage, tree, changedFiles };\n}\n\nfunction requireSafePath(path: string | undefined): string {\n if (path === undefined || path === \"\" || !safePathPattern.test(path) || path.includes(\"..\")) {\n throw new Error(`refusing to publish unsafe path: ${path ?? \"(missing)\"}`);\n }\n return path;\n}\n"],"mappings":"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"}
@@ -70,6 +70,7 @@ declare const factoryConfigSchema: z.ZodReadonly<z.ZodObject<{
70
70
  connect: "connect";
71
71
  vercel: "vercel";
72
72
  }>>;
73
+ sandboxGitHubActAs: z.ZodOptional<z.ZodString>;
73
74
  commitIdentity: z.ZodDefault<z.ZodReadonly<z.ZodObject<{
74
75
  name: z.ZodString;
75
76
  email: z.ZodString;
@@ -53,6 +53,7 @@ const factoryConfigSchema = z.strictObject({
53
53
  repositories: z.array(factoryConfigRepositorySchema).min(1).readonly().describe("Repositories this factory is allowed to inspect and change."),
54
54
  operators: z.array(z.string().min(1)).min(1).readonly().describe("Provider-qualified identities allowed to operate this factory."),
55
55
  sandboxGitHubCredentials: z.enum(["connect", "vercel"]).default("connect").describe("Credential source selected for trusted GitHub Sandbox operations."),
56
+ sandboxGitHubActAs: z.string().regex(/^[1-9][0-9]*$/u).max(16).refine((id) => Number.isSafeInteger(Number(id))).optional().describe("GitHub user ID selected for Vercel-managed GitHub API Sandbox operations."),
56
57
  commitIdentity: commitIdentitySchema.default({
57
58
  name: "Vercel Factory",
58
59
  email: "not+real@example.org"
@@ -79,6 +80,11 @@ const factoryConfigSchema = z.strictObject({
79
80
  ],
80
81
  message: "PR notification destinations must name a configured repository."
81
82
  });
83
+ if (config.sandboxGitHubActAs !== void 0 && config.sandboxGitHubCredentials !== "vercel") ctx.addIssue({
84
+ code: "custom",
85
+ path: ["sandboxGitHubActAs"],
86
+ message: "A managed GitHub act-as identity requires Vercel-managed Sandbox credentials."
87
+ });
82
88
  }).readonly();
83
89
  /** Validates a Factory configuration and applies its declared defaults. */
84
90
  function defineFactory(config) {
@@ -1 +1 @@
1
- {"version":3,"file":"factory-config.mjs","names":[],"sources":["../../src/schema/factory-config.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { allowByDefaultApprovalPolicy, approvalPolicySchema } from \"../approval\";\nimport { budgetLimitsSchema } from \"./budget\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./repository\";\nimport { taskKindSchema } from \"./task\";\nimport { slackPrNotificationsSchema } from \"./slack-pr-notifications\";\n\n/** Validates one repository allowlist entry and its configured dependency ordering. */\nexport const factoryConfigRepositorySchema = z\n .strictObject({\n slug: repositorySlugSchema.describe(\"Repository this factory may work on.\"),\n defaultBranch: z\n .string()\n .min(1)\n .default(\"main\")\n .describe(\"Branch changes land on, usually main.\"),\n dependsOn: z\n .array(repositorySlugSchema)\n .readonly()\n .default([])\n .describe(\"Repositories that must land changes before this repository.\"),\n })\n .readonly();\n\nconst githubConnectorSchema = z\n .strictObject({\n owner: z\n .string()\n .regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/)\n .describe(\"GitHub user or organization that owns this connector installation.\"),\n connector: z\n .string()\n .regex(/^github\\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/)\n .describe(\"Vercel Connect UID installed for this GitHub owner.\"),\n })\n .readonly();\n\nconst slackConnectorSchema = z\n .strictObject({\n connector: z\n .string()\n .regex(/^slack\\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/)\n .describe(\"Vercel Connect UID installed for this Slack app.\"),\n operatorDirectMessages: z\n .boolean()\n .default(false)\n .describe(\n \"Opt in to operator DMs for human-action requests, digests, and budget alerts. Independent of operator authorization, PR announcements, and replies in the original conversation.\",\n ),\n approvalChannel: z\n .string()\n .regex(/^[CDG][A-Z0-9]+$/u)\n .optional()\n .describe(\n \"Explicit Slack channel for approval proposals that have no originating Slack thread. Absent disables cross-channel approval notifications.\",\n ),\n autonomousPullRequests: slackPrNotificationsSchema\n .optional()\n .describe(\n \"Channel announcements for every Factory-produced PR, including human-requested work, in addition to the original conversation reply. Saved Slack settings override this default; resetting restores it. Absent disables announcements unless Slack enables them.\",\n ),\n autonomousPullRequestsByRepository: z\n .record(repositorySlugSchema, slackPrNotificationsSchema.nullable())\n .readonly()\n .optional()\n .describe(\n \"Repository-specific PR destinations, taking precedence over the factory-wide default. Null disables announcements for that repository. Saved repository settings override these entries.\",\n ),\n })\n .readonly();\n\nfunction isSupportedCommitIdentityValue(value: string, maxBytes: number): boolean {\n return (\n value.trim() === value &&\n !/[\\0\\r\\n<>]/u.test(value) &&\n new TextEncoder().encode(value).byteLength <= maxBytes\n );\n}\n\nconst commitIdentitySchema = z\n .strictObject({\n name: z\n .string()\n .min(1)\n .refine((value) => isSupportedCommitIdentityValue(value, 256))\n .describe(\"Name recorded on Factory-authored commits.\"),\n email: z\n .string()\n .email()\n .refine((value) => isSupportedCommitIdentityValue(value, 320))\n .describe(\"Email recorded on Factory-authored commits.\"),\n })\n .readonly();\n\n/** Validates stall detection and replacement-attempt limits for running Tasks. */\nexport const executionPolicySchema = z\n .strictObject({\n maxAttempts: z\n .number()\n .int()\n .min(1)\n .describe(\"Attempts a task may consume before a stall fails it for good.\"),\n stallMinutes: z\n .number()\n .int()\n .min(1)\n .describe(\"Minutes without progress before a running task is marked stalled.\"),\n stallMinutesByKind: z\n .partialRecord(taskKindSchema, z.number().int().min(1))\n .readonly()\n .default({})\n .describe(\"Per-kind stall windows for long single-step work, e.g. security_scan: 300.\"),\n })\n .readonly();\n\n/** Stall detection and retry limits applied to running Tasks. */\nexport type ExecutionPolicy = z.infer<typeof executionPolicySchema>;\n\n/** Conservative default stall window and three-attempt execution policy. */\nexport const defaultExecutionPolicy = executionPolicySchema.parse({\n maxAttempts: 3,\n stallMinutes: 45,\n stallMinutesByKind: {},\n});\n\n/** Validates the repositories, operators, connectors, budget, and policies of a Factory. */\nexport const factoryConfigSchema = z\n .strictObject({\n connectors: z\n .strictObject({\n github: z\n .array(githubConnectorSchema)\n .readonly()\n .refine(\n (connectors) =>\n new Set(connectors.map(({ owner }) => owner)).size === connectors.length,\n \"GitHub connector owners must be unique.\",\n ),\n slack: z\n .array(slackConnectorSchema)\n .max(1, \"A factory may configure one Slack connector.\")\n .readonly()\n .default([]),\n })\n .readonly()\n .default({ github: [], slack: [] })\n .describe(\"Provider connections available to this factory.\"),\n repositories: z\n .array(factoryConfigRepositorySchema)\n .min(1)\n .readonly()\n .describe(\"Repositories this factory is allowed to inspect and change.\"),\n operators: z\n .array(z.string().min(1))\n .min(1)\n .readonly()\n .describe(\"Provider-qualified identities allowed to operate this factory.\"),\n sandboxGitHubCredentials: z\n .enum([\"connect\", \"vercel\"])\n .default(\"connect\")\n .describe(\"Credential source selected for trusted GitHub Sandbox operations.\"),\n commitIdentity: commitIdentitySchema\n .default({ name: \"Vercel Factory\", email: \"not+real@example.org\" })\n .describe(\"Replaceable attribution metadata for Factory-authored commits.\"),\n approval: approvalPolicySchema\n .default(allowByDefaultApprovalPolicy)\n .describe(\"Which Tasks wait for a human before they run. First match wins.\"),\n budget: budgetLimitsSchema\n .default({\n totalUsd: 500,\n investigationUsd: 100,\n perTaskReservationUsd: 5,\n warningPercent: 80,\n })\n .describe(\"Monthly spending thresholds and per-task accounting reservations.\"),\n enforceBudget: z\n .boolean()\n .default(true)\n .describe(\n \"Refuse new work above the monthly budget. False keeps cost accounting without spending limits or budget alerts.\",\n ),\n execution: executionPolicySchema\n .default(defaultExecutionPolicy)\n .describe(\"Stall detection and retry limits for running tasks.\"),\n })\n .superRefine((config, ctx) => {\n const repositories = new Set<string>(config.repositories.map(({ slug }) => slug));\n for (const [index, connector] of config.connectors.slack.entries()) {\n for (const slug of Object.keys(connector.autonomousPullRequestsByRepository ?? {})) {\n if (!repositories.has(slug))\n ctx.addIssue({\n code: \"custom\",\n path: [\"connectors\", \"slack\", index, \"autonomousPullRequestsByRepository\", slug],\n message: \"PR notification destinations must name a configured repository.\",\n });\n }\n }\n })\n .readonly();\n\n/** Fully resolved repository allowlist entry in a Factory configuration. */\nexport type FactoryConfigRepository = z.infer<typeof factoryConfigRepositorySchema>;\n\n/** Fully resolved and validated Factory configuration. */\nexport type FactoryConfig = z.infer<typeof factoryConfigSchema>;\ntype FactoryConfigSchemaInput = z.input<typeof factoryConfigSchema>;\ntype FactoryConfigConnectorsInput = Readonly<{\n github: readonly Readonly<z.input<typeof githubConnectorSchema>>[];\n slack?: readonly Readonly<z.input<typeof slackConnectorSchema>>[];\n}>;\n/** Repository allowlist entry accepted when defining a Factory, before defaults are applied. */\nexport type FactoryConfigRepositoryInput = Readonly<{\n slug: RepositorySlug;\n defaultBranch?: string;\n dependsOn?: readonly RepositorySlug[];\n}>;\n/** Caller input accepted when defining a Factory, before schema defaults are applied. */\nexport type FactoryConfigInput = Readonly<\n Omit<FactoryConfigSchemaInput, \"connectors\" | \"repositories\" | \"operators\"> & {\n connectors?: FactoryConfigConnectorsInput;\n repositories: readonly FactoryConfigRepositoryInput[];\n operators: readonly string[];\n }\n>;\n\n/** Validates a Factory configuration and applies its declared defaults. */\nexport function defineFactory(config: FactoryConfigInput): FactoryConfig {\n return factoryConfigSchema.parse(config);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"factory-config.mjs","names":[],"sources":["../../src/schema/factory-config.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { allowByDefaultApprovalPolicy, approvalPolicySchema } from \"../approval\";\nimport { budgetLimitsSchema } from \"./budget\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./repository\";\nimport { taskKindSchema } from \"./task\";\nimport { slackPrNotificationsSchema } from \"./slack-pr-notifications\";\n\n/** Validates one repository allowlist entry and its configured dependency ordering. */\nexport const factoryConfigRepositorySchema = z\n .strictObject({\n slug: repositorySlugSchema.describe(\"Repository this factory may work on.\"),\n defaultBranch: z\n .string()\n .min(1)\n .default(\"main\")\n .describe(\"Branch changes land on, usually main.\"),\n dependsOn: z\n .array(repositorySlugSchema)\n .readonly()\n .default([])\n .describe(\"Repositories that must land changes before this repository.\"),\n })\n .readonly();\n\nconst githubConnectorSchema = z\n .strictObject({\n owner: z\n .string()\n .regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/)\n .describe(\"GitHub user or organization that owns this connector installation.\"),\n connector: z\n .string()\n .regex(/^github\\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/)\n .describe(\"Vercel Connect UID installed for this GitHub owner.\"),\n })\n .readonly();\n\nconst slackConnectorSchema = z\n .strictObject({\n connector: z\n .string()\n .regex(/^slack\\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/)\n .describe(\"Vercel Connect UID installed for this Slack app.\"),\n operatorDirectMessages: z\n .boolean()\n .default(false)\n .describe(\n \"Opt in to operator DMs for human-action requests, digests, and budget alerts. Independent of operator authorization, PR announcements, and replies in the original conversation.\",\n ),\n approvalChannel: z\n .string()\n .regex(/^[CDG][A-Z0-9]+$/u)\n .optional()\n .describe(\n \"Explicit Slack channel for approval proposals that have no originating Slack thread. Absent disables cross-channel approval notifications.\",\n ),\n autonomousPullRequests: slackPrNotificationsSchema\n .optional()\n .describe(\n \"Channel announcements for every Factory-produced PR, including human-requested work, in addition to the original conversation reply. Saved Slack settings override this default; resetting restores it. Absent disables announcements unless Slack enables them.\",\n ),\n autonomousPullRequestsByRepository: z\n .record(repositorySlugSchema, slackPrNotificationsSchema.nullable())\n .readonly()\n .optional()\n .describe(\n \"Repository-specific PR destinations, taking precedence over the factory-wide default. Null disables announcements for that repository. Saved repository settings override these entries.\",\n ),\n })\n .readonly();\n\nfunction isSupportedCommitIdentityValue(value: string, maxBytes: number): boolean {\n return (\n value.trim() === value &&\n !/[\\0\\r\\n<>]/u.test(value) &&\n new TextEncoder().encode(value).byteLength <= maxBytes\n );\n}\n\nconst commitIdentitySchema = z\n .strictObject({\n name: z\n .string()\n .min(1)\n .refine((value) => isSupportedCommitIdentityValue(value, 256))\n .describe(\"Name recorded on Factory-authored commits.\"),\n email: z\n .string()\n .email()\n .refine((value) => isSupportedCommitIdentityValue(value, 320))\n .describe(\"Email recorded on Factory-authored commits.\"),\n })\n .readonly();\n\n/** Validates stall detection and replacement-attempt limits for running Tasks. */\nexport const executionPolicySchema = z\n .strictObject({\n maxAttempts: z\n .number()\n .int()\n .min(1)\n .describe(\"Attempts a task may consume before a stall fails it for good.\"),\n stallMinutes: z\n .number()\n .int()\n .min(1)\n .describe(\"Minutes without progress before a running task is marked stalled.\"),\n stallMinutesByKind: z\n .partialRecord(taskKindSchema, z.number().int().min(1))\n .readonly()\n .default({})\n .describe(\"Per-kind stall windows for long single-step work, e.g. security_scan: 300.\"),\n })\n .readonly();\n\n/** Stall detection and retry limits applied to running Tasks. */\nexport type ExecutionPolicy = z.infer<typeof executionPolicySchema>;\n\n/** Conservative default stall window and three-attempt execution policy. */\nexport const defaultExecutionPolicy = executionPolicySchema.parse({\n maxAttempts: 3,\n stallMinutes: 45,\n stallMinutesByKind: {},\n});\n\n/** Validates the repositories, operators, connectors, budget, and policies of a Factory. */\nexport const factoryConfigSchema = z\n .strictObject({\n connectors: z\n .strictObject({\n github: z\n .array(githubConnectorSchema)\n .readonly()\n .refine(\n (connectors) =>\n new Set(connectors.map(({ owner }) => owner)).size === connectors.length,\n \"GitHub connector owners must be unique.\",\n ),\n slack: z\n .array(slackConnectorSchema)\n .max(1, \"A factory may configure one Slack connector.\")\n .readonly()\n .default([]),\n })\n .readonly()\n .default({ github: [], slack: [] })\n .describe(\"Provider connections available to this factory.\"),\n repositories: z\n .array(factoryConfigRepositorySchema)\n .min(1)\n .readonly()\n .describe(\"Repositories this factory is allowed to inspect and change.\"),\n operators: z\n .array(z.string().min(1))\n .min(1)\n .readonly()\n .describe(\"Provider-qualified identities allowed to operate this factory.\"),\n sandboxGitHubCredentials: z\n .enum([\"connect\", \"vercel\"])\n .default(\"connect\")\n .describe(\"Credential source selected for trusted GitHub Sandbox operations.\"),\n sandboxGitHubActAs: z\n .string()\n .regex(/^[1-9][0-9]*$/u)\n .max(16)\n .refine((id) => Number.isSafeInteger(Number(id)))\n .optional()\n .describe(\"GitHub user ID selected for Vercel-managed GitHub API Sandbox operations.\"),\n commitIdentity: commitIdentitySchema\n .default({ name: \"Vercel Factory\", email: \"not+real@example.org\" })\n .describe(\"Replaceable attribution metadata for Factory-authored commits.\"),\n approval: approvalPolicySchema\n .default(allowByDefaultApprovalPolicy)\n .describe(\"Which Tasks wait for a human before they run. First match wins.\"),\n budget: budgetLimitsSchema\n .default({\n totalUsd: 500,\n investigationUsd: 100,\n perTaskReservationUsd: 5,\n warningPercent: 80,\n })\n .describe(\"Monthly spending thresholds and per-task accounting reservations.\"),\n enforceBudget: z\n .boolean()\n .default(true)\n .describe(\n \"Refuse new work above the monthly budget. False keeps cost accounting without spending limits or budget alerts.\",\n ),\n execution: executionPolicySchema\n .default(defaultExecutionPolicy)\n .describe(\"Stall detection and retry limits for running tasks.\"),\n })\n .superRefine((config, ctx) => {\n const repositories = new Set<string>(config.repositories.map(({ slug }) => slug));\n for (const [index, connector] of config.connectors.slack.entries()) {\n for (const slug of Object.keys(connector.autonomousPullRequestsByRepository ?? {})) {\n if (!repositories.has(slug))\n ctx.addIssue({\n code: \"custom\",\n path: [\"connectors\", \"slack\", index, \"autonomousPullRequestsByRepository\", slug],\n message: \"PR notification destinations must name a configured repository.\",\n });\n }\n }\n if (config.sandboxGitHubActAs !== undefined && config.sandboxGitHubCredentials !== \"vercel\") {\n ctx.addIssue({\n code: \"custom\",\n path: [\"sandboxGitHubActAs\"],\n message: \"A managed GitHub act-as identity requires Vercel-managed Sandbox credentials.\",\n });\n }\n })\n .readonly();\n\n/** Fully resolved repository allowlist entry in a Factory configuration. */\nexport type FactoryConfigRepository = z.infer<typeof factoryConfigRepositorySchema>;\n\n/** Fully resolved and validated Factory configuration. */\nexport type FactoryConfig = z.infer<typeof factoryConfigSchema>;\ntype FactoryConfigSchemaInput = z.input<typeof factoryConfigSchema>;\ntype FactoryConfigConnectorsInput = Readonly<{\n github: readonly Readonly<z.input<typeof githubConnectorSchema>>[];\n slack?: readonly Readonly<z.input<typeof slackConnectorSchema>>[];\n}>;\n/** Repository allowlist entry accepted when defining a Factory, before defaults are applied. */\nexport type FactoryConfigRepositoryInput = Readonly<{\n slug: RepositorySlug;\n defaultBranch?: string;\n dependsOn?: readonly RepositorySlug[];\n}>;\n/** Caller input accepted when defining a Factory, before schema defaults are applied. */\nexport type FactoryConfigInput = Readonly<\n Omit<FactoryConfigSchemaInput, \"connectors\" | \"repositories\" | \"operators\"> & {\n connectors?: FactoryConfigConnectorsInput;\n repositories: readonly FactoryConfigRepositoryInput[];\n operators: readonly string[];\n }\n>;\n\n/** Validates a Factory configuration and applies its declared defaults. */\nexport function defineFactory(config: FactoryConfigInput): FactoryConfig {\n return factoryConfigSchema.parse(config);\n}\n"],"mappings":"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"}
@@ -20,6 +20,7 @@ interface VercelManagedGitHubApiSandboxCreateInput {
20
20
  github: [{
21
21
  repositories: [RepositorySlug];
22
22
  actions: [VercelManagedGitHubApiAction];
23
+ actAs?: string;
23
24
  }];
24
25
  };
25
26
  networkPolicy: NetworkPolicy;
@@ -32,6 +33,8 @@ interface VercelManagedGitHubApiSandboxCreateInput {
32
33
  }
33
34
  /** Configures fresh trusted Sandboxes for brokered GitHub API requests. */
34
35
  interface VercelManagedGitHubApiOptions {
36
+ /** GitHub user ID selected for managed GitHub API requests. */
37
+ actAs?: string;
35
38
  /** Attribution metadata supplied when managed publication creates a signed commit. */
36
39
  commitIdentity?: {
37
40
  name: string;
@@ -15,6 +15,7 @@ const sandboxResponseSchema = z.object({
15
15
  status: z.number().int().min(100).max(599),
16
16
  body: z.unknown()
17
17
  });
18
+ const githubUserIdSchema = z.string().regex(/^[1-9][0-9]*$/u).max(16).refine((id) => Number.isSafeInteger(Number(id)));
18
19
  const issueSchema = z.object({
19
20
  title: z.string(),
20
21
  body: z.string().nullable(),
@@ -108,11 +109,12 @@ async function createManagedSandbox(input) {
108
109
  const { Sandbox } = await import("@vercel/sandbox");
109
110
  return Sandbox.create({ ...input });
110
111
  }
111
- function createInput(repository, action) {
112
+ function createInput(repository, action, actAs) {
112
113
  return {
113
114
  __credentials: { github: [{
114
115
  repositories: [repository],
115
- actions: [action]
116
+ actions: [action],
117
+ ...actAs === void 0 ? {} : { actAs }
116
118
  }] },
117
119
  networkPolicy: { allow: ["api.github.com"] },
118
120
  persistent: false,
@@ -121,7 +123,7 @@ function createInput(repository, action) {
121
123
  timeout: 6e4
122
124
  };
123
125
  }
124
- function createPublicationInput(repository, commitIdentity) {
126
+ function createPublicationInput(repository, commitIdentity, actAs) {
125
127
  return {
126
128
  source: {
127
129
  type: "git",
@@ -131,7 +133,8 @@ function createPublicationInput(repository, commitIdentity) {
131
133
  __commitAs: commitIdentity,
132
134
  __credentials: { github: [{
133
135
  repositories: [repository],
134
- actions: ["github:pull-request:create"]
136
+ actions: ["github:pull-request:create"],
137
+ ...actAs === void 0 ? {} : { actAs }
135
138
  }] },
136
139
  networkPolicy: { allow: ["github.com", "api.github.com"] },
137
140
  persistent: false,
@@ -141,7 +144,7 @@ function createPublicationInput(repository, commitIdentity) {
141
144
  };
142
145
  }
143
146
  async function request(createSandbox, input) {
144
- const sandbox = await createSandbox(createInput(input.repository, input.action));
147
+ const sandbox = await createSandbox(createInput(input.repository, input.action, input.actAs));
145
148
  try {
146
149
  await input.authorize();
147
150
  const result = await sandbox.runCommand({
@@ -197,6 +200,7 @@ async function sandboxRequest(sandbox, input) {
197
200
  /** Create repository-scoped GitHub API operations backed by managed Sandbox credentials. */
198
201
  function createVercelManagedGitHubApi(options = {}) {
199
202
  const createSandbox = options.createSandbox ?? createManagedSandbox;
203
+ const actAs = options.actAs === void 0 ? void 0 : githubUserIdSchema.parse(options.actAs);
200
204
  return {
201
205
  async readIssue(input) {
202
206
  const repository = repositorySlugSchema.parse(input.repository.toLowerCase());
@@ -204,6 +208,7 @@ function createVercelManagedGitHubApi(options = {}) {
204
208
  const issue = issueSchema.parse(await request(createSandbox, {
205
209
  repository,
206
210
  action: "github:issues:read",
211
+ actAs,
207
212
  method: "GET",
208
213
  path: `/issues/${input.issueNumber}`,
209
214
  authorize: input.authorize
@@ -219,7 +224,7 @@ function createVercelManagedGitHubApi(options = {}) {
219
224
  const repository = repositorySlugSchema.parse(input.repository.toLowerCase());
220
225
  if (!Number.isSafeInteger(input.pullRequestNumber) || input.pullRequestNumber < 1) throw new Error("Invalid GitHub pull request number");
221
226
  const label = labelInputSchema.parse(input);
222
- const sandbox = await createSandbox(createInput(repository, "github:labels:write"));
227
+ const sandbox = await createSandbox(createInput(repository, "github:labels:write", actAs));
223
228
  try {
224
229
  const authorizedRequest = async (request) => {
225
230
  await input.authorize();
@@ -268,6 +273,7 @@ function createVercelManagedGitHubApi(options = {}) {
268
273
  const pull = pullRequestSchema.parse(await request(createSandbox, {
269
274
  repository,
270
275
  action: "github:pull-request:create",
276
+ actAs,
271
277
  method: "POST",
272
278
  path: "/pulls",
273
279
  body: {
@@ -295,7 +301,7 @@ function createVercelManagedGitHubApi(options = {}) {
295
301
  const title = publicationTitleSchema.parse(input.title);
296
302
  const body = publicationBodySchema.parse(input.body);
297
303
  const commitMessage = publicationCommitMessageSchema.parse(`${input.commitMessage}\n\nCo-authored-by: ${options.commitIdentity.name} <${options.commitIdentity.email}>`);
298
- const sandbox = await createSandbox(createPublicationInput(repository, options.commitIdentity));
304
+ const sandbox = await createSandbox(createPublicationInput(repository, options.commitIdentity, actAs));
299
305
  try {
300
306
  const authorizedRequest = async (request) => {
301
307
  await input.authorize();
@@ -1 +1 @@
1
- {"version":3,"file":"vercel-github-api.mjs","names":[],"sources":["../src/vercel-github-api.ts"],"sourcesContent":["import type { Sandbox, NetworkPolicy } from \"@vercel/sandbox\";\nimport { z } from \"zod\";\nimport { isSafeGitRef, type GitHubTreeEntry } from \"./github-publication\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./schema/repository\";\n\ntype TrustedGitHubApiSandbox = Pick<Sandbox, \"runCommand\" | \"stop\">;\n\n/** GitHub API actions supported by Vercel-managed Sandbox credentials. */\nexport type VercelManagedGitHubApiAction =\n | \"github:issues:read\"\n | \"github:pull-request:create\"\n | \"github:labels:write\";\n\n/** Exact creation request for one Vercel-managed GitHub API operation. */\nexport interface VercelManagedGitHubApiSandboxCreateInput {\n source?: {\n type: \"git\";\n url: string;\n };\n __source_credentials?: true;\n __commitAs?: {\n name: string;\n email: string;\n };\n __credentials: {\n github: [\n {\n repositories: [RepositorySlug];\n actions: [VercelManagedGitHubApiAction];\n },\n ];\n };\n networkPolicy: NetworkPolicy;\n persistent: false;\n resources: { vcpus: 6 };\n runtime: \"node24\";\n timeout: 60_000 | 180_000;\n}\n\n/** Configures fresh trusted Sandboxes for brokered GitHub API requests. */\nexport interface VercelManagedGitHubApiOptions {\n /** Attribution metadata supplied when managed publication creates a signed commit. */\n commitIdentity?: { name: string; email: string };\n createSandbox?: (\n input: VercelManagedGitHubApiSandboxCreateInput,\n ) => Promise<TrustedGitHubApiSandbox>;\n}\n\n/** Authorized request to read one exact GitHub issue. */\nexport interface VercelManagedGitHubIssueInput {\n repository: RepositorySlug;\n issueNumber: number;\n authorize(): Promise<void>;\n}\n\n/** Issue fields returned by a Vercel-managed GitHub API request. */\nexport interface VercelManagedGitHubIssue {\n title: string;\n body: string | null;\n url: string;\n pullRequest: boolean;\n}\n\n/** Authorized request to ensure and attach a repository flow label to a pull request. */\nexport interface VercelManagedGitHubLabelInput {\n repository: RepositorySlug;\n pullRequestNumber: number;\n name: string;\n color: string;\n description: string;\n authorize(): Promise<void>;\n}\n\n/** Authorized request to create one draft or ready GitHub pull request. */\nexport interface VercelManagedGitHubPullRequestInput {\n repository: RepositorySlug;\n title: string;\n body: string;\n head: string;\n base: string;\n draft: boolean;\n authorize(): Promise<void>;\n}\n\n/** Pull-request identity returned by a Vercel-managed GitHub API request. */\nexport interface VercelManagedGitHubPullRequest {\n pullRequestNumber: number;\n pullRequestUrl: string;\n draft: boolean;\n}\n\n/** Git Data and pull-request inputs for one idempotent managed publication. */\nexport interface VercelManagedGitHubPublicationInput {\n repository: RepositorySlug;\n baseCommit: string;\n tree: readonly GitHubTreeEntry[];\n commitMessage: string;\n branch: string;\n title: string;\n body: string;\n baseBranch: string;\n draft: boolean;\n authorize(): Promise<void>;\n}\n\n/** Commit and pull-request identities returned after managed publication. */\nexport interface VercelManagedGitHubPublication extends VercelManagedGitHubPullRequest {\n commitSha: string;\n}\n\n/** Repository-scoped brokered GitHub API operations supplied by Vercel Sandbox. */\nexport interface VercelManagedGitHubApi {\n readIssue(input: VercelManagedGitHubIssueInput): Promise<VercelManagedGitHubIssue>;\n labelPullRequest(input: VercelManagedGitHubLabelInput): Promise<void>;\n createPullRequest(\n input: VercelManagedGitHubPullRequestInput,\n ): Promise<VercelManagedGitHubPullRequest>;\n publishPullRequest(\n input: VercelManagedGitHubPublicationInput,\n ): Promise<VercelManagedGitHubPublication>;\n}\n\n/** GitHub API failure returned through the managed credential Sandbox. */\nexport class VercelManagedGitHubApiError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(`GitHub API request failed (${status}): ${message}`);\n this.name = \"VercelManagedGitHubApiError\";\n }\n}\n\nconst sandboxResponseSchema = z.object({\n status: z.number().int().min(100).max(599),\n body: z.unknown(),\n});\nconst issueSchema = z.object({\n title: z.string(),\n body: z.string().nullable(),\n html_url: z.url(),\n pull_request: z.unknown().optional(),\n});\nconst labelSchema = z.object({ name: z.string() });\nconst labelInputSchema = z.object({\n name: z\n .string()\n .min(1)\n .max(50)\n .refine(\n (name) =>\n Buffer.byteLength(name, \"utf8\") <= 50 &&\n name.trim() === name &&\n [...name].every((character) => {\n const code = character.charCodeAt(0);\n return code > 31 && code !== 127 && character !== \"\\\\\";\n }) &&\n name.split(\"/\").every((part) => part !== \"\" && part !== \".\" && part !== \"..\"),\n ),\n color: z.string().regex(/^[a-fA-F0-9]{6}$/u),\n description: z\n .string()\n .max(100)\n .refine((description) => Buffer.byteLength(description, \"utf8\") <= 100),\n});\nconst pullRequestSchema = z.object({\n number: z.number().int().positive(),\n html_url: z.url(),\n draft: z.boolean(),\n});\nconst shaSchema = z.string().regex(/^[a-f0-9]{40}$/u);\nconst commitSchema = z.object({\n sha: shaSchema,\n tree: z.object({ sha: shaSchema }),\n parents: z.array(z.object({ sha: shaSchema })),\n});\nconst treeSchema = z.object({ sha: shaSchema });\nconst refSchema = z.object({ object: z.object({ sha: shaSchema }) });\nconst publicationPullSchema = pullRequestSchema.extend({\n state: z.enum([\"open\", \"closed\"]),\n head: z.object({ ref: z.string(), sha: shaSchema }),\n});\nconst publicationPathSchema = z\n .string()\n .min(1)\n .max(1_024)\n .refine((path) => Buffer.byteLength(path, \"utf8\") <= 1_024, {\n message: \"Managed publication path exceeds byte limit\",\n })\n .refine(\n (path) =>\n /^[A-Za-z0-9.][A-Za-z0-9._/-]*$/u.test(path) &&\n !path.includes(\"..\") &&\n !path.includes(\"//\") &&\n !path.endsWith(\"/\") &&\n !path.split(\"/\").some((part) => part === \".\"),\n { message: \"Invalid managed publication path\" },\n );\nconst publicationBranchSchema = z\n .string()\n .min(1)\n .max(256)\n .refine(\n (branch) =>\n isSafeGitRef(branch) &&\n branch\n .split(\"/\")\n .every(\n (component) =>\n component.length > 0 &&\n !component.startsWith(\".\") &&\n !component.endsWith(\".\") &&\n !component.endsWith(\".lock\"),\n ),\n { message: \"Invalid managed publication branch\" },\n );\nconst publicationTextSchema = (maximum: number, field: string) =>\n z\n .string()\n .max(maximum)\n .refine((value) => Buffer.byteLength(value, \"utf8\") <= maximum, {\n message: `Managed publication ${field} exceeds byte limit`,\n });\nconst publicationCommitMessageSchema = publicationTextSchema(65_536, \"commit message\").min(1);\nconst publicationTitleSchema = publicationTextSchema(256, \"title\").min(1);\nconst publicationBodySchema = publicationTextSchema(65_536, \"body\");\nconst publicationBaseBranchSchema = z\n .string()\n .min(1)\n .max(256)\n .refine((branch) => isSafeGitRef(branch), {\n message: \"Invalid managed publication base branch\",\n });\nconst publicationContentSchema = z\n .string()\n .max(200_000)\n .refine((content) => Buffer.byteLength(content, \"utf8\") <= 200_000, {\n message: \"Managed publication content exceeds byte limit\",\n });\nconst publicationTreeSchema = z\n .array(\n z.union([\n z.strictObject({\n path: publicationPathSchema,\n mode: z.enum([\"100644\", \"100755\"]),\n type: z.literal(\"blob\"),\n content: publicationContentSchema,\n }),\n z.strictObject({\n path: publicationPathSchema,\n mode: z.enum([\"100644\", \"100755\"]),\n type: z.literal(\"blob\"),\n sha: z.null(),\n }),\n ]),\n )\n .min(1)\n .max(25)\n .refine(\n (entries) =>\n new TextEncoder().encode(JSON.stringify({ tree: entries })).byteLength <= 1_000_000,\n \"Managed publication tree exceeds transfer limit\",\n );\nconst githubRequestScript = `\nconst request = JSON.parse(process.argv[1]);\nconst response = await fetch(request.url, {\n method: request.method,\n headers: {\n accept: \"application/vnd.github+json\",\n \"content-type\": \"application/json\",\n \"x-github-api-version\": \"2022-11-28\",\n },\n body: request.body === undefined ? undefined : JSON.stringify(request.body),\n redirect: \"error\",\n});\nconst reader = response.body?.getReader();\nconst chunks = [];\nlet byteLength = 0;\nif (reader) {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n byteLength += value.byteLength;\n if (byteLength > 1_000_000) {\n await reader.cancel();\n throw new Error(\"GitHub API response exceeds transfer limit\");\n }\n chunks.push(value);\n }\n}\nconst bytes = new Uint8Array(byteLength);\nlet offset = 0;\nfor (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }\nconst text = new TextDecoder().decode(bytes);\nlet body = null;\ntry { body = text === \"\" ? null : JSON.parse(text); } catch { body = { message: text }; }\nprocess.stdout.write(JSON.stringify({ status: response.status, body }));\n`;\n\nasync function createManagedSandbox(\n input: VercelManagedGitHubApiSandboxCreateInput,\n): Promise<TrustedGitHubApiSandbox> {\n const { Sandbox } = await import(\"@vercel/sandbox\");\n return Sandbox.create({ ...input });\n}\n\nfunction createInput(\n repository: RepositorySlug,\n action: VercelManagedGitHubApiAction,\n): VercelManagedGitHubApiSandboxCreateInput {\n return {\n __credentials: { github: [{ repositories: [repository], actions: [action] }] },\n networkPolicy: { allow: [\"api.github.com\"] },\n persistent: false,\n resources: { vcpus: 6 },\n runtime: \"node24\",\n timeout: 60_000,\n };\n}\n\nfunction createPublicationInput(\n repository: RepositorySlug,\n commitIdentity: { name: string; email: string },\n): VercelManagedGitHubApiSandboxCreateInput {\n return {\n source: { type: \"git\", url: `https://github.com/${repository}.git` },\n __source_credentials: true,\n __commitAs: commitIdentity,\n __credentials: {\n github: [\n {\n repositories: [repository],\n actions: [\"github:pull-request:create\"],\n },\n ],\n },\n networkPolicy: { allow: [\"github.com\", \"api.github.com\"] },\n persistent: false,\n resources: { vcpus: 6 },\n runtime: \"node24\",\n timeout: 180_000,\n };\n}\n\nasync function request(\n createSandbox: (\n input: VercelManagedGitHubApiSandboxCreateInput,\n ) => Promise<TrustedGitHubApiSandbox>,\n input: {\n repository: RepositorySlug;\n action: VercelManagedGitHubApiAction;\n method: \"GET\" | \"POST\";\n path: string;\n body?: unknown;\n authorize(): Promise<void>;\n },\n): Promise<unknown> {\n const sandbox = await createSandbox(createInput(input.repository, input.action));\n try {\n await input.authorize();\n const result = await sandbox.runCommand({\n cmd: \"node\",\n args: [\n \"--input-type=module\",\n \"--eval\",\n githubRequestScript,\n JSON.stringify({\n method: input.method,\n url: `https://api.github.com/repos/${input.repository}${input.path}`,\n ...(input.body === undefined ? {} : { body: input.body }),\n }),\n ],\n timeoutMs: 30_000,\n });\n const stderr = (await result.stderr()).trim();\n if (result.exitCode !== 0) {\n throw new Error(`Managed GitHub API operation failed (${result.exitCode}): ${stderr}`);\n }\n const response = sandboxResponseSchema.parse(JSON.parse((await result.stdout()).trim()));\n if (response.status < 200 || response.status >= 300) {\n const message = z.object({ message: z.string() }).safeParse(response.body);\n throw new VercelManagedGitHubApiError(\n response.status,\n message.success ? message.data.message : \"Unexpected response\",\n );\n }\n return response.body;\n } finally {\n await sandbox.stop();\n }\n}\n\nasync function sandboxRequest(\n sandbox: TrustedGitHubApiSandbox,\n input: {\n repository: RepositorySlug;\n method: \"GET\" | \"POST\";\n path: string;\n body?: unknown;\n },\n): Promise<unknown> {\n const result = await sandbox.runCommand({\n cmd: \"node\",\n args: [\n \"--input-type=module\",\n \"--eval\",\n githubRequestScript,\n JSON.stringify({\n method: input.method,\n url: `https://api.github.com/repos/${input.repository}${input.path}`,\n ...(input.body === undefined ? {} : { body: input.body }),\n }),\n ],\n timeoutMs: 30_000,\n });\n const stderr = (await result.stderr()).trim();\n if (result.exitCode !== 0) {\n throw new Error(`Managed GitHub API operation failed (${result.exitCode}): ${stderr}`);\n }\n const response = sandboxResponseSchema.parse(JSON.parse((await result.stdout()).trim()));\n if (response.status < 200 || response.status >= 300) {\n const message = z.object({ message: z.string() }).safeParse(response.body);\n throw new VercelManagedGitHubApiError(\n response.status,\n message.success ? message.data.message : \"Unexpected response\",\n );\n }\n return response.body;\n}\n\n/** Create repository-scoped GitHub API operations backed by managed Sandbox credentials. */\nexport function createVercelManagedGitHubApi(\n options: VercelManagedGitHubApiOptions = {},\n): VercelManagedGitHubApi {\n const createSandbox = options.createSandbox ?? createManagedSandbox;\n return {\n async readIssue(input) {\n const repository = repositorySlugSchema.parse(input.repository.toLowerCase());\n if (!Number.isSafeInteger(input.issueNumber) || input.issueNumber < 1) {\n throw new Error(\"Invalid GitHub issue number\");\n }\n const issue = issueSchema.parse(\n await request(createSandbox, {\n repository,\n action: \"github:issues:read\",\n method: \"GET\",\n path: `/issues/${input.issueNumber}`,\n authorize: input.authorize,\n }),\n );\n return {\n title: issue.title,\n body: issue.body,\n url: issue.html_url,\n pullRequest: issue.pull_request !== undefined,\n };\n },\n async labelPullRequest(input) {\n const repository = repositorySlugSchema.parse(input.repository.toLowerCase());\n if (!Number.isSafeInteger(input.pullRequestNumber) || input.pullRequestNumber < 1) {\n throw new Error(\"Invalid GitHub pull request number\");\n }\n const label = labelInputSchema.parse(input);\n const sandbox = await createSandbox(createInput(repository, \"github:labels:write\"));\n try {\n const authorizedRequest = async (\n request: Omit<Parameters<typeof sandboxRequest>[1], \"repository\">,\n ) => {\n await input.authorize();\n return sandboxRequest(sandbox, { repository, ...request });\n };\n const labelPath = `/labels/${encodeURIComponent(label.name)}`;\n const read = async () => {\n const existing = labelSchema.parse(\n await authorizedRequest({ method: \"GET\", path: labelPath }),\n );\n if (existing.name.toLowerCase() !== label.name.toLowerCase()) {\n throw new Error(\"GitHub returned a different repository label\");\n }\n };\n try {\n await read();\n } catch (error) {\n if (!(error instanceof VercelManagedGitHubApiError) || error.status !== 404) throw error;\n try {\n await authorizedRequest({ method: \"POST\", path: \"/labels\", body: label });\n } catch (creationError) {\n if (\n !(creationError instanceof VercelManagedGitHubApiError) ||\n creationError.status !== 422\n ) {\n throw creationError;\n }\n await read();\n }\n }\n await authorizedRequest({\n method: \"POST\",\n path: `/issues/${input.pullRequestNumber}/labels`,\n body: { labels: [label.name] },\n });\n } finally {\n await sandbox.stop();\n }\n },\n async createPullRequest(input) {\n const repository = repositorySlugSchema.parse(input.repository.toLowerCase());\n const head = publicationBranchSchema.parse(input.head);\n const base = publicationBaseBranchSchema.parse(input.base);\n const title = publicationTitleSchema.parse(input.title);\n const body = publicationBodySchema.parse(input.body);\n const pull = pullRequestSchema.parse(\n await request(createSandbox, {\n repository,\n action: \"github:pull-request:create\",\n method: \"POST\",\n path: \"/pulls\",\n body: {\n title,\n body,\n head,\n base,\n draft: input.draft,\n },\n authorize: input.authorize,\n }),\n );\n return {\n pullRequestNumber: pull.number,\n pullRequestUrl: pull.html_url,\n draft: pull.draft,\n };\n },\n async publishPullRequest(input) {\n const repository = repositorySlugSchema.parse(input.repository.toLowerCase());\n if (!options.commitIdentity) throw new Error(\"Managed publication requires commit identity\");\n if (!/^[a-f0-9]{40}$/u.test(input.baseCommit) || input.commitMessage.trim() === \"\") {\n throw new Error(\"Invalid managed GitHub publication\");\n }\n const publicationTree = publicationTreeSchema.parse(input.tree);\n const branch = publicationBranchSchema.parse(input.branch);\n const baseBranch = publicationBaseBranchSchema.parse(input.baseBranch);\n const title = publicationTitleSchema.parse(input.title);\n const body = publicationBodySchema.parse(input.body);\n const commitMessage = publicationCommitMessageSchema.parse(\n `${input.commitMessage}\\n\\nCo-authored-by: ${options.commitIdentity.name} <${options.commitIdentity.email}>`,\n );\n const sandbox = await createSandbox(\n createPublicationInput(repository, options.commitIdentity),\n );\n try {\n const authorizedRequest = async (\n request: Omit<Parameters<typeof sandboxRequest>[1], \"repository\">,\n ) => {\n await input.authorize();\n return sandboxRequest(sandbox, { repository, ...request });\n };\n const base = commitSchema.parse(\n await authorizedRequest({\n method: \"GET\",\n path: `/git/commits/${input.baseCommit}`,\n }),\n );\n const tree = treeSchema.parse(\n await authorizedRequest({\n method: \"POST\",\n path: \"/git/trees\",\n body: { base_tree: base.tree.sha, tree: publicationTree },\n }),\n );\n const pullPath = `/pulls?${new URLSearchParams({\n state: \"all\",\n head: `${repository.split(\"/\")[0]}:${branch}`,\n per_page: \"100\",\n })}`;\n const pulls = async () =>\n z\n .array(publicationPullSchema)\n .parse(await authorizedRequest({ method: \"GET\", path: pullPath }));\n const result = (pull: z.infer<typeof pullRequestSchema>, commitSha: string) => ({\n commitSha,\n pullRequestNumber: pull.number,\n pullRequestUrl: pull.html_url,\n draft: pull.draft,\n });\n const existingPull = (await pulls()).find((pull) => pull.head.ref === branch);\n const refPath = `/git/ref/heads/${branch.split(\"/\").map(encodeURIComponent).join(\"/\")}`;\n let existingRef: z.infer<typeof refSchema> | null;\n try {\n existingRef = refSchema.parse(await authorizedRequest({ method: \"GET\", path: refPath }));\n } catch (error) {\n if (!(error instanceof VercelManagedGitHubApiError) || error.status !== 404) throw error;\n existingRef = null;\n }\n let commitSha = existingRef?.object.sha;\n if (existingPull) {\n if (existingPull.state !== \"open\") {\n throw new Error(\"Managed publication pull request is closed\");\n }\n if (commitSha !== existingPull.head.sha) {\n throw new Error(\"Managed publication pull request head differs from its branch\");\n }\n const existingCommit = commitSchema.parse(\n await authorizedRequest({\n method: \"GET\",\n path: `/git/commits/${existingPull.head.sha}`,\n }),\n );\n if (\n existingCommit.tree.sha !== tree.sha ||\n existingCommit.parents.length !== 1 ||\n existingCommit.parents[0]?.sha !== input.baseCommit\n ) {\n throw new Error(\"Managed publication pull request contains different changes\");\n }\n return result(existingPull, existingPull.head.sha);\n }\n if (commitSha) {\n const existingCommit = commitSchema.parse(\n await authorizedRequest({\n method: \"GET\",\n path: `/git/commits/${commitSha}`,\n }),\n );\n if (\n existingCommit.tree.sha !== tree.sha ||\n existingCommit.parents.length !== 1 ||\n existingCommit.parents[0]?.sha !== input.baseCommit\n ) {\n throw new Error(\"Managed publication branch contains different changes\");\n }\n } else {\n const commit = commitSchema.parse(\n await authorizedRequest({\n method: \"POST\",\n path: \"/git/commits\",\n body: {\n message: commitMessage,\n tree: tree.sha,\n parents: [input.baseCommit],\n },\n }),\n );\n commitSha = commit.sha;\n try {\n await authorizedRequest({\n method: \"POST\",\n path: \"/git/refs\",\n body: { ref: `refs/heads/${branch}`, sha: commitSha },\n });\n } catch (error) {\n const reconciled = refSchema.parse(\n await authorizedRequest({ method: \"GET\", path: refPath }),\n );\n if (reconciled.object.sha !== commitSha) throw error;\n }\n }\n let pull: z.infer<typeof pullRequestSchema>;\n try {\n pull = pullRequestSchema.parse(\n await authorizedRequest({\n method: \"POST\",\n path: \"/pulls\",\n body: {\n title,\n body,\n head: branch,\n base: baseBranch,\n draft: input.draft,\n },\n }),\n );\n } catch (error) {\n const reconciled = (await pulls()).find((candidate) => candidate.head.ref === branch);\n if (!reconciled || reconciled.state !== \"open\" || reconciled.head.sha !== commitSha) {\n throw error;\n }\n pull = reconciled;\n }\n return result(pull, commitSha);\n } finally {\n await sandbox.stop();\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"vercel-github-api.mjs","names":[],"sources":["../src/vercel-github-api.ts"],"sourcesContent":["import type { Sandbox, NetworkPolicy } from \"@vercel/sandbox\";\nimport { z } from \"zod\";\nimport { isSafeGitRef, type GitHubTreeEntry } from \"./github-publication\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./schema/repository\";\n\ntype TrustedGitHubApiSandbox = Pick<Sandbox, \"runCommand\" | \"stop\">;\n\n/** GitHub API actions supported by Vercel-managed Sandbox credentials. */\nexport type VercelManagedGitHubApiAction =\n | \"github:issues:read\"\n | \"github:pull-request:create\"\n | \"github:labels:write\";\n\n/** Exact creation request for one Vercel-managed GitHub API operation. */\nexport interface VercelManagedGitHubApiSandboxCreateInput {\n source?: {\n type: \"git\";\n url: string;\n };\n __source_credentials?: true;\n __commitAs?: {\n name: string;\n email: string;\n };\n __credentials: {\n github: [\n {\n repositories: [RepositorySlug];\n actions: [VercelManagedGitHubApiAction];\n actAs?: string;\n },\n ];\n };\n networkPolicy: NetworkPolicy;\n persistent: false;\n resources: { vcpus: 6 };\n runtime: \"node24\";\n timeout: 60_000 | 180_000;\n}\n\n/** Configures fresh trusted Sandboxes for brokered GitHub API requests. */\nexport interface VercelManagedGitHubApiOptions {\n /** GitHub user ID selected for managed GitHub API requests. */\n actAs?: string;\n /** Attribution metadata supplied when managed publication creates a signed commit. */\n commitIdentity?: { name: string; email: string };\n createSandbox?: (\n input: VercelManagedGitHubApiSandboxCreateInput,\n ) => Promise<TrustedGitHubApiSandbox>;\n}\n\n/** Authorized request to read one exact GitHub issue. */\nexport interface VercelManagedGitHubIssueInput {\n repository: RepositorySlug;\n issueNumber: number;\n authorize(): Promise<void>;\n}\n\n/** Issue fields returned by a Vercel-managed GitHub API request. */\nexport interface VercelManagedGitHubIssue {\n title: string;\n body: string | null;\n url: string;\n pullRequest: boolean;\n}\n\n/** Authorized request to ensure and attach a repository flow label to a pull request. */\nexport interface VercelManagedGitHubLabelInput {\n repository: RepositorySlug;\n pullRequestNumber: number;\n name: string;\n color: string;\n description: string;\n authorize(): Promise<void>;\n}\n\n/** Authorized request to create one draft or ready GitHub pull request. */\nexport interface VercelManagedGitHubPullRequestInput {\n repository: RepositorySlug;\n title: string;\n body: string;\n head: string;\n base: string;\n draft: boolean;\n authorize(): Promise<void>;\n}\n\n/** Pull-request identity returned by a Vercel-managed GitHub API request. */\nexport interface VercelManagedGitHubPullRequest {\n pullRequestNumber: number;\n pullRequestUrl: string;\n draft: boolean;\n}\n\n/** Git Data and pull-request inputs for one idempotent managed publication. */\nexport interface VercelManagedGitHubPublicationInput {\n repository: RepositorySlug;\n baseCommit: string;\n tree: readonly GitHubTreeEntry[];\n commitMessage: string;\n branch: string;\n title: string;\n body: string;\n baseBranch: string;\n draft: boolean;\n authorize(): Promise<void>;\n}\n\n/** Commit and pull-request identities returned after managed publication. */\nexport interface VercelManagedGitHubPublication extends VercelManagedGitHubPullRequest {\n commitSha: string;\n}\n\n/** Repository-scoped brokered GitHub API operations supplied by Vercel Sandbox. */\nexport interface VercelManagedGitHubApi {\n readIssue(input: VercelManagedGitHubIssueInput): Promise<VercelManagedGitHubIssue>;\n labelPullRequest(input: VercelManagedGitHubLabelInput): Promise<void>;\n createPullRequest(\n input: VercelManagedGitHubPullRequestInput,\n ): Promise<VercelManagedGitHubPullRequest>;\n publishPullRequest(\n input: VercelManagedGitHubPublicationInput,\n ): Promise<VercelManagedGitHubPublication>;\n}\n\n/** GitHub API failure returned through the managed credential Sandbox. */\nexport class VercelManagedGitHubApiError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(`GitHub API request failed (${status}): ${message}`);\n this.name = \"VercelManagedGitHubApiError\";\n }\n}\n\nconst sandboxResponseSchema = z.object({\n status: z.number().int().min(100).max(599),\n body: z.unknown(),\n});\nconst githubUserIdSchema = z\n .string()\n .regex(/^[1-9][0-9]*$/u)\n .max(16)\n .refine((id) => Number.isSafeInteger(Number(id)));\nconst issueSchema = z.object({\n title: z.string(),\n body: z.string().nullable(),\n html_url: z.url(),\n pull_request: z.unknown().optional(),\n});\nconst labelSchema = z.object({ name: z.string() });\nconst labelInputSchema = z.object({\n name: z\n .string()\n .min(1)\n .max(50)\n .refine(\n (name) =>\n Buffer.byteLength(name, \"utf8\") <= 50 &&\n name.trim() === name &&\n [...name].every((character) => {\n const code = character.charCodeAt(0);\n return code > 31 && code !== 127 && character !== \"\\\\\";\n }) &&\n name.split(\"/\").every((part) => part !== \"\" && part !== \".\" && part !== \"..\"),\n ),\n color: z.string().regex(/^[a-fA-F0-9]{6}$/u),\n description: z\n .string()\n .max(100)\n .refine((description) => Buffer.byteLength(description, \"utf8\") <= 100),\n});\nconst pullRequestSchema = z.object({\n number: z.number().int().positive(),\n html_url: z.url(),\n draft: z.boolean(),\n});\nconst shaSchema = z.string().regex(/^[a-f0-9]{40}$/u);\nconst commitSchema = z.object({\n sha: shaSchema,\n tree: z.object({ sha: shaSchema }),\n parents: z.array(z.object({ sha: shaSchema })),\n});\nconst treeSchema = z.object({ sha: shaSchema });\nconst refSchema = z.object({ object: z.object({ sha: shaSchema }) });\nconst publicationPullSchema = pullRequestSchema.extend({\n state: z.enum([\"open\", \"closed\"]),\n head: z.object({ ref: z.string(), sha: shaSchema }),\n});\nconst publicationPathSchema = z\n .string()\n .min(1)\n .max(1_024)\n .refine((path) => Buffer.byteLength(path, \"utf8\") <= 1_024, {\n message: \"Managed publication path exceeds byte limit\",\n })\n .refine(\n (path) =>\n /^[A-Za-z0-9.][A-Za-z0-9._/-]*$/u.test(path) &&\n !path.includes(\"..\") &&\n !path.includes(\"//\") &&\n !path.endsWith(\"/\") &&\n !path.split(\"/\").some((part) => part === \".\"),\n { message: \"Invalid managed publication path\" },\n );\nconst publicationBranchSchema = z\n .string()\n .min(1)\n .max(256)\n .refine(\n (branch) =>\n isSafeGitRef(branch) &&\n branch\n .split(\"/\")\n .every(\n (component) =>\n component.length > 0 &&\n !component.startsWith(\".\") &&\n !component.endsWith(\".\") &&\n !component.endsWith(\".lock\"),\n ),\n { message: \"Invalid managed publication branch\" },\n );\nconst publicationTextSchema = (maximum: number, field: string) =>\n z\n .string()\n .max(maximum)\n .refine((value) => Buffer.byteLength(value, \"utf8\") <= maximum, {\n message: `Managed publication ${field} exceeds byte limit`,\n });\nconst publicationCommitMessageSchema = publicationTextSchema(65_536, \"commit message\").min(1);\nconst publicationTitleSchema = publicationTextSchema(256, \"title\").min(1);\nconst publicationBodySchema = publicationTextSchema(65_536, \"body\");\nconst publicationBaseBranchSchema = z\n .string()\n .min(1)\n .max(256)\n .refine((branch) => isSafeGitRef(branch), {\n message: \"Invalid managed publication base branch\",\n });\nconst publicationContentSchema = z\n .string()\n .max(200_000)\n .refine((content) => Buffer.byteLength(content, \"utf8\") <= 200_000, {\n message: \"Managed publication content exceeds byte limit\",\n });\nconst publicationTreeSchema = z\n .array(\n z.union([\n z.strictObject({\n path: publicationPathSchema,\n mode: z.enum([\"100644\", \"100755\"]),\n type: z.literal(\"blob\"),\n content: publicationContentSchema,\n }),\n z.strictObject({\n path: publicationPathSchema,\n mode: z.enum([\"100644\", \"100755\"]),\n type: z.literal(\"blob\"),\n sha: z.null(),\n }),\n ]),\n )\n .min(1)\n .max(25)\n .refine(\n (entries) =>\n new TextEncoder().encode(JSON.stringify({ tree: entries })).byteLength <= 1_000_000,\n \"Managed publication tree exceeds transfer limit\",\n );\nconst githubRequestScript = `\nconst request = JSON.parse(process.argv[1]);\nconst response = await fetch(request.url, {\n method: request.method,\n headers: {\n accept: \"application/vnd.github+json\",\n \"content-type\": \"application/json\",\n \"x-github-api-version\": \"2022-11-28\",\n },\n body: request.body === undefined ? undefined : JSON.stringify(request.body),\n redirect: \"error\",\n});\nconst reader = response.body?.getReader();\nconst chunks = [];\nlet byteLength = 0;\nif (reader) {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n byteLength += value.byteLength;\n if (byteLength > 1_000_000) {\n await reader.cancel();\n throw new Error(\"GitHub API response exceeds transfer limit\");\n }\n chunks.push(value);\n }\n}\nconst bytes = new Uint8Array(byteLength);\nlet offset = 0;\nfor (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }\nconst text = new TextDecoder().decode(bytes);\nlet body = null;\ntry { body = text === \"\" ? null : JSON.parse(text); } catch { body = { message: text }; }\nprocess.stdout.write(JSON.stringify({ status: response.status, body }));\n`;\n\nasync function createManagedSandbox(\n input: VercelManagedGitHubApiSandboxCreateInput,\n): Promise<TrustedGitHubApiSandbox> {\n const { Sandbox } = await import(\"@vercel/sandbox\");\n return Sandbox.create({ ...input });\n}\n\nfunction createInput(\n repository: RepositorySlug,\n action: VercelManagedGitHubApiAction,\n actAs: string | undefined,\n): VercelManagedGitHubApiSandboxCreateInput {\n return {\n __credentials: {\n github: [\n {\n repositories: [repository],\n actions: [action],\n ...(actAs === undefined ? {} : { actAs }),\n },\n ],\n },\n networkPolicy: { allow: [\"api.github.com\"] },\n persistent: false,\n resources: { vcpus: 6 },\n runtime: \"node24\",\n timeout: 60_000,\n };\n}\n\nfunction createPublicationInput(\n repository: RepositorySlug,\n commitIdentity: { name: string; email: string },\n actAs: string | undefined,\n): VercelManagedGitHubApiSandboxCreateInput {\n return {\n source: { type: \"git\", url: `https://github.com/${repository}.git` },\n __source_credentials: true,\n __commitAs: commitIdentity,\n __credentials: {\n github: [\n {\n repositories: [repository],\n actions: [\"github:pull-request:create\"],\n ...(actAs === undefined ? {} : { actAs }),\n },\n ],\n },\n networkPolicy: { allow: [\"github.com\", \"api.github.com\"] },\n persistent: false,\n resources: { vcpus: 6 },\n runtime: \"node24\",\n timeout: 180_000,\n };\n}\n\nasync function request(\n createSandbox: (\n input: VercelManagedGitHubApiSandboxCreateInput,\n ) => Promise<TrustedGitHubApiSandbox>,\n input: {\n repository: RepositorySlug;\n action: VercelManagedGitHubApiAction;\n actAs?: string;\n method: \"GET\" | \"POST\";\n path: string;\n body?: unknown;\n authorize(): Promise<void>;\n },\n): Promise<unknown> {\n const sandbox = await createSandbox(createInput(input.repository, input.action, input.actAs));\n try {\n await input.authorize();\n const result = await sandbox.runCommand({\n cmd: \"node\",\n args: [\n \"--input-type=module\",\n \"--eval\",\n githubRequestScript,\n JSON.stringify({\n method: input.method,\n url: `https://api.github.com/repos/${input.repository}${input.path}`,\n ...(input.body === undefined ? {} : { body: input.body }),\n }),\n ],\n timeoutMs: 30_000,\n });\n const stderr = (await result.stderr()).trim();\n if (result.exitCode !== 0) {\n throw new Error(`Managed GitHub API operation failed (${result.exitCode}): ${stderr}`);\n }\n const response = sandboxResponseSchema.parse(JSON.parse((await result.stdout()).trim()));\n if (response.status < 200 || response.status >= 300) {\n const message = z.object({ message: z.string() }).safeParse(response.body);\n throw new VercelManagedGitHubApiError(\n response.status,\n message.success ? message.data.message : \"Unexpected response\",\n );\n }\n return response.body;\n } finally {\n await sandbox.stop();\n }\n}\n\nasync function sandboxRequest(\n sandbox: TrustedGitHubApiSandbox,\n input: {\n repository: RepositorySlug;\n method: \"GET\" | \"POST\";\n path: string;\n body?: unknown;\n },\n): Promise<unknown> {\n const result = await sandbox.runCommand({\n cmd: \"node\",\n args: [\n \"--input-type=module\",\n \"--eval\",\n githubRequestScript,\n JSON.stringify({\n method: input.method,\n url: `https://api.github.com/repos/${input.repository}${input.path}`,\n ...(input.body === undefined ? {} : { body: input.body }),\n }),\n ],\n timeoutMs: 30_000,\n });\n const stderr = (await result.stderr()).trim();\n if (result.exitCode !== 0) {\n throw new Error(`Managed GitHub API operation failed (${result.exitCode}): ${stderr}`);\n }\n const response = sandboxResponseSchema.parse(JSON.parse((await result.stdout()).trim()));\n if (response.status < 200 || response.status >= 300) {\n const message = z.object({ message: z.string() }).safeParse(response.body);\n throw new VercelManagedGitHubApiError(\n response.status,\n message.success ? message.data.message : \"Unexpected response\",\n );\n }\n return response.body;\n}\n\n/** Create repository-scoped GitHub API operations backed by managed Sandbox credentials. */\nexport function createVercelManagedGitHubApi(\n options: VercelManagedGitHubApiOptions = {},\n): VercelManagedGitHubApi {\n const createSandbox = options.createSandbox ?? createManagedSandbox;\n const actAs = options.actAs === undefined ? undefined : githubUserIdSchema.parse(options.actAs);\n return {\n async readIssue(input) {\n const repository = repositorySlugSchema.parse(input.repository.toLowerCase());\n if (!Number.isSafeInteger(input.issueNumber) || input.issueNumber < 1) {\n throw new Error(\"Invalid GitHub issue number\");\n }\n const issue = issueSchema.parse(\n await request(createSandbox, {\n repository,\n action: \"github:issues:read\",\n actAs,\n method: \"GET\",\n path: `/issues/${input.issueNumber}`,\n authorize: input.authorize,\n }),\n );\n return {\n title: issue.title,\n body: issue.body,\n url: issue.html_url,\n pullRequest: issue.pull_request !== undefined,\n };\n },\n async labelPullRequest(input) {\n const repository = repositorySlugSchema.parse(input.repository.toLowerCase());\n if (!Number.isSafeInteger(input.pullRequestNumber) || input.pullRequestNumber < 1) {\n throw new Error(\"Invalid GitHub pull request number\");\n }\n const label = labelInputSchema.parse(input);\n const sandbox = await createSandbox(createInput(repository, \"github:labels:write\", actAs));\n try {\n const authorizedRequest = async (\n request: Omit<Parameters<typeof sandboxRequest>[1], \"repository\">,\n ) => {\n await input.authorize();\n return sandboxRequest(sandbox, { repository, ...request });\n };\n const labelPath = `/labels/${encodeURIComponent(label.name)}`;\n const read = async () => {\n const existing = labelSchema.parse(\n await authorizedRequest({ method: \"GET\", path: labelPath }),\n );\n if (existing.name.toLowerCase() !== label.name.toLowerCase()) {\n throw new Error(\"GitHub returned a different repository label\");\n }\n };\n try {\n await read();\n } catch (error) {\n if (!(error instanceof VercelManagedGitHubApiError) || error.status !== 404) throw error;\n try {\n await authorizedRequest({ method: \"POST\", path: \"/labels\", body: label });\n } catch (creationError) {\n if (\n !(creationError instanceof VercelManagedGitHubApiError) ||\n creationError.status !== 422\n ) {\n throw creationError;\n }\n await read();\n }\n }\n await authorizedRequest({\n method: \"POST\",\n path: `/issues/${input.pullRequestNumber}/labels`,\n body: { labels: [label.name] },\n });\n } finally {\n await sandbox.stop();\n }\n },\n async createPullRequest(input) {\n const repository = repositorySlugSchema.parse(input.repository.toLowerCase());\n const head = publicationBranchSchema.parse(input.head);\n const base = publicationBaseBranchSchema.parse(input.base);\n const title = publicationTitleSchema.parse(input.title);\n const body = publicationBodySchema.parse(input.body);\n const pull = pullRequestSchema.parse(\n await request(createSandbox, {\n repository,\n action: \"github:pull-request:create\",\n actAs,\n method: \"POST\",\n path: \"/pulls\",\n body: {\n title,\n body,\n head,\n base,\n draft: input.draft,\n },\n authorize: input.authorize,\n }),\n );\n return {\n pullRequestNumber: pull.number,\n pullRequestUrl: pull.html_url,\n draft: pull.draft,\n };\n },\n async publishPullRequest(input) {\n const repository = repositorySlugSchema.parse(input.repository.toLowerCase());\n if (!options.commitIdentity) throw new Error(\"Managed publication requires commit identity\");\n if (!/^[a-f0-9]{40}$/u.test(input.baseCommit) || input.commitMessage.trim() === \"\") {\n throw new Error(\"Invalid managed GitHub publication\");\n }\n const publicationTree = publicationTreeSchema.parse(input.tree);\n const branch = publicationBranchSchema.parse(input.branch);\n const baseBranch = publicationBaseBranchSchema.parse(input.baseBranch);\n const title = publicationTitleSchema.parse(input.title);\n const body = publicationBodySchema.parse(input.body);\n const commitMessage = publicationCommitMessageSchema.parse(\n `${input.commitMessage}\\n\\nCo-authored-by: ${options.commitIdentity.name} <${options.commitIdentity.email}>`,\n );\n const sandbox = await createSandbox(\n createPublicationInput(repository, options.commitIdentity, actAs),\n );\n try {\n const authorizedRequest = async (\n request: Omit<Parameters<typeof sandboxRequest>[1], \"repository\">,\n ) => {\n await input.authorize();\n return sandboxRequest(sandbox, { repository, ...request });\n };\n const base = commitSchema.parse(\n await authorizedRequest({\n method: \"GET\",\n path: `/git/commits/${input.baseCommit}`,\n }),\n );\n const tree = treeSchema.parse(\n await authorizedRequest({\n method: \"POST\",\n path: \"/git/trees\",\n body: { base_tree: base.tree.sha, tree: publicationTree },\n }),\n );\n const pullPath = `/pulls?${new URLSearchParams({\n state: \"all\",\n head: `${repository.split(\"/\")[0]}:${branch}`,\n per_page: \"100\",\n })}`;\n const pulls = async () =>\n z\n .array(publicationPullSchema)\n .parse(await authorizedRequest({ method: \"GET\", path: pullPath }));\n const result = (pull: z.infer<typeof pullRequestSchema>, commitSha: string) => ({\n commitSha,\n pullRequestNumber: pull.number,\n pullRequestUrl: pull.html_url,\n draft: pull.draft,\n });\n const existingPull = (await pulls()).find((pull) => pull.head.ref === branch);\n const refPath = `/git/ref/heads/${branch.split(\"/\").map(encodeURIComponent).join(\"/\")}`;\n let existingRef: z.infer<typeof refSchema> | null;\n try {\n existingRef = refSchema.parse(await authorizedRequest({ method: \"GET\", path: refPath }));\n } catch (error) {\n if (!(error instanceof VercelManagedGitHubApiError) || error.status !== 404) throw error;\n existingRef = null;\n }\n let commitSha = existingRef?.object.sha;\n if (existingPull) {\n if (existingPull.state !== \"open\") {\n throw new Error(\"Managed publication pull request is closed\");\n }\n if (commitSha !== existingPull.head.sha) {\n throw new Error(\"Managed publication pull request head differs from its branch\");\n }\n const existingCommit = commitSchema.parse(\n await authorizedRequest({\n method: \"GET\",\n path: `/git/commits/${existingPull.head.sha}`,\n }),\n );\n if (\n existingCommit.tree.sha !== tree.sha ||\n existingCommit.parents.length !== 1 ||\n existingCommit.parents[0]?.sha !== input.baseCommit\n ) {\n throw new Error(\"Managed publication pull request contains different changes\");\n }\n return result(existingPull, existingPull.head.sha);\n }\n if (commitSha) {\n const existingCommit = commitSchema.parse(\n await authorizedRequest({\n method: \"GET\",\n path: `/git/commits/${commitSha}`,\n }),\n );\n if (\n existingCommit.tree.sha !== tree.sha ||\n existingCommit.parents.length !== 1 ||\n existingCommit.parents[0]?.sha !== input.baseCommit\n ) {\n throw new Error(\"Managed publication branch contains different changes\");\n }\n } else {\n const commit = commitSchema.parse(\n await authorizedRequest({\n method: \"POST\",\n path: \"/git/commits\",\n body: {\n message: commitMessage,\n tree: tree.sha,\n parents: [input.baseCommit],\n },\n }),\n );\n commitSha = commit.sha;\n try {\n await authorizedRequest({\n method: \"POST\",\n path: \"/git/refs\",\n body: { ref: `refs/heads/${branch}`, sha: commitSha },\n });\n } catch (error) {\n const reconciled = refSchema.parse(\n await authorizedRequest({ method: \"GET\", path: refPath }),\n );\n if (reconciled.object.sha !== commitSha) throw error;\n }\n }\n let pull: z.infer<typeof pullRequestSchema>;\n try {\n pull = pullRequestSchema.parse(\n await authorizedRequest({\n method: \"POST\",\n path: \"/pulls\",\n body: {\n title,\n body,\n head: branch,\n base: baseBranch,\n draft: input.draft,\n },\n }),\n );\n } catch (error) {\n const reconciled = (await pulls()).find((candidate) => candidate.head.ref === branch);\n if (!reconciled || reconciled.state !== \"open\" || reconciled.head.sha !== commitSha) {\n throw error;\n }\n pull = reconciled;\n }\n return result(pull, commitSha);\n } finally {\n await sandbox.stop();\n }\n },\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/factory",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "description": "Schema, state machines, and kernel primitives for Agent Factory.",
5
5
  "homepage": "https://github.com/vercel-labs/agent-factory/tree/main/packages/factory",
6
6
  "bugs": "https://github.com/vercel-labs/agent-factory/issues",