diff --git a/.github/runtime-unfixed.json b/.github/runtime-unfixed.json new file mode 100644 index 0000000..42fb294 --- /dev/null +++ b/.github/runtime-unfixed.json @@ -0,0 +1,676 @@ +{ + "repository": "PastureStack/system-image-preloader", + "unfixed": [ + { + "severity": "MEDIUM", + "package": "dash", + "id": "CVE-2026-102473", + "purl": "pkg:deb/ubuntu/dash@0.5.12-12ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.5.12-12ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-102473", + "reason": "Canonical Ubuntu 26.04 status: resolute_dash: deferred (2026-10-15). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "dash", + "id": "CVE-2026-102474", + "purl": "pkg:deb/ubuntu/dash@0.5.12-12ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.5.12-12ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-102474", + "reason": "Canonical Ubuntu 26.04 status: resolute_dash: deferred (2026-10-15). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libc-bin", + "id": "CVE-2026-18374", + "purl": "pkg:deb/ubuntu/libc-bin@2.43-2ubuntu2.4?arch=amd64&distro=ubuntu-26.04", + "version": "2.43-2ubuntu2.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-18374", + "reason": "Canonical Ubuntu 26.04 status: resolute_glibc: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libc-bin", + "id": "CVE-2026-89092", + "purl": "pkg:deb/ubuntu/libc-bin@2.43-2ubuntu2.4?arch=amd64&distro=ubuntu-26.04", + "version": "2.43-2ubuntu2.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89092", + "reason": "Canonical Ubuntu 26.04 status: resolute_glibc: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libc-gconv-modules-extra", + "id": "CVE-2026-18374", + "purl": "pkg:deb/ubuntu/libc-gconv-modules-extra@2.43-2ubuntu2.4?arch=amd64&distro=ubuntu-26.04", + "version": "2.43-2ubuntu2.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-18374", + "reason": "Canonical Ubuntu 26.04 status: resolute_glibc: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libc-gconv-modules-extra", + "id": "CVE-2026-89092", + "purl": "pkg:deb/ubuntu/libc-gconv-modules-extra@2.43-2ubuntu2.4?arch=amd64&distro=ubuntu-26.04", + "version": "2.43-2ubuntu2.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89092", + "reason": "Canonical Ubuntu 26.04 status: resolute_glibc: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libc6", + "id": "CVE-2026-18374", + "purl": "pkg:deb/ubuntu/libc6@2.43-2ubuntu2.4?arch=amd64&distro=ubuntu-26.04", + "version": "2.43-2ubuntu2.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-18374", + "reason": "Canonical Ubuntu 26.04 status: resolute_glibc: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libc6", + "id": "CVE-2026-89092", + "purl": "pkg:deb/ubuntu/libc6@2.43-2ubuntu2.4?arch=amd64&distro=ubuntu-26.04", + "version": "2.43-2ubuntu2.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89092", + "reason": "Canonical Ubuntu 26.04 status: resolute_glibc: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libgnutls30t64", + "id": "CVE-2026-67693", + "purl": "pkg:deb/ubuntu/libgnutls30t64@3.8.12-2ubuntu1.1?arch=amd64&distro=ubuntu-26.04", + "version": "3.8.12-2ubuntu1.1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-67693", + "reason": "Canonical Ubuntu 26.04 status: resolute_gnutls28: deferred (2026-10-15). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libgnutls30t64", + "id": "CVE-2026-88647", + "purl": "pkg:deb/ubuntu/libgnutls30t64@3.8.12-2ubuntu1.1?arch=amd64&distro=ubuntu-26.04", + "version": "3.8.12-2ubuntu1.1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-88647", + "reason": "Canonical Ubuntu 26.04 status: resolute_gnutls28: deferred (2026-10-15). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libgnutls30t64", + "id": "CVE-2026-88648", + "purl": "pkg:deb/ubuntu/libgnutls30t64@3.8.12-2ubuntu1.1?arch=amd64&distro=ubuntu-26.04", + "version": "3.8.12-2ubuntu1.1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-88648", + "reason": "Canonical Ubuntu 26.04 status: resolute_gnutls28: deferred (2026-10-15). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libgnutls30t64", + "id": "CVE-2026-95184", + "purl": "pkg:deb/ubuntu/libgnutls30t64@3.8.12-2ubuntu1.1?arch=amd64&distro=ubuntu-26.04", + "version": "3.8.12-2ubuntu1.1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-95184", + "reason": "Canonical Ubuntu 26.04 status: resolute_gnutls28: deferred (2026-10-15). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libgnutls30t64", + "id": "CVE-2026-95209", + "purl": "pkg:deb/ubuntu/libgnutls30t64@3.8.12-2ubuntu1.1?arch=amd64&distro=ubuntu-26.04", + "version": "3.8.12-2ubuntu1.1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-95209", + "reason": "Canonical Ubuntu 26.04 status: resolute_gnutls28: deferred (2026-10-15). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libgnutls30t64", + "id": "CVE-2026-95210", + "purl": "pkg:deb/ubuntu/libgnutls30t64@3.8.12-2ubuntu1.1?arch=amd64&distro=ubuntu-26.04", + "version": "3.8.12-2ubuntu1.1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-95210", + "reason": "Canonical Ubuntu 26.04 status: resolute_gnutls28: deferred (2026-10-15). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libp11-kit0", + "id": "CVE-2026-13757", + "purl": "pkg:deb/ubuntu/libp11-kit0@0.26.2-2?arch=amd64&distro=ubuntu-26.04", + "version": "0.26.2-2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-13757", + "reason": "Canonical Ubuntu 26.04 status: resolute_p11-kit: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libpcre2-8-0", + "id": "CVE-2026-103111", + "purl": "pkg:deb/ubuntu/libpcre2-8-0@10.46-1build1?arch=amd64&distro=ubuntu-26.04", + "version": "10.46-1build1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-103111", + "reason": "Canonical Ubuntu 26.04 status: resolute_pcre2: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libpcre2-8-0", + "id": "CVE-2026-86145", + "purl": "pkg:deb/ubuntu/libpcre2-8-0@10.46-1build1?arch=amd64&distro=ubuntu-26.04", + "version": "10.46-1build1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-86145", + "reason": "Canonical Ubuntu 26.04 status: resolute_pcre2: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libpcre2-8-0", + "id": "CVE-2026-89156", + "purl": "pkg:deb/ubuntu/libpcre2-8-0@10.46-1build1?arch=amd64&distro=ubuntu-26.04", + "version": "10.46-1build1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89156", + "reason": "Canonical Ubuntu 26.04 status: resolute_pcre2: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libpcre2-8-0", + "id": "CVE-2026-89157", + "purl": "pkg:deb/ubuntu/libpcre2-8-0@10.46-1build1?arch=amd64&distro=ubuntu-26.04", + "version": "10.46-1build1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89157", + "reason": "Canonical Ubuntu 26.04 status: resolute_pcre2: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libpcre2-8-0", + "id": "CVE-2026-89158", + "purl": "pkg:deb/ubuntu/libpcre2-8-0@10.46-1build1?arch=amd64&distro=ubuntu-26.04", + "version": "10.46-1build1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89158", + "reason": "Canonical Ubuntu 26.04 status: resolute_pcre2: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libpcre2-8-0", + "id": "CVE-2026-89160", + "purl": "pkg:deb/ubuntu/libpcre2-8-0@10.46-1build1?arch=amd64&distro=ubuntu-26.04", + "version": "10.46-1build1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89160", + "reason": "Canonical Ubuntu 26.04 status: resolute_pcre2: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libpcre2-8-0", + "id": "CVE-2026-89161", + "purl": "pkg:deb/ubuntu/libpcre2-8-0@10.46-1build1?arch=amd64&distro=ubuntu-26.04", + "version": "10.46-1build1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89161", + "reason": "Canonical Ubuntu 26.04 status: resolute_pcre2: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libpcre2-8-0", + "id": "CVE-2026-89162", + "purl": "pkg:deb/ubuntu/libpcre2-8-0@10.46-1build1?arch=amd64&distro=ubuntu-26.04", + "version": "10.46-1build1", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-89162", + "reason": "Canonical Ubuntu 26.04 status: resolute_pcre2: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libsasl2-2", + "id": "CVE-2026-107161", + "purl": "pkg:deb/ubuntu/libsasl2-2@2.1.28%2Bdfsg1-9ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "2.1.28+dfsg1-9ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-107161", + "reason": "Canonical Ubuntu 26.04 status: resolute_cyrus-sasl2: deferred (2026-10-14). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libsasl2-modules-db", + "id": "CVE-2026-107161", + "purl": "pkg:deb/ubuntu/libsasl2-modules-db@2.1.28%2Bdfsg1-9ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "2.1.28+dfsg1-9ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-107161", + "reason": "Canonical Ubuntu 26.04 status: resolute_cyrus-sasl2: deferred (2026-10-14). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "LOW", + "package": "libsystemd0", + "id": "CVE-2026-40228", + "purl": "pkg:deb/ubuntu/libsystemd0@259.5-0ubuntu3.4?arch=amd64&distro=ubuntu-26.04", + "version": "259.5-0ubuntu3.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-40228", + "reason": "Canonical Ubuntu 26.04 status: resolute_systemd: deferred (2026-06-05). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "LOW", + "package": "libudev1", + "id": "CVE-2026-40228", + "purl": "pkg:deb/ubuntu/libudev1@259.5-0ubuntu3.4?arch=amd64&distro=ubuntu-26.04", + "version": "259.5-0ubuntu3.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-40228", + "reason": "Canonical Ubuntu 26.04 status: resolute_systemd: deferred (2026-06-05). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "LOW", + "package": "login.defs", + "id": "CVE-2024-56433", + "purl": "pkg:deb/ubuntu/login.defs@4.17.4-2ubuntu3?arch=all&distro=ubuntu-26.04&epoch=1", + "version": "1:4.17.4-2ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2024-56433", + "reason": "Canonical Ubuntu 26.04 status: resolute_shadow: deferred (2026-08-31). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "LOW", + "package": "passwd", + "id": "CVE-2024-56433", + "purl": "pkg:deb/ubuntu/passwd@4.17.4-2ubuntu3?arch=amd64&distro=ubuntu-26.04&epoch=1", + "version": "1:4.17.4-2ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2024-56433", + "reason": "Canonical Ubuntu 26.04 status: resolute_shadow: deferred (2026-08-31). No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35341", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35341", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35344", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35344", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35345", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35345", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35348", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35348", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35350", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35350", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35351", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35351", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35352", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35352", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35354", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35354", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35357", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35357", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35359", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35359", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35360", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35360", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35363", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35363", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35364", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35364", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35367", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35367", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35368", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35368", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35370", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35370", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35371", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35371", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35373", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35373", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35374", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35374", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "rust-coreutils", + "id": "CVE-2026-35377", + "purl": "pkg:deb/ubuntu/rust-coreutils@0.8.0-0ubuntu3?arch=amd64&distro=ubuntu-26.04", + "version": "0.8.0-0ubuntu3", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-35377", + "reason": "Canonical Ubuntu 26.04 status: resolute_rust-coreutils: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "tar", + "id": "CVE-2026-18477", + "purl": "pkg:deb/ubuntu/tar@1.35%2Bdfsg-4ubuntu0.4?arch=amd64&distro=ubuntu-26.04", + "version": "1.35+dfsg-4ubuntu0.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-18477", + "reason": "Canonical Ubuntu 26.04 status: resolute_tar: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "tar", + "id": "CVE-2026-18508", + "purl": "pkg:deb/ubuntu/tar@1.35%2Bdfsg-4ubuntu0.4?arch=amd64&distro=ubuntu-26.04", + "version": "1.35+dfsg-4ubuntu0.4", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-18508", + "reason": "Canonical Ubuntu 26.04 status: resolute_tar: needed. No official resolute fixed package is available; keep tracking.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "jq", + "id": "CVE-2026-41256", + "purl": "pkg:deb/ubuntu/jq@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-41256", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "jq", + "id": "CVE-2026-41257", + "purl": "pkg:deb/ubuntu/jq@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-41257", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "jq", + "id": "CVE-2026-43895", + "purl": "pkg:deb/ubuntu/jq@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-43895", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "jq", + "id": "CVE-2026-43896", + "purl": "pkg:deb/ubuntu/jq@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-43896", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "jq", + "id": "CVE-2026-44777", + "purl": "pkg:deb/ubuntu/jq@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-44777", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libjq1", + "id": "CVE-2026-41256", + "purl": "pkg:deb/ubuntu/libjq1@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-41256", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libjq1", + "id": "CVE-2026-41257", + "purl": "pkg:deb/ubuntu/libjq1@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-41257", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libjq1", + "id": "CVE-2026-43895", + "purl": "pkg:deb/ubuntu/libjq1@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-43895", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libjq1", + "id": "CVE-2026-43896", + "purl": "pkg:deb/ubuntu/libjq1@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-43896", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + }, + { + "severity": "MEDIUM", + "package": "libjq1", + "id": "CVE-2026-44777", + "purl": "pkg:deb/ubuntu/libjq1@1.8.1-4ubuntu2?arch=amd64&distro=ubuntu-26.04", + "version": "1.8.1-4ubuntu2", + "status": "no_official_fix", + "officialEvidence": "https://git.launchpad.net/ubuntu-cve-tracker/plain/active/CVE-2026-44777", + "reason": "Canonical resolute_jq: needed, checked 2026-10-23. No official Ubuntu 26.04 fixed package is available; upstream patches do not change this distribution package's status.", + "checkedAt": "2026-10-23" + } + ] +} diff --git a/.github/workflows/security-build.yml b/.github/workflows/security-build.yml index dd63984..1a6a70c 100644 --- a/.github/workflows/security-build.yml +++ b/.github/workflows/security-build.yml @@ -35,14 +35,28 @@ jobs: set -euo pipefail test "$(go env GOVERSION)" = go1.27.3 make validate test + python3 -B scripts/test-runtime-vulnerability-policy.py -v + python3 -B tests/test_runtime_security_review.py -v make build smoke integration - name: Retain the exact verified runtime shell: bash run: | set -euo pipefail mkdir -p dist/security-runtime - docker image inspect local/system-image-preloader:v0.3.1 > dist/security-runtime/images.json - docker save local/system-image-preloader:v0.3.1 | gzip -n > dist/security-runtime/images.tar.gz + docker image inspect local/system-image-preloader:v0.3.2 > dist/security-runtime/images.json + container=$(docker create --entrypoint /bin/true local/system-image-preloader:v0.3.2) + trap 'docker rm -f "$container" >/dev/null 2>&1 || true' EXIT + docker cp "$container:/licenses/third-party/security/." dist/security-runtime/ + docker cp "$container:/usr/local/bin/docker" dist/security-runtime/docker-cli + docker run --rm --network none --entrypoint sha256sum \ + local/system-image-preloader:v0.3.2 /usr/local/bin/docker \ + > dist/security-runtime/docker-sha256.txt + python3 -B tests/docker_manifest_digest_proof.py \ + > dist/security-runtime/docker-manifest-digest-proof.json + rm dist/security-runtime/docker-cli + docker rm "$container" >/dev/null + trap - EXIT + docker save local/system-image-preloader:v0.3.2 | gzip -n > dist/security-runtime/images.tar.gz printf '%s\n' "$GITHUB_SHA" > dist/security-runtime/source-revision.txt (cd dist/security-runtime && sha256sum images.json images.tar.gz source-revision.txt > SHA256SUMS) - name: Scan the exact runtime and generate its SBOM @@ -51,13 +65,15 @@ jobs: set -euo pipefail scanner=aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969 docker pull "$scanner" - for runtime in local/system-image-preloader:v0.3.1; do + for runtime in local/system-image-preloader:v0.3.2; do name=${runtime##*/}; name=${name%%:*} docker save "$runtime" --output "$RUNNER_TEMP/$name.tar" - docker run --rm -v "$RUNNER_TEMP/$name.tar:/image.tar:ro" -v "$PWD/dist/security-runtime:/evidence" "$scanner" image --input /image.tar --scanners vuln,secret --severity HIGH,CRITICAL --exit-code 1 --format json --output "/evidence/$name-security.json" + docker run --rm -v "$RUNNER_TEMP/$name.tar:/image.tar:ro" -v "$PWD/dist/security-runtime:/evidence" "$scanner" image --input /image.tar --scanners vuln,secret --list-all-pkgs --format json --output "/evidence/$name-security.json" docker run --rm -v "$RUNNER_TEMP/$name.tar:/image.tar:ro" -v "$PWD/dist/security-runtime:/evidence" "$scanner" image --input /image.tar --format cyclonedx --output "/evidence/$name-sbom.cdx.json" done - (cd dist/security-runtime && sha256sum -- *.json images.tar.gz source-revision.txt > SHA256SUMS) + python3 -B scripts/review-runtime-security.py + python3 -B scripts/enforce-runtime-vulnerabilities.py --phase runtime + (cd dist/security-runtime && sha256sum -- *.json *.txt images.tar.gz > SHA256SUMS) - name: Upload verified runtime and checksums if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -78,7 +94,7 @@ jobs: packages: write env: GH_TOKEN: ${{ github.token }} - RELEASE_TAG: v0.3.1 + RELEASE_TAG: v0.3.2 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: @@ -97,7 +113,7 @@ jobs: printf '%s' "$GH_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin trap 'docker logout ghcr.io >/dev/null 2>&1 || true' EXIT : > dist/security-runtime/registry-images.jsonl - local_image='local/system-image-preloader:v0.3.1' + local_image='local/system-image-preloader:v0.3.2' remote_image="ghcr.io/pasturestack/system-image-preloader:$RELEASE_TAG" if docker manifest inspect "$remote_image" >/dev/null 2>"$RUNNER_TEMP/manifest-error"; then echo "Refusing to replace an existing immutable image tag: $remote_image" >&2; exit 1 diff --git a/Dockerfile b/Dockerfile index 9eea8af..2684d88 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,9 +10,10 @@ ARG YQ_VERSION=v4.53.3 ARG YQ_GIT_COMMIT=1b9b4ac5187171d2e5e3129be0cfa827c7f9d53d ARG GOMPLATE_VERSION=v5.1.0 ARG GOMPLATE_GIT_COMMIT=0f4c15bc8521939478426bf6ffca4718837b9cb4 -ARG DOCKER_VERSION=29.4.2 -ARG DOCKER_GIT_COMMIT=055a478ea9010a19d0d4674c0d0e87ade37a4223 -ARG DOCKER_SOURCE_DATE_EPOCH=1776697064 +ARG DOCKER_VERSION=29.9.2 +ARG DOCKER_GIT_COMMIT=a82e528901260c8df6073311379eac65f92db204 +ARG DOCKER_ARCHIVE_SHA256=9ac225999fd5e863f7694c728ef23d480616b1e5639328fa309befd4243d69eb +ARG DOCKER_BINARY_SHA256=6c71cfe71faff949a602946a4df4799b563232e79d0b8b6fd343d0ef081c9621 ARG UBUNTU_SNAPSHOT=20260825T000000Z ADD --checksum=sha256:5b6326f1932cfd7be57130561dc78192f09ed9f58bfbe6606ed0c50510c3b6cd \ @@ -86,44 +87,36 @@ RUN set -eux; \ github.com/go-git/go-git/v5@v5.19.2 \ golang.org/x/crypto@v0.57.0 \ golang.org/x/net@v0.60.0 \ + go.opentelemetry.io/otel/sdk@v1.45.0 \ google.golang.org/grpc@v1.83.2; \ go mod tidy; \ test "$(go list -m -f '{{.Version}}' golang.org/x/net)" = v0.60.0; \ + test "$(go list -m -f '{{.Version}}' go.opentelemetry.io/otel/sdk)" = v1.45.0; \ + mkdir -p /out/licenses/security; \ + go list -deps -f '{{.ImportPath}}' ./cmd/gomplate > /out/licenses/security/gomplate-dependencies.txt; \ + ! grep -Eq '^golang.org/x/crypto/openpgp(/|$)' /out/licenses/security/gomplate-dependencies.txt; \ go build -trimpath -buildvcs=false \ -ldflags "-s -w -X github.com/hairyhenderson/gomplate/v5/version.Version=${GOMPLATE_VERSION} -X github.com/hairyhenderson/gomplate/v5/version.GitCommit=${GOMPLATE_GIT_COMMIT}" \ -o /out/gomplate ./cmd/gomplate; \ cp LICENSE /out/licenses/gomplate/LICENSE; \ /out/gomplate --version; \ go version -m /out/gomplate | grep -F 'golang.org/x/net'; \ + go version -m /out/gomplate > /out/licenses/security/gomplate-buildinfo.txt; \ rm -rf /src/gomplate /tmp/go-build-cache /tmp/go-mod-cache RUN set -eux; \ mkdir -p /out/licenses/docker-cli; \ - mkdir -p /go/src/github.com/docker; \ - git clone --branch "v${DOCKER_VERSION}" --depth 1 \ - https://github.com/docker/cli /go/src/github.com/docker/cli; \ - cd /go/src/github.com/docker/cli; \ - test "$(git rev-parse HEAD)" = "${DOCKER_GIT_COMMIT}"; \ - cp vendor.mod go.mod; \ - cp vendor.sum go.sum; \ - go get golang.org/x/net@v0.60.0 \ - github.com/klauspost/compress@v1.18.7 \ - github.com/moby/go-archive@v0.3.0 \ - google.golang.org/grpc@v1.83.2; \ - go mod vendor; \ - test "$(go list -m -f '{{.Version}}' golang.org/x/net)" = v0.60.0; \ - CGO_ENABLED=0 \ - GOPATH=/go \ - GO_STRIP=1 \ - GITCOMMIT="${DOCKER_GIT_COMMIT}" \ - SOURCE_DATE_EPOCH="${DOCKER_SOURCE_DATE_EPOCH}" \ - TARGET=/out \ - VERSION="${DOCKER_VERSION}" \ - ./scripts/build/binary; \ - test -x /out/docker; \ - cp LICENSE NOTICE /out/licenses/docker-cli/; \ + git clone --branch "v${DOCKER_VERSION}" --depth 1 https://github.com/docker/cli /src/docker-cli; \ + test "$(git -C /src/docker-cli rev-parse HEAD)" = "${DOCKER_GIT_COMMIT}"; \ + cp /src/docker-cli/LICENSE /src/docker-cli/NOTICE /out/licenses/docker-cli/; \ + curl -fsSL --retry 5 --retry-all-errors --connect-timeout 10 --max-time 300 \ + -o /tmp/docker.tgz "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz"; \ + echo "${DOCKER_ARCHIVE_SHA256} /tmp/docker.tgz" | sha256sum -c -; \ + tar -xOf /tmp/docker.tgz docker/docker > /out/docker; \ + echo "${DOCKER_BINARY_SHA256} /out/docker" | sha256sum -c -; \ + chmod +x /out/docker; \ /out/docker --version; \ - rm -rf /go/src/github.com/docker/cli /tmp/go-build-cache /tmp/go-mod-cache + rm -rf /src/docker-cli /tmp/docker.tgz FROM ${UBUNTU_IMAGE} diff --git a/Makefile b/Makefile index a24858c..67b4048 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Created by PastureStack contributors for repeatable validation. -VERSION ?= v0.3.1 +VERSION ?= v0.3.2 REVISION ?= $(shell git rev-parse HEAD) IMAGE_REPOSITORY ?= local/system-image-preloader IMAGE ?= $(IMAGE_REPOSITORY):$(VERSION) diff --git a/README.md b/README.md index b703a68..f83939b 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ This repository is a derivative maintenance project. It preserves the upstream G ## Reviewed release -The `v0.3.1` release provides: +The `v0.3.2` release provides: - a self-contained public build based on a digest-pinned Ubuntu image; - the `system-image-preloader` executable and image name; - a checksum-verified Go toolchain download; -- source-pinned Docker CLI, `yq`, and `gomplate` builds; +- checksum-pinned official Docker CLI and source-pinned `yq`/`gomplate` builds; - a finite, configurable image-pull retry policy; - offline retry and URL-contract tests; - offline `--help` and `--version` smoke paths; and @@ -54,7 +54,8 @@ make smoke ``` The build needs internet access only for the pinned public Ubuntu base, Go -archive, and pinned Docker CLI, `yq`, and `gomplate` source trees. +archive, official Docker CLI archive and license source, and pinned `yq` and +`gomplate` source trees. Run the isolated API-to-Docker integration test on a disposable Docker host: @@ -72,7 +73,7 @@ restores the image-presence state. It never performs a broad image prune. Use the immutable semantic tag: ```text -ghcr.io/pasturestack/system-image-preloader:v0.3.1 +ghcr.io/pasturestack/system-image-preloader:v0.3.2 ``` The deployment definition must mount `/var/run/docker.sock`, run one instance @@ -118,6 +119,20 @@ This project is a background service with no user interface or runtime localizat ## October 2026 security maintenance -The source-built yq, gomplate, and Docker CLI helpers select `golang.org/x/net v0.60.0` for the October HTTP/2 fixes. Their scanned runtime module graph also pins official security fixes: x/text 0.42.0, go-git 5.19.2, grpc-go 1.83.2, klauspost/compress 1.18.7, and moby/go-archive 0.3.0. Upstream helper feature versions stay unchanged; CI exercises the rebuilt helpers and scans the actual final runtime. +Source-built yq and gomplate select `golang.org/x/net v0.60.0` for the October HTTP/2 fixes, with x/text 0.42.0, go-git 5.19.2 and grpc-go 1.83.2 where applicable. Their upstream feature versions stay unchanged. The official Docker CLI 29.9.2 is pinned by archive and executable SHA-256 and carries the vendor's patched Go 1.26.10 compiler; its exact source is commit `a82e528901260c8df6073311379eac65f92db204`. CI exercises these exact helpers and scans the actual final runtime. Maintained Go builds select the patched Go 1.27.3 compiler without raising the existing Go language requirement. Ubuntu build/runtime stages apply the checksum-pinned `ca-certificates 20260816ubuntu0.26.04.1` security package after their frozen APT baseline; the final trust store and installed version are verified. Release artifacts must pass the repository's existing checks before publication. + +The 0.3.2 rebuild pins gomplate's affected OpenTelemetry SDK to official 1.45.0 +(CVE-2026-81870) and adopts the checksum-pinned official Docker CLI 29.9.2, +within the existing 29.x series. The daemon and gomplate 5.1.0 are unchanged. +Every scan severity is retained. Any available fix or unreviewed +finding blocks publication; Low/Medium vendor-unfixed entries require an exact +package/version/PURL and official branch-specific no-fix evidence. The only +OpenPGP non-applicability decision requires the exact built gomplate package +graph to exclude all deprecated OpenPGP packages; raw findings remain retained. +Docker's distribution finding is scoped to the exact official CLI bytes: its +existing manifest-digest validation was independently tested with valid and +forged schema2, OCI, and manifest-list responses. This is a CLI mitigation, not +a claim that the underlying distribution package is fixed. Missing Go module +metadata in the official binary does not imply that dependencies are absent. diff --git a/SECURITY.md b/SECURITY.md index 502e9de..0115924 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Project status -PastureStack System Image Preloader is an independent compatibility maintenance project. Release `v0.3.0` has completed offline policy tests, container smoke tests, an isolated compatibility API-to-Docker cache lifecycle test, and a HIGH/CRITICAL container vulnerability gate. +PastureStack System Image Preloader is an independent compatibility maintenance project. Release candidates require offline policy tests, container smoke tests, an isolated compatibility API-to-Docker cache lifecycle test, and a full-severity container vulnerability gate. Every available fix, unreviewed Low/Medium finding, High/Critical/Unknown finding, or secret blocks publication. Exact official branch-specific no-fix evidence may admit Low/Medium findings; a narrowly scoped OpenPGP decision additionally requires proof that the affected packages are absent from the built gomplate dependency graph. Raw scans are always retained. ## Reporting a vulnerability diff --git a/scripts/enforce-runtime-vulnerabilities.py b/scripts/enforce-runtime-vulnerabilities.py new file mode 100644 index 0000000..7f97409 --- /dev/null +++ b/scripts/enforce-runtime-vulnerabilities.py @@ -0,0 +1,61 @@ +"""Enforce release findings; only exact, reviewed unfixed low/medium entries may pass.""" +import argparse +import json +from pathlib import Path + +REPOSITORY = "PastureStack/system-image-preloader" +ROOT = Path(__file__).resolve().parent.parent +REPORTS = {"runtime": ROOT / "dist/security-runtime/system-image-preloader-security-effective.json"} +LEDGER = ROOT / ".github/runtime-unfixed.json" + + +def violations(report, ledger, repository): + if (not isinstance(report, dict) or report.get("SchemaVersion") != 2 + or not isinstance(report.get("Results"), list) or not report["Results"]): + raise ValueError("missing or malformed Trivy scan results") + for result in report["Results"]: + if not isinstance(result, dict) or not isinstance(result.get("Target"), str): + raise ValueError("malformed Trivy result") + for key in ("Vulnerabilities", "Secrets"): + if key in result and result[key] is not None and not isinstance(result[key], list): + raise ValueError("malformed Trivy findings") + if ledger.get("repository") != repository: + raise ValueError("allowlist repository mismatch") + reviewed = {} + for entry in ledger.get("unfixed", []): + key = (entry["id"], entry["package"], entry["version"], entry.get("purl", "")) + if key in reviewed: + raise ValueError("duplicate reviewed finding") + if (entry.get("severity") not in ("LOW", "MEDIUM") + or entry.get("status") != "no_official_fix" + or not entry.get("officialEvidence", "").startswith("https://") + or not entry.get("reason") or not entry.get("checkedAt")): + raise ValueError("incomplete official no-fix evidence") + reviewed[key] = entry + errors = [] + for result in report.get("Results") or []: + if result.get("Secrets"): + errors.append("secret findings remain") + for finding in result.get("Vulnerabilities") or []: + severity = finding.get("Severity", "UNKNOWN") + key = (finding.get("VulnerabilityID"), finding.get("PkgName"), + finding.get("InstalledVersion"), + (finding.get("PkgIdentifier") or {}).get("PURL", "")) + entry = reviewed.get(key) + fixed = str(finding.get("FixedVersion") or "").strip() + if (severity not in ("LOW", "MEDIUM") or fixed + or entry is None or entry["severity"] != severity): + errors.append("%s %s@%s severity=%s fixed=%s" % ( + key[0], key[1], key[2], severity, fixed or "none")) + return errors + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--phase", choices=tuple(REPORTS), required=True) + args = parser.parse_args() + failures = violations(json.loads(REPORTS[args.phase].read_text(encoding="utf-8")), + json.loads(LEDGER.read_text(encoding="utf-8")), REPOSITORY) + if failures: + raise SystemExit("Release vulnerability policy failed:\n" + "\n".join(failures)) + print("RELEASE_VULNERABILITY_POLICY_OK") diff --git a/scripts/integration-smoke b/scripts/integration-smoke index f1c1390..a0bb7d2 100755 --- a/scripts/integration-smoke +++ b/scripts/integration-smoke @@ -4,7 +4,7 @@ set -Eeuo pipefail PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -IMAGE="${IMAGE:-local/system-image-preloader:v0.3.1}" +IMAGE="${IMAGE:-local/system-image-preloader:v0.3.2}" TEST_PULL_IMAGE="${TEST_PULL_IMAGE:-ghcr.io/pasturestack/container-cron:v0.6.0}" PLATFORM_VERSION="${PLATFORM_VERSION:-v1.6.281}" ACCESS_KEY="integration-access" diff --git a/scripts/review-runtime-security.py b/scripts/review-runtime-security.py new file mode 100644 index 0000000..5fb6105 --- /dev/null +++ b/scripts/review-runtime-security.py @@ -0,0 +1,122 @@ +"""Review exact runtime evidence; never suppress a whole module or severity.""" +import copy +import importlib.util +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +EVIDENCE = ROOT / 'dist/security-runtime' +CRYPTO_PURL = 'pkg:golang/golang.org/x/crypto@v0.57.0' +DOCKER_SHA256 = '6c71cfe71faff949a602946a4df4799b563232e79d0b8b6fd343d0ef081c9621' +DISTRIBUTION_PURL = 'pkg:golang/github.com/docker/distribution@v2.8.3%2Bincompatible' +SPEC = importlib.util.spec_from_file_location( + 'policy', ROOT / 'scripts/enforce-runtime-vulnerabilities.py') +POLICY = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(POLICY) + + +def module_version(info, name): + matches = [line.split()[2] for line in info.splitlines() + if len(line.split()) >= 3 + and line.split()[:2] == ['dep', name]] + if len(matches) != 1: + raise ValueError('missing or duplicate build module: ' + name) + return matches[0] + + +def review(report, dependencies, gomplate_info, docker_sha256, image_id): + imports = dependencies.splitlines() + if ('github.com/hairyhenderson/gomplate/v5/cmd/gomplate' not in imports + or any(name == 'golang.org/x/crypto/openpgp' + or name.startswith('golang.org/x/crypto/openpgp/') + for name in imports)): + raise ValueError('gomplate OpenPGP package-absence proof failed') + if module_version(gomplate_info, 'golang.org/x/crypto') != 'v0.57.0': + raise ValueError('gomplate crypto identity changed') + if module_version(gomplate_info, 'go.opentelemetry.io/otel/sdk') != 'v1.45.0': + raise ValueError('OpenTelemetry security pin changed') + if docker_sha256.split() != [DOCKER_SHA256, '/usr/local/bin/docker']: + raise ValueError('official Docker CLI identity changed') + effective = copy.deepcopy(report) + removed = [] + for result in effective.get('Results') or []: + retained = [] + for finding in result.get('Vulnerabilities') or []: + if (result.get('Target') == 'usr/local/bin/gomplate' + and finding.get('VulnerabilityID') == 'GO-2026-5932' + and finding.get('PkgName') == 'golang.org/x/crypto' + and finding.get('InstalledVersion') == 'v0.57.0' + and finding.get('Severity') == 'UNKNOWN' + and not finding.get('FixedVersion') + and (finding.get('PkgIdentifier') or {}).get('PURL') == CRYPTO_PURL): + removed.append(finding) + elif (result.get('Target') == 'usr/local/bin/docker' + and finding.get('VulnerabilityID') == 'CVE-2026-85747' + and finding.get('PkgName') == 'github.com/docker/distribution' + and finding.get('InstalledVersion') == 'v2.8.3+incompatible' + and finding.get('Severity') == 'MEDIUM' + and not finding.get('FixedVersion') + and (finding.get('PkgIdentifier') or {}).get('PURL') == DISTRIBUTION_PURL): + # Exact official CLI bytes independently reject forged digest bodies. + # This does not assert that distribution itself has been patched. + pass + else: + retained.append(finding) + if 'Vulnerabilities' in result: + result['Vulnerabilities'] = retained + if len(removed) > 1: + raise ValueError('duplicate OpenPGP finding') + vex = { + '@context': 'https://openvex.dev/ns/v0.2.0', + '@id': 'https://github.com/PastureStack/system-image-preloader/security/openpgp/' + image_id, + 'author': 'PastureStack', 'timestamp': '2026-10-23T00:00:00Z', 'version': 1, + 'statements': [{ + 'vulnerability': {'@id': 'https://github.com/distribution/distribution/security/advisories/GHSA-685w-q87j-wqw3', + 'name': 'CVE-2026-85747'}, + 'products': [{'@id': image_id, + 'subcomponents': [{'@id': DISTRIBUTION_PURL}]}], + 'status': 'not_affected', 'justification': 'inline_mitigations_already_exist', + 'impact_statement': 'Only official Docker CLI 29.9.2 SHA256 ' + DOCKER_SHA256 + + ' is covered: its validateManifestDigest checks schema2, OCI, ' + 'manifest-list and child bodies before use. Seven loopback TLS ' + 'controls/forged-response cases passed. The distribution package ' + 'remains affected in other products; missing binary module metadata ' + 'is not evidence that the dependency is absent.', + }], + } + if removed: + vex['statements'].append({ + 'vulnerability': {'@id': 'https://pkg.go.dev/vuln/GO-2026-5932', + 'name': 'GO-2026-5932'}, + 'products': [{'@id': image_id, + 'subcomponents': [{'@id': CRYPTO_PURL}]}], + 'status': 'not_affected', 'justification': 'vulnerable_code_not_present', + 'impact_statement': 'Exact built gomplate imports no golang.org/x/crypto/openpgp package; ' + 'the Go advisory affects only that deprecated package subtree.', + }) + return effective, vex + + +def main(): + report = json.loads((EVIDENCE / 'system-image-preloader-security.json').read_text()) + images = json.loads((EVIDENCE / 'images.json').read_text()) + if len(images) != 1 or report.get('Metadata', {}).get('ImageID') != images[0]['Id']: + raise ValueError('scan does not identify the exact built image') + image_id = images[0]['Id'] + effective, vex = review( + report, (EVIDENCE / 'gomplate-dependencies.txt').read_text(), + (EVIDENCE / 'gomplate-buildinfo.txt').read_text(), + (EVIDENCE / 'docker-sha256.txt').read_text(), image_id) + ledger = json.loads((ROOT / '.github/runtime-unfixed.json').read_text()) + errors = POLICY.violations(effective, ledger, 'PastureStack/system-image-preloader') + (EVIDENCE / 'system-image-preloader-security-effective.json').write_text( + json.dumps(effective, indent=2) + '\n') + (EVIDENCE / 'system-image-preloader.openvex.json').write_text( + json.dumps(vex, indent=2) + '\n') + if errors: + raise SystemExit('Runtime security policy failed:\n' + '\n'.join(errors)) + print('RUNTIME_FULL_SEVERITY_AND_EXACT_OPENPGP_PROOF_OK') + + +if __name__ == '__main__': + main() diff --git a/scripts/test-runtime-vulnerability-policy.py b/scripts/test-runtime-vulnerability-policy.py new file mode 100644 index 0000000..24d317a --- /dev/null +++ b/scripts/test-runtime-vulnerability-policy.py @@ -0,0 +1,88 @@ +import copy +import importlib.util +import pathlib +import subprocess +import sys +import unittest + +sys.dont_write_bytecode = True + +PATH = pathlib.Path(__file__).with_name('enforce-runtime-vulnerabilities.py') +SPEC = importlib.util.spec_from_file_location('gate', PATH) +GATE = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(GATE) +REPO = 'PastureStack/system-image-preloader' + + +class RuntimePolicy(unittest.TestCase): + def setUp(self): + self.finding = {'VulnerabilityID': 'TEST-1', 'PkgName': 'lib', 'InstalledVersion': '1', + 'Severity': 'MEDIUM', 'FixedVersion': '', + 'PkgIdentifier': {'PURL': 'pkg:test/lib@1'}} + self.report = {'SchemaVersion': 2, 'Results': [{'Target': 'fixture', 'Vulnerabilities': [self.finding]}]} + self.ledger = {'repository': REPO, 'unfixed': [{'id': 'TEST-1', 'package': 'lib', + 'version': '1', 'severity': 'MEDIUM', 'purl': 'pkg:test/lib@1', + 'status': 'no_official_fix', 'officialEvidence': 'https://fixture.invalid/advisory', + 'reason': 'Test fixture only', 'checkedAt': '2026-10-23'}]} + + def test_exact_reviewed_unfixed_medium_passes(self): + self.assertEqual(GATE.violations(self.report, self.ledger, REPO), []) + + def test_clean_scan_passes(self): + self.assertEqual(GATE.violations({'SchemaVersion': 2, 'Results': [{'Target': 'fixture'}]}, + {'repository': REPO, 'unfixed': []}, REPO), []) + + def test_missing_or_malformed_scan_fails_closed(self): + for report in ({}, {'Results': []}, {'SchemaVersion': 2, 'Results': []}, + {'SchemaVersion': 2, 'Results': [{}]}, + {'SchemaVersion': 2, 'Results': [{'Target': 'fixture', 'Vulnerabilities': {}}]}): + with self.assertRaises(ValueError): + GATE.violations(report, self.ledger, REPO) + + def test_unregistered_medium_blocks(self): + self.ledger['unfixed'] = [] + self.assertTrue(GATE.violations(self.report, self.ledger, REPO)) + + def test_fixed_medium_blocks(self): + self.finding['FixedVersion'] = '2' + self.assertTrue(GATE.violations(self.report, self.ledger, REPO)) + + def test_fixed_low_is_not_an_unfixed_exception(self): + self.finding['Severity'] = 'LOW' + self.ledger['unfixed'][0]['severity'] = 'LOW' + self.finding['FixedVersion'] = '2' + self.assertTrue(GATE.violations(self.report, self.ledger, REPO)) + + def test_high_critical_and_unknown_always_block(self): + for severity in ('HIGH', 'CRITICAL', 'UNKNOWN'): + self.finding['Severity'] = severity + self.assertTrue(GATE.violations(self.report, self.ledger, REPO)) + + def test_version_or_purl_drift_blocks(self): + for key in ('version', 'purl'): + ledger = copy.deepcopy(self.ledger) + ledger['unfixed'][0][key] = 'different' + self.assertTrue(GATE.violations(self.report, ledger, REPO)) + + def test_secrets_always_block(self): + self.report['Results'][0]['Secrets'] = [{'RuleID': 'test'}] + self.assertTrue(GATE.violations(self.report, self.ledger, REPO)) + + def test_repository_drift_fails_closed(self): + with self.assertRaises(ValueError): + GATE.violations(self.report, self.ledger, 'another/repo') + + def test_incomplete_evidence_fails_closed(self): + del self.ledger['unfixed'][0]['checkedAt'] + with self.assertRaises(ValueError): + GATE.violations(self.report, self.ledger, REPO) + + def test_cli_rejects_free_form_paths(self): + result = subprocess.run( + [sys.executable, str(PATH), '--phase', '../../etc/passwd'], + capture_output=True, text=True) + self.assertEqual(result.returncode, 2) + self.assertIn('invalid choice', result.stderr) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/docker_manifest_digest_proof.py b/tests/docker_manifest_digest_proof.py new file mode 100644 index 0000000..b65042e --- /dev/null +++ b/tests/docker_manifest_digest_proof.py @@ -0,0 +1,71 @@ +import hashlib, http.server, json, subprocess, threading, ssl, tempfile, os +from pathlib import Path + +BINARY = str(Path(__file__).resolve().parents[1] / "dist/security-runtime/docker-cli") +assert hashlib.sha256(Path(BINARY).read_bytes()).hexdigest() == "6c71cfe71faff949a602946a4df4799b563232e79d0b8b6fd343d0ef081c9621" +def raw(x): return json.dumps(x, separators=(",", ":")).encode() +def digest(x): return "sha256:" + hashlib.sha256(x).hexdigest() +config = raw({"architecture":"amd64","os":"linux","rootfs":{"type":"layers","diff_ids":[]},"config":{}}) +def manifest(oci=False, evil=False): + return raw({"schemaVersion":2, "mediaType":"application/vnd.oci.image.manifest.v1+json" if oci else "application/vnd.docker.distribution.manifest.v2+json", + "config":{"mediaType":"application/vnd.oci.image.config.v1+json" if oci else "application/vnd.docker.container.image.v1+json","size":len(config),"digest":digest(config)}, + "layers":[], "annotations":{"proof":"attacker" if evil else "trusted"}}) +schema = manifest() +index = raw({"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.list.v2+json","manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","size":len(schema),"digest":digest(schema),"platform":{"os":"linux","architecture":"amd64"}}]}) +state = {} +requests_seen = [] +class Handler(http.server.BaseHTTPRequestHandler): + def log_message(self, *args): pass + def do_GET(self): + requests_seen.append(self.path) + if self.path == "/v2/": data, media = b"{}", "application/json" + elif "/manifests/" in self.path: + requested = self.path.rsplit("/", 1)[1] + data = state["body"] if requested == state["requested"] else state.get("child", schema) + media = json.loads(data)["mediaType"] + # Forge the expected digest using fixture-owned values, never request + # bytes. The proof tests the CLI's content validation, not a registry + # header parser, and must not make the local server header-injectable. + advertised_digest = state["requested"] if requested == state["requested"] else digest(schema) + elif "/blobs/" in self.path: data, media = config, "application/octet-stream" + else: self.send_error(404); return + self.send_response(200) + self.send_header("Content-Type", media) + self.send_header("Content-Length", str(len(data))) + if "/manifests/" in self.path: + self.send_header("Docker-Content-Digest", advertised_digest) + self.end_headers(); self.wfile.write(data) +fixture = tempfile.TemporaryDirectory(prefix="docker-manifest-proof-") +config_dir = Path(fixture.name) / "docker-config" +config_dir.mkdir() +environment = dict(os.environ, DOCKER_CONFIG=str(config_dir)) +cert = Path(fixture.name) / "cert.pem" +key = Path(fixture.name) / "key.pem" +subprocess.run(["openssl","req","-x509","-newkey","rsa:2048","-nodes","-keyout",str(key),"-out",str(cert),"-subj","/CN=localhost","-days","1","-addext","subjectAltName=IP:127.0.0.1"],check=True,capture_output=True) +server = http.server.ThreadingHTTPServer(("127.0.0.1",0), Handler) +tls = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) +tls.minimum_version = ssl.TLSVersion.TLSv1_2 +tls.load_cert_chain(cert, key) +server.socket = tls.wrap_socket(server.socket, server_side=True) +threading.Thread(target=server.serve_forever, daemon=True).start() +cases = [("valid_schema2",schema,schema,None,True), + ("forged_schema2",schema,manifest(evil=True),None,False), + ("valid_oci",manifest(True),manifest(True),None,True), + ("forged_oci",manifest(True),manifest(True,True),None,False), + ("valid_list",index,index,schema,True), + ("forged_list_parent",index,raw({"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.list.v2+json","manifests":[]}),schema,False), + ("forged_list_child",index,index,manifest(evil=True),False)] +results = [] +try: + for name, expected, body, child, accepted in cases: + state.clear(); state.update(requested=digest(expected),body=body,child=child or schema) + requests_seen.clear() + result = subprocess.run([BINARY,"manifest","inspect","--insecure",f"127.0.0.1:{server.server_port}/library/test@{digest(expected)}"],capture_output=True,text=True,timeout=30,env=environment) + passed = (result.returncode == 0) if accepted else (result.returncode != 0 and not result.stdout.strip() and not any("/blobs/" in p for p in requests_seen) and ("manifest verification failed" in result.stderr or "unsupported manifest format" in result.stderr)) + results.append({"case":name,"passed":passed,"accepted":result.returncode==0,"expectedAccept":accepted, + "returnCode":result.returncode,"stderr":result.stderr.strip(), + "requestPaths":list(requests_seen)}) + if not passed: raise AssertionError(results[-1]) +finally: + server.shutdown() + print(json.dumps({"binarySha256":hashlib.sha256(Path(BINARY).read_bytes()).hexdigest(),"sourceCommit":"a82e528901260c8df6073311379eac65f92db204","cases":results},indent=2)) diff --git a/tests/test_runtime_security_review.py b/tests/test_runtime_security_review.py new file mode 100644 index 0000000..b3a8dfe --- /dev/null +++ b/tests/test_runtime_security_review.py @@ -0,0 +1,77 @@ +import importlib.util +import pathlib +import sys +import unittest + +sys.dont_write_bytecode = True +SPEC = importlib.util.spec_from_file_location( + 'review', pathlib.Path(__file__).resolve().parents[1] / 'scripts/review-runtime-security.py') +REVIEW = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(REVIEW) + + +class ExactOpenPGPProof(unittest.TestCase): + def setUp(self): + self.finding = {'VulnerabilityID': 'GO-2026-5932', 'PkgName': 'golang.org/x/crypto', + 'InstalledVersion': 'v0.57.0', 'Severity': 'UNKNOWN', + 'PkgIdentifier': {'PURL': REVIEW.CRYPTO_PURL}} + self.report = {'SchemaVersion': 2, 'Results': [{ + 'Target': 'usr/local/bin/gomplate', 'Vulnerabilities': [self.finding]}]} + self.deps = 'github.com/hairyhenderson/gomplate/v5/cmd/gomplate\ngolang.org/x/crypto/ssh\n' + self.gom = 'dep golang.org/x/crypto v0.57.0 h1:test\ndep go.opentelemetry.io/otel/sdk v1.45.0 h1:test' + self.docker = REVIEW.DOCKER_SHA256 + ' /usr/local/bin/docker' + + def review(self): + return REVIEW.review(self.report, self.deps, self.gom, self.docker, 'sha256:test') + + def test_exact_package_absence_filters_only_one_advisory(self): + effective, vex = self.review() + self.assertEqual(effective['Results'][0]['Vulnerabilities'], []) + self.assertEqual(len(self.report['Results'][0]['Vulnerabilities']), 1) + self.assertEqual(vex['statements'][1]['justification'], 'vulnerable_code_not_present') + + def test_any_openpgp_package_refuses_proof(self): + for name in ('golang.org/x/crypto/openpgp', 'golang.org/x/crypto/openpgp/packet'): + self.deps += name + '\n' + with self.assertRaises(ValueError): + self.review() + + def test_other_binary_and_new_identity_are_never_filtered(self): + self.report['Results'][0]['Target'] = 'usr/local/bin/docker' + self.assertEqual(len(self.review()[0]['Results'][0]['Vulnerabilities']), 1) + self.report['Results'][0]['Target'] = 'usr/local/bin/gomplate' + self.finding['VulnerabilityID'] = 'ANOTHER' + self.assertEqual(len(self.review()[0]['Results'][0]['Vulnerabilities']), 1) + + def test_changed_purl_or_fixed_version_is_never_filtered(self): + self.finding['FixedVersion'] = 'v0.58.0' + self.assertEqual(len(self.review()[0]['Results'][0]['Vulnerabilities']), 1) + del self.finding['FixedVersion'] + self.finding['PkgIdentifier']['PURL'] = 'pkg:golang/golang.org/x/crypto@v0.58.0' + self.assertEqual(len(self.review()[0]['Results'][0]['Vulnerabilities']), 1) + + def test_old_otel_or_missing_proof_refuses_release(self): + self.gom = self.gom.replace('v1.45.0', 'v1.44.0') + with self.assertRaises(ValueError): + self.review() + + def test_changed_docker_bytes_refuse_mitigation(self): + self.docker = '0' * 64 + ' /usr/local/bin/docker' + with self.assertRaises(ValueError): + self.review() + + def test_distribution_exception_is_exact_and_does_not_hide_new_fixes(self): + self.report['Results'][0]['Target'] = 'usr/local/bin/docker' + self.report['Results'][0]['Vulnerabilities'] = [{ + 'VulnerabilityID': 'CVE-2026-85747', 'PkgName': 'github.com/docker/distribution', + 'InstalledVersion': 'v2.8.3+incompatible', 'Severity': 'MEDIUM', + 'PkgIdentifier': {'PURL': REVIEW.DISTRIBUTION_PURL}}] + self.assertEqual(self.review()[0]['Results'][0]['Vulnerabilities'], []) + self.report['Results'][0]['Vulnerabilities'][0]['FixedVersion'] = '2.8.4' + self.assertEqual(len(self.review()[0]['Results'][0]['Vulnerabilities']), 1) + self.report['Results'][0]['Target'] = 'usr/local/bin/another-product' + self.assertEqual(len(self.review()[0]['Results'][0]['Vulnerabilities']), 1) + + +if __name__ == '__main__': + unittest.main()