feat: publish Toolbox 0.7.0

This commit is contained in:
2026-07-27 01:16:20 +02:00
parent 5c052bc6d1
commit 470ee49ca2
15 changed files with 147 additions and 576 deletions

View File

@@ -2,7 +2,7 @@ import { createReadStream, createWriteStream } from 'node:fs';
import { mkdir, readdir, stat } from 'node:fs/promises';
import path from 'node:path';
import { pipeline } from 'node:stream/promises';
import archiver from 'archiver';
import { ZipArchive } from 'archiver';
import {
canonicalExistingPath,
canonicalPathsOverlap,
@@ -56,7 +56,7 @@ export async function createStaticArchive(inputDirectory, outputFile) {
throw new Error(`Archive input is not a directory: ${source}`);
await mkdir(path.dirname(output), { recursive: true });
const archive = archiver('zip', { zlib: { level: 9 } });
const archive = new ZipArchive({ zlib: { level: 9 } });
const destination = createWriteStream(output, { flags: 'wx' });
archive.on('warning', (error) => {
if (error.code !== 'ENOENT') destination.destroy(error);

View File

@@ -14,7 +14,7 @@ import os from 'node:os';
import path from 'node:path';
import { pipeline } from 'node:stream/promises';
import { pathToFileURL } from 'node:url';
import archiver from 'archiver';
import { ZipArchive } from 'archiver';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { assembleRelease } from './assemble.mjs';
import { createStaticArchive } from './archive.mjs';
@@ -46,7 +46,7 @@ async function zipEntries(
output: string,
entries: Array<{ name: string; content: string }>
) {
const archive = archiver('zip', { zlib: { level: 9 } });
const archive = new ZipArchive({ zlib: { level: 9 } });
const writing = pipeline(archive, createWriteStream(output, { flags: 'wx' }));
for (const entry of entries)
archive.append(entry.content, { name: entry.name });
@@ -83,7 +83,7 @@ function makeLock(artifact: string, sha256: string) {
return {
schemaVersion: 1,
releaseVersion: '0.1.0',
portalVersion: '0.2.5',
portalVersion: '0.2.6',
catalogue: {
id: 'de.add-ideas.toolbox',
name: 'Test Toolbox',
@@ -238,7 +238,7 @@ describe('release assembly integrity', () => {
it('blocks symbolic links before extraction', async () => {
const directory = await temporaryDirectory();
const artifact = path.join(directory, 'symlink.zip');
const archive = archiver('zip', { zlib: { level: 9 } });
const archive = new ZipArchive({ zlib: { level: 9 } });
const writing = pipeline(
archive,
createWriteStream(artifact, { flags: 'wx' })

View File

@@ -90,7 +90,7 @@ describe('production deployment', () => {
expect(containerfile).toMatch(/\nUSER 101:101\nEXPOSE 8080\n/u);
});
it('uses only the requested external Traefik network and HTTPS router', () => {
it('uses only the requested external Traefik network and redirects HTTP to HTTPS', () => {
expect(compose).toContain('dockerfile: Containerfile.release');
expect(compose).toContain('traefik.enable: "true"');
expect(compose).toContain(
@@ -105,6 +105,27 @@ describe('production deployment', () => {
expect(compose).toContain(
'traefik.http.routers.addideas-toolbox.tls.certresolver: "${TRAEFIK_CERT_RESOLVER:-netcup}"'
);
expect(compose).toContain(
'traefik.http.routers.addideas-toolbox-http.rule: "Host(`${TOOLBOX_HOST:-toolbox.add-ideas.de}`)"'
);
expect(compose).toContain(
'traefik.http.routers.addideas-toolbox-http.entrypoints: web'
);
expect(compose).toContain(
'traefik.http.routers.addideas-toolbox-http.priority: 900'
);
expect(compose).toContain(
'traefik.http.routers.addideas-toolbox-http.middlewares: addideas-toolbox-https-redirect'
);
expect(compose).toContain(
'traefik.http.routers.addideas-toolbox-http.service: addideas-toolbox'
);
expect(compose).toContain(
'traefik.http.middlewares.addideas-toolbox-https-redirect.redirectscheme.scheme: https'
);
expect(compose).toContain(
'traefik.http.middlewares.addideas-toolbox-https-redirect.redirectscheme.permanent: "true"'
);
expect(compose).toContain('external: true');
expect(compose).not.toMatch(/^\s+ports:/mu);
});
@@ -127,6 +148,12 @@ describe('production deployment', () => {
'/apps/av/vendor/ffmpeg/0.12.10/mt/ffmpeg-core.js',
'/apps/av/vendor/ffmpeg/0.12.10/mt/ffmpeg-core.wasm',
'/apps/av/vendor/ffmpeg/0.12.10/mt/ffmpeg-core.worker.js',
'/apps/av/vendor/ffmpeg/0.12.10-reviewed-stack5m.1/version.json',
'/apps/av/vendor/ffmpeg/0.12.10-reviewed-stack5m.1/st/ffmpeg-core.js',
'/apps/av/vendor/ffmpeg/0.12.10-reviewed-stack5m.1/st/ffmpeg-core.wasm',
'/apps/av/vendor/ffmpeg/0.12.10-reviewed-stack5m.1/mt/ffmpeg-core.js',
'/apps/av/vendor/ffmpeg/0.12.10-reviewed-stack5m.1/mt/ffmpeg-core.wasm',
'/apps/av/vendor/ffmpeg/0.12.10-reviewed-stack5m.1/mt/ffmpeg-core.worker.js',
]) {
expect(isImmutable(uri), uri).toBe(true);
}
@@ -147,6 +174,11 @@ describe('production deployment', () => {
'/apps/av/vendor/ffmpeg/0.12.10/st/other.wasm',
'/apps/av/vendor/ffmpeg/0.12.10/mt/ffmpeg-core.worker.wasm',
'/apps/av/vendor/ffmpeg/0.12.10/ffmpeg-core.wasm',
'/apps/av/vendor/ffmpeg/0.12.10-/st/ffmpeg-core.wasm',
'/apps/av/vendor/ffmpeg/0.12.10-reviewed_/st/ffmpeg-core.wasm',
'/apps/av/vendor/ffmpeg/0.12.10-latest/st/ffmpeg-core.wasm',
'/apps/av/vendor/ffmpeg/0.12.10-SNAPSHOT/st/ffmpeg-core.wasm',
'/apps/av/vendor/ffmpeg/0.12.10-reviewed-stack5m.2/st/ffmpeg-core.wasm',
]) {
expect(isImmutable(uri), uri).toBe(false);
}