Files
ForgeFlow/tests/diagnostics.test.mjs
T
NuklearRabbit 8cca1bfc01
Managed validation / full (pull_request) Successful in 44s
ChatGPT validation / quality (push) Failing after 2m28s
Prepare ForgeFlow for public release
2026-08-31 20:10:07 +02:00

79 lines
4.0 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtemp, readFile, rm } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import zlib from 'node:zlib';
import diagnosticsModule from '../src/main/diagnostics-service.cjs';
const { DiagnosticsService } = diagnosticsModule;
function unzipLocalEntries(buffer) {
const entries = new Map();
let offset = 0;
while (offset + 4 <= buffer.length && buffer.readUInt32LE(offset) === 0x04034b50) {
const method = buffer.readUInt16LE(offset + 8);
const compressedSize = buffer.readUInt32LE(offset + 18);
const nameLength = buffer.readUInt16LE(offset + 26);
const extraLength = buffer.readUInt16LE(offset + 28);
const nameStart = offset + 30;
const dataStart = nameStart + nameLength + extraLength;
const name = buffer.subarray(nameStart, nameStart + nameLength).toString('utf8');
const compressed = buffer.subarray(dataStart, dataStart + compressedSize);
entries.set(name, method === 8 ? zlib.inflateRawSync(compressed) : compressed);
offset = dataStart + compressedSize;
}
return entries;
}
test('writes structured local diagnostics and exports a secret-free support bundle', async (t) => {
const root = await mkdtemp(path.join(os.tmpdir(), 'forgeflow-diagnostics-'));
t.after(() => rm(root, { recursive: true, force: true }));
const secret = ['gitea', 'TEST', 'ONLY', 'ULTRA', 'SECRET', '1234567890'].join('_');
const service = new DiagnosticsService({
userDataPath: root,
appInfo: { name: 'ForgeFlow', version: '0.3.0-test' },
secretProvider: () => [secret],
preferencesProvider: () => ({ diagnosticsEnabled: true, diagnosticLevel: 'debug', logRetentionDays: 14, maxLogFileMb: 8 })
});
await service.initialize();
await service.error('test.failure', {
authorization: `token ${secret}`,
password: 'unsafe-password',
message: `request failed with ${secret}`,
path: path.join(os.homedir(), 'private', 'repository'),
host: '192.168.10.20',
basePath: '/mnt/user/appdata/private-app'
});
await service.flush();
const status = await service.getStatus();
assert.equal(status.enabled, true);
assert.ok(status.fileCount >= 1);
const raw = (await Promise.all((await service.listLogFiles()).map((file) => readFile(file.path, 'utf8')))).join('\n');
assert.doesNotMatch(raw, new RegExp(secret));
assert.doesNotMatch(raw, /unsafe-password/);
assert.doesNotMatch(raw, new RegExp(os.homedir().replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
const destination = path.join(root, 'support.zip');
const result = await service.exportSupportBundle({
destinationPath: destination,
privacyMode: 'strict',
publicState: { gitea: { baseUrl: 'https://gitea.example.test', hasToken: true, encryptedToken: 'ciphertext' }, servers: [{ host: '192.168.10.20', username: 'deploy', basePath: '/mnt/user/appdata/private-app' }], preferences: {} },
repositories: [{ id: 1, fullName: 'jens/private-repo', localPath: path.join(os.homedir(), 'private-repo'), localStatus: { head: 'a'.repeat(40), branch: { head: 'main' }, counts: {}, clean: true } }],
operations: [{ repository: 'jens/private-repo', status: 'failed', runnerLog: `Authorization: token ${secret}` }],
preflight: { checks: [] }
});
assert.equal(service.isKnownBundlePath(result.path), true);
const entries = unzipLocalEntries(await readFile(destination));
const bundleText = [...entries.values()].map((value) => value.toString('utf8')).join('\n');
assert.doesNotMatch(bundleText, new RegExp(secret));
assert.doesNotMatch(bundleText, /ciphertext|unsafe-password|jens\/private-repo/);
assert.doesNotMatch(bundleText, /192\.168\.10\.20|\/mnt\/user\/appdata\/private-app/);
assert.match(entries.get('manifest.json').toString(), /"containsSecrets": false/);
assert.match(entries.get('repositories-sanitized.json').toString(), /fullname-[a-f0-9]{12}/);
const cleared = await service.clear();
assert.ok(cleared.fileCount >= 1, 'clear writes a new safe session marker');
});