104 lines
2.7 KiB
TypeScript
104 lines
2.7 KiB
TypeScript
export const BUILD_PROTOCOL_VERSION = 1 as const;
|
|
|
|
export type Sha256Digest = `sha256:${string}`;
|
|
export type BuildArchitecture = "amd64" | "arm64";
|
|
|
|
export type WorkspaceFile = {
|
|
path: string;
|
|
type: "file" | "symlink";
|
|
digest: Sha256Digest;
|
|
size: number;
|
|
mode: 0o644 | 0o755 | 0o777;
|
|
};
|
|
|
|
export type WorkspaceManifest = {
|
|
version: typeof BUILD_PROTOCOL_VERSION;
|
|
files: WorkspaceFile[];
|
|
};
|
|
|
|
export type BuildSpec = {
|
|
/** Absent means the legacy BuildKit Dockerfile builder. */
|
|
builder?: "buildkit" | "buildpacks";
|
|
/** GitHub release CNB package, optionally pinned with #sha256=<hex>. */
|
|
buildpackUri?: string;
|
|
architecture: BuildArchitecture;
|
|
image: string;
|
|
context: string;
|
|
dockerfile?: string;
|
|
target?: string;
|
|
buildArgs: string[];
|
|
workspace: Sha256Digest;
|
|
};
|
|
|
|
export type BuildRequest = {
|
|
version: typeof BUILD_PROTOCOL_VERSION;
|
|
id: string;
|
|
project: string;
|
|
service: string;
|
|
spec: BuildSpec;
|
|
/** Additional service destinations for the same build artifact. */
|
|
destinations?: Array<{ service: string; image: string }>;
|
|
};
|
|
|
|
export type BuildState = "queued" | "running" | "succeeded" | "failed";
|
|
export type BuildPhase =
|
|
| "queued"
|
|
| "creating"
|
|
| "starting"
|
|
| "running"
|
|
| "done";
|
|
|
|
export type BuildStatus = {
|
|
version: typeof BUILD_PROTOCOL_VERSION;
|
|
id: string;
|
|
state: BuildState;
|
|
/** Optional lifecycle detail; absent on older persisted builds and servers. */
|
|
phase?: BuildPhase;
|
|
createdAt: string;
|
|
startedAt?: string;
|
|
finishedAt?: string;
|
|
digest?: Sha256Digest;
|
|
error?: string;
|
|
};
|
|
|
|
export type BuildEvent =
|
|
| { type: "status"; status: BuildStatus }
|
|
| { type: "log"; id: string; sequence: number; message: string };
|
|
|
|
export function isSha256Digest(value: unknown): value is Sha256Digest {
|
|
return typeof value === "string" && /^sha256:[a-f0-9]{64}$/.test(value);
|
|
}
|
|
|
|
export function validateBuildpackUri(value: unknown): asserts value is string {
|
|
if (typeof value !== "string" || value.length > 4096 || /[\s\\]/.test(value))
|
|
throw new Error("Invalid buildpack URI");
|
|
let url: URL;
|
|
try {
|
|
url = new URL(value);
|
|
} catch {
|
|
throw new Error("Invalid buildpack URI");
|
|
}
|
|
if (
|
|
url.protocol !== "https:" ||
|
|
url.hostname !== "github.com" ||
|
|
url.port ||
|
|
url.username ||
|
|
url.password ||
|
|
url.search ||
|
|
!/^\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/releases\/download\/[^/]+\/[^/]+\.cnb$/.test(
|
|
url.pathname,
|
|
) ||
|
|
(url.hash && !/^#sha256=[a-f0-9]{64}$/.test(url.hash))
|
|
)
|
|
throw new Error(
|
|
"Buildpack URI must be an HTTPS GitHub release .cnb URL (optional #sha256=<hex>)",
|
|
);
|
|
}
|
|
|
|
export function assertSha256Digest(
|
|
value: unknown,
|
|
): asserts value is Sha256Digest {
|
|
if (!isSha256Digest(value))
|
|
throw new Error(`Invalid SHA-256 digest: ${value}`);
|
|
}
|