fix(KAN-65): recover verified S3 writes from empty error responses
CI/CD / preconditions (push) Successful in 2s
Native JavaScript checks / Native launcher and release tests (push) Successful in 58s
macOS checks / Native Rust tests and unsigned build (push) Successful in 1m35s
CI/CD / test_and_check_app (push) Successful in 6m31s
macOS release to Hetzner / Validate release ref and configuration (push) Successful in 21s
CI/CD / Publish immutable image (push) Successful in 1m18s
macOS release to Hetzner / Sign, notarize, verify and publish macOS (push) Failing after 4m57s

This commit is contained in:
2026-09-27 23:05:35 +02:00
parent 48f5fc410b
commit dc9f400f34
6 changed files with 119 additions and 19 deletions
+25 -9
View File
@@ -63,6 +63,14 @@ export function storageConfiguration(env = process.env) {
const sha256 = (data) => createHash('sha256').update(data).digest('hex');
function requiresExistingObjectCheck(error) {
// AWS CLI can crash while formatting Hetzner's empty error Message.
// This only permits a readback; content checks and conditional writes still apply.
return /\(PreconditionFailed\)|\(412\)|argument of type 'NoneType' is not (?:a container or )?iterable/.test(
error.message,
);
}
export async function publishMacos({
env = process.env,
directory,
@@ -116,13 +124,21 @@ export async function publishMacos({
's3api',
];
function s3(operation, args) {
return run('aws', [
...common,
operation,
'--bucket',
storage.bucket,
...args,
]);
try {
return run('aws', [
...common,
operation,
'--bucket',
storage.bucket,
...args,
]);
} catch (error) {
const keyIndex = args.indexOf('--key');
const key = keyIndex >= 0 ? ` ${args[keyIndex + 1]}` : '';
throw new Error(`S3 ${operation}${key}: ${error.message}`, {
cause: error,
});
}
}
const versioningOutput = s3('get-bucket-versioning', [
'--output',
@@ -213,7 +229,7 @@ export async function publishMacos({
`sha256=${sha256(contents)}`,
]);
} catch (error) {
if (!/\(PreconditionFailed\)|\(412\)/.test(error.message)) {
if (!requiresExistingObjectCheck(error)) {
throw error;
}
const existing = join(staging, `existing-${name}`);
@@ -301,7 +317,7 @@ export async function publishMacos({
try {
publishLatest(['--if-none-match', '*']);
} catch (error) {
if (!/\(PreconditionFailed\)|\(412\)/.test(error.message)) {
if (!requiresExistingObjectCheck(error)) {
throw error;
}
const previousFile = join(staging, 'previous-latest.json');