From 967b25beaa8297e402a9d7302d3ec49e802d34a9 Mon Sep 17 00:00:00 2001 From: Andres Cera Date: Wed, 15 Jul 2026 00:09:30 -0500 Subject: [PATCH 01/18] feat(packaging): provenance-verified upstream pin manifest --- packaging/README.md | 30 ++- .../ci/fixtures/altered-dsc/modemmanager.dsc | 51 ++++ packaging/ci/fixtures/altered-dsc/pins.yaml | 30 +++ .../ci/fixtures/altered-orig/modemmanager.dsc | 51 ++++ .../modemmanager_1.24.0.orig.tar.xz | 1 + packaging/ci/fixtures/altered-orig/pins.yaml | 29 ++ .../ci/fixtures/wrong-signer/modemmanager.dsc | 51 ++++ packaging/ci/fixtures/wrong-signer/pins.yaml | 29 ++ packaging/ci/test-verify-upstream-pins.sh | 60 +++++ packaging/ci/verify-upstream-pins.sh | 254 ++++++++++++++++++ ...F6CCDF96229D09286B2AC325BF86524AFCC1E3.asc | 135 ++++++++++ ...6DB393DC3FF40222B6EA22D3EBB5966BB99196.asc | 128 +++++++++ packaging/keys/README.md | 68 +++++ packaging/upstream-pins.yaml | 134 +++++++++ 14 files changed, 1046 insertions(+), 5 deletions(-) create mode 100644 packaging/ci/fixtures/altered-dsc/modemmanager.dsc create mode 100644 packaging/ci/fixtures/altered-dsc/pins.yaml create mode 100644 packaging/ci/fixtures/altered-orig/modemmanager.dsc create mode 100644 packaging/ci/fixtures/altered-orig/modemmanager_1.24.0.orig.tar.xz create mode 100644 packaging/ci/fixtures/altered-orig/pins.yaml create mode 100644 packaging/ci/fixtures/wrong-signer/modemmanager.dsc create mode 100644 packaging/ci/fixtures/wrong-signer/pins.yaml create mode 100755 packaging/ci/test-verify-upstream-pins.sh create mode 100755 packaging/ci/verify-upstream-pins.sh create mode 100644 packaging/keys/63F6CCDF96229D09286B2AC325BF86524AFCC1E3.asc create mode 100644 packaging/keys/796DB393DC3FF40222B6EA22D3EBB5966BB99196.asc create mode 100644 packaging/keys/README.md create mode 100644 packaging/upstream-pins.yaml diff --git a/packaging/README.md b/packaging/README.md index 9259219..62bb12d 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -14,12 +14,30 @@ from CI artifacts; nothing is published to `apt.ceralive.tv` in Phase A. | libqrtr-glib | QRTR (IPC router) GLib bindings | Each is rebuilt from its pinned, provenance-verified upstream release and its pinned -Debian packaging tag. The authoritative pin manifest (`upstream-pins.yaml`) and the -provenance-verification script land in a later task; this directory currently holds the -CI scaffold only. +Debian packaging tag. The authoritative pin manifest is [`upstream-pins.yaml`](upstream-pins.yaml), +re-verified end-to-end by [`ci/verify-upstream-pins.sh`](ci/verify-upstream-pins.sh). -> **Status:** `[GREENFIELD]` — scaffold only. Real `debian/` recipes, the pin manifest, -> and the container build order arrive in the packaging wave. +> **Status:** `[PARTIAL]` — provenance pin manifest + verifier landed. Real `debian/` +> recipes and the container build order arrive in the packaging wave. + +## Provenance pins + +[`upstream-pins.yaml`](upstream-pins.yaml) pins each source to an exact upstream release +tag and its matching Debian (salsa) packaging tag, and records a three-link chain: + +1. **Lineage** — the upstream git tag object + peeled commit SHA (re-resolved by + `git ls-remote`; the tag is never byte-compared to a git archive). +2. **Authority** — the signed Debian `.dsc`, GPG-verified against a pinned signer + fingerprint whose armored key lives in [`keys/`](keys/) (acquisition documented in + [`keys/README.md`](keys/README.md)). A verified `.dsc` is the authority for its tarball + checksums. +3. **Artifact** — the `.orig.tar`, whose sha256 must equal the pin, which equals the + `.dsc`'s own `Checksums-Sha256` entry (copied verbatim into the manifest). + +`ci/verify-upstream-pins.sh` re-checks all of it in an **isolated** `GNUPGHOME` (never the +caller's `~/.gnupg`) and fails closed with a NAMED field on any drift. The current pins are +ModemManager 1.24.0, libmbim 1.32.0, libqmi 1.36.0, libqrtr-glib 1.2.2 (salsa +`debian/-1`). ## Versioning @@ -33,4 +51,6 @@ CI scaffold only. | [`ci/tag-guard.sh`](ci/tag-guard.sh) | The release-tag contract: accepts only `vX.Y.Z`, fails closed on pre-release / build-metadata / missing-`v`. Sourced by `release.yml` (job 1) and by the version-injection + test scripts. | | [`ci/test-tag-guard.sh`](ci/test-tag-guard.sh) | Executable proof of the tag-guard negatives (`v1.0.0-rc.1`, `v1.0.0+build5`, `1.0.0`, …). Run in CI and locally. | | [`ci/inject-deb-version.sh`](ci/inject-deb-version.sh) | Writes `-~ceralive` (or `~ceralive0.0.0~dev` for non-tag builds) into each source's `debian/changelog` top entry via `dch --force-bad-version`. Reads upstream versions from each source's changelog — never hardcoded here. | +| [`ci/verify-upstream-pins.sh`](ci/verify-upstream-pins.sh) | Re-verifies every field of `upstream-pins.yaml` in an isolated `GNUPGHOME`: git-tag lineage (`git ls-remote`), `.dsc` GPG signature vs pinned signer, `.dsc` checksums vs manifest, and the downloaded `.orig.tar` sha256. Exit 0 on success; non-zero with a NAMED failing field on any drift. | +| [`ci/test-verify-upstream-pins.sh`](ci/test-verify-upstream-pins.sh) | Offline fail-closed proof: runs the three [`ci/fixtures/`](ci/fixtures) tampers (wrong-signer / altered-`.dsc` / altered-`.orig.tar`) and asserts each is rejected on the correct named field. Run standalone; the packaging-wave container lane can adopt it. | | [`ci/contract.sh`](ci/contract.sh) | The packaging **container lane** (bookworm) entry point. Wave-A1 stub: asserts the scaffold is present and the tag-guard + version-injection scripts are wired. Real contract tests (metadata / closure / upgrade / rollback / ordering / daemon smoke) land with the recipes. | diff --git a/packaging/ci/fixtures/altered-dsc/modemmanager.dsc b/packaging/ci/fixtures/altered-dsc/modemmanager.dsc new file mode 100644 index 0000000..21e0c0e --- /dev/null +++ b/packaging/ci/fixtures/altered-dsc/modemmanager.dsc @@ -0,0 +1,51 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +Format: 3.0 (quilt) +Source: modemmanager +Binary: modemmanager, modemmanager-dev, modemmanager-doc, libmm-glib0, libmm-glib-dev, libmm-glib-doc, gir1.2-modemmanager-1.0 +Architecture: linux-any all +Version: 1.24.0-1 +Maintainer: DebianOnMobile Maintainers +Uploaders: Arnaud Ferraris , Guido Günther , Henry-Nicolas Tourneur , Martin +Homepage: https://www.freedesktop.org/wiki/Software/ModemManager/ +Standards-Version: 4.7.2 +Vcs-Browser: https://salsa.debian.org/DebianOnMobile-team/modemmanager +Vcs-Git: https://salsa.debian.org/DebianOnMobile-team/modemmanager.git +Testsuite: autopkgtest +Testsuite-Triggers: @builddeps@, dpkg-dev, pkgconf +Build-Depends: debhelper-compat (= 13), debhelper (>= 13.11.6), dh-sequence-gir, bash-completion, gettext, libdbus-1-dev, libgirepository1.0-dev, libglib2.0-dev, libgudev-1.0-dev, libmbim-glib-dev (>= 1.32~), libpolkit-gobject-1-dev (>= 0.97), libqmi-glib-dev (>= 1.36~), libsystemd-dev (>= 209), meson, polkitd, python3-dbus, python3-gi, systemd-dev, valac (>= 0.22), xsltproc, gtk-doc-tools , libglib2.0-doc , dbus +Package-List: + gir1.2-modemmanager-1.0 deb introspection optional arch=linux-any + libmm-glib-dev deb libdevel optional arch=linux-any + libmm-glib-doc deb doc optional arch=all profile=!nodoc + libmm-glib0 deb libs optional arch=linux-any + modemmanager deb net optional arch=linux-any + modemmanager-dev deb libdevel optional arch=linux-any + modemmanager-doc deb doc optional arch=all profile=!nodoc +Checksums-Sha1: + d0d6f2b3d5d003bb9825d5158bcee9cbd4853009 1361836 modemmanager_1.24.0.orig.tar.xz + b675ec976905fe175947a8aafcc66ec99edd6dd5 36680 modemmanager_1.24.0-1.debian.tar.xz +Checksums-Sha256: + 63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9169 1361836 modemmanager_1.24.0.orig.tar.xz + 7585e8cf6fb920e516372ed54d8f5c3d2faf1ffec920ec90fb550b9aaa11de12 36680 modemmanager_1.24.0-1.debian.tar.xz +Files: + 288cdf074430ef95268c9fe04873f047 1361836 modemmanager_1.24.0.orig.tar.xz + 97dce306035804a7bfb5e263febb1e98 36680 modemmanager_1.24.0-1.debian.tar.xz + +-----BEGIN PGP SIGNATURE----- + +iQIzBAEBCgAdFiEEY/bM35YinQkoayrDJb+GUkr8weMFAmf6CusACgkQJb+GUkr8 +weM7YRAAuDc4hy8TDZN/nqGAvk5so+r5v/ixxlQ3pvJG6cih08LkzTOrjgSS+tg/ +k4+3FiDQ+NgeOry7NcDdXldTUfN9GqRk5bznVzavNugrrN0HmgiHhQYTjHEttlh6 +JS6trZdINHTx4LpOlfMFhq+A1skK6JDDLcjS+YM1AXbBRGAoThd0VGb7hZhEn33U +aVXYFuD9ULxjDPzEVSqeTZrqy/6CaQkx8J7XSbpWh1u1MLBBvEABbqI5vN47/qHp +LfpBcNeExmbPbBMW267tcnlLvC3jeasCM7B8Ioq+hrnYqpJnW6lioFUjEhNShJzy +CiG19h8mkXNRAUdwnv63Bcnt9tsFL74SfHfJPkwW0OruGaJbB88A9yvotrRllCsn +xHnMxTB2Pf6qUF6gdPwkxfThil4FWKI6dgxIVLFamsuByrNt5CU3Ejdw2MKKeRRc +SPjftsy3yZPLD8XYKUCigDEzzXQU/5uNURJ7ZfLSjmBW0rqW63Wd3/kLDh/j8+BY +oDz4iyH1iWbPxpjqh63J0fhUYxgRRo7ORA5sLvEbr7sUbQyZFa1u5xlh8HlM8A9h +jOWpIaMD8aUJcm7VVhkYX4S7mZqHU2beEls5aSh3/EKk6lWn8XOL3dXDWuFJZWhv +o3wBsmPF/YAiRZtHuM5g/qhJHrXUEtR0WLrbxWvQk58l6kJ5r7o= +=9bMe +-----END PGP SIGNATURE----- diff --git a/packaging/ci/fixtures/altered-dsc/pins.yaml b/packaging/ci/fixtures/altered-dsc/pins.yaml new file mode 100644 index 0000000..aaee935 --- /dev/null +++ b/packaging/ci/fixtures/altered-dsc/pins.yaml @@ -0,0 +1,30 @@ +# FIXTURE — NOT A REAL PIN. Negative test for verify-upstream-pins.sh. +# +# Tamper: the packaged .dsc has ONE hex digit flipped inside its signed body +# (…218c9168 -> …218c9169 in the Checksums-Sha256 orig line), so the GPG clearsign +# no longer matches the content. `dsc_sha256` here is the hash of the ALTERED file, +# so the integrity pre-check passes — proving the GPG signature (not just a recorded +# hash) is what catches the tamper. The signer pin is the correct Guido key. +# Expected: FAIL [modemmanager] dsc_signature: signature invalid (BADSIG) … (exit 1). +schema_version: 1 +sources: + modemmanager: + upstream_tag: "1.24.0" + upstream_repo: "https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git" + upstream_tag_sha: "8e8dbf92f4e3be2aa9ae1b42edbbde275b3426c2" + upstream_commit_sha: "dfa41adf391b090720fb1ea56d884f61ea7fba29" + signer_fingerprint: "63F6CCDF96229D09286B2AC325BF86524AFCC1E3" + signer_key_file: "keys/63F6CCDF96229D09286B2AC325BF86524AFCC1E3.asc" + orig_tar_name: "modemmanager_1.24.0.orig.tar.xz" + orig_tar_url: "local:UNREACHED-fails-at-signature-check" + orig_tar_sha256: "63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9168" + salsa_repo: "https://salsa.debian.org/DebianOnMobile-team/modemmanager.git" + salsa_tag: "debian/1.24.0-1" + salsa_tag_sha: "92692e6a3f030dded827b74f29e45fa216e2a421" + salsa_commit_sha: "260e3c0fe1878929ab3f2d727f9ae47c69f729f1" + dsc_url: "local:modemmanager.dsc" + dsc_sha256: "760ec3116216655b6b677df93eaa1e4df73b15d33f61559b887b02e0d93c2b0a" + dsc_signer: "Guido Günther " + dsc_checksums_sha256: | + 63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9169 1361836 modemmanager_1.24.0.orig.tar.xz + 7585e8cf6fb920e516372ed54d8f5c3d2faf1ffec920ec90fb550b9aaa11de12 36680 modemmanager_1.24.0-1.debian.tar.xz diff --git a/packaging/ci/fixtures/altered-orig/modemmanager.dsc b/packaging/ci/fixtures/altered-orig/modemmanager.dsc new file mode 100644 index 0000000..00b557a --- /dev/null +++ b/packaging/ci/fixtures/altered-orig/modemmanager.dsc @@ -0,0 +1,51 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +Format: 3.0 (quilt) +Source: modemmanager +Binary: modemmanager, modemmanager-dev, modemmanager-doc, libmm-glib0, libmm-glib-dev, libmm-glib-doc, gir1.2-modemmanager-1.0 +Architecture: linux-any all +Version: 1.24.0-1 +Maintainer: DebianOnMobile Maintainers +Uploaders: Arnaud Ferraris , Guido Günther , Henry-Nicolas Tourneur , Martin +Homepage: https://www.freedesktop.org/wiki/Software/ModemManager/ +Standards-Version: 4.7.2 +Vcs-Browser: https://salsa.debian.org/DebianOnMobile-team/modemmanager +Vcs-Git: https://salsa.debian.org/DebianOnMobile-team/modemmanager.git +Testsuite: autopkgtest +Testsuite-Triggers: @builddeps@, dpkg-dev, pkgconf +Build-Depends: debhelper-compat (= 13), debhelper (>= 13.11.6), dh-sequence-gir, bash-completion, gettext, libdbus-1-dev, libgirepository1.0-dev, libglib2.0-dev, libgudev-1.0-dev, libmbim-glib-dev (>= 1.32~), libpolkit-gobject-1-dev (>= 0.97), libqmi-glib-dev (>= 1.36~), libsystemd-dev (>= 209), meson, polkitd, python3-dbus, python3-gi, systemd-dev, valac (>= 0.22), xsltproc, gtk-doc-tools , libglib2.0-doc , dbus +Package-List: + gir1.2-modemmanager-1.0 deb introspection optional arch=linux-any + libmm-glib-dev deb libdevel optional arch=linux-any + libmm-glib-doc deb doc optional arch=all profile=!nodoc + libmm-glib0 deb libs optional arch=linux-any + modemmanager deb net optional arch=linux-any + modemmanager-dev deb libdevel optional arch=linux-any + modemmanager-doc deb doc optional arch=all profile=!nodoc +Checksums-Sha1: + d0d6f2b3d5d003bb9825d5158bcee9cbd4853009 1361836 modemmanager_1.24.0.orig.tar.xz + b675ec976905fe175947a8aafcc66ec99edd6dd5 36680 modemmanager_1.24.0-1.debian.tar.xz +Checksums-Sha256: + 63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9168 1361836 modemmanager_1.24.0.orig.tar.xz + 7585e8cf6fb920e516372ed54d8f5c3d2faf1ffec920ec90fb550b9aaa11de12 36680 modemmanager_1.24.0-1.debian.tar.xz +Files: + 288cdf074430ef95268c9fe04873f047 1361836 modemmanager_1.24.0.orig.tar.xz + 97dce306035804a7bfb5e263febb1e98 36680 modemmanager_1.24.0-1.debian.tar.xz + +-----BEGIN PGP SIGNATURE----- + +iQIzBAEBCgAdFiEEY/bM35YinQkoayrDJb+GUkr8weMFAmf6CusACgkQJb+GUkr8 +weM7YRAAuDc4hy8TDZN/nqGAvk5so+r5v/ixxlQ3pvJG6cih08LkzTOrjgSS+tg/ +k4+3FiDQ+NgeOry7NcDdXldTUfN9GqRk5bznVzavNugrrN0HmgiHhQYTjHEttlh6 +JS6trZdINHTx4LpOlfMFhq+A1skK6JDDLcjS+YM1AXbBRGAoThd0VGb7hZhEn33U +aVXYFuD9ULxjDPzEVSqeTZrqy/6CaQkx8J7XSbpWh1u1MLBBvEABbqI5vN47/qHp +LfpBcNeExmbPbBMW267tcnlLvC3jeasCM7B8Ioq+hrnYqpJnW6lioFUjEhNShJzy +CiG19h8mkXNRAUdwnv63Bcnt9tsFL74SfHfJPkwW0OruGaJbB88A9yvotrRllCsn +xHnMxTB2Pf6qUF6gdPwkxfThil4FWKI6dgxIVLFamsuByrNt5CU3Ejdw2MKKeRRc +SPjftsy3yZPLD8XYKUCigDEzzXQU/5uNURJ7ZfLSjmBW0rqW63Wd3/kLDh/j8+BY +oDz4iyH1iWbPxpjqh63J0fhUYxgRRo7ORA5sLvEbr7sUbQyZFa1u5xlh8HlM8A9h +jOWpIaMD8aUJcm7VVhkYX4S7mZqHU2beEls5aSh3/EKk6lWn8XOL3dXDWuFJZWhv +o3wBsmPF/YAiRZtHuM5g/qhJHrXUEtR0WLrbxWvQk58l6kJ5r7o= +=9bMe +-----END PGP SIGNATURE----- diff --git a/packaging/ci/fixtures/altered-orig/modemmanager_1.24.0.orig.tar.xz b/packaging/ci/fixtures/altered-orig/modemmanager_1.24.0.orig.tar.xz new file mode 100644 index 0000000..aea4d57 --- /dev/null +++ b/packaging/ci/fixtures/altered-orig/modemmanager_1.24.0.orig.tar.xz @@ -0,0 +1 @@ +this is NOT the real modemmanager tarball diff --git a/packaging/ci/fixtures/altered-orig/pins.yaml b/packaging/ci/fixtures/altered-orig/pins.yaml new file mode 100644 index 0000000..2b92c26 --- /dev/null +++ b/packaging/ci/fixtures/altered-orig/pins.yaml @@ -0,0 +1,29 @@ +# FIXTURE — NOT A REAL PIN. Negative test for verify-upstream-pins.sh. +# +# Tamper: the .dsc is real & valid (correct Guido signature, checksums intact), so +# lineage/signature/checksum-consistency all pass — but the packaged .orig.tar is a +# tiny impostor whose sha256 does not match the pinned `orig_tar_sha256` (the real one +# from the verified .dsc). This is the last link in the chain: a swapped-out artifact. +# Expected: FAIL [modemmanager] orig_tar_sha256: checksum mismatch … (exit 1). +schema_version: 1 +sources: + modemmanager: + upstream_tag: "1.24.0" + upstream_repo: "https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git" + upstream_tag_sha: "8e8dbf92f4e3be2aa9ae1b42edbbde275b3426c2" + upstream_commit_sha: "dfa41adf391b090720fb1ea56d884f61ea7fba29" + signer_fingerprint: "63F6CCDF96229D09286B2AC325BF86524AFCC1E3" + signer_key_file: "keys/63F6CCDF96229D09286B2AC325BF86524AFCC1E3.asc" + orig_tar_name: "modemmanager_1.24.0.orig.tar.xz" + orig_tar_url: "local:modemmanager_1.24.0.orig.tar.xz" + orig_tar_sha256: "63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9168" + salsa_repo: "https://salsa.debian.org/DebianOnMobile-team/modemmanager.git" + salsa_tag: "debian/1.24.0-1" + salsa_tag_sha: "92692e6a3f030dded827b74f29e45fa216e2a421" + salsa_commit_sha: "260e3c0fe1878929ab3f2d727f9ae47c69f729f1" + dsc_url: "local:modemmanager.dsc" + dsc_sha256: "f2a0a21fdce6619bf874ab182385225c65b82d217d6b6ed20933ded5c375fa1c" + dsc_signer: "Guido Günther " + dsc_checksums_sha256: | + 63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9168 1361836 modemmanager_1.24.0.orig.tar.xz + 7585e8cf6fb920e516372ed54d8f5c3d2faf1ffec920ec90fb550b9aaa11de12 36680 modemmanager_1.24.0-1.debian.tar.xz diff --git a/packaging/ci/fixtures/wrong-signer/modemmanager.dsc b/packaging/ci/fixtures/wrong-signer/modemmanager.dsc new file mode 100644 index 0000000..00b557a --- /dev/null +++ b/packaging/ci/fixtures/wrong-signer/modemmanager.dsc @@ -0,0 +1,51 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +Format: 3.0 (quilt) +Source: modemmanager +Binary: modemmanager, modemmanager-dev, modemmanager-doc, libmm-glib0, libmm-glib-dev, libmm-glib-doc, gir1.2-modemmanager-1.0 +Architecture: linux-any all +Version: 1.24.0-1 +Maintainer: DebianOnMobile Maintainers +Uploaders: Arnaud Ferraris , Guido Günther , Henry-Nicolas Tourneur , Martin +Homepage: https://www.freedesktop.org/wiki/Software/ModemManager/ +Standards-Version: 4.7.2 +Vcs-Browser: https://salsa.debian.org/DebianOnMobile-team/modemmanager +Vcs-Git: https://salsa.debian.org/DebianOnMobile-team/modemmanager.git +Testsuite: autopkgtest +Testsuite-Triggers: @builddeps@, dpkg-dev, pkgconf +Build-Depends: debhelper-compat (= 13), debhelper (>= 13.11.6), dh-sequence-gir, bash-completion, gettext, libdbus-1-dev, libgirepository1.0-dev, libglib2.0-dev, libgudev-1.0-dev, libmbim-glib-dev (>= 1.32~), libpolkit-gobject-1-dev (>= 0.97), libqmi-glib-dev (>= 1.36~), libsystemd-dev (>= 209), meson, polkitd, python3-dbus, python3-gi, systemd-dev, valac (>= 0.22), xsltproc, gtk-doc-tools , libglib2.0-doc , dbus +Package-List: + gir1.2-modemmanager-1.0 deb introspection optional arch=linux-any + libmm-glib-dev deb libdevel optional arch=linux-any + libmm-glib-doc deb doc optional arch=all profile=!nodoc + libmm-glib0 deb libs optional arch=linux-any + modemmanager deb net optional arch=linux-any + modemmanager-dev deb libdevel optional arch=linux-any + modemmanager-doc deb doc optional arch=all profile=!nodoc +Checksums-Sha1: + d0d6f2b3d5d003bb9825d5158bcee9cbd4853009 1361836 modemmanager_1.24.0.orig.tar.xz + b675ec976905fe175947a8aafcc66ec99edd6dd5 36680 modemmanager_1.24.0-1.debian.tar.xz +Checksums-Sha256: + 63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9168 1361836 modemmanager_1.24.0.orig.tar.xz + 7585e8cf6fb920e516372ed54d8f5c3d2faf1ffec920ec90fb550b9aaa11de12 36680 modemmanager_1.24.0-1.debian.tar.xz +Files: + 288cdf074430ef95268c9fe04873f047 1361836 modemmanager_1.24.0.orig.tar.xz + 97dce306035804a7bfb5e263febb1e98 36680 modemmanager_1.24.0-1.debian.tar.xz + +-----BEGIN PGP SIGNATURE----- + +iQIzBAEBCgAdFiEEY/bM35YinQkoayrDJb+GUkr8weMFAmf6CusACgkQJb+GUkr8 +weM7YRAAuDc4hy8TDZN/nqGAvk5so+r5v/ixxlQ3pvJG6cih08LkzTOrjgSS+tg/ +k4+3FiDQ+NgeOry7NcDdXldTUfN9GqRk5bznVzavNugrrN0HmgiHhQYTjHEttlh6 +JS6trZdINHTx4LpOlfMFhq+A1skK6JDDLcjS+YM1AXbBRGAoThd0VGb7hZhEn33U +aVXYFuD9ULxjDPzEVSqeTZrqy/6CaQkx8J7XSbpWh1u1MLBBvEABbqI5vN47/qHp +LfpBcNeExmbPbBMW267tcnlLvC3jeasCM7B8Ioq+hrnYqpJnW6lioFUjEhNShJzy +CiG19h8mkXNRAUdwnv63Bcnt9tsFL74SfHfJPkwW0OruGaJbB88A9yvotrRllCsn +xHnMxTB2Pf6qUF6gdPwkxfThil4FWKI6dgxIVLFamsuByrNt5CU3Ejdw2MKKeRRc +SPjftsy3yZPLD8XYKUCigDEzzXQU/5uNURJ7ZfLSjmBW0rqW63Wd3/kLDh/j8+BY +oDz4iyH1iWbPxpjqh63J0fhUYxgRRo7ORA5sLvEbr7sUbQyZFa1u5xlh8HlM8A9h +jOWpIaMD8aUJcm7VVhkYX4S7mZqHU2beEls5aSh3/EKk6lWn8XOL3dXDWuFJZWhv +o3wBsmPF/YAiRZtHuM5g/qhJHrXUEtR0WLrbxWvQk58l6kJ5r7o= +=9bMe +-----END PGP SIGNATURE----- diff --git a/packaging/ci/fixtures/wrong-signer/pins.yaml b/packaging/ci/fixtures/wrong-signer/pins.yaml new file mode 100644 index 0000000..eb741a4 --- /dev/null +++ b/packaging/ci/fixtures/wrong-signer/pins.yaml @@ -0,0 +1,29 @@ +# FIXTURE — NOT A REAL PIN. Negative test for verify-upstream-pins.sh. +# +# Tamper: the .dsc (packaged here, real & unaltered, signed by Guido Günther +# 63F6CCDF…C1E3) is pinned to the WRONG signer — Arnaud Ferraris' fingerprint +# 796DB393…9196. Only that pinned key is imported into the isolated keyring, so +# gpg cannot verify the signature made by Guido's key and reports NO_PUBKEY for it. +# Expected: FAIL [modemmanager] signer_fingerprint: signer mismatch … (exit 1). +schema_version: 1 +sources: + modemmanager: + upstream_tag: "1.24.0" + upstream_repo: "https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git" + upstream_tag_sha: "8e8dbf92f4e3be2aa9ae1b42edbbde275b3426c2" + upstream_commit_sha: "dfa41adf391b090720fb1ea56d884f61ea7fba29" + signer_fingerprint: "796DB393DC3FF40222B6EA22D3EBB5966BB99196" + signer_key_file: "keys/796DB393DC3FF40222B6EA22D3EBB5966BB99196.asc" + orig_tar_name: "modemmanager_1.24.0.orig.tar.xz" + orig_tar_url: "local:UNREACHED-fails-at-signer-check" + orig_tar_sha256: "63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9168" + salsa_repo: "https://salsa.debian.org/DebianOnMobile-team/modemmanager.git" + salsa_tag: "debian/1.24.0-1" + salsa_tag_sha: "92692e6a3f030dded827b74f29e45fa216e2a421" + salsa_commit_sha: "260e3c0fe1878929ab3f2d727f9ae47c69f729f1" + dsc_url: "local:modemmanager.dsc" + dsc_sha256: "f2a0a21fdce6619bf874ab182385225c65b82d217d6b6ed20933ded5c375fa1c" + dsc_signer: "Guido Günther " + dsc_checksums_sha256: | + 63ded4c0f3936bb0db5ae35ef1dfd57c5d5b4dd8a5cdaa7fb2182255218c9168 1361836 modemmanager_1.24.0.orig.tar.xz + 7585e8cf6fb920e516372ed54d8f5c3d2faf1ffec920ec90fb550b9aaa11de12 36680 modemmanager_1.24.0-1.debian.tar.xz diff --git a/packaging/ci/test-verify-upstream-pins.sh b/packaging/ci/test-verify-upstream-pins.sh new file mode 100755 index 0000000..d10d1c5 --- /dev/null +++ b/packaging/ci/test-verify-upstream-pins.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# test-verify-upstream-pins.sh — executable proof that verify-upstream-pins.sh FAILS CLOSED. +# +# Runs the three negative fixtures under ci/fixtures/ and asserts that each makes the verifier +# exit non-zero AND print the correct NAMED failing field on stderr: +# +# wrong-signer -> FAIL [modemmanager] signer_fingerprint: signer mismatch … +# altered-dsc -> FAIL [modemmanager] dsc_signature: signature invalid (BADSIG) … +# altered-orig -> FAIL [modemmanager] orig_tar_sha256: checksum mismatch … +# +# Fixtures are OFFLINE: they use `local:` URLs (files packaged next to each fixture manifest) +# and are run with --no-lineage, so this test needs no network and isolates the one tamper it +# targets. The real acceptance run (verify-upstream-pins.sh with no flags) does the full +# network verification and is exercised by ci/contract.sh, not here. +set -uo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PKG_ROOT="$(cd "$HERE/.." && pwd)" # packaging/ (holds keys/) +FIX="$HERE/fixtures" +VERIFY="$HERE/verify-upstream-pins.sh" + +rc=0 + +# assert_reject +# Runs the verifier on /pins.yaml and requires: non-zero exit, a +# `FAIL [..] :` line, and somewhere in stderr. +assert_reject() { + local dir="$1" field="$2" needle="$3" + local manifest="$FIX/$dir/pins.yaml" out ec + out="$(bash "$VERIFY" --no-lineage --source modemmanager --keys-base "$PKG_ROOT" "$manifest" 2>&1)" + ec=$? + if [ "$ec" -eq 0 ]; then + echo "FAIL: '$dir' unexpectedly PASSED (exit 0) — fail-closed broken" + rc=1 + return + fi + if ! printf '%s\n' "$out" | grep -q "FAIL \[modemmanager\] $field:"; then + echo "FAIL: '$dir' rejected but not on field '$field'; got:" + printf ' %s\n' "$out" | tail -1 + rc=1 + return + fi + if ! printf '%s\n' "$out" | grep -qi "$needle"; then + echo "FAIL: '$dir' rejected on '$field' but message lacked '$needle'" + rc=1 + return + fi + echo "ok: REJECT '$dir' (exit $ec) -> $(printf '%s\n' "$out" | grep -o "FAIL \[modemmanager\] $field:.*" | sed 's/^FAIL \[modemmanager\] //')" +} + +assert_reject wrong-signer signer_fingerprint "signer mismatch" +assert_reject altered-dsc dsc_signature "signature invalid" +assert_reject altered-orig orig_tar_sha256 "checksum mismatch" + +if [ "$rc" -eq 0 ]; then + echo "PASS: verify-upstream-pins fails closed on wrong-signer / altered-.dsc / altered-.orig.tar" +else + echo "FAIL: fail-closed contract violated" +fi +exit "$rc" diff --git a/packaging/ci/verify-upstream-pins.sh b/packaging/ci/verify-upstream-pins.sh new file mode 100755 index 0000000..9257add --- /dev/null +++ b/packaging/ci/verify-upstream-pins.sh @@ -0,0 +1,254 @@ +#!/usr/bin/env bash +# verify-upstream-pins.sh — re-verify every field in packaging/upstream-pins.yaml. +# +# Proves the provenance chain for the four ModemManager-stack sources CeraLive rebuilds: +# +# 1. LINEAGE — `git ls-remote --tags ` still resolves to +# the pinned tag-object SHA and peeled commit SHA (and the same for the +# salsa packaging tag). The git tag authenticates *which commit* the release +# names; it is never byte-compared to a git archive. +# 2. AUTHORITY — the signed Debian `.dsc`'s GPG clearsign verifies against the pinned +# `signer_fingerprint`, whose armored key lives in packaging/keys/. A verified +# `.dsc` is the authority for the tarball checksums it embeds. +# 3. ARTIFACT — the `.orig.tar` downloads and its sha256 equals `orig_tar_sha256`, which +# equals the matching line in the `.dsc`'s Checksums-Sha256 (copied verbatim +# into the manifest's `dsc_checksums_sha256`). Chain closed. +# +# ALL GPG work happens in a throwaway isolated GNUPGHOME (mktemp -d, 0700, rm -rf on exit). +# The caller's ~/.gnupg is never touched or read. +# +# Exit status: +# 0 every field of every checked source verified. +# 1 a verification failure — a single line `FAIL [] : ` on stderr +# names exactly which field failed (fail-closed). +# 2 usage / environment error (missing tool, unreadable manifest). +# +# Usage: +# verify-upstream-pins.sh [OPTIONS] [MANIFEST] +# MANIFEST path to the pin manifest (default: