From d0a5f3ebad87053cae68dd6eba8aa1fe8b657441 Mon Sep 17 00:00:00 2001 From: brdandu Date: Mon, 11 May 2026 14:51:36 -0400 Subject: [PATCH 1/3] pkg zap-cli with node20-linuxstatic + CI portability checks - Switch pkg:linux targets from node20-linux-{x64,arm64} to node20-linuxstatic-{x64,arm64} to avoid host GLIBC version coupling. - In matter.yml and release.yml: after the Linux build, assert zap-cli is fully static (file/objdump) and has no GLIBC versioned symbols. - Add linux-portability-test job (ubuntu:22.04, debian:bullseye, rockylinux:8) to run zap-cli --version on old glibc and selfCheck dquote> - JIRA: ZAPP-1717 --- .github/workflows/matter.yml | 81 +++++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 81 +++++++++++++++++++++++++++++++++++ package.json | 2 +- 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/.github/workflows/matter.yml b/.github/workflows/matter.yml index d9f78e1e5b..627b98c880 100644 --- a/.github/workflows/matter.yml +++ b/.github/workflows/matter.yml @@ -103,6 +103,20 @@ jobs: # CSC_LINK: ${{ secrets.api_key_id }} # CSC_KEY_PASSWORD: ${{ secrets.api_key_issuer_id }} + - name: Assert zap-cli is statically linked (no GLIBC) + if: startsWith(matrix.os, 'ubuntu') + run: | + set -e + unzip -o dist/zap-linux-x64.zip -d /tmp/zap-static-check + BIN=/tmp/zap-static-check/zap-cli + file "$BIN" + file "$BIN" | grep -q 'statically linked' || { echo 'FAIL: zap-cli is not statically linked'; exit 1; } + GLIBC_REFS=$(objdump -T "$BIN" 2>/dev/null | grep -oE 'GLIBC_[0-9.]+' | sort -uV || true) + echo "GLIBC versioned symbols: ${GLIBC_REFS:-(none)}" + if [ -n "$GLIBC_REFS" ]; then echo 'FAIL: zap-cli still imports GLIBC symbols'; exit 1; fi + ldd "$BIN" || true + rm -rf /tmp/zap-static-check + - name: Verify zap-cli exists in Linux x64 .zip package if: startsWith(matrix.os, 'ubuntu') run: | @@ -182,6 +196,73 @@ jobs: name: zap-linux-x64-deb path: dist/zap-linux-x64.deb + linux-portability-test: + name: Verify static zap-cli on ${{ matrix.label }} + needs: [build-zap] + runs-on: ubuntu-22.04 + container: + image: ${{ matrix.image }} + strategy: + fail-fast: false + matrix: + include: + - label: 'ubuntu:22.04 (glibc 2.35)' + image: 'ubuntu:22.04' + installer: 'apt' + - label: 'debian:bullseye (glibc 2.31)' + image: 'debian:bullseye-slim' + installer: 'apt' + - label: 'rockylinux:8 (glibc 2.28)' + image: 'rockylinux:8' + installer: 'dnf' + steps: + - name: Install minimal tooling + run: | + if [ "${{ matrix.installer }}" = "apt" ]; then + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + ca-certificates binutils file unzip + else + dnf install -y binutils file unzip + fi + - name: Print baseline OS info + run: | + cat /etc/os-release || true + ldd --version 2>/dev/null | head -n 1 || true + uname -a || true + - uses: actions/download-artifact@v4 + with: + name: zap-linux-x64-zip + - name: Unpack zap-linux-x64.zip + run: | + mkdir -p zap-release + ART_ZIP=zap-linux-x64-zip/zap-linux-x64.zip + if [ ! -f "$ART_ZIP" ]; then + ART_ZIP=zap-linux-x64.zip + fi + unzip -o "$ART_ZIP" -d zap-release + - name: Inspect zap-cli binary + run: | + chmod +x zap-release/zap-cli + file zap-release/zap-cli + objdump -T zap-release/zap-cli 2>/dev/null | grep -oE 'GLIBC_[0-9.]+' | sort -uV || echo '(no GLIBC refs)' + ldd zap-release/zap-cli || true + - name: Run zap-cli --version (must succeed; proves binary loads with old glibc) + run: | + set -euo pipefail + ./zap-release/zap-cli --version + - name: Run zap-cli selfCheck (SQLite-touching path) + run: | + set -euo pipefail + CLI=./zap-release/zap-cli + PROP=zap-release/zcl-builtin/silabs/zcl-test.properties + GEN=zap-release/test/gen-template/zigbee/gen-templates.json + if [[ -f "$PROP" ]] && [[ -f "$GEN" ]]; then + "$CLI" selfCheck --zclProperties "$PROP" --genTemplateJson "$GEN" + else + "$CLI" selfCheck + fi + matter-sdk-codegen-master: name: Test matter sdk codegen changes (master) needs: [build-zap] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 355d6f3b5d..21f08bdd4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -256,6 +256,20 @@ jobs: # CSC_LINK: ${{ secrets.api_key_id }} # CSC_KEY_PASSWORD: ${{ secrets.api_key_issuer_id }} + - name: Assert zap-cli is statically linked (no GLIBC) + if: startsWith(matrix.os, 'ubuntu') + run: | + set -e + unzip -o dist/zap-linux-x64.zip -d /tmp/zap-static-check + BIN=/tmp/zap-static-check/zap-cli + file "$BIN" + file "$BIN" | grep -q 'statically linked' || { echo 'FAIL: zap-cli is not statically linked'; exit 1; } + GLIBC_REFS=$(objdump -T "$BIN" 2>/dev/null | grep -oE 'GLIBC_[0-9.]+' | sort -uV || true) + echo "GLIBC versioned symbols: ${GLIBC_REFS:-(none)}" + if [ -n "$GLIBC_REFS" ]; then echo 'FAIL: zap-cli still imports GLIBC symbols'; exit 1; fi + ldd "$BIN" || true + rm -rf /tmp/zap-static-check + - name: Verify zap-cli exists in Linux x64 .zip package if: startsWith(matrix.os, 'ubuntu') run: | @@ -535,6 +549,73 @@ jobs: name: zap-linux-x64-deb path: dist/zap-linux-x64.deb + linux-portability-test: + name: Verify static zap-cli on ${{ matrix.label }} + needs: [build-zap] + runs-on: ubuntu-22.04 + container: + image: ${{ matrix.image }} + strategy: + fail-fast: false + matrix: + include: + - label: 'ubuntu:22.04 (glibc 2.35)' + image: 'ubuntu:22.04' + installer: 'apt' + - label: 'debian:bullseye (glibc 2.31)' + image: 'debian:bullseye-slim' + installer: 'apt' + - label: 'rockylinux:8 (glibc 2.28)' + image: 'rockylinux:8' + installer: 'dnf' + steps: + - name: Install minimal tooling + run: | + if [ "${{ matrix.installer }}" = "apt" ]; then + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + ca-certificates binutils file unzip + else + dnf install -y binutils file unzip + fi + - name: Print baseline OS info + run: | + cat /etc/os-release || true + ldd --version 2>/dev/null | head -n 1 || true + uname -a || true + - uses: actions/download-artifact@v4 + with: + name: zap-linux-x64-zip + - name: Unpack zap-linux-x64.zip + run: | + mkdir -p zap-release + ART_ZIP=zap-linux-x64-zip/zap-linux-x64.zip + if [ ! -f "$ART_ZIP" ]; then + ART_ZIP=zap-linux-x64.zip + fi + unzip -o "$ART_ZIP" -d zap-release + - name: Inspect zap-cli binary + run: | + chmod +x zap-release/zap-cli + file zap-release/zap-cli + objdump -T zap-release/zap-cli 2>/dev/null | grep -oE 'GLIBC_[0-9.]+' | sort -uV || echo '(no GLIBC refs)' + ldd zap-release/zap-cli || true + - name: Run zap-cli --version (must succeed; proves binary loads with old glibc) + run: | + set -euo pipefail + ./zap-release/zap-cli --version + - name: Run zap-cli selfCheck (SQLite-touching path) + run: | + set -euo pipefail + CLI=./zap-release/zap-cli + PROP=zap-release/zcl-builtin/silabs/zcl-test.properties + GEN=zap-release/test/gen-template/zigbee/gen-templates.json + if [[ -f "$PROP" ]] && [[ -f "$GEN" ]]; then + "$CLI" selfCheck --zclProperties "$PROP" --genTemplateJson "$GEN" + else + "$CLI" selfCheck + fi + release: if: startsWith(github.ref, 'refs/tags/') needs: [build-zap] diff --git a/package.json b/package.json index 64a1ca650f..d0a1ee130e 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "pack:cli:win": "node ./src-script/pack-cli.js -p win", "pack:cli:mac": "node ./src-script/pack-cli.js -p mac", "pkg": "npx pkg --out-path dist/ --compress GZip --options max-old-space-size=4096 .", - "pkg:linux": "npx pkg -t node20-linux-x64,node20-linux-arm64 --public --no-bytecode --output dist/zap-linux --compress GZip --options max-old-space-size=4096 .", + "pkg:linux": "npx pkg -t node20-linuxstatic-x64,node20-linuxstatic-arm64 --public --no-bytecode --output dist/zap-linux --compress GZip --options max-old-space-size=4096 .", "pkg-use-local-fork": "node ../pkg/lib-es5/bin.js -t node20-linux-x64 --output dist/zap-linux --compress GZip --options max-old-space-size=4096 .", "pkg:win": "npx pkg -t node20-win-x64,node20-win-arm64 --public --no-bytecode --output dist/zap-win --compress GZip --options max-old-space-size=4096 .", "pkg:mac": "npx pkg -t node20-macos-x64,node20-macos-arm64 --output dist/zap-macos --compress GZip --options max-old-space-size=4096 .", From 490eb8cc135bfdfa61b7f10a568a2b463a1275b3 Mon Sep 17 00:00:00 2001 From: brdandu Date: Mon, 11 May 2026 15:05:30 -0400 Subject: [PATCH 2/3] minor cleanup with staticall linked and static-pie linked --- .github/workflows/matter.yml | 6 +++++- .github/workflows/release.yml | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/matter.yml b/.github/workflows/matter.yml index 627b98c880..b0bedc48c1 100644 --- a/.github/workflows/matter.yml +++ b/.github/workflows/matter.yml @@ -110,7 +110,11 @@ jobs: unzip -o dist/zap-linux-x64.zip -d /tmp/zap-static-check BIN=/tmp/zap-static-check/zap-cli file "$BIN" - file "$BIN" | grep -q 'statically linked' || { echo 'FAIL: zap-cli is not statically linked'; exit 1; } + # file(1): classic static says "statically linked"; musl static PIE says "static-pie linked" + file "$BIN" | grep -qE 'statically linked|static-pie linked' || { + echo 'FAIL: zap-cli is not a static ELF (expected "statically linked" or "static-pie linked")' + exit 1 + } GLIBC_REFS=$(objdump -T "$BIN" 2>/dev/null | grep -oE 'GLIBC_[0-9.]+' | sort -uV || true) echo "GLIBC versioned symbols: ${GLIBC_REFS:-(none)}" if [ -n "$GLIBC_REFS" ]; then echo 'FAIL: zap-cli still imports GLIBC symbols'; exit 1; fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 21f08bdd4f..ea3d62cbdb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -263,7 +263,11 @@ jobs: unzip -o dist/zap-linux-x64.zip -d /tmp/zap-static-check BIN=/tmp/zap-static-check/zap-cli file "$BIN" - file "$BIN" | grep -q 'statically linked' || { echo 'FAIL: zap-cli is not statically linked'; exit 1; } + # file(1): classic static says "statically linked"; musl static PIE says "static-pie linked" + file "$BIN" | grep -qE 'statically linked|static-pie linked' || { + echo 'FAIL: zap-cli is not a static ELF (expected "statically linked" or "static-pie linked")' + exit 1 + } GLIBC_REFS=$(objdump -T "$BIN" 2>/dev/null | grep -oE 'GLIBC_[0-9.]+' | sort -uV || true) echo "GLIBC versioned symbols: ${GLIBC_REFS:-(none)}" if [ -n "$GLIBC_REFS" ]; then echo 'FAIL: zap-cli still imports GLIBC symbols'; exit 1; fi From b1220f520b761c779c0a4959c3ac4471d1b8e184 Mon Sep 17 00:00:00 2001 From: brdandu Date: Mon, 11 May 2026 15:18:57 -0400 Subject: [PATCH 3/3] Minor cleanup --- .github/workflows/matter.yml | 4 ++++ .github/workflows/release.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/matter.yml b/.github/workflows/matter.yml index b0bedc48c1..1ca27999f7 100644 --- a/.github/workflows/matter.yml +++ b/.github/workflows/matter.yml @@ -204,6 +204,10 @@ jobs: name: Verify static zap-cli on ${{ matrix.label }} needs: [build-zap] runs-on: ubuntu-22.04 + defaults: + run: + # Container jobs default to dash; bash provides pipefail and [[ ]] in run scripts + shell: bash container: image: ${{ matrix.image }} strategy: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ea3d62cbdb..d9507f781a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -557,6 +557,10 @@ jobs: name: Verify static zap-cli on ${{ matrix.label }} needs: [build-zap] runs-on: ubuntu-22.04 + defaults: + run: + # Container jobs default to dash; bash provides pipefail and [[ ]] in run scripts + shell: bash container: image: ${{ matrix.image }} strategy: