xgauntlet 0.8.3 → 0.8.4
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/bin/xgauntlet.js +47 -11
- package/package.json +1 -1
package/bin/xgauntlet.js
CHANGED
|
@@ -236,6 +236,34 @@ function findLocalBinary() {
|
|
|
236
236
|
return null;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
export async function fetchAttestationBundle(repo = REPO, version = VERSION, customFetcher = null) {
|
|
240
|
+
const fetchFn = customFetcher || fetch;
|
|
241
|
+
const candidates = [
|
|
242
|
+
`https://github.com/${repo}/releases/download/v${version}/attestation.bundle`,
|
|
243
|
+
`https://github.com/${repo}/releases/download/v${version}/attestation.json`,
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
let lastStatus = 404;
|
|
247
|
+
let lastStatusText = 'Not Found';
|
|
248
|
+
|
|
249
|
+
for (const url of candidates) {
|
|
250
|
+
try {
|
|
251
|
+
const res = await fetchFn(url, { redirect: 'follow' });
|
|
252
|
+
if (res && res.ok) {
|
|
253
|
+
return await res.json();
|
|
254
|
+
}
|
|
255
|
+
if (res) {
|
|
256
|
+
lastStatus = res.status;
|
|
257
|
+
lastStatusText = res.statusText || 'Not Found';
|
|
258
|
+
}
|
|
259
|
+
} catch (err) {
|
|
260
|
+
lastStatusText = err.message;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
throw new Error(`HTTP ${lastStatus} fetching attestation bundle: ${lastStatusText}`);
|
|
265
|
+
}
|
|
266
|
+
|
|
239
267
|
async function downloadAndCacheBinary() {
|
|
240
268
|
if (process.env.XGAUNTLET_TEST_FORCE_NOT_FOUND === '1') {
|
|
241
269
|
throw new Error('Forced missing binary for test');
|
|
@@ -254,27 +282,22 @@ async function downloadAndCacheBinary() {
|
|
|
254
282
|
}
|
|
255
283
|
|
|
256
284
|
const downloadUrl = `https://github.com/${REPO}/releases/download/v${VERSION}/${archiveName}`;
|
|
257
|
-
const bundleUrl = `https://github.com/${REPO}/releases/download/v${VERSION}/attestation.bundle`;
|
|
258
285
|
process.stderr.write(`[xgauntlet] Fetching native engine v${VERSION} for ${platform}-${arch}...\n`);
|
|
259
286
|
|
|
260
|
-
|
|
261
|
-
|
|
287
|
+
let tempArchive = null;
|
|
288
|
+
let createdCacheDir = false;
|
|
262
289
|
|
|
263
290
|
try {
|
|
264
|
-
const [resArchive,
|
|
291
|
+
const [resArchive, bundleJson] = await Promise.all([
|
|
265
292
|
fetch(downloadUrl, { redirect: 'follow' }),
|
|
266
|
-
|
|
293
|
+
fetchAttestationBundle(REPO, VERSION),
|
|
267
294
|
]);
|
|
268
295
|
|
|
269
296
|
if (!resArchive.ok) {
|
|
270
297
|
throw new Error(`HTTP ${resArchive.status} fetching binary archive: ${resArchive.statusText}`);
|
|
271
298
|
}
|
|
272
|
-
if (!resBundle.ok) {
|
|
273
|
-
throw new Error(`HTTP ${resBundle.status} fetching attestation bundle: ${resBundle.statusText}`);
|
|
274
|
-
}
|
|
275
299
|
|
|
276
300
|
const archiveBuffer = Buffer.from(await resArchive.arrayBuffer());
|
|
277
|
-
const bundleJson = await resBundle.json();
|
|
278
301
|
|
|
279
302
|
process.stderr.write(`[xgauntlet] Verifying cryptographic release attestation for ${archiveName}...\n`);
|
|
280
303
|
await verifyReleaseArchive({
|
|
@@ -288,6 +311,11 @@ async function downloadAndCacheBinary() {
|
|
|
288
311
|
});
|
|
289
312
|
process.stderr.write(`[xgauntlet] Attestation verified successfully (Repo ID: ${EXPECTED_REPOSITORY_ID}).\n`);
|
|
290
313
|
|
|
314
|
+
if (!fs.existsSync(cacheDir)) {
|
|
315
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
316
|
+
createdCacheDir = true;
|
|
317
|
+
}
|
|
318
|
+
tempArchive = path.join(cacheDir, `temp-${Date.now()}-${archiveName}`);
|
|
291
319
|
fs.writeFileSync(tempArchive, archiveBuffer);
|
|
292
320
|
|
|
293
321
|
if (archiveName.endsWith('.tar.gz')) {
|
|
@@ -300,7 +328,7 @@ async function downloadAndCacheBinary() {
|
|
|
300
328
|
}
|
|
301
329
|
}
|
|
302
330
|
|
|
303
|
-
if (fs.existsSync(tempArchive)) {
|
|
331
|
+
if (tempArchive && fs.existsSync(tempArchive)) {
|
|
304
332
|
fs.unlinkSync(tempArchive);
|
|
305
333
|
}
|
|
306
334
|
|
|
@@ -315,9 +343,17 @@ async function downloadAndCacheBinary() {
|
|
|
315
343
|
throw new Error(`Extracted archive did not contain expected binary: ${binName}`);
|
|
316
344
|
}
|
|
317
345
|
} catch (err) {
|
|
318
|
-
if (fs.existsSync(tempArchive)) {
|
|
346
|
+
if (tempArchive && fs.existsSync(tempArchive)) {
|
|
319
347
|
try { fs.unlinkSync(tempArchive); } catch {}
|
|
320
348
|
}
|
|
349
|
+
if (createdCacheDir && fs.existsSync(cacheDir)) {
|
|
350
|
+
try {
|
|
351
|
+
const files = fs.readdirSync(cacheDir);
|
|
352
|
+
if (files.length === 0) {
|
|
353
|
+
fs.rmdirSync(cacheDir);
|
|
354
|
+
}
|
|
355
|
+
} catch {}
|
|
356
|
+
}
|
|
321
357
|
throw err;
|
|
322
358
|
}
|
|
323
359
|
}
|