@@ -133,6 +133,106 @@ export interface DepositInBoxHostResult {
133133 outcome : PipelineHostRunResult [ "outcome" ] ;
134134}
135135
136+ /** Full or abbreviated git object id (7–40 hex). */
137+ const GIT_COMMIT_SHA_RE = / ^ [ 0 - 9 a - f ] { 7 , 40 } $ / i;
138+
139+ export type DepositSandboxGitRevisionStrategy =
140+ | "branch-shallow"
141+ | "commit-full"
142+ | "ref-shallow" ;
143+
144+ /**
145+ * Git source for `Sandbox.create` deposit clones.
146+ *
147+ * Vercel Sandbox performs a single git clone at create time. A common failure
148+ * is `bad_request: git clone failed` when `revision` is a commit SHA with
149+ * `depth: 1` — shallow clones fetch advertised refs (branches/tags), not
150+ * arbitrary SHAs (GitHub often rejects unadvertised objects).
151+ *
152+ * Strategy (mirrors LocalHost intent, adapted for create-time-only clone):
153+ * 1. **Branch present** → shallow clone that branch tip (`depth: 1`).
154+ * 2. **Commit SHA only** → full clone at that revision (omit `depth`).
155+ * 3. **Other ref** (tag / symbolic) → shallow clone that ref.
156+ *
157+ * Evidence still records the exact `commit` via `sourceRevision`; only the
158+ * create-time clone ref is adjusted for Vercel reachability.
159+ */
160+ export function buildDepositSandboxGitSource ( input : {
161+ repositoryFullName : string ;
162+ /** Preferred product revision (often the selected commit SHA). */
163+ revision : string ;
164+ branch : string | null ;
165+ commit : string | null ;
166+ token ?: string ;
167+ } ) : {
168+ source : {
169+ type : "git" ;
170+ url : string ;
171+ revision : string ;
172+ username ?: string ;
173+ password ?: string ;
174+ depth ?: number ;
175+ } ;
176+ strategy : DepositSandboxGitRevisionStrategy ;
177+ /** Ref actually passed to Sandbox.create (branch, SHA, or other). */
178+ cloneRevision : string ;
179+ depth : number | null ;
180+ } {
181+ const branch = input . branch ?. trim ( ) || "" ;
182+ const commit = ( input . commit || "" ) . trim ( ) ;
183+ const revision = ( input . revision || "" ) . trim ( ) ;
184+ const url = `https://github.com/${ input . repositoryFullName } .git` ;
185+ const auth =
186+ input . token
187+ ? { username : "x-access-token" as const , password : input . token }
188+ : { } ;
189+
190+ // Prefer a non-SHA branch name even when revision/commit is a full SHA.
191+ if ( branch && ! GIT_COMMIT_SHA_RE . test ( branch ) ) {
192+ return {
193+ source : {
194+ type : "git" ,
195+ url,
196+ revision : branch ,
197+ depth : 1 ,
198+ ...auth ,
199+ } ,
200+ strategy : "branch-shallow" ,
201+ cloneRevision : branch ,
202+ depth : 1 ,
203+ } ;
204+ }
205+
206+ const effective = commit || revision || "HEAD" ;
207+ if ( GIT_COMMIT_SHA_RE . test ( effective ) ) {
208+ // Omit depth: shallow + bare SHA is the create failure mode we hit in prod.
209+ return {
210+ source : {
211+ type : "git" ,
212+ url,
213+ revision : effective ,
214+ ...auth ,
215+ } ,
216+ strategy : "commit-full" ,
217+ cloneRevision : effective ,
218+ depth : null ,
219+ } ;
220+ }
221+
222+ return {
223+ source : {
224+ type : "git" ,
225+ url,
226+ revision : effective ,
227+ depth : 1 ,
228+ ...auth ,
229+ } ,
230+ strategy : "ref-shallow" ,
231+ cloneRevision : effective ,
232+ depth : 1 ,
233+ } ;
234+ }
235+
136236/**
137237 * Run the deposit synthesis IN the sandbox box (#25). Builds an asset-pack host in
138238 * DEPOSIT mode (git source for the revision + steering), dispatches it on the sandbox
@@ -160,6 +260,13 @@ export async function runDepositInBoxHost(input: {
160260 shouldAbort ?: ( ) => boolean | Promise < boolean > ;
161261 hostFactory ?: ( ) => Promise < DepositInBoxHost > ;
162262} ) : Promise < DepositInBoxHostResult > {
263+ const gitSource = buildDepositSandboxGitSource ( {
264+ repositoryFullName : input . repositoryFullName ,
265+ revision : input . revision ,
266+ branch : input . branch ,
267+ commit : input . commit ,
268+ token : input . token ,
269+ } ) ;
163270 const plan = buildAssetPackSandboxHostPlan ( {
164271 mode : "asset_pack_pipeline" ,
165272 synthesizeMode : "deposit" ,
@@ -176,14 +283,7 @@ export async function runDepositInBoxHost(input: {
176283 branch : input . branch || "main" ,
177284 commit : input . commit || input . revision ,
178285 } ,
179- source : {
180- type : "git" ,
181- url : `https://github.com/${ input . repositoryFullName } .git` ,
182- revision : input . revision ,
183- username : input . token ? "x-access-token" : undefined ,
184- password : input . token ,
185- depth : 1 ,
186- } ,
286+ source : gitSource . source ,
187287 depositSteering : {
188288 obfuscations : input . obfuscations ,
189289 forcedExclusions : input . forcedExclusions ,
@@ -212,6 +312,11 @@ export async function runDepositInBoxHost(input: {
212312 hasGitSource : Boolean ( plan . createOptions . source ) ,
213313 synthesizeMode : plan . manifest . synthesizeMode ?? null ,
214314 repositoryFullName : input . repositoryFullName ,
315+ gitRevisionStrategy : gitSource . strategy ,
316+ gitCloneRevision : gitSource . cloneRevision ,
317+ gitDepth : gitSource . depth ,
318+ sourceCommit : input . commit || null ,
319+ sourceBranch : input . branch || null ,
215320 } ;
216321 bitcodeServerTelemetry ( "info" , "deposit-sandbox-host" , "plan-ready" , createSummary ) ;
217322
0 commit comments