UNPKG

buildahcker

Version:

Buildahcker is a node.js library to create and run commands in OCI (Open Container Initiative) container images (or docker images), based on Buildah and a hash-based cache. It also contains utilities to easily create a partitioned bootable disk image of a

1,909 lines (1,900 loc) 66.9 kB
import { mkdir as U, readlink as Qt, open as Xt, writeFile as A, readFile as x, readdir as j, rmdir as _e, constants as M, lstat as rt, rm as H, lchown as Yt, chmod as yt, symlink as ke, mkdtemp as Se, stat as Q, truncate as $t, cp as _t, copyFile as Re } from "fs/promises"; import { homedir as kt } from "os"; import { join as v, normalize as gt, sep as N, isAbsolute as Ie, basename as Be, dirname as Y, posix as Ce, resolve as G, relative as St } from "path"; import { createHash as k, randomUUID as bt } from "crypto"; import { read as Fe, open as xe, close as Te, createWriteStream as te, createReadStream as Rt } from "fs"; import { promisify as Ae } from "util"; import { spawn as Ue } from "child_process"; import { Writable as Oe } from "stream"; import { pipeline as It } from "stream/promises"; const V = (e, t) => { const a = async (i) => { let s = [...e]; s = await t?.beforeRun?.(i, s) ?? s, await i.run(s, [ ...t?.buildahArgs ?? [], ...t?.buildahArgsNoHash ?? [] ]); }; return a.getCacheKey = async () => { const i = k("sha256"); return i.update(JSON.stringify(e)), i.update(JSON.stringify(t?.buildahArgs ?? [])), i.update(JSON.stringify(t?.extraHashData ?? [])), `RUN-${i.digest("base64url")}`; }, a; }, Le = (e, { apkCache: t } = {}) => { const a = {}; return t && (a.buildahArgsNoHash = [ "--volume", `${t}:/etc/apk/cache:rw` ], a.extraHashData = ["--volume", ":/etc/apk/cache:rw"], a.beforeRun = async () => { await U(t, { recursive: !0 }); }), V(["apk", "add", ...e], a); }; let ut; const za = () => (ut || (ut = v(kt(), ".buildahcker", "cache", "apk")), ut), ee = async (e, t, a = !1) => { const i = Be(t); if (i === "." || i === ".." || i === "") throw new Error(`Invalid path: ${t}`); return v( await Bt(e, Y(t), a), i ); }, Bt = async (e, t, a = !1) => { const i = /* @__PURE__ */ new Set(), s = gt(t).split(N); for (let n = 0; n < s.length; n++) { const r = s[n]; if (!r || r === "." || n < 1 && r === ".." && !a) { s.splice(n, 1), n--; continue; } else if (r === "..") { if (n < 1) throw new Error(`Invalid path: ${t}`); s.splice(n - 1, 2), n -= 2; continue; } const o = v(e, ...s.slice(0, n + 1)); if (i.has(o)) throw new Error(`Recursive link in path: ${o}`); i.add(o); try { const c = await Qt(o, "utf8"), u = gt(c).split(N); Ie(c) ? (s.splice(0, n + 1, ...u), n = -1) : (s.splice(n, 1, ...u), n--); } catch { } } return v(e, ...s); }, Lt = () => ({ directories: [], files: [] }); class Pe { #t = Lt(); #e = "."; packagesMap = /* @__PURE__ */ new Map(); addLine(t) { if (t.length === 0) { this.#t = Lt(), this.#e = "."; return; } if (t[1] != ":") throw new Error("Unexpected line syntax!"); const a = t[0], i = t.substring(2); switch (a) { case "P": { this.#t.packageName = i, this.packagesMap.set(i, this.#t); break; } case "F": { this.#e = i, this.#t.directories.push(i); break; } case "R": { const s = Ce.join(this.#e, i); this.#t.files.push(s); break; } } } } const Ke = async (e) => { const t = await Bt( e, "lib/apk/db/installed" ), a = await Xt(t); try { const i = new Pe(); for await (const s of a.readLines()) i.addLine(s); return i; } finally { await a.close(); } }, ae = async (e) => { try { (await j(e)).length === 0 && await _e(e); } catch (t) { if (t.code !== "ENOENT") throw t; } }, He = async (e, t) => { try { return await x(e); } catch (a) { if (a.code === "ENOENT") { const i = await t(); return await U(Y(e), { recursive: !0 }), await A(e, i), i; } throw a; } }, Ne = async (e, t, a) => (await He( e, async () => Buffer.from(await t(), a) )).toString(a), I = async (e) => (e = G(e), await U(Y(e), { recursive: !0 }), await A(e, ""), e), ie = async (e, t) => typeof e == "number" ? e : await new Promise( (a, i) => xe( e, t, (s, n) => s ? i(s) : a(n) ) ), se = async (e, t) => typeof t == "number" ? void 0 : new Promise((a) => Te(e, a)), De = Ae(Fe), ze = async (e, t, a) => { const { buffer: i, bytesRead: s } = await De(e, { buffer: Buffer.alloc(a), position: t }); if (s !== a) throw new Error(`Could not read ${s} bytes from file`); return i; }, ne = (e) => { const t = gt(e).split(N); if (t[t.length - 1] === "" && t.pop(), (t[0] === "." || t[0] === "") && t.shift(), t.length === 0 || t[0] === "..") throw new Error(`Unsafe path: ${e}`); return t.join(N); }, Me = ([e, t]) => [ne(e), t], Ge = (e, t) => e < t ? -1 : e > t ? 1 : 0, Je = ([e], [t]) => Ge(e, t), Ct = (e) => new Map(Object.entries(e).map(Me).sort(Je)), re = async (e) => { const t = k("sha256"); for (const [a, i] of e) { const s = await i.getHash(); t.update(`${a.length},${s.length},`), t.update(a), t.update(s); } return t.digest(); }, Ve = (e) => (e & M.S_IFMT) === M.S_IFLNK; class oe { async getHash() { const t = k("sha256"), a = await this.getAttributes(); t.update( `${a.mode.toString(8)},${a.uid},${a.gid}` ); const i = await this.getContentHash(); return t.update(i), t.digest(); } async writeTo(t) { try { (await rt(t)).isDirectory() || await H(t); } catch (i) { if (i.code !== "ENOENT") throw i; } await this.writeContentTo(t); const a = await this.getAttributes(); await Yt(t, a.uid, a.gid), Ve(a.mode) || await yt(t, a.mode); } } class je extends oe { #t; async getUnderlyingFile() { return this.#t || (this.#t = await this._getFile()), this.#t; } async getAttributes() { return await (await this.getUnderlyingFile()).getAttributes(); } async getContentHash() { return await (await this.getUnderlyingFile()).getContentHash(); } async writeContentTo(t) { return await (await this.getUnderlyingFile()).writeContentTo(t); } } class We extends oe { _modeAllow = 65535; _modeMandatory = 0; attributes; constructor(t) { super(), this.attributes = { uid: 0, gid: 0, mode: 420, ...t }; } async getAttributes() { return { ...this.attributes, mode: this.attributes.mode & this._modeAllow | this._modeMandatory }; } } class Ft extends We { #t; #e; async getContent() { return this.#t || (this.#t = await this._getContent()), this.#t; } async getContentHash() { return this.#e || (this.#e = await this._getContentHash()), this.#e; } } class ce extends Ft { constructor(t) { super(t), this._modeAllow = ~M.S_IFMT, this._modeMandatory = M.S_IFREG; } async _getContentHash() { const t = k("sha256"); return t.update(await this.getContent()), t.digest(); } async writeContentTo(t) { await A(t, await this.getContent()); } } class ue extends Ft { constructor(t) { super(t), this._modeAllow = 0, this._modeMandatory = M.S_IFLNK | 511; } async _getContentHash() { const t = k("sha256"); return t.update(await this.getContent()), t.digest(); } async writeContentTo(t) { await ke(await this.getContent(), t); } } class le extends Ft { constructor(t) { super({ mode: 493, ...t }), this._modeAllow = ~M.S_IFMT, this._modeMandatory = M.S_IFDIR; } async _getContent() { return Ct(await this._getDirectoryContent()); } async _getContentHash() { return await re(await this.getContent()); } async writeContentTo(t) { try { await U(t); } catch (a) { if (a.code !== "EEXIST") throw a; } for (const [a, i] of await this.getContent()) await i.writeTo(v(t, a)); } } class st extends je { constructor(t, a) { super(), this.sourceFilePath = t, this.options = a, this.sourceFilePath = G(t); } async _getFile() { const t = this.sourceFilePath, a = await rt(t), i = { uid: a.uid, gid: a.gid, mode: a.mode, ...this.options?.overrideAttributes }; if (a.isDirectory()) return new he(t, i, this.options); if (a.isFile()) return new X(t, i); if (a.isSymbolicLink()) return new qe(t, i); throw new Error(`Unsupported file type ${a.mode.toString(8)}`); } } class he extends le { constructor(t, a, i) { super(a), this.sourceFilePath = t, this.options = i, this.sourceFilePath = G(t); } async _getDirectoryContent() { const t = this.sourceFilePath, a = {}, i = await j(t); for (const s of i) a[s] = new st(v(t, s), this.options); return a; } } class X extends ce { constructor(t, a) { super(a), this.sourceFilePath = t, this.sourceFilePath = G(t); } async _getContent() { return await x(this.sourceFilePath); } } class qe extends ue { constructor(t, a) { super(a), this.sourceFilePath = t, this.sourceFilePath = G(t); } async _getContent() { return await Qt(this.sourceFilePath); } } const fe = async (e, t) => { for (const [a, i] of e) { const s = await t.resolve(a); await U(Y(s), { recursive: !0 }), await i.writeTo(s); } }, Ma = (e) => { const t = new he(e, { uid: 0, gid: 0, mode: 493 }), a = async (i) => { await fe(await t.getContent(), i); }; return a.getCacheKey = async () => `ADD-ROOT-DIRECTORY-${(await t.getContentHash()).toString("base64url")}`, a; }, de = (e) => { const t = Ct(e), a = async (i) => { await fe(t, i); }; return a.getCacheKey = async () => `ADD-FILES-${(await re(t)).toString("base64url")}`, a; }, we = (e) => { e = e.map(ne).sort(); const t = async (a) => { const i = await a.mount(); for (const s of e) { const n = await ee( i, s ); await H(n, { force: !0, recursive: !0 }); } }; return t.getCacheKey = async () => { const a = k("sha256"); return a.update(JSON.stringify(e)), `RM-FILES-${a.digest("base64url")}`; }, t; }, Ze = (e, t) => { e = e.sort(); const a = async (i) => { const s = await i.mount(), n = await Ke(s), r = [], o = []; for (const c of e) { const u = n.packagesMap.get(c); if (!u) { t?.write(`Package not installed: ${c} `); continue; } r.push(...u.files), o.push(...u.directories); } for (const c of r) { const u = await i.resolveParent(c); t?.write(`rm ${c} `), await H(u, { force: !0 }); } o.sort().reverse(); for (const c of o) { const u = await i.resolveParent(c); await ae(u); } }; return a.getCacheKey = async () => { const i = k("sha256"); return i.update(JSON.stringify(e)), `APK-REMOVE-${i.digest("base64url")}`; }, a; }, Ga = (e = [], t) => [ Ze(["apk-tools", ...e], t), we([ "var/lib/apk", "lib/apk", "etc/apk", "usr/share/apk", "var/cache/apk" ]) ]; class Pt extends Oe { #t = []; promise; constructor() { super(), this.promise = new Promise((t) => { this._final = t; }).then(() => { const t = Buffer.concat(this.#t); return this.#t = [], t; }); } _write(t, a, i) { this.#t.push( Buffer.isBuffer(t) ? t : Buffer.from(t, a) ), i(); } } class Qe extends Error { constructor(t, a, i, s) { super( `Command failed: ${t.join(" ")} ${i?.toString("utf8") ?? ""} ${s?.toString("utf8") ?? ""}` ), this.command = t, this.exitCode = a, this.stdout = i, this.stderr = s; } } const P = async (e, { logger: t } = {}, a = {}) => { const i = Ue(e[0], e.slice(1), { ...a, stdio: "pipe" }); t?.write(`[${i.pid}]$ ${e.join(" ")} `), t && (i.stdout.pipe(t, { end: !1 }), i.stderr.pipe(t, { end: !1 })); const s = new Pt(); i.stdout.pipe(s); const n = new Pt(); i.stderr.pipe(n), await new Promise((c) => i.on("exit", c)), t?.write(`[${i.pid}] Exit code: ${i.exitCode} `); const r = await s.promise, o = await n.promise; if (i.exitCode !== 0) throw new Qe(e, i.exitCode, r, o); return { stdout: r, stderr: o }; }; class ot { constructor(t, a) { this.options = a, this.#t = t; } #t = null; #e = null; static async from(t, a) { const s = (await P(["buildah", "from", t], a)).stdout.toString("utf8").trim() || null; if (!s) throw new Error(`Failed to create a container from ${t}.`); return new ot(s, a); } get name() { const t = this.#t; if (!t) throw new Error("The container has been destroyed!"); return t; } get mountPath() { const t = this.#e; if (!t) throw new Error("The container is not mounted!"); return t; } async mount() { let t = this.#e; if (!t) { const a = this.name; if (t = (await P(["buildah", "mount", a], this.options)).stdout.toString("utf8").trim() || null, !t) throw new Error(`Could not mount container ${a}`); this.#e = t; } return t; } toPathInContainer(t) { const a = St(this.mountPath, t).split(N); if (a[0] === "..") throw new Error("Path is not in container"); return a.unshift(""), a.join(N); } async tempFolder() { const t = await this.resolve("tmp"), a = await Se(v(t, "buildahcker-")); return { pathInHost: a, pathInContainer: this.toPathInContainer(a), remove: async () => { await H(a, { recursive: !0, force: !0 }); } }; } async resolve(t, a) { return await this.mount(), await Bt(this.mountPath, t, a); } async resolveParent(t, a) { return await this.mount(), await ee( this.mountPath, t, a ); } async remove() { const t = this.#t; t && (this.#t = null, this.#e = null, await P(["buildah", "rm", t], this.options)); } async run(t, a = []) { return await P( ["buildah", "run", ...a, "--", this.name, ...t], this.options ); } async commit({ timestamp: t } = {}) { return (await P( [ "buildah", "commit", ...t != null ? ["--timestamp", `${Math.round(t / 1e3)}`] : [], this.name ], this.options )).stdout.toString("utf8").trim(); } async executeStep(t) { if (Array.isArray(t)) for (const a of t) await this.executeStep(a); else await t(this); } } const pe = async (e, t, a) => { const i = await ot.from(e, a); try { return await t(i); } finally { await i.remove(); } }, W = async (e, t, a) => typeof e == "string" ? await pe(e, t, a) : await t(e), Xe = async ({ source: e, command: t, buildahRunOptions: a, ...i }) => await W( e, async (s) => await s.run(t, a), i ), Ja = async (e, t, a) => { const i = await P( ["buildah", "inspect", ...t ? ["--type", t] : [], "--", e], a ); return JSON.parse(i.stdout.toString("utf8")); }, Kt = async (e, t) => (await P( [ "buildah", "inspect", "--format", "{{.FromImageID}}", "--type", "image", "--", e ], t )).stdout.toString("utf8").trim(); class T { constructor(t, a) { this.options = a, this.#t = t; } #t; static async from(t, a) { const i = t === "scratch" ? t : await Kt(t, a); if (!i) throw new Error(`Could not get information about image ${t}`); return new T(i, a); } clone() { return new T(this.#t, this.options); } get imageId() { return this.#t; } async tag(t, a = {}) { await P(["buildah", "tag", this.#t, t], a); } async #e(t, a) { return await pe( a ?? this.#t, async (i) => { await i.executeStep(t); const s = await i.commit(this.options?.commitOptions); return a && (this.#t = s), s; }, this.options ); } async executeStep(t) { const a = this.options?.containerCache; if (!a) { await this.#e(t); return; } if (Array.isArray(t)) { for (const r of t) await this.executeStep(r); return; } const i = this.#t; let s; const n = await t.getCacheKey?.(); if (n && (s = await a.getEntry(i, n), s)) try { s = await Kt(s, this.options); } catch { s = void 0; } s || (s = await this.#e(t, i), n && await a.setEntry(i, n, s)), this.#t = s; } } const J = async ({ baseImage: e = "alpine", apkPackages: t, commitOptions: a, logger: i, apkCache: s, containerCache: n }) => { const r = await T.from(e, { containerCache: n, commitOptions: a, logger: i }); return await r.executeStep(Le(t, { apkCache: s })), r.imageId; }, q = async ({ existingSource: e, command: t, buildahRunOptions: a, ...i }) => await Xe({ source: e ?? await J(i), command: t, buildahRunOptions: a, logger: i.logger }); var lt = {}; var Ht; function Ye() { return Ht || (Ht = 1, (function(e) { (function(t) { t(typeof DO_NOT_EXPORT_CRC > "u" ? e : {}); })(function(t) { t.version = "1.2.2"; function a() { for (var l = 0, S = new Array(256), h = 0; h != 256; ++h) l = h, l = l & 1 ? -306674912 ^ l >>> 1 : l >>> 1, l = l & 1 ? -306674912 ^ l >>> 1 : l >>> 1, l = l & 1 ? -306674912 ^ l >>> 1 : l >>> 1, l = l & 1 ? -306674912 ^ l >>> 1 : l >>> 1, l = l & 1 ? -306674912 ^ l >>> 1 : l >>> 1, l = l & 1 ? -306674912 ^ l >>> 1 : l >>> 1, l = l & 1 ? -306674912 ^ l >>> 1 : l >>> 1, l = l & 1 ? -306674912 ^ l >>> 1 : l >>> 1, S[h] = l; return typeof Int32Array < "u" ? new Int32Array(S) : S; } var i = a(); function s(l) { var S = 0, h = 0, g = 0, E = typeof Int32Array < "u" ? new Int32Array(4096) : new Array(4096); for (g = 0; g != 256; ++g) E[g] = l[g]; for (g = 0; g != 256; ++g) for (h = l[g], S = 256 + g; S < 4096; S += 256) h = E[S] = h >>> 8 ^ l[h & 255]; var _ = []; for (g = 1; g != 16; ++g) _[g - 1] = typeof Int32Array < "u" ? E.subarray(g * 256, g * 256 + 256) : E.slice(g * 256, g * 256 + 256); return _; } var n = s(i), r = n[0], o = n[1], c = n[2], u = n[3], d = n[4], f = n[5], p = n[6], m = n[7], b = n[8], y = n[9], w = n[10], $ = n[11], C = n[12], F = n[13], B = n[14]; function R(l, S) { for (var h = S ^ -1, g = 0, E = l.length; g < E; ) h = h >>> 8 ^ i[(h ^ l.charCodeAt(g++)) & 255]; return ~h; } function tt(l, S) { for (var h = S ^ -1, g = l.length - 15, E = 0; E < g; ) h = B[l[E++] ^ h & 255] ^ F[l[E++] ^ h >> 8 & 255] ^ C[l[E++] ^ h >> 16 & 255] ^ $[l[E++] ^ h >>> 24] ^ w[l[E++]] ^ y[l[E++]] ^ b[l[E++]] ^ m[l[E++]] ^ p[l[E++]] ^ f[l[E++]] ^ d[l[E++]] ^ u[l[E++]] ^ c[l[E++]] ^ o[l[E++]] ^ r[l[E++]] ^ i[l[E++]]; for (g += 15; E < g; ) h = h >>> 8 ^ i[(h ^ l[E++]) & 255]; return ~h; } function et(l, S) { for (var h = S ^ -1, g = 0, E = l.length, _ = 0, O = 0; g < E; ) _ = l.charCodeAt(g++), _ < 128 ? h = h >>> 8 ^ i[(h ^ _) & 255] : _ < 2048 ? (h = h >>> 8 ^ i[(h ^ (192 | _ >> 6 & 31)) & 255], h = h >>> 8 ^ i[(h ^ (128 | _ & 63)) & 255]) : _ >= 55296 && _ < 57344 ? (_ = (_ & 1023) + 64, O = l.charCodeAt(g++) & 1023, h = h >>> 8 ^ i[(h ^ (240 | _ >> 8 & 7)) & 255], h = h >>> 8 ^ i[(h ^ (128 | _ >> 2 & 63)) & 255], h = h >>> 8 ^ i[(h ^ (128 | O >> 6 & 15 | (_ & 3) << 4)) & 255], h = h >>> 8 ^ i[(h ^ (128 | O & 63)) & 255]) : (h = h >>> 8 ^ i[(h ^ (224 | _ >> 12 & 15)) & 255], h = h >>> 8 ^ i[(h ^ (128 | _ >> 6 & 63)) & 255], h = h >>> 8 ^ i[(h ^ (128 | _ & 63)) & 255]); return ~h; } t.table = i, t.bstr = R, t.buf = tt, t.str = et; }); })(lt)), lt; } var ht = Ye(); const xt = async (e) => { const t = e.outputFile, a = await ie(t, "r+"); try { for (const i of e.partitions) { const s = te("", { fd: a, start: i.output.offset, autoClose: !1 }); if ("inputFile" in i) { const n = i.input?.offset ?? 0, r = i.input?.size ?? (await Q(i.inputFile)).size - n; if (r > i.output.size) throw new Error( `Partition too small for content: ${r} > ${i.output.size}` ); const o = Rt(i.inputFile, { start: n, end: n + r, autoClose: !1 }); try { await It(o, s); } finally { await o.close(); } } else { if (i.inputBuffer.length > i.output.size) throw new Error( `Partition too small for content: ${i.inputBuffer.length} > ${i.output.size}` ); await new Promise( (n, r) => s.write( i.inputBuffer, (o) => o ? r(o) : n() ) ); } } } finally { await se(a, t); } }; var z = /* @__PURE__ */ ((e) => (e.EfiSystem = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", e.BiosBoot = "21686148-6449-6E6F-744E-656564454649", e.LinuxData = "0FC63DAF-8483-4772-8E79-3D69D8477DE4", e))(z || {}); const ft = (e, t, a) => { const i = Buffer.from(e.replaceAll("-", ""), "hex"); if (i.length != 16) throw new Error(`Invalid GUID: ${e}`); i.copy(t, a); }, ta = async (e) => { const t = [], n = Math.ceil( 34 ), r = Buffer.alloc(16384); let o = n, c = 0; for (const C of e.partitions) { const F = o, B = Math.ceil(C.size / 512 / 2048) * 2048; o += B, t.push({ offset: F * 512, size: B * 512 }); const R = Buffer.alloc(128); ft(C.type, R, 0), ft(C.guid ?? bt(), R, 16), R.writeBigInt64LE(BigInt(F), 32), R.writeBigInt64LE(BigInt(F + B - 1), 40), R.write(C.name, 56, 72, "utf-16le"), R.copy(r, c * 128), c++; } o += n; const u = await I(e.outputFile); await $t(u, o * 512); const d = [], f = Buffer.alloc(512); f.write("000200", 447, "hex"), f.writeUInt8(238, 450), f.write("FFFFFF", 447, "hex"), f.writeUint32LE(1, 454), f.writeUint32LE(Math.min(4294967295, o - 1), 458), f.writeUint8(85, 510), f.writeUint8(170, 511); const p = 1, m = o - 1, b = 2, y = o - n, w = Buffer.alloc(512); w.write("EFI PART", 0, "ascii"), w.write("00000100", 8, "hex"), w.writeUInt32LE(92, 12), w.writeBigUInt64LE(BigInt(p), 24), w.writeBigUInt64LE(BigInt(m), 32), w.writeBigUInt64LE(BigInt(n), 40), w.writeBigUInt64LE( BigInt(y - 1), 48 ), ft(e.guid ?? bt(), w, 56), w.writeBigUInt64LE(BigInt(b), 72), w.writeUInt32LE(128, 80), w.writeUInt32LE(128, 84), w.writeInt32LE(ht.buf(r), 88), w.writeInt32LE( ht.buf(w.subarray(0, 92)), 16 ); const $ = Buffer.from(w); return $.writeBigUInt64LE(BigInt(m), 24), $.writeBigUInt64LE(BigInt(p), 32), $.writeBigUInt64LE( BigInt(y), 72 ), $.writeUint32LE(0, 16), $.writeInt32LE( ht.buf($.subarray(0, 92)), 16 ), d.push( { inputBuffer: f, output: { offset: 0, size: f.length } }, { inputBuffer: w, output: { offset: p * 512, size: w.length } }, { inputBuffer: r, output: { offset: b * 512, size: r.length } }, { inputBuffer: r, output: { offset: y * 512, size: r.length } }, { inputBuffer: $, output: { offset: m * 512, size: $.length } } ), await xt({ outputFile: u, partitions: d }), t; }, K = 512, Et = 9, Nt = 3, ea = 90, aa = 92, Dt = 440, ia = 510, zt = 102, me = 12, nt = K - me, dt = nt - me, sa = 2048, Mt = (e, t, a) => e.writeBigUint64LE(a, t), Gt = (e, t, a) => e.writeUint16LE(a, t + 8), Jt = (e, t, a) => e.writeUint16LE(a, t + 10), ye = (e, t) => { const a = e.length % K; a !== 0 && (e = Buffer.concat([ e, Buffer.alloc(K - a) ])); const i = BigInt(t >> Et); return Mt(e, nt, i + 1n), Gt( e, nt, (e.length >> Et) - 1 ), Jt( e, nt, sa + (K >> 4) ), Mt(e, dt, 0n), Gt(e, dt, 0), Jt(e, dt, 0), e; }, ge = (e, t, a) => { if (e.length !== K) throw new Error( `The boot file should have a size of ${K} bytes.` ); a?.copy( e, Nt, Nt, ea ), a?.copy( e, Dt, Dt, ia ); const i = BigInt(t >> Et); return e.writeBigUint64LE(i, aa), e.writeUInt8(144, zt), e.writeUInt8(144, zt + 1), e; }, na = async (e) => { const t = e.imageFile, a = await ie(t, "r+"); try { const i = await ze(a, 0, K), s = await x(e.bootFile), n = await x(e.coreFile); await xt({ outputFile: a, partitions: [ { inputBuffer: ge( s, e.partition.offset, i ), output: { offset: 0, size: K } }, { inputBuffer: ye(n, e.partition.offset), output: e.partition } ] }); } finally { await se(a, t); } }, ra = async (e) => { const t = await x(e.bootFile ?? e.outputBootFile), a = e.existingBootSectorFile ? await x(e.existingBootSectorFile) : void 0; await A( await I(e.outputBootFile), ge(t, e.diskOffset, a) ); }, oa = async (e) => { const t = await x(e.coreFile ?? e.outputCoreFile); await A( await I(e.outputCoreFile), ye(t, e.diskOffset) ); }, ca = async ({ outputCoreFile: e, outputBootFile: t, biosSetupDiskOffset: a, modules: i, prefix: s, config: n, pubkey: r, memdisk: o, disableCli: c, disableShimLock: u, target: d, grubSource: f, containerCache: p, apkCache: m, logger: b }) => { e = await I(e), f || (f = await J({ apkPackages: ["grub", "grub-bios", "grub-efi"], containerCache: p, apkCache: m, logger: b })), await W( f, async (y) => { const w = await y.tempFolder(); try { n && await A(v(w.pathInHost, "config.cfg"), n), await y.run( [ "grub-mkimage", "-O", d ?? "x86_64-efi", "-o", "core.img", ...n ? ["-c", "config.cfg"] : [], ...o ? ["-m", "memdisk.img"] : [], ...r ? ["-k", "pubkey.key"] : [], ...c ? ["--disable-cli"] : [], ...u ? ["--disable-shim-lock"] : [], ...s ? ["-p", s] : [], "--", ...i ?? [] ], [ "--workingdir", w.pathInContainer, "-v", `${e}:${w.pathInContainer}/core.img:rw`, ...o ? [ "-v", `${o}:${w.pathInContainer}/memdisk.img:ro` ] : [], ...r ? ["-v", `${r}:${w.pathInContainer}/pubkey.key:ro`] : [] ] ), t && (t = await I(t), await _t( await y.resolve(`usr/lib/grub/${d}/boot.img`), t )), a && (await oa({ diskOffset: a, outputCoreFile: e }), t && await ra({ diskOffset: a, outputBootFile: t })); } finally { await w.remove(); } }, { logger: b } ); }, be = ({ outputCoreFile: e, outputBootFile: t, biosSetupDiskOffset: a, modules: i, prefix: s, config: n, memdisk: r, pubkey: o, disableCli: c, disableShimLock: u, target: d, ...f }) => { const p = async (m) => { const b = await m.resolve(e), y = t ? await m.resolve(t) : void 0, w = r ? await m.resolve(r) : void 0, $ = o ? await m.resolve(o) : void 0; await ca({ outputCoreFile: b, outputBootFile: y, biosSetupDiskOffset: a, modules: i, prefix: s, config: n, memdisk: w, pubkey: $, disableCli: c, disableShimLock: u, target: d, ...f }); }; return p.getCacheKey = async () => { const m = k("sha256"); return m.update( JSON.stringify({ outputCoreFile: e, outputBootFile: t, biosSetupDiskOffset: a, modules: i, prefix: s, config: n, memdisk: r, pubkey: o, disableCli: c, disableShimLock: u, target: d }) ), `GRUB-MKIMAGE-${m.digest("base64url")}`; }, p; }, ua = async ({ outputFile: e, variables: t, grubSource: a, containerCache: i, apkCache: s, logger: n }) => { e = await I(e), a || (a = await J({ apkPackages: ["grub", "grub-bios", "grub-efi"], containerCache: i, apkCache: s, logger: n })), await W( a, async (r) => { const o = await r.tempFolder(), c = ["--workingdir", o.pathInContainer]; try { await r.run( ["grub-editenv", "grubenv", "create"], c ), t && t.length > 0 && await r.run( ["grub-editenv", "grubenv", "set", ...t], c ), await _t(v(o.pathInHost, "grubenv"), e); } finally { await o.remove(); } }, { logger: n } ); }, la = ({ outputFile: e, variables: t, ...a }) => { const i = async (s) => { const n = await s.resolve(e); await ua({ outputFile: n, variables: t, ...a }); }; return i.getCacheKey = async () => { const s = k("sha256"); return s.update( JSON.stringify({ outputFile: e, variables: t }) ), `GRUB-MKENV-${s.digest("base64url")}`; }, i; }, Vt = async (e) => (await Q(e)).size, jt = async (e, t) => { const a = Rt(e), i = te(t, { flags: "a" }); await It(a, i); }, Ee = async ({ file: e, metadataFile: t = `${e}.json`, salt: a = "", uuid: i = "00000000-0000-0000-0000-000000000000", cryptsetupSource: s, containerCache: n, apkCache: r, logger: o }) => { s || (s = await J({ apkPackages: ["cryptsetup"], containerCache: n, apkCache: r, logger: o })), await W( s, async (c) => { const d = (await c.run( [ "veritysetup", "format", "/image", "/image.hash", "--fec-device=/image.fec", `--salt=${a}`, `--uuid=${i}` ], ["-v", `${e}:/image:rw`] )).stdout.toString("utf8"), [, f] = /Root hash:\s*([0-9a-f]{64})/.exec(d), p = await Vt(e), m = await c.resolve("/image.hash"); await jt(m, e); const b = await Vt(e), y = await c.resolve("/image.fec"); await jt(y, e), await H(m), await H(y); let w = {}; try { w = JSON.parse(await x(t, "utf8")); } catch { } const $ = { ...w, rootHash: f, hashOffset: p, fecOffset: b }; await A(t, JSON.stringify($)); }, { logger: o } ); }, ha = async ({ inputFolder: e, squashfsToolsSource: t, outputFile: a, timestamp: i = 0, veritySetup: s, containerCache: n, apkCache: r, logger: o }) => { a = await I(a); const c = St(e, a), u = []; c.startsWith(`..${N}`) || u.push("-e", c), await q({ apkPackages: ["squashfs-tools"], existingSource: t, command: [ "mksquashfs", "/in", "/out", "-noappend", "-no-xattrs", "-mkfs-time", `${i}`, "-all-time", `${i}`, ...u ], buildahRunOptions: [ "-v", `${e}:/in:ro`, "-v", `${a}:/out:rw` ], containerCache: n, apkCache: r, logger: o }), s && await Ee({ file: a, ...s }); }, ve = ({ inputFolder: e, outputFile: t, ...a }) => { const i = async (s) => { const n = await s.resolve(e), r = await s.resolve(t); await ha({ inputFolder: n, outputFile: r, ...a }); }; return i.getCacheKey = async () => { const s = k("sha256"); return s.update( JSON.stringify({ inputFolder: e, outputFile: t, timestamp: a.timestamp ?? void 0, veritySetup: a?.veritySetup ? { salt: a.veritySetup.salt ?? void 0, uuid: a.veritySetup.uuid ?? void 0 } : void 0 }) ), `MKSQUASHFS-${s.digest("base64url")}`; }, i; }, fa = async ({ inputFolder: e, mtoolsSource: t, outputFileSize: a, outputFile: i, containerCache: s, apkCache: n, logger: r }) => { t || (t = await J({ apkPackages: ["mtools"], containerCache: s, apkCache: n, logger: r })), i = await I(i), await $t(i, a), await W( t, async (o) => { await o.run( ["mformat", "-i", "/out", "-F", "::"], ["-v", `${i}:/out:rw`] ); const c = await j(e); c.length > 0 && await o.run( [ "mcopy", "-i", "/out", "-s", "-b", "-p", ...c.map((u) => `./${u}`), "::/" ], [ "-v", `${e}:/in:ro`, "-v", `${i}:/out:rw`, "--workingdir", "/in" ] ); }, { logger: r } ); }, da = ({ inputFolder: e, outputFile: t, ...a }) => { const i = async (s) => { const n = await s.resolve(e), r = await s.resolve(t); await fa({ inputFolder: n, outputFile: r, ...a }); }; return i.getCacheKey = async () => { const s = k("sha256"); return s.update( JSON.stringify({ inputFolder: e, outputFile: t, outputFileSize: a.outputFileSize }) ), `MKVFATFS-${s.digest("base64url")}`; }, i; }; class wa extends le { content; constructor({ content: t = {}, ...a } = {}) { super(a), this.content = t; } async _getDirectoryContent() { return this.content; } } class vt extends ce { content; constructor({ content: t = "", ...a } = {}) { super(a), this.content = t; } async _getContent() { const t = this.content; return Buffer.isBuffer(t) ? t : Buffer.from(t, "utf8"); } } class Va extends ue { content; constructor({ content: t, ...a }) { super(a), this.content = t; } async _getContent() { return this.content; } } const ja = (e) => { const t = Ct(e), a = async (i) => { for (const [ s, { recursive: n, mode: r, dmode: o = r, uid: c, gid: u } ] of t) { const d = [await i.resolve(s)]; for (; d.length > 0; ) { const f = d.shift(), p = await rt(f); if (p.isDirectory() && (o != null && await yt(f, o), n)) { const b = await j(f); d.push(...b.map((y) => v(f, y))); } const m = p.isDirectory() ? o : r; m != null && !p.isSymbolicLink() && await yt(f, m), (c != null || u != null) && await Yt(f, c ?? p.uid, u ?? p.gid); } } }; return a.getCacheKey = async () => { const i = k("sha256"); return i.update(JSON.stringify(e)), `SETATTRIBUTES-${i.digest("base64url")}`; }, a; }, pa = ["ed25519"], Wa = async ({ outputFolder: e, opensshSource: t, types: a = pa, prefix: i = "ssh_host_", suffix: s = "_key", containerCache: n, apkCache: r, logger: o }) => { const c = {}; e = G(e), await U(e, { recursive: !0 }); let u = !1; const d = await Promise.all( a.map(async (f) => { const p = `${i}${f}${s}`, m = `${p}.pub`; let b = !1; const y = v(e, m), w = v(e, p); c[p] = new X(w, { mode: 384 }), c[m] = new X(y, { mode: 384 }); try { const [$, C] = await Promise.all([ Q(y), Q(w) ]); if (!$.isFile() || !C.isFile()) throw new Error( `${p}.pub or ${p} exists in ${e} and is not a regular file.` ); b = !0; } catch ($) { if ($.code != "ENOENT") throw $; u = !0; } return { alreadyPresent: b, keyFile: p, type: f }; }) ); return u && await W( t ?? await J({ apkPackages: ["openssh"], containerCache: n, apkCache: r, logger: o }), async (f) => { const p = await f.tempFolder(); try { for (const { alreadyPresent: m, type: b, keyFile: y } of d) m || await f.run( ["ssh-keygen", "-t", b, "-f", y, "-N", ""], [ "-v", `${e}:${p.pathInContainer}`, "--workingdir", p.pathInContainer ] ); } finally { await p.remove(); } }, { logger: o } ), c; }, $e = async (e, t) => { const a = /* @__PURE__ */ new Map(); try { return await e(async (i) => { if (typeof i != "string") { let s = a.get(i.imageId); s || (s = await ot.from(i.imageId, t), a.set(i.imageId, s)), i = await s.resolve(i.file); } return i; }); } finally { for (const i of a.values()) await i.remove(); } }, qa = async (e, t) => { t = await I(t), await $e(async (a) => { await _t(await a(e), t); }); }, ma = 33 * 1024 * 1024, ya = async ({ grubDiskDevice: e = "hd0", grubEnvPartitionIndex: t, grubEnvPath: a = "/grubenv", grubExtraConfig: i = "", grubSourceImage: s, grubSourcePath: n = "/usr/lib/grub", grubTimeout: r = 3, linuxDiskDevice: o = "/dev/sda", rootPartitionAIndex: c, rootPartitionBIndex: u, rootPartitionGrubCfg: d = "/boot/grub.cfg", squashfsToolsSource: f, apkCache: p, containerCache: m, logger: b }) => { const y = await T.from(s, { containerCache: m, logger: b }); return await y.executeStep([ de({ [v(n, "grub.cfg")]: new vt({ content: ` insmod all_video set envfile=(${e},gpt${t})/${a} load_env --file $envfile buildahcker_stable buildahcker_new if [ ( $buildahcker_new == b ) -o ( ( $buildahcker_new != a ) -a ( $buildahcker_stable == b ) ) ] ; then set default=b set fallback=a else set default=a set fallback=b fi if [ $buildahcker_new != n ] ; then set buildahcker_new=n save_env --file $envfile buildahcker_stable buildahcker_new fi export buildahcker_params set timeout=${r} ${i} menuentry A --id=a { set root=(${e},gpt${c}) set buildahcker_params="buildahcker_current=a buildahcker_grubenv_device=${o}${t} buildahcker_grubenv=${a} buildahcker_other_root=${o}${u} root=${o}${c}" configfile ${d} } menuentry B --id=b { set root=(${e},gpt${u}) set buildahcker_params="buildahcker_current=b buildahcker_grubenv_device=${o}${t} buildahcker_grubenv=${a} buildahcker_other_root=${o}${c} root=${o}${u}" configfile ${d} } ` }) }), ve({ inputFolder: n, outputFile: "/buildahcker.img", squashfsToolsSource: f, apkCache: p, containerCache: m, logger: b }) ]), { imageId: y.imageId, file: "buildahcker.img" }; }, Za = async ({ grubSourceImage: e, containerCache: t, logger: a }) => { const i = await T.from(e, { containerCache: t, logger: a }); return await i.executeStep([ V(["grub-editenv", "/buildahcker.img", "create"]), V([ "grub-editenv", "/buildahcker.img", "set", "buildahcker_stable=a", "buildahcker_new=n" ]) ]), { imageId: i.imageId, file: "buildahcker.img" }; }, ga = async ({ efiPartitionSize: e, grubDiskDevice: t = "hd0", grubEnvPath: a = "/grubenv", grubPartitionIndex: i, grubSourceImage: s, mtoolsSource: n, useEfi: r, containerCache: o, apkCache: c, logger: u }) => { const d = await T.from( "scratch", // TODO: allow passing this as a parameter? { containerCache: o, logger: u } ); return await d.executeStep([ la({ grubSource: s, outputFile: v("efi", a), variables: ["buildahcker_stable=a", "buildahcker_new=n"], containerCache: o, apkCache: c, logger: u }) ]), r && await d.executeStep( be({ outputCoreFile: "efi/EFI/boot/bootx64.efi", grubSource: s, target: "x86_64-efi", modules: ["part_gpt", "squash4"], prefix: `(${t},gpt${i})/`, containerCache: o, apkCache: c, logger: u }) ), await d.executeStep( da({ inputFolder: "efi", outputFile: "/buildahcker.img", outputFileSize: e, mtoolsSource: n, apkCache: c, containerCache: o, logger: u }) ), { imageId: d.imageId, file: "buildahcker.img" }; }, ba = async ({ grubDiskDevice: e = "hd0", grubPartitionIndex: t, grubSourceImage: a, containerCache: i, apkCache: s, logger: n }) => { const r = await T.from("scratch", { containerCache: i, logger: n }); return await r.executeStep([ be({ outputCoreFile: "buildahcker_grub_core.img", outputBootFile: "buildahcker_grub_boot.img", grubSource: a, target: "i386-pc", modules: ["biosdisk", "part_gpt", "squash4"], prefix: `(${e},gpt${t})/`, containerCache: i, apkCache: s, logger: n }) ]), { core: { imageId: r.imageId, file: "buildahcker_grub_core.img" }, boot: { imageId: r.imageId, file: "buildahcker_grub_boot.img" } }; }, Qa = async ({ biosBootPartitionSize: e, bootType: t = "both", efiPartitionSize: a, grubDiskDevice: i, grubEnvPath: s, grubExtraConfig: n, grubSourceImage: r, grubSourcePath: o, grubTimeout: c, linuxDiskDevice: u, mtoolsSource: d, rootPartition: f, rootPartitionGrubCfg: p, rootPartitionSize: m, squashfsToolsSource: b, apkCache: y, containerCache: w, logger: $ }) => { const C = t === "bios" || t === "both", F = t === "efi" || t === "both"; r || (r = await J({ apkPackages: [ ...F ? ["grub-efi"] : [], ...C ? ["grub-bios"] : [] ], apkCache: y, containerCache: w, logger: $ })); const B = {}; let R = 0; const tt = C ? ++R : -1, et = ++R, l = ++R, S = ++R, h = ++R, g = C ? await ba({ grubDiskDevice: i, grubPartitionIndex: l, grubSourceImage: r, apkCache: y, containerCache: w, logger: $ }) : void 0; g && (B[tt] = { type: z.BiosBoot, name: "biosboot", size: e, file: g.core }), a = Math.max(ma, a ?? 0), B[et] = { name: F ? "efi" : "grubenv", type: F ? z.EfiSystem : z.LinuxData, file: await ga({ efiPartitionSize: a, grubDiskDevice: i, grubEnvPath: s, grubPartitionIndex: l, grubSourceImage: r, mtoolsSource: d, useEfi: F, apkCache: y, containerCache: w, logger: $ }) }, B[l] = { name: "grub", type: z.LinuxData, file: await ya({ grubDiskDevice: i, grubEnvPartitionIndex: et, grubExtraConfig: n, grubSourceImage: r, grubSourcePath: o, grubTimeout: c, linuxDiskDevice: u, rootPartitionAIndex: S, rootPartitionBIndex: h, rootPartitionGrubCfg: p, squashfsToolsSource: b, apkCache: y, containerCache: w, logger: $ }) }, B[S] = { name: "systemA", type: z.LinuxData, size: m, file: f }, B[h] = { name: "systemB", type: z.LinuxData, size: m }; const E = await T.from("scratch", { containerCache: w, logger: $ }), _ = async (O) => await $e(async (at) => { const ct = await O.resolve("buildahcker.img"), At = []; for (let L = 1; L <= R; L++) { const D = B[L]; At.push({ name: D.name, size: D.size ?? (await Q(await at(D.file))).size, type: D.type }); } const Ut = await ta({ partitions: At, outputFile: ct }), Ot = []; for (let L = 1; L <= R; L++) { const D = B[L]; D.file && Ot.push({ inputFile: await at(D.file), output: Ut[L - 1] }); } await xt({ outputFile: ct, partitions: Ot }), g && await na({ imageFile: ct, bootFile: await at(g.boot), coreFile: await at(g.core), partition: Ut[tt - 1] }); }); return _.getCacheKey = async () => { const O = k("sha256"); return O.update(JSON.stringify(B)), `ABPARTITIONSDISK-${O.digest("base64url")}`; }, await E.executeStep(_), { imageId: E.imageId, file: "buildahcker.img" }; }, Xa = async ({ kernelCmdline: e, rootPartitionGrubCfg: t = "/boot/grub.cfg", sourceRootImage: a, sourceRootInitrdPath: i = "/boot/initramfs-lts", sourceRootKernelPath: s = "/boot/vmlinuz-lts", squashfsToolsSource: n, updateToolPath: r = "/sbin/buildahckerABTool", apkCache: o, containerCache: c, logger: u }) => { const d = await T.from(a, { containerCache: c, logger: u }); return await d.executeStep([ de({ [t]: new vt({ content: `linux ${s} $buildahcker_params${e ? ` ${e}` : ""}${i ? ` initrd ${i}` : ""} ` }), [r]: new vt({ content: `#!/bin/sh set -e function readCmdline() { cat /proc/cmdline | sed -nE 's/^.*[[:space:]]'"$1"'=([^[:space:]]*)([[:space:]]|$).*$/\\1/p' } BUILDHACKER_CURRENT="$(readCmdline buildahcker_current)" BUILDHACKER_CURRENT_ROOT="$(readCmdline root)" BUILDHACKER_OTHER_ROOT="$(readCmdline buildahcker_other_root)" BUILDHACKER_GRUBENV="$(readCmdline buildahcker_grubenv)" BUILDHACKER_GRUBENV_DEVICE="$(readCmdline buildahcker_grubenv_device)" if [ -z "$BUILDHACKER_CURRENT" ] || [ -z "$BUILDHACKER_OTHER_ROOT" ] || [ -z "$BUILDHACKER_GRUBENV" ] || [ -z "$BUILDHACKER_GRUBENV_DEVICE" ] ; then echo Not running in expected buildahcker A/B partition environment. exit 1 fi case "$BUILDHACKER_CURRENT" in 'a') BUILDHACKER_OTHER=b ;; 'b') BUILDHACKER_OTHER=a ;; *) echo Invalid buildahcker_current value: $BUILDHACKER_CURRENT exit 1 ;; esac mkdir -p /run/buildahcker-ab-grubenv if ! mountpoint /run/buildahcker-ab-grubenv &> /dev/null ; then mount -o ro -t vfat $BUILDHACKER_GRUBENV_DEVICE /run/buildahcker-ab-grubenv fi function readGrubenv() { grub-editenv "/run/buildahcker-ab-grubenv$BUILDHACKER_GRUBENV" list | sed -nE 's/(^.*[[:space:]]|^)'"$1"'=([^[:space:]]*)([[:space:]]|$).*$/\\2/p' } function updateGrubenv() { mount -o remount,rw /run/buildahcker-ab-grubenv grub-editenv "/run/buildahcker-ab-grubenv$BUILDHACKER_GRUBENV" set "$@" mount -o remount,ro /run/buildahcker-ab-grubenv } BUILDAHCKER_STABLE=$(readGrubenv buildahcker_stable) BUILDAHCKER_NEW=$(readGrubenv buildahcker_new) case "$*" in 'show' | '') echo Current: "$BUILDHACKER_CURRENT" echo Current root: "$BUILDHACKER_CURRENT_ROOT" echo Other: "$BUILDHACKER_OTHER" echo Other root: "$BUILDHACKER_OTHER_ROOT" echo Stable: "$BUILDAHCKER_STABLE" if [ "$BUILDAHCKER_STABLE" != "$BUILDHACKER_CURRENT" ] ; then echo "Warning: current system is not marked as stable!" fi if [ "$BUILDAHCKER_NEW" != "n" ] ; then echo "Warning: next reboot will be on $BUILDAHCKER_NEW" fi ;; 'update') if [ "$BUILDAHCKER_STABLE" != "$BUILDHACKER_CURRENT" ]; then echo Current system is not marked as stable! echo Updates should only be done from a stable system. echo Use mark-stable or reboot the system before updating. exit 1 fi echo "Target partition: $BUILDHACKER_OTHER_ROOT" echo "Update in progress..." dd of="$BUILDHACKER_OTHER_ROOT" echo "Finished writing on $BUILDHACKER_OTHER_ROOT" updateGrubenv buildahcker_new=$BUILDHACKER_OTHER echo Next reboot will be on "$BUILDHACKER_OTHER"! echo To cancel, use cancel-update or run update with a different update. ;; 'cancel-update') if [ "$BUILDAHCKER_NEW" != "n" ]; then updateGrubenv buildahcker_new=n echo Update cancelled, next reboot will be on "$BUILDHACKER_STABLE" else echo There is no update in progress. fi ;; 'mark-stable') if [ "$BUILDAHCKER_STABLE" != "$BUILDHACKER_CURRENT" ]; then updateGrubenv buildahcker_stable=$BUILDHACKER_CURRENT echo "Current system successfully marked as stable." else echo "Current system was already marked as stable." fi ;; 'is-stable') if [ "$BUILDAHCKER_STABLE" == "$BUILDHACKER_CURRENT" ]; then exit 0 else exit 1 fi ;; *) echo Invalid command: "$*" exit 1 ;; esac `, mode: 320 }) }), ve({ inputFolder: ".", outputFile: "/buildahcker.img", squashfsToolsSource: n, apkCache: o, containerCache: c, logger: u }) ]), { imageId: d.imageId, file: "buildahcker.img" }; }; class Tt { #t; #e; #a; constructor(t, a) { this.#t = t, this.#e = a, this.#a = new wa({ content: { cert: t, key: a } }); } async certificatePath() { return this.#t.sourceFilePath; } async privateKeyPath() { return this.#e.sourceFilePath; } async getHash() { return await this.#a.getContentHash(); } static from(t, a) { return new Tt( new X(t, { uid: 0, gid: 0, mode: 384 }), new X(a, { uid: 0, gid: 0, mode: 384 }) ); } } const Ea = async ({ inputFile: e, outputFile: t, key: a, sbsignSource: i, containerCache: s, apkCache: n, logger: r }) => { t || (t = `${e}.signed`), t = await I(t), await q({ apkPackages: ["sbsigntool"], existingSource: i, command: [ "sbsign", "--key", "/in.key", "--cert", "/in.crt", "--output", "/out.efi", "/in.efi" ], buildahRunOptions: [ "-v", `${e}:/in.efi:ro`, "-v", `${await a.certificatePath()}:/in.crt:ro`, "-v", `${await a.privateKeyPath()}:/in.key:ro`, "-v", `${t}:/out.efi:rw` ], containerCache: s, apkCache: n, logger: r }); }, va = ({ inputFile: e, outputFile: t, key: a, ...i }) => { t || (t = `${e}.signed`); const s = async (n) => { const r = e === t, o = r ? `${e}.unsigned` : e, c = await n.resolve(o), u = await n.resolve(t); r && (await Re(u, c), await $t(u)), await Ea({ inputFile: c, outputFile: u, key: a, ...i }), r && await H(c); }; return s.getCacheKey = async () => { const n = k("sha256"); return n.update( JSON.stringify({ inputFile: e, outputFile: t }) ), n.update(await a.getHash()), `SBSIGN-${n.digest("base64url")}`; }, s; }, Z = 1024, $a = Z + 12, wt = 48, Wt = 4, _a = [ 0, 4067132163, 3778769143, 324072436, 3348797215, 904991772, 648144872, 3570033899, 2329499855, 2024987596, 1809983544, 2575936315, 1296289744, 3207089363, 2893594407, 1578318884, 274646895, 3795141740, 4049975192, 51262619, 3619967088, 632279923, 922689671, 3298075524, 2592579488, 1760304291, 2075979607, 2312596564, 1562183871, 2943781820, 3156637768, 1313733451, 549293790, 3537243613, 3246849577, 871202090, 3878