Harden upload finalization and release verification
CI / verify (push) Failing after 21m12s

Preserve uncertain remote commits and destructive source-cleanup requirements across cancellation, persistence failures, retries, and restart recovery. Revalidate account availability after admission waits and prevent late upload results from bypassing cancellation state. Strengthen release argument, CI tag, source allowlist, and secret scanning gates. Run the Electron smoke suite in a fully hidden offscreen harness that cannot reveal, focus, or elevate native windows.
This commit is contained in:
Sucukdeluxe
2026-08-15 04:06:53 +02:00
parent 692d994037
commit b286574902
20 changed files with 1739 additions and 170 deletions
+22 -5
View File
@@ -81,6 +81,19 @@
return requiredHosters.filter((hoster) => provisional.has(hoster));
}
function startedHosters(jobs, requiredHosters) {
const values = [];
let legacyMetadata = false;
for (const job of jobs) {
if (job.sourceCleanupMetadataVersion !== metadataVersion) continue;
if (!Array.isArray(job.sourceCleanupStartedHosters)) legacyMetadata = true;
else values.push(...job.sourceCleanupStartedHosters);
}
if (legacyMetadata) return [...requiredHosters];
const started = new Set(uniqueHosters(values));
return requiredHosters.filter((hoster) => started.has(hoster));
}
function storedToken(jobs) {
for (const job of jobs) {
if (typeof job.sourceCleanupToken === 'string' && job.sourceCleanupToken) {
@@ -98,13 +111,14 @@
return null;
}
function assignMetadata(jobs, token, requiredHosters, confirmed, provisional, fingerprint, touchedJobs, touchedSet) {
function assignMetadata(jobs, token, requiredHosters, confirmed, provisional, started, fingerprint, touchedJobs, touchedSet) {
for (const job of jobs) {
job.sourceCleanupMetadataVersion = metadataVersion;
job.sourceCleanupToken = token;
job.sourceCleanupRequiredHosters = [...requiredHosters];
job.sourceCleanupConfirmedHosters = [...confirmed];
job.sourceCleanupProvisionalHosters = [...provisional];
job.sourceCleanupStartedHosters = [...started];
job.sourceCleanupFingerprint = cloneFingerprint(fingerprint);
delete job.sourceCleanupCompletedHosters;
if (!touchedSet.has(job)) {
@@ -138,15 +152,16 @@
...persistedRequired,
...siblings.map((job) => job.hoster)
]);
const startedHosters = new Set(uniqueHosters(
const currentStartedHosters = new Set(uniqueHosters(
siblings.filter((job) => currentRoundJobs.has(job)).map((job) => job.hoster)
));
const started = uniqueHosters([...startedHosters(siblings, requiredHosters), ...currentStartedHosters]);
const storedConfirmed = confirmedHosters(siblings, requiredHosters);
const confirmed = storedConfirmed.filter((hoster) => !startedHosters.has(hoster));
const confirmed = storedConfirmed.filter((hoster) => !currentStartedHosters.has(hoster));
const provisional = provisionalHosters(siblings, requiredHosters)
.filter((hoster) => !startedHosters.has(hoster));
.filter((hoster) => !currentStartedHosters.has(hoster));
for (const hoster of storedConfirmed) {
if (!startedHosters.has(hoster) || revokedSet.has(hoster)) continue;
if (!currentStartedHosters.has(hoster) || revokedSet.has(hoster)) continue;
revokedSet.add(hoster);
revokedHosters.push(hoster);
}
@@ -158,6 +173,7 @@
requiredHosters,
confirmed,
provisional,
started,
fingerprint,
touchedJobs,
touchedSet
@@ -249,6 +265,7 @@
if (!job || job.status !== 'preview' || job.interrupted) return [];
const siblings = relatedJobs(queueJobs, job, platform);
const removedHoster = normalizeHoster(job.hoster);
if (startedHosters(siblings, storedRequiredHosters(siblings)).includes(removedHoster)) return [];
for (const sibling of siblings) {
const required = Array.isArray(sibling.sourceCleanupRequiredHosters)
? sibling.sourceCleanupRequiredHosters