From f24b1ae2177ed3b647e208f72623115c47ad52b1 Mon Sep 17 00:00:00 2001 From: vendoo-updater-build Date: Fri, 10 Jul 2026 12:43:56 +0000 Subject: [PATCH] feat: validate updater 3.4 package provenance --- .github/workflows/patch-updater34-release.yml | 62 ------------------- tools/release-manifest-lib.mjs | 18 +++++- 2 files changed, 16 insertions(+), 64 deletions(-) delete mode 100644 .github/workflows/patch-updater34-release.yml diff --git a/.github/workflows/patch-updater34-release.yml b/.github/workflows/patch-updater34-release.yml deleted file mode 100644 index e53bc1d..0000000 --- a/.github/workflows/patch-updater34-release.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Patch Updater 3.4 Release Provenance - -on: - push: - branches: - - feature/updater-3.4-lifecycle - -permissions: - contents: write - -concurrency: - group: patch-updater-34-release - cancel-in-progress: false - -jobs: - patch: - if: ${{ github.actor != 'github-actions[bot]' }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: feature/updater-3.4-lifecycle - fetch-depth: 0 - - - name: Manifestvertrag auf Paket-Provenienz v2 erweitern - shell: python - run: | - from pathlib import Path - - path = Path('tools/release-manifest-lib.mjs') - text = path.read_text(encoding='utf-8') - - old = "import { createHash } from 'node:crypto';\n" - new = old + "import { computePackagePayloadHash, PACKAGE_MANIFEST_SCHEMA } from './updater-lifecycle-3.4.mjs';\n" - if text.count(old) != 1: - raise SystemExit('createHash-Import nicht eindeutig gefunden') - text = text.replace(old, new) - - old = " 'scripts/updater/Vendoo.Updater.Worker.ps1',\n 'tools/apply-release-manifest.mjs'," - new = " 'scripts/updater/Vendoo.Updater.Worker34.ps1',\n 'tools/apply-release-manifest.mjs',\n 'tools/updater-lifecycle-3.4.mjs',\n 'tools/check-release-payload-3.4.mjs'," - if text.count(old) != 1: - raise SystemExit('alter Worker-Pflichtvertrag nicht eindeutig gefunden') - text = text.replace(old, new) - - old = " if (manifest.schema !== MANIFEST_SCHEMA) throw new Error(`Unbekanntes Manifest-Schema: ${manifest.schema}`);\n if (manifest.mode !== 'overlay-with-explicit-removals') throw new Error(`Unzulässiger Release-Modus: ${manifest.mode}`);" - new = " if (![MANIFEST_SCHEMA, PACKAGE_MANIFEST_SCHEMA].includes(manifest.schema)) throw new Error(`Unbekanntes Manifest-Schema: ${manifest.schema}`);\n if (manifest.mode !== 'overlay-with-explicit-removals') throw new Error(`Unzulässiger Release-Modus: ${manifest.mode}`);\n if (manifest.schema === PACKAGE_MANIFEST_SCHEMA) {\n if (manifest.targetVersion !== manifest.version) throw new Error('targetVersion und version des Paketmanifests stimmen nicht überein.');\n for (const field of ['sourceCommit', 'baseCommit']) {\n if (!/^[a-f0-9]{40}$/.test(String(manifest[field] || ''))) throw new Error(`Ungültige Paket-Provenienz: ${field}`);\n }\n const createdAt = Date.parse(String(manifest.createdAt || ''));\n if (!Number.isFinite(createdAt)) throw new Error('Ungültige Paket-Provenienz: createdAt');\n if (!/^[a-f0-9]{64}$/.test(String(manifest.payloadHash || ''))) throw new Error('Ungültige Paket-Provenienz: payloadHash');\n const expectedPayloadHash = computePackagePayloadHash(manifest);\n if (manifest.payloadHash !== expectedPayloadHash) throw new Error('Payload-Hash des Paketmanifests stimmt nicht.');\n }" - if text.count(old) != 1: - raise SystemExit('Schema-Prüfung nicht eindeutig gefunden') - text = text.replace(old, new) - - path.write_text(text, encoding='utf-8', newline='\n') - - - name: Patch committen und temporären Workflow entfernen - shell: bash - run: | - set -euo pipefail - rm -f .github/workflows/patch-updater34-release.yml - git config user.name 'vendoo-updater-build' - git config user.email 'vendoo-updater-build@users.noreply.github.com' - git add --all - git commit -m 'feat: validate updater 3.4 package provenance' - git push origin HEAD:feature/updater-3.4-lifecycle diff --git a/tools/release-manifest-lib.mjs b/tools/release-manifest-lib.mjs index dd30567..7d8f770 100644 --- a/tools/release-manifest-lib.mjs +++ b/tools/release-manifest-lib.mjs @@ -10,6 +10,7 @@ import { statSync, } from 'node:fs'; import { createHash } from 'node:crypto'; +import { computePackagePayloadHash, PACKAGE_MANIFEST_SCHEMA } from './updater-lifecycle-3.4.mjs'; import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from 'node:path'; export const MANIFEST_SCHEMA = 'vendoo-release-manifest-v1'; @@ -27,8 +28,10 @@ export const REQUIRED_RELEASE_FILES = Object.freeze([ 'scripts/updater/Vendoo.Updater.Preflight.ps1', 'scripts/updater/Vendoo.Updater.UI.ps1', 'scripts/updater/Vendoo.Updater.Host.ps1', - 'scripts/updater/Vendoo.Updater.Worker.ps1', + 'scripts/updater/Vendoo.Updater.Worker34.ps1', 'tools/apply-release-manifest.mjs', + 'tools/updater-lifecycle-3.4.mjs', + 'tools/check-release-payload-3.4.mjs', ]); const allowedEnvTemplates = new Set(['.env.example', '.env.docker.example']); @@ -142,8 +145,19 @@ export function readAndValidateManifest(sourceRoot, { allowExtraFiles = false } const manifestPath = join(base, MANIFEST_FILE); if (!existsSync(manifestPath)) throw new Error(`${MANIFEST_FILE} fehlt.`); const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')); - if (manifest.schema !== MANIFEST_SCHEMA) throw new Error(`Unbekanntes Manifest-Schema: ${manifest.schema}`); + if (![MANIFEST_SCHEMA, PACKAGE_MANIFEST_SCHEMA].includes(manifest.schema)) throw new Error(`Unbekanntes Manifest-Schema: ${manifest.schema}`); if (manifest.mode !== 'overlay-with-explicit-removals') throw new Error(`Unzulässiger Release-Modus: ${manifest.mode}`); + if (manifest.schema === PACKAGE_MANIFEST_SCHEMA) { + if (manifest.targetVersion !== manifest.version) throw new Error('targetVersion und version des Paketmanifests stimmen nicht überein.'); + for (const field of ['sourceCommit', 'baseCommit']) { + if (!/^[a-f0-9]{40}$/.test(String(manifest[field] || ''))) throw new Error(`Ungültige Paket-Provenienz: ${field}`); + } + const createdAt = Date.parse(String(manifest.createdAt || '')); + if (!Number.isFinite(createdAt)) throw new Error('Ungültige Paket-Provenienz: createdAt'); + if (!/^[a-f0-9]{64}$/.test(String(manifest.payloadHash || ''))) throw new Error('Ungültige Paket-Provenienz: payloadHash'); + const expectedPayloadHash = computePackagePayloadHash(manifest); + if (manifest.payloadHash !== expectedPayloadHash) throw new Error('Payload-Hash des Paketmanifests stimmt nicht.'); + } if (!Array.isArray(manifest.files) || manifest.files.length === 0) throw new Error('Release-Manifest enthält keine Dateien.'); if (!Array.isArray(manifest.removedFiles)) throw new Error('removedFiles fehlt im Release-Manifest.'); const seen = new Set();