release: v2.1.12 reliability and security hardening

Verify update artifacts with exact metadata and SHA-512, require host-confirmed upload completion before cleanup, harden credentials and backups, improve queue recovery and skipped-state reporting, expand Windows path coverage, and add CI packaging checks.
This commit is contained in:
Sucukdeluxe
2026-08-11 22:36:20 +02:00
parent 7eec990811
commit 26dcf9c698
47 changed files with 2069 additions and 1192 deletions
+48 -3
View File
@@ -23,16 +23,18 @@
if (!file || !Array.isArray(file.results)) continue;
for (const r of file.results) {
if (!r || !r.hoster) continue;
const bucket = out[r.hoster] || (out[r.hoster] = { ok: 0, fail: 0, total: 0 });
const bucket = out[r.hoster] || (out[r.hoster] = { ok: 0, fail: 0, skipped: 0, total: 0 });
bucket.total++;
if (r.status === 'done') bucket.ok++;
else if (r.status === 'skipped') bucket.skipped++;
else bucket.fail++;
}
}
}
for (const h of Object.keys(out)) {
const b = out[h];
b.rate = b.total > 0 ? b.ok / b.total : null;
const attempted = b.ok + b.fail;
b.rate = attempted > 0 ? b.ok / attempted : null;
}
return out;
}
@@ -61,7 +63,7 @@
for (const f of batchSummary.files) {
if (!f || !Array.isArray(f.results)) continue;
for (const r of f.results) {
if (!r || r.status === 'done') continue;
if (!r || r.status === 'done' || r.status === 'skipped') continue;
const cat = classifyErrorCategory(r.error);
buckets[cat].push({
fileName: f.name || f.fileName || '',
@@ -74,6 +76,48 @@
return buckets;
}
function mergeSkippedIntoSummary(summary, skippedJobs) {
const source = summary && typeof summary === 'object' ? summary : {};
const merged = {
...source,
files: Array.isArray(source.files)
? source.files.map(file => ({ ...file, results: Array.isArray(file.results) ? [...file.results] : [] }))
: []
};
const existingJobIds = new Set();
const filesByName = new Map();
for (const file of merged.files) {
filesByName.set(String(file.name || file.fileName || ''), file);
for (const result of file.results) {
if (result?.jobId) existingJobIds.add(result.jobId);
}
}
let added = 0;
for (const skipped of Array.isArray(skippedJobs) ? skippedJobs : []) {
if (!skipped || (skipped.jobId && existingJobIds.has(skipped.jobId))) continue;
const fileName = String(skipped.fileName || skipped.file || '').split(/[\\/]/).pop() || '';
let file = filesByName.get(fileName);
if (!file) {
file = { name: fileName, size: Number(skipped.size) || 0, results: [] };
merged.files.push(file);
filesByName.set(fileName, file);
}
file.results.push({
jobId: skipped.jobId || null,
hoster: skipped.hoster || '',
status: 'skipped',
error: skipped.reason || 'Übersprungen'
});
if (skipped.jobId) existingJobIds.add(skipped.jobId);
added++;
}
merged.total = (Number(source.total) || 0) + added;
merged.succeeded = Number(source.succeeded) || 0;
merged.failed = Number(source.failed) || 0;
merged.skipped = (Number(source.skipped) || 0) + added;
return merged;
}
const RETRYABLE_CATEGORIES = new Set(['hoster-transient', 'network', 'unknown']);
function isRetryableCategory(cat) {
return RETRYABLE_CATEGORIES.has(cat);
@@ -128,6 +172,7 @@
summarizePerHoster,
classifyErrorCategory,
summarizeBatchErrors,
mergeSkippedIntoSummary,
isRetryableCategory,
RETRYABLE_CATEGORIES,
CATEGORY_LABELS,