fix(ci): scan extracted UI release files only

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-08-09 02:39:09 +02:00
1 parent 1ad53bb13d
commit 23e4fb0b4e
17 files changed
+204 -288

No files matched your search

+14 -119
View File
@@ -12,11 +12,6 @@ on:
description: 'Generate build provenance attestations for release artifacts'
type: boolean
default: false
ui_only:
description: 'Build only the UI runtime archives'
type: boolean
default: false
permissions:
contents: read
id-token: write
@@ -67,34 +62,7 @@ jobs:
with:
node-version: "22"
- name: Build standard binary
if: ${{ !inputs.ui_only }}
env:
VERSION: ${{ inputs.version }}
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
run: |
if [ -n "$VERSION" ]; then
scripts/build.sh --version "$VERSION" "CC=$CC" "CXX=$CXX"
else
scripts/build.sh "CC=$CC" "CXX=$CXX"
fi
- name: Ad-hoc sign macOS standard binary
if: ${{ !inputs.ui_only && startsWith(matrix.os, 'macos') }}
run: codesign --sign - --force build/c/codebase-memory-mcp
- name: Archive standard binary (canonical package-release.sh)
if: ${{ !inputs.ui_only }}
run: scripts/package-release.sh ${{ matrix.goos }} ${{ matrix.goarch }}
- name: Attest standard binary provenance
if: ${{ inputs.attest && !inputs.ui_only }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: codebase-memory-mcp-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz
- name: Build UI binary
- name: Build release binary with UI
env:
VERSION: ${{ inputs.version }}
CC: ${{ matrix.cc }}
@@ -106,7 +74,7 @@ jobs:
scripts/build.sh --with-ui "CC=$CC" "CXX=$CXX"
fi
- name: Ad-hoc sign macOS UI binary
- name: Ad-hoc sign macOS release binary
if: startsWith(matrix.os, 'macos')
run: codesign --sign - --force build/c/codebase-memory-mcp
@@ -116,10 +84,10 @@ jobs:
# Archive layout/name live in the ONE canonical script the local
# artifact-flow smoke lane also runs (venue-parity contract).
- name: Archive UI binary (canonical package-release.sh)
- name: Archive release binary (canonical package-release.sh)
run: scripts/package-release.sh ${{ matrix.goos }} ${{ matrix.goarch }} --variant ui
- name: Attest UI binary provenance
- name: Attest release binary provenance
if: ${{ inputs.attest }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
@@ -150,30 +118,7 @@ jobs:
with:
node-version: "22"
- name: Build standard binary
if: ${{ !inputs.ui_only }}
shell: msys2 {0}
env:
VERSION: ${{ inputs.version }}
run: |
if [ -n "$VERSION" ]; then
scripts/build.sh --version "$VERSION" CC=clang CXX=clang++
else
scripts/build.sh CC=clang CXX=clang++
fi
- name: Archive standard binary (canonical package-release.sh)
if: ${{ !inputs.ui_only }}
shell: msys2 {0}
run: scripts/package-release.sh windows amd64 CC=clang CXX=clang++
- name: Attest standard binary provenance
if: ${{ inputs.attest && !inputs.ui_only }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: codebase-memory-mcp-windows-amd64.zip
- name: Build UI binary
- name: Build release binary with UI
shell: msys2 {0}
env:
VERSION: ${{ inputs.version }}
@@ -186,11 +131,11 @@ jobs:
# Archive layout/name live in the ONE canonical script the local
# artifact-flow smoke lane also runs (venue-parity contract).
- name: Archive UI binary (canonical package-release.sh)
- name: Archive release binary (canonical package-release.sh)
shell: msys2 {0}
run: scripts/package-release.sh windows amd64 --variant ui CC=clang CXX=clang++
- name: Attest UI binary provenance
- name: Attest release binary provenance
if: ${{ inputs.attest }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
@@ -225,30 +170,7 @@ jobs:
with:
node-version: "22"
- name: Build standard binary
if: ${{ !inputs.ui_only }}
shell: msys2 {0}
env:
VERSION: ${{ inputs.version }}
run: |
if [ -n "$VERSION" ]; then
scripts/build.sh --version "$VERSION" CC=clang CXX=clang++
else
scripts/build.sh CC=clang CXX=clang++
fi
- name: Archive standard binary (canonical package-release.sh)
if: ${{ !inputs.ui_only }}
shell: msys2 {0}
run: scripts/package-release.sh windows arm64 CC=clang CXX=clang++
- name: Attest standard binary provenance
if: ${{ inputs.attest && !inputs.ui_only }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: codebase-memory-mcp-windows-arm64.zip
- name: Build UI binary
- name: Build release binary with UI
shell: msys2 {0}
env:
VERSION: ${{ inputs.version }}
@@ -259,11 +181,11 @@ jobs:
scripts/build.sh --with-ui CC=clang CXX=clang++
fi
- name: Archive UI binary (canonical package-release.sh)
- name: Archive release binary (canonical package-release.sh)
shell: msys2 {0}
run: scripts/package-release.sh windows arm64 --variant ui CC=clang CXX=clang++
- name: Attest UI binary provenance
- name: Attest release binary provenance
if: ${{ inputs.attest }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
@@ -297,34 +219,7 @@ jobs:
with:
node-version: "22"
- name: Build standard binary (static)
if: ${{ !inputs.ui_only }}
env:
VERSION: ${{ inputs.version }}
run: |
if [ -n "$VERSION" ]; then
scripts/build.sh --version "$VERSION" CC=gcc CXX=g++ STATIC=1
else
scripts/build.sh CC=gcc CXX=g++ STATIC=1
fi
- name: Verify standard static linking
if: ${{ !inputs.ui_only }}
run: |
file build/c/codebase-memory-mcp
ldd build/c/codebase-memory-mcp 2>&1 | grep -q "not a dynamic executable" || ldd build/c/codebase-memory-mcp 2>&1 | grep -q "statically linked"
- name: Archive standard binary (canonical package-release.sh)
if: ${{ !inputs.ui_only }}
run: scripts/package-release.sh linux ${{ matrix.arch }}-portable
- name: Attest standard binary provenance
if: ${{ inputs.attest && !inputs.ui_only }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: codebase-memory-mcp-linux-${{ matrix.arch }}-portable.tar.gz
- name: Build UI binary (static)
- name: Build release binary with UI (static)
env:
VERSION: ${{ inputs.version }}
run: |
@@ -334,15 +229,15 @@ jobs:
scripts/build.sh --with-ui CC=gcc CXX=g++ STATIC=1
fi
- name: Verify UI static linking
- name: Verify release static linking
run: |
file build/c/codebase-memory-mcp
ldd build/c/codebase-memory-mcp 2>&1 | grep -q "not a dynamic executable" || ldd build/c/codebase-memory-mcp 2>&1 | grep -q "statically linked"
- name: Archive UI binary (canonical package-release.sh)
- name: Archive release binary (canonical package-release.sh)
run: scripts/package-release.sh linux ${{ matrix.arch }}-portable --variant ui
- name: Attest UI binary provenance
- name: Attest release binary provenance
if: ${{ inputs.attest }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
+4 -15
View File
@@ -8,11 +8,6 @@ on:
description: 'Smoke the shipped binaries on the broad platform matrix (extra OS versions) instead of the core set'
type: boolean
default: false
ui_only:
description: 'Smoke only the UI runtime archives'
type: boolean
default: false
permissions:
contents: read
@@ -34,7 +29,6 @@ jobs:
id: set
env:
BROAD: ${{ inputs.broad_platforms }}
UI_ONLY: ${{ inputs.ui_only }}
run: |
CORE_UNIX='[
{"os":"ubuntu-latest","goos":"linux","goarch":"amd64"},
@@ -77,14 +71,9 @@ jobs:
WIN=$(jq -cn --argjson a "$CORE_WIN" '$a')
PORTABLE=$(jq -cn --argjson a "$CORE_PORTABLE" '$a')
fi
# Keep the variant dimension explicit because the smoke wrappers use it
# to require and validate the UI pack. VT-focused dry runs select only
# UI; release compatibility retains both variants until migration.
if [ "$UI_ONLY" = "true" ]; then
VARIANTS='["ui"]'
else
VARIANTS='["standard","ui"]'
fi
# Keep the UI marker explicit because the smoke wrappers use it to
# require and validate the shipped content-addressed frontend pack.
VARIANTS='["ui"]'
UNIX_M=$(jq -cn --argjson a "$UNIX" --argjson v "$VARIANTS" '{include:[$a[] as $o | $v[] as $t | ($o + {variant:$t})]}')
WIN_M=$(jq -cn --argjson a "$WIN" --argjson v "$VARIANTS" '{include:[$a[] as $o | $v[] as $t | ($o + {variant:$t})]}')
PORTABLE_M=$(jq -cn --argjson a "$PORTABLE" --argjson v "$VARIANTS" '{include:[$a[] as $o | $v[] as $t | ($o + {variant:$t})]}')
@@ -140,7 +129,7 @@ jobs:
scripts/security-network.sh "$BIN"
- name: MCP robustness test (selected linux-amd64 runtime)
if: matrix.goos == 'linux' && matrix.goarch == 'amd64' && (inputs.ui_only || matrix.variant == 'standard')
if: matrix.goos == 'linux' && matrix.goarch == 'amd64'
run: |
BIN="$RUNNER_TEMP/cbm-artifact/codebase-memory-mcp"
scripts/security-fuzz.sh "$BIN"
+3 -5
View File
@@ -91,7 +91,6 @@ jobs:
uses: ./.github/workflows/_build.yml
with:
attest: false
ui_only: true
# ── Smoke test every binary ────────────────────────────────────
# Run unless builds were skipped or a build leg FAILED. Every build leg
@@ -103,7 +102,6 @@ jobs:
uses: ./.github/workflows/_smoke.yml
with:
broad_platforms: true
ui_only: true
# ── Soak tests (optional, parallel with smoke) ────────────────
soak:
@@ -148,8 +146,8 @@ jobs:
merge-multiple: true
path: ${{ runner.temp }}/release-archives
# Same extraction the release verify job performs, so the bytes handed to
# VirusTotal here are the bytes a user would download and run.
# Same extraction the release verify job performs. VirusTotal receives
# only extracted files and unpacked UI assets, never .tar.gz/.zip containers.
- name: Extract archive artifacts
run: |
scripts/ci/extract-release-archives.sh "$RUNNER_TEMP/release-archives" binaries \
@@ -167,7 +165,7 @@ jobs:
files: binaries/objects/*
request_rate: 4
# Same ZERO-tolerance gate as the release. Every artifact must arrive
# Same ZERO-tolerance gate as the release. Every extracted object must arrive
# naturally clean; any malicious or suspicious verdict fails this run.
- name: Wait for VirusTotal results
env:
+9 -8
View File
@@ -216,15 +216,16 @@ jobs:
mkdir -p "$ARCHIVE_DIR" binaries
gh release download "$VERSION" --dir "$ARCHIVE_DIR" --repo "$GITHUB_REPOSITORY" --pattern '*.tar.gz' --pattern '*.zip'
scripts/ci/extract-release-archives.sh "$ARCHIVE_DIR" binaries \
--expect-archives=16 \
--expect-binaries=16 \
--archive-scope=ui \
--expect-archives=8 \
--expect-binaries=8 \
--expect-packs=8 \
--expect-runtime-files=64
--expect-runtime-files=32
- name: Security audits on all unique release objects
- name: Security audits on all unique extracted release objects
run: |
# Audit every distinct archive/member/UI-asset byte sequence. The
# associations manifest preserves every shipped archive location.
# Audit every distinct extracted member/UI-asset byte sequence. The
# associations manifest retains each source archive's SHA-256.
# security-strings.sh detects file type and applies binary-only
# rules (URL allowlist, dangerous-command detection) only to real
# binaries; for shell scripts it still runs credential and base64
@@ -243,7 +244,7 @@ jobs:
files: binaries/objects/*
request_rate: 4
# ZERO tolerance: every artifact must arrive naturally clean. Any
# ZERO tolerance: every extracted object must arrive naturally clean. Any
# malicious or suspicious verdict blocks the release with no exception.
- name: Wait for VirusTotal results
env:
@@ -275,7 +276,7 @@ jobs:
VT_RESULTS_PATH: binaries/vt-results.tsv
run: bash scripts/ci/publish-vt-evidence.sh
# Renders the exact scan scope plus archive SHA-256/engine evidence. It
# Renders extracted-file scan results plus archive SHA-256 provenance. It
# runs only after the exact-set zero-tolerance gate passed.
- name: Append VirusTotal scan links to release notes
env: