fix: resolve gitbundle source from repo ref

This commit is contained in:
Codex
2026-06-08 15:04:08 +08:00
parent e753b853ce
commit 32318ea881
11 changed files with 161 additions and 66 deletions
+3 -1
View File
@@ -60,6 +60,7 @@ export interface GitBundleItemRef extends JsonRecord {
name?: string;
repoUrl?: string;
commitId?: string;
ref?: string;
subpath: string;
targetPath: string;
}
@@ -67,7 +68,8 @@ export interface GitBundleItemRef extends JsonRecord {
export interface ResourceBundleRef extends JsonRecord {
kind: "gitbundle";
repoUrl: string;
commitId: string;
commitId?: string;
ref?: string;
bundles: GitBundleItemRef[];
promptRefs?: Array<{
name: string;
+18 -7
View File
@@ -85,10 +85,11 @@ export function validateResourceBundleRef(value: unknown): ResourceBundleRef | n
const kind = requiredString(record, "kind");
if (kind !== "gitbundle") throw new AgentRunError("schema-invalid", "resourceBundleRef.kind must be gitbundle", { httpStatus: 400 });
const repoUrl = requiredString(record, "repoUrl");
const commitId = requiredString(record, "commitId");
validateCommitId(commitId, "resourceBundleRef.commitId");
const commitId = optionalString(record.commitId);
if (commitId) validateCommitId(commitId, "resourceBundleRef.commitId");
const ref = validateGitRef(record.ref, "resourceBundleRef.ref");
rejectLegacyResourceBundleFields(record);
const result: ResourceBundleRef = { kind: "gitbundle", repoUrl, commitId, bundles: validateResourceGitBundles(record.bundles, repoUrl, commitId) };
const result: ResourceBundleRef = { kind: "gitbundle", repoUrl, ...(commitId ? { commitId } : {}), ...(ref ? { ref } : {}), bundles: validateResourceGitBundles(record.bundles, repoUrl, commitId, ref) };
if (record.promptRefs !== undefined) result.promptRefs = validateResourcePromptRefs(record.promptRefs);
if (record.submodules !== undefined && record.submodules !== false) throw new AgentRunError("schema-invalid", "resourceBundleRef.submodules can only be false in v0.1", { httpStatus: 400 });
if (record.lfs !== undefined && record.lfs !== false) throw new AgentRunError("schema-invalid", "resourceBundleRef.lfs can only be false in v0.1", { httpStatus: 400 });
@@ -104,7 +105,7 @@ function rejectLegacyResourceBundleFields(record: JsonRecord): void {
}
}
function validateResourceGitBundles(value: unknown, defaultRepoUrl: string, defaultCommitId: string): ResourceBundleRef["bundles"] {
function validateResourceGitBundles(value: unknown, defaultRepoUrl: string, defaultCommitId?: string, defaultRef?: string): ResourceBundleRef["bundles"] {
if (!Array.isArray(value)) throw new AgentRunError("schema-invalid", "resourceBundleRef.bundles must be an array", { httpStatus: 400 });
if (value.length === 0) throw new AgentRunError("schema-invalid", "resourceBundleRef.bundles must contain at least one entry", { httpStatus: 400 });
if (value.length > 64) throw new AgentRunError("schema-invalid", "resourceBundleRef.bundles must contain at most 64 entries", { httpStatus: 400 });
@@ -115,15 +116,16 @@ function validateResourceGitBundles(value: unknown, defaultRepoUrl: string, defa
if (name) validateResourceName(name, `resourceBundleRef.bundles[${index}].name`);
const repoUrl = optionalString(record.repoUrl) ?? defaultRepoUrl;
const commitId = optionalString(record.commitId) ?? defaultCommitId;
validateCommitId(commitId, `resourceBundleRef.bundles[${index}].commitId`);
if (commitId) validateCommitId(commitId, `resourceBundleRef.bundles[${index}].commitId`);
const ref = validateGitRef(record.ref, `resourceBundleRef.bundles[${index}].ref`) ?? (commitId ? undefined : defaultRef);
const subpath = validateBundleSubpath(requiredString(record, "subpath"), `resourceBundleRef.bundles[${index}].subpath`);
const rawTargetPath = typeof record.targetPath === "string" ? record.targetPath : record.target_path;
if (typeof rawTargetPath !== "string" || rawTargetPath.trim().length === 0) throw new AgentRunError("schema-invalid", `resourceBundleRef.bundles[${index}].target_path is required`, { httpStatus: 400 });
const targetPath = validateWorkspaceRelativePath(rawTargetPath.trim(), `resourceBundleRef.bundles[${index}].target_path`);
const identity = `${repoUrl}\0${commitId}\0${subpath}\0${targetPath}`;
const identity = `${repoUrl}\0${commitId ?? ""}\0${ref ?? ""}\0${subpath}\0${targetPath}`;
if (seen.has(identity)) throw new AgentRunError("schema-invalid", `resourceBundleRef.bundles[${index}] duplicates an earlier bundle target`, { httpStatus: 400 });
seen.add(identity);
return { ...(name ? { name } : {}), ...(repoUrl === defaultRepoUrl ? {} : { repoUrl }), ...(commitId === defaultCommitId ? {} : { commitId }), subpath, targetPath };
return { ...(name ? { name } : {}), ...(repoUrl === defaultRepoUrl ? {} : { repoUrl }), ...(commitId && commitId !== defaultCommitId ? { commitId } : {}), ...(ref && ref !== defaultRef ? { ref } : {}), subpath, targetPath };
});
}
@@ -131,6 +133,15 @@ function validateCommitId(commitId: string, fieldName: string): void {
if (!/^[0-9a-f]{40}$/u.test(commitId)) throw new AgentRunError("schema-invalid", `${fieldName} must be a full 40-character git commit sha`, { httpStatus: 400 });
}
function validateGitRef(value: unknown, fieldName: string): string | undefined {
const ref = optionalString(value);
if (!ref) return undefined;
if (ref.length > 200 || ref.startsWith("-") || ref.includes("..") || ref.includes("@{") || ref.endsWith("/") || ref.endsWith(".") || /[\s~^:?*[\\\x00-\x1f\x7f]/u.test(ref)) {
throw new AgentRunError("schema-invalid", `${fieldName} must be a bounded git ref name`, { httpStatus: 400 });
}
return ref;
}
function validateResourcePromptRefs(value: unknown): NonNullable<ResourceBundleRef["promptRefs"]> {
if (!Array.isArray(value)) throw new AgentRunError("schema-invalid", "resourceBundleRef.promptRefs must be an array", { httpStatus: 400 });
if (value.length > 16) throw new AgentRunError("schema-invalid", "resourceBundleRef.promptRefs must contain at most 16 entries", { httpStatus: 400 });