feat: release toolbox portal 0.1.0

This commit is contained in:
2026-07-20 18:40:51 +02:00
commit 5d2e466ad6
55 changed files with 11127 additions and 0 deletions

145
scripts/artifact.mjs Normal file
View File

@@ -0,0 +1,145 @@
import { createHash } from 'node:crypto';
import { constants, createReadStream, createWriteStream } from 'node:fs';
import { copyFile, lstat, mkdir } from 'node:fs/promises';
import path from 'node:path';
import { Readable, Transform } from 'node:stream';
import { pipeline } from 'node:stream/promises';
import { fileURLToPath } from 'node:url';
const MAX_DOWNLOAD_SIZE = 1024 * 1024 * 1024;
const MAX_REDIRECTS = 5;
function usesLatestAlias(value) {
let decoded = value;
try {
decoded = decodeURIComponent(value);
} catch {
// The URL parser below reports malformed encodings where relevant.
}
return /(?:^|[^a-z0-9])latest(?:[^a-z0-9]|$)/i.test(decoded);
}
function parseArtifactSource(source, lockDirectory) {
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(source)) {
const url = new URL(source);
if (url.protocol === 'file:')
return { type: 'local', path: fileURLToPath(url) };
if (url.protocol === 'https:') {
return { type: 'https', url: validateHttpsArtifactUrl(url) };
}
throw new Error(`Artifact URL protocol is not allowed: ${url.protocol}`);
}
return { type: 'local', path: path.resolve(lockDirectory, source) };
}
function validateHttpsArtifactUrl(value, label = 'Artifact HTTPS URL') {
const url = value instanceof URL ? value : new URL(value);
if (url.protocol !== 'https:')
throw new Error(`${label} must use HTTPS: ${url.href}`);
if (url.username || url.password)
throw new Error(`${label} must not contain credentials.`);
if (usesLatestAlias(url.href))
throw new Error(`${label} must not use a latest alias.`);
return url;
}
async function fetchArtifact(url) {
let current = validateHttpsArtifactUrl(url);
for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {
const response = await fetch(current, {
redirect: 'manual',
headers: { Accept: 'application/zip, application/octet-stream' },
});
if ([301, 302, 303, 307, 308].includes(response.status)) {
if (redirects === MAX_REDIRECTS)
throw new Error(
`Artifact download exceeded ${MAX_REDIRECTS} redirects.`
);
const location = response.headers.get('location');
if (!location)
throw new Error('Artifact redirect did not include a Location header.');
current = validateHttpsArtifactUrl(
new URL(location, current),
'Artifact redirect URL'
);
continue;
}
if (response.url) {
const finalUrl = validateHttpsArtifactUrl(
new URL(response.url),
'Artifact final response URL'
);
if (finalUrl.href !== current.href) {
throw new Error(
`Artifact fetch unexpectedly changed URL from ${current.href} to ${finalUrl.href}.`
);
}
}
return { response, finalUrl: current };
}
throw new Error(`Artifact download exceeded ${MAX_REDIRECTS} redirects.`);
}
export async function sha256File(file) {
const hash = createHash('sha256');
for await (const chunk of createReadStream(file)) hash.update(chunk);
return hash.digest('hex');
}
export async function acquireArtifact(
source,
expectedSha256,
lockDirectory,
downloadDirectory
) {
const parsed = parseArtifactSource(source, lockDirectory);
await mkdir(downloadDirectory, { recursive: true });
const file = path.join(downloadDirectory, `${expectedSha256}.zip`);
let downloaded = false;
if (parsed.type === 'local') {
const details = await lstat(parsed.path);
if (!details.isFile() || details.isSymbolicLink())
throw new Error(`Local artifact is not a regular file: ${parsed.path}`);
// Work from a private snapshot. The checksum below therefore covers the
// exact bytes later inspected and extracted, even if the source is replaced.
await copyFile(parsed.path, file, constants.COPYFILE_EXCL);
} else {
const { response, finalUrl } = await fetchArtifact(parsed.url);
if (!response.ok || !response.body)
throw new Error(
`Artifact download failed with HTTP ${response.status}: ${finalUrl.href}`
);
const declaredLength = Number(response.headers.get('content-length'));
if (Number.isFinite(declaredLength) && declaredLength > MAX_DOWNLOAD_SIZE)
throw new Error('Artifact download exceeds the size limit.');
let bytes = 0;
const limiter = new Transform({
transform(chunk, _encoding, callback) {
bytes += chunk.length;
callback(
bytes > MAX_DOWNLOAD_SIZE
? new Error('Artifact download exceeds the size limit.')
: null,
chunk
);
},
});
await pipeline(
Readable.fromWeb(response.body),
limiter,
createWriteStream(file, { flags: 'wx', mode: 0o600 })
);
downloaded = true;
}
const actualSha256 = await sha256File(file);
if (actualSha256 !== expectedSha256) {
throw new Error(
`SHA-256 mismatch for ${source}: expected ${expectedSha256}, received ${actualSha256}.`
);
}
return { file, downloaded, sha256: actualSha256 };
}