feat: build updater packages with immutable provenance
This commit is contained in:
+23
-5
@@ -8,22 +8,38 @@ import {
|
||||
writeFileSync,
|
||||
} from 'node:fs';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { dirname, join, relative, sep } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { generateReleaseManifest } from './generate-release-manifest.mjs';
|
||||
import { MANIFEST_FILE, readAndValidateManifest } from './release-manifest-lib.mjs';
|
||||
import { createPackageManifest } from './updater-lifecycle-3.4.mjs';
|
||||
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
|
||||
const outputRoot = join(root, 'release-output');
|
||||
const packageName = `Vendoo_${pkg.version}`;
|
||||
const stage = join(outputRoot, packageName);
|
||||
const normalize = value => value.split(sep).join('/');
|
||||
|
||||
// The committed manifest is the only release payload contract. Regenerate it first so
|
||||
// stale hashes or accidentally omitted source files make the release fail immediately.
|
||||
function git(args, { allowFailure = false } = {}) {
|
||||
const result = spawnSync('git', ['-C', root, ...args], { encoding: 'utf8' });
|
||||
if (!allowFailure && result.status !== 0) {
|
||||
throw new Error(`git ${args.join(' ')} fehlgeschlagen: ${(result.stderr || result.stdout || '').trim()}`);
|
||||
}
|
||||
return result.status === 0 ? String(result.stdout || '').trim() : '';
|
||||
}
|
||||
|
||||
// Das committed Manifest bleibt der reproduzierbare Quellvertrag. Das ausgelieferte
|
||||
// Paket erhält zusätzlich eine unveränderliche Git-Herkunft und einen Payload-Hash.
|
||||
generateReleaseManifest(root);
|
||||
const manifest = readAndValidateManifest(root);
|
||||
const sourceCommit = process.env.VENDOO_SOURCE_COMMIT || git(['rev-parse', 'HEAD']);
|
||||
const configuredBase = process.env.VENDOO_BASE_COMMIT || '';
|
||||
const discoveredBase = configuredBase || git(['merge-base', sourceCommit, 'origin/main'], { allowFailure: true });
|
||||
const baseCommit = discoveredBase || sourceCommit;
|
||||
const createdAt = process.env.VENDOO_SOURCE_CREATED_AT || git(['show', '-s', '--format=%cI', sourceCommit]);
|
||||
const packageManifest = createPackageManifest(manifest, { sourceCommit, baseCommit, createdAt });
|
||||
const packageName = `Vendoo_${pkg.version}_Updater_${manifest.updaterVersion}`;
|
||||
const stage = join(outputRoot, packageName);
|
||||
|
||||
rmSync(outputRoot, { recursive: true, force: true });
|
||||
mkdirSync(stage, { recursive: true });
|
||||
@@ -34,7 +50,8 @@ for (const entry of manifest.files) {
|
||||
copyFileSync(source, target);
|
||||
if (statSync(target).size !== entry.size) throw new Error(`Release-Kopie hat falsche Größe: ${entry.path}`);
|
||||
}
|
||||
copyFileSync(join(root, MANIFEST_FILE), join(stage, MANIFEST_FILE));
|
||||
writeFileSync(join(stage, MANIFEST_FILE), `${JSON.stringify(packageManifest, null, 2)}\n`, 'utf8');
|
||||
readAndValidateManifest(stage);
|
||||
|
||||
const checksums = [];
|
||||
function hashTree(dir) {
|
||||
@@ -55,3 +72,4 @@ writeFileSync(join(stage, 'FILE_CHECKSUMS_SHA256.txt'), `${checksums.join('\n')}
|
||||
writeFileSync(join(outputRoot, 'RELEASE_NAME.txt'), `${packageName}\n`, 'utf8');
|
||||
console.log(`Manifestbasiertes Release-Staging erstellt: ${stage}`);
|
||||
console.log(`${manifest.files.length} Payload-Dateien und ${checksums.length} Paketdateien mit SHA-256 erfasst.`);
|
||||
console.log(`Paket-Provenienz: source=${sourceCommit}, base=${baseCommit}, payload=${packageManifest.payloadHash}`);
|
||||
|
||||
Reference in New Issue
Block a user