diff --git a/.github/workflows/key-continuity.yml b/.github/workflows/key-continuity.yml new file mode 100644 index 0000000..5422b1f --- /dev/null +++ b/.github/workflows/key-continuity.yml @@ -0,0 +1,22 @@ +--- + +name: key-continuity + +# yamllint disable-line rule:truthy +on: [push, pull_request, workflow_dispatch] + +jobs: + testjob: + runs-on: ubuntu-22.04 + + steps: + - name: apt-get update + run: sudo apt-get update + + - name: apt-get install + run: sudo apt-get -y install bats + + - uses: actions/checkout@v2 + + - name: run signing key continuity tests + run: bats tests/key_continuity.bats diff --git a/tarball_multi_releases.bash b/tarball_multi_releases.bash index 220c807..95375e6 100755 --- a/tarball_multi_releases.bash +++ b/tarball_multi_releases.bash @@ -168,7 +168,16 @@ main() done | LC_ALL=C sort -k2 > "$archive_name"/sha256sum.txt ( cd "${archive_name}"/; set -x - sha256sum --quiet --check sha256sum.txt + # Not using 'sha256sum --check sha256sum.txt': its checksum-file + # parsing is not consistent across implementations (e.g., GNU + # coreutils vs. Rust/uutils coreutils reject our tab-separated + # format), so verify each entry directly instead. + while IFS=$'\t' read -r sum fname; do + test -n "$sum" || continue + actual=$(sha256sum "$fname" | awk '{ print $1 }') + test "$actual" = "$sum" || + die 'checksum mismatch for %s\n' "$fname" + done < sha256sum.txt ) # Final tarball diff --git a/tests/key_continuity.bats b/tests/key_continuity.bats new file mode 100644 index 0000000..3c77884 --- /dev/null +++ b/tests/key_continuity.bats @@ -0,0 +1,124 @@ + +# https://bats-core.readthedocs.io/en/stable/tutorial.html + +setup() +{ + mkdir -p testruns/ + RUN_DIR=$(mktemp -d testruns/run-XXXXXX) +} + +teardown() +{ + test -d "$RUN_DIR"/ || return 1 + rm -rf "${RUN_DIR:?}"/ +} + +# You MUST call popd at the end +test_init() +{ + pushd "$RUN_DIR"/ || exit 1 + load 'common_helpers.bash'; set_constants +} + +# Workaround for https://github.com/koalaman/shellcheck/issues/2431 +# shellcheck disable=SC2030 +@test "signing key continuity: sof-ipc4-v*" { + test_init + + local pair + cd "$TOP_DIR" + while IFS= read -r pair; do + test -n "$pair" || continue + local prev="${pair%% *}" curr="${pair##* }" + + run_compare_signing_keys "$prev" "$curr" + + case "$prev $curr" in + + # No mismatch expected + *) + assert_eq_signing_key $status 0;; + esac + done < <(discover_point_release_pairs 'sof-ipc4-v*') + + popd || return 1 +} + +# Workaround for https://github.com/koalaman/shellcheck/issues/2431 +# shellcheck disable=SC2030 +@test "signing key continuity: sof-ipc4-lib-v*" { + test_init + + local pair + cd "$TOP_DIR" + while IFS= read -r pair; do + test -n "$pair" || continue + local prev="${pair%% *}" curr="${pair##* }" + + run_compare_signing_keys "$prev" "$curr" + + case "$prev $curr" in + + # No mismatch expected + *) + assert_eq_signing_key $status 0;; + esac + done < <(discover_point_release_pairs 'sof-ipc4-lib-v*') + + popd || return 1 +} + +# For every vX.Y.x directory with 2+ matches of $1 (a glob like +# 'sof-ipc4-v*'), emit every consecutive (prev, curr) pair, one pair per +# line as "prev curr", sorted by version. +discover_point_release_pairs() +{ + local glob_pattern="$1" + local vdir + for vdir in v*.x; do + test -d "$vdir" || continue + + local matches=() + while IFS= read -r m; do + matches+=("$m") + done < <(find "$vdir" -maxdepth 1 -type d -name "$glob_pattern" | sort -V) + + local n=${#matches[@]} + test "$n" -ge 2 || continue + + local i + for ((i = 0; i < n - 1; i++)); do + printf '%s %s\n' "${matches[$i]}" "${matches[$((i + 1))]}" + done + done +} + +run_compare_signing_keys() +{ + local prev="$1" curr="$2" + local run_cmd=("$TOP_DIR"/validate_sof_install.py --compare-signing-keys "$prev" "$curr") + + unset BATS_RUN_COMMAND + run "${run_cmd[@]}" + # BATS_RUN_COMMAND is not available in bats version 1.2.1 + test -n "$BATS_RUN_COMMAND" || BATS_RUN_COMMAND="${run_cmd[*]}" + + # This is not modifying $output, shellcheck seems wrong + # shellcheck disable=SC2031 + printf '%s\n' "$output" + # This is not modifying $status, shellcheck seems wrong + # shellcheck disable=SC2031 + printf '\n --- %d returned by %s ---\n\n' \ + $status "$BATS_RUN_COMMAND" +} + +assert_eq_signing_key() +{ + local actual=$1 expected=$2 + + test "$actual" -eq "$expected" || { + >&2 printf 'FAIL: expected %d, got %d from %s\n' \ + "$expected" "$actual" "$BATS_RUN_COMMAND" + false + } +} diff --git a/v2.15.x/sof-ipc4-v2.15.1/arl-s/community/sof-arl-s.ri b/v2.15.x/sof-ipc4-v2.15.1/arl-s/community/sof-arl-s.ri new file mode 120000 index 0000000..1e89e3a --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/arl-s/community/sof-arl-s.ri @@ -0,0 +1 @@ +../../mtl/community/sof-mtl.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/arl-s/intel-signed/sof-arl-s.ri b/v2.15.x/sof-ipc4-v2.15.1/arl-s/intel-signed/sof-arl-s.ri new file mode 120000 index 0000000..5affe7e --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/arl-s/intel-signed/sof-arl-s.ri @@ -0,0 +1 @@ +../../mtl-s/intel-signed/sof-mtl-s.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/arl-s/sof-arl-s.ri b/v2.15.x/sof-ipc4-v2.15.1/arl-s/sof-arl-s.ri new file mode 120000 index 0000000..403ce2a --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/arl-s/sof-arl-s.ri @@ -0,0 +1 @@ +intel-signed/sof-arl-s.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/arl/community/sof-arl.ri b/v2.15.x/sof-ipc4-v2.15.1/arl/community/sof-arl.ri new file mode 120000 index 0000000..1e89e3a --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/arl/community/sof-arl.ri @@ -0,0 +1 @@ +../../mtl/community/sof-mtl.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/lnl/community/sof-lnl.ri b/v2.15.x/sof-ipc4-v2.15.1/lnl/community/sof-lnl.ri new file mode 100644 index 0000000..e8160dd Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/lnl/community/sof-lnl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/lnl/intel-signed/sof-lnl.ri b/v2.15.x/sof-ipc4-v2.15.1/lnl/intel-signed/sof-lnl.ri new file mode 100644 index 0000000..011e84c Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/lnl/intel-signed/sof-lnl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/lnl/sof-lnl.ri b/v2.15.x/sof-ipc4-v2.15.1/lnl/sof-lnl.ri new file mode 120000 index 0000000..87b5f24 --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/lnl/sof-lnl.ri @@ -0,0 +1 @@ +intel-signed/sof-lnl.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/mtl-s/intel-signed/sof-mtl-s.ri b/v2.15.x/sof-ipc4-v2.15.1/mtl-s/intel-signed/sof-mtl-s.ri new file mode 100644 index 0000000..9a66a16 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/mtl-s/intel-signed/sof-mtl-s.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/mtl-s/sof-mtl-s.ri b/v2.15.x/sof-ipc4-v2.15.1/mtl-s/sof-mtl-s.ri new file mode 120000 index 0000000..f126dfa --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/mtl-s/sof-mtl-s.ri @@ -0,0 +1 @@ +intel-signed/sof-mtl-s.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/mtl/community/sof-mtl.ri b/v2.15.x/sof-ipc4-v2.15.1/mtl/community/sof-mtl.ri new file mode 100644 index 0000000..d8de1f3 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/mtl/community/sof-mtl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/mtl/intel-signed/sof-mtl.ri b/v2.15.x/sof-ipc4-v2.15.1/mtl/intel-signed/sof-mtl.ri new file mode 100644 index 0000000..1ba6125 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/mtl/intel-signed/sof-mtl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/mtl/sof-mtl.ri b/v2.15.x/sof-ipc4-v2.15.1/mtl/sof-mtl.ri new file mode 120000 index 0000000..3d21fe5 --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/mtl/sof-mtl.ri @@ -0,0 +1 @@ +intel-signed/sof-mtl.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl-s/community/sof-nvl-s-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/community/sof-nvl-s-openmodules.ri new file mode 100644 index 0000000..d29cc4b Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/community/sof-nvl-s-openmodules.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl-s/community/sof-nvl-s.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/community/sof-nvl-s.ri new file mode 100644 index 0000000..fa986f8 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/community/sof-nvl-s.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl-s/intel-signed/sof-nvl-s-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/intel-signed/sof-nvl-s-openmodules.ri new file mode 100644 index 0000000..230e9a3 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/intel-signed/sof-nvl-s-openmodules.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl-s/intel-signed/sof-nvl-s.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/intel-signed/sof-nvl-s.ri new file mode 100644 index 0000000..ce08535 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/intel-signed/sof-nvl-s.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl-s/sof-nvl-s-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/sof-nvl-s-openmodules.ri new file mode 120000 index 0000000..06b062f --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/sof-nvl-s-openmodules.ri @@ -0,0 +1 @@ +intel-signed/sof-nvl-s-openmodules.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl-s/sof-nvl-s.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/sof-nvl-s.ri new file mode 120000 index 0000000..870100c --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/nvl-s/sof-nvl-s.ri @@ -0,0 +1 @@ +intel-signed/sof-nvl-s.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl/community/sof-nvl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl/community/sof-nvl-openmodules.ri new file mode 100644 index 0000000..fe41abc Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/nvl/community/sof-nvl-openmodules.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl/community/sof-nvl.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl/community/sof-nvl.ri new file mode 100644 index 0000000..165a0e8 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/nvl/community/sof-nvl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl/intel-signed/sof-nvl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl/intel-signed/sof-nvl-openmodules.ri new file mode 100644 index 0000000..376d628 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/nvl/intel-signed/sof-nvl-openmodules.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl/intel-signed/sof-nvl.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl/intel-signed/sof-nvl.ri new file mode 100644 index 0000000..b32df48 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/nvl/intel-signed/sof-nvl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl/sof-nvl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl/sof-nvl-openmodules.ri new file mode 120000 index 0000000..183b378 --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/nvl/sof-nvl-openmodules.ri @@ -0,0 +1 @@ +intel-signed/sof-nvl-openmodules.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/nvl/sof-nvl.ri b/v2.15.x/sof-ipc4-v2.15.1/nvl/sof-nvl.ri new file mode 120000 index 0000000..49be50d --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/nvl/sof-nvl.ri @@ -0,0 +1 @@ +intel-signed/sof-nvl.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/ptl/community/sof-ptl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/ptl/community/sof-ptl-openmodules.ri new file mode 100644 index 0000000..ac2e0a8 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/ptl/community/sof-ptl-openmodules.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/ptl/community/sof-ptl.ri b/v2.15.x/sof-ipc4-v2.15.1/ptl/community/sof-ptl.ri new file mode 100644 index 0000000..e2effba Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/ptl/community/sof-ptl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/ptl/intel-signed/sof-ptl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/ptl/intel-signed/sof-ptl-openmodules.ri new file mode 100644 index 0000000..7f920ba Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/ptl/intel-signed/sof-ptl-openmodules.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/ptl/intel-signed/sof-ptl.ri b/v2.15.x/sof-ipc4-v2.15.1/ptl/intel-signed/sof-ptl.ri new file mode 100644 index 0000000..ca2113a Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/ptl/intel-signed/sof-ptl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/ptl/sof-ptl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/ptl/sof-ptl-openmodules.ri new file mode 120000 index 0000000..7896274 --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/ptl/sof-ptl-openmodules.ri @@ -0,0 +1 @@ +intel-signed/sof-ptl-openmodules.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/ptl/sof-ptl.ri b/v2.15.x/sof-ipc4-v2.15.1/ptl/sof-ptl.ri new file mode 120000 index 0000000..9b22355 --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/ptl/sof-ptl.ri @@ -0,0 +1 @@ +intel-signed/sof-ptl.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/wcl/community/sof-wcl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/wcl/community/sof-wcl-openmodules.ri new file mode 100644 index 0000000..0634583 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/wcl/community/sof-wcl-openmodules.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/wcl/community/sof-wcl.ri b/v2.15.x/sof-ipc4-v2.15.1/wcl/community/sof-wcl.ri new file mode 100644 index 0000000..c002e1c Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/wcl/community/sof-wcl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/wcl/intel-signed/sof-wcl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/wcl/intel-signed/sof-wcl-openmodules.ri new file mode 100644 index 0000000..f9c3aa1 Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/wcl/intel-signed/sof-wcl-openmodules.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/wcl/intel-signed/sof-wcl.ri b/v2.15.x/sof-ipc4-v2.15.1/wcl/intel-signed/sof-wcl.ri new file mode 100644 index 0000000..d2f5bfd Binary files /dev/null and b/v2.15.x/sof-ipc4-v2.15.1/wcl/intel-signed/sof-wcl.ri differ diff --git a/v2.15.x/sof-ipc4-v2.15.1/wcl/sof-wcl-openmodules.ri b/v2.15.x/sof-ipc4-v2.15.1/wcl/sof-wcl-openmodules.ri new file mode 120000 index 0000000..4247e48 --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/wcl/sof-wcl-openmodules.ri @@ -0,0 +1 @@ +intel-signed/sof-wcl-openmodules.ri \ No newline at end of file diff --git a/v2.15.x/sof-ipc4-v2.15.1/wcl/sof-wcl.ri b/v2.15.x/sof-ipc4-v2.15.1/wcl/sof-wcl.ri new file mode 120000 index 0000000..17fcfe6 --- /dev/null +++ b/v2.15.x/sof-ipc4-v2.15.1/wcl/sof-wcl.ri @@ -0,0 +1 @@ +intel-signed/sof-wcl.ri \ No newline at end of file diff --git a/validate_sof_install.py b/validate_sof_install.py index b445f15..4cf1983 100755 --- a/validate_sof_install.py +++ b/validate_sof_install.py @@ -123,13 +123,36 @@ def compute_file_md5(file_path: Path, block_size: int = 65536) -> Optional[str]: return None +def extract_signing_key_hash(data: bytes) -> Optional[str]: + """ + Extract a stable identifier for the RSA signing key embedded in a signed + firmware (.ri) or LLEXT CSS manifest ($MN2), as the sha256 of the raw + modulus bytes. + + Layout (relative to the offset of the "$MN2" header_id string itself, + matching sof/tools/sof_ri_info.py's parse_css_manifest_4()): + modulus_size (u32, in dwords) at +92, modulus bytes starting at +100. + """ + pos_mn2 = data.find(b"$MN2") + if pos_mn2 == -1: + return None + try: + modulus_size = struct.unpack_from(" Dict[str, Any]: """ Parse embedded manifest and metadata from firmware (.ri), LLEXT (.llext/.bin), and topology (.tplg) binaries. - + Supports: - - CSS headers ($MN2): BCD build date (YYYY-MM-DD) + - CSS headers ($MN2): BCD build date (YYYY-MM-DD), signing key identity - ADSP FW header ($AM1): SOF major/minor/hotfix/build version, component name, modules - Extended Manifest (XMan): FW version, ABI version, date/time strings - Embedded build strings: Zephyr version/commit, SOF tags @@ -151,6 +174,9 @@ def parse_binary_manifest(data: bytes) -> Dict[str, Any]: info["build_date"] = f"{year:04d}-{month:02d}-{day:02d}" except Exception: pass + signing_key_hash = extract_signing_key_hash(data) + if signing_key_hash: + info["signing_key_hash"] = signing_key_hash # 2. ADSP FW Manifest ($AM1) pos_am1 = data.find(b"$AM1") @@ -248,6 +274,58 @@ def parse_binary_manifest(data: bytes) -> Dict[str, Any]: return info +def compare_signing_keys(dir_a: Path, dir_b: Path) -> Tuple[int, List[str]]: + """ + Compare the Intel signing-key identity of every .ri/.llext file found + under dir_a against the same relative path under dir_b (e.g. a previous + point release vs the current one). + + A file present under only one of the two directories is reported + informationally (new/removed platform or file), never as an error. A + mismatched signing_key_hash for a path present on both sides is an error. + """ + def collect(root: Path) -> Dict[str, Path]: + found: Dict[str, Path] = {} + for path in sorted(root.rglob("*")): + if path.is_file() and path.suffix in (".ri", ".llext"): + found[str(path.relative_to(root))] = path + return found + + files_a = collect(dir_a) + files_b = collect(dir_b) + + report: List[str] = [] + error_count = 0 + match_count = 0 + + for rel_path in sorted(set(files_a) | set(files_b)): + path_a = files_a.get(rel_path) + path_b = files_b.get(rel_path) + if path_a is None: + report.append(f"INFO: {rel_path}: only present in {dir_b} (new file)") + continue + if path_b is None: + report.append(f"INFO: {rel_path}: only present in {dir_a} (removed file)") + continue + + hash_a = extract_signing_key_hash(path_a.read_bytes()) + hash_b = extract_signing_key_hash(path_b.read_bytes()) + if hash_a is None or hash_b is None: + report.append(f"INFO: {rel_path}: not signed (or unsigned) on one or both sides, skipping") + continue + if hash_a != hash_b: + error_count += 1 + report.append( + f"ERROR: {rel_path}: signing key changed! " + f"{dir_a}={hash_a[:16]} {dir_b}={hash_b[:16]}" + ) + else: + match_count += 1 + + report.append(f"Signing key continuity: {match_count} matched, {error_count} mismatched") + return error_count, report + + def format_manifest_summary(man: Optional[Dict[str, Any]]) -> str: """Format manifest dictionary into a concise single-line description.""" if not man: @@ -1044,6 +1122,12 @@ def _build_remote_manifest_script() -> str: " if 1970 <= y <= 2099 and 1 <= m <= 12 and 1 <= d <= 31:\n" " info['build_date'] = f'{y:04d}-{m:02d}-{d:02d}'\n" " except Exception: pass\n" + " try:\n" + " mod_sz = struct.unpack_from(' argparse.Namespace: action="store_true", help="Strict mode: fail on any missing optional files or symlink differences.", ) + parser.add_argument( + "--compare-signing-keys", + nargs=2, + default=None, + metavar=("PREV_DIR", "CURR_DIR"), + help="Compare Intel signing-key identity of matching .ri/.llext files between two " + "version directories (e.g. a previous and current point release) and exit. " + "Files present in only one directory are reported informationally, not as errors.", + ) return parser.parse_args() @@ -2511,6 +2604,12 @@ def parse_arguments() -> argparse.Namespace: def main() -> int: args = parse_arguments() + if args.compare_signing_keys: + prev_dir, curr_dir = (Path(p) for p in args.compare_signing_keys) + error_count, report_lines = compare_signing_keys(prev_dir, curr_dir) + print("\n".join(report_lines)) + return 1 if error_count else 0 + try: repo = SofBinRepo.find_repo(args.sof_bin_dir) except Exception as e: