mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-12 09:47:20 +08:00
Externalizing the integration templates (#1492/#1493) and the UI bundle
(#1501/#1503) was done to reduce the Microsoft `Wacatac.B!ml` surface. It did
not work: across dry runs the flagged artifact count stayed at ~3 and the
detections merely moved between artifacts.
Dissection of run 31286803592 shows there is no structural cause to fix. The
verdicts split across every axis at once — linux-amd64 (dynamic) flagged while
linux-amd64-portable (static) is clean, but linux-arm64 (dynamic) clean while
linux-arm64-portable (static) is flagged. The two macOS binaries have identical
segment structure and split clean/flagged. Siblings from one build landed in
different variant buckets (.B vs .C). Entropy is low everywhere
(code_vectors.bin 4.166, grammar tables 3.464 bits/byte, against 7.5-8.0 for
packed payloads), so the packed-payload hypothesis is excluded too.
So the complexity bought nothing, and installation goes back to being
self-contained: one binary that carries its own UI and agent integration
templates, with no adjacent data file that has to resolve before `install`
works. Only the UI-capable composition ships from now on, under the historical
unsuffixed archive name.
Removed: src/ui/asset_pack.{c,h}, asset_pack_stub.c, asset_manifest_stub.c,
scripts/pack-ui-assets.mjs, src/cli/integration_assets.{c,h},
assets/cbm-integrations.json, scripts/gen-integrations-hash.sh, the
--verify-runtime-assets probe (nothing adjacent left to verify), and the
composition gates A6/A7 whose property is now deliberately inverted.
Restored: scripts/embed-frontend.sh, src/ui/embedded_{assets.h,stub.c}, the
compiled-in hook/adapter template bodies, and the embed/EMBED_OBJS build path.
Kept from the reverted commits, re-applied by hand where a wholesale file
restore would have dropped them:
- cbm_module_path_utf8() in both self-path sites. GetModuleFileNameA renders
through the ANSI code page and mangles non-ASCII install paths.
- the /__cbm/ui-readiness HMAC proof, secure_random and cbm_hmac_sha256, so
`daemon start --open` still waits for a genuine CBM listener.
- X-Content-Type-Options: nosniff on served assets.
- the MinGW noexecstack gate, -lbcrypt, and the cppcheck/zip CI fixes.
Archives are now codebase-memory-mcp-<os>-<arch>[-portable] with exactly four
members (binary, LICENSE, installer, THIRD_PARTY_NOTICES.md). That restores the
names every static package manifest already points at — aur, chocolatey,
homebrew, scoop, winget and glama were all broken by the -ui- rename.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
204 lines
8.3 KiB
Bash
Executable File
204 lines
8.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# package-release.sh — THE canonical release-archive step. Every venue that
|
|
# turns built binaries into a release archive (release/_build.yml, the local
|
|
# artifact-flow smoke lane) runs this file; workflows provide only
|
|
# checkout/toolchain/upload around it. Archive names and contents are defined
|
|
# HERE, nowhere else, so a local artifact smoke provably exercises the same
|
|
# bytes-layout the release publishes.
|
|
#
|
|
# This script ARCHIVES what scripts/build.sh already produced; it never builds
|
|
# or synthesizes another executable.
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: scripts/package-release.sh <goos> <goarch> [--out-dir DIR] [VAR=VAL ...]
|
|
|
|
The canonical release-archive step: identical in the release build and the
|
|
local artifact-flow smoke lane.
|
|
|
|
goos linux | darwin | windows
|
|
goarch arch label used verbatim in the archive name (amd64, arm64,
|
|
arm64-portable, ...)
|
|
--out-dir where to place the archive (default: repository root).
|
|
|
|
Make passthrough (VAR=VAL, forwarded to the build):
|
|
CC= CXX= compiler override, e.g. CC=clang CXX=clang++.
|
|
|
|
Environment:
|
|
BUILD_DIR build tree to archive from (default build/c).
|
|
|
|
Archive contents (defined here, canonical) — ONE executable, no sidecars:
|
|
unix: codebase-memory-mcp LICENSE install.sh THIRD_PARTY_NOTICES.md (.tar.gz)
|
|
windows: codebase-memory-mcp.exe LICENSE install.ps1 THIRD_PARTY_NOTICES.md (.zip)
|
|
|
|
Only one build variant ships: the binary carries the graph UI and the agent
|
|
integration templates inside itself, so an extracted archive is immediately
|
|
complete — no adjacent data file has to resolve for `install` to work.
|
|
EOF
|
|
}
|
|
|
|
GOOS=""
|
|
GOARCH=""
|
|
OUT_DIR="$ROOT"
|
|
MAKE_ARGS=()
|
|
expect_value=""
|
|
for arg in "$@"; do
|
|
case "$expect_value" in
|
|
out-dir) OUT_DIR="$arg"; expect_value=""; continue ;;
|
|
esac
|
|
case "$arg" in
|
|
-h | --help) usage; exit 0 ;;
|
|
--out-dir) expect_value="out-dir" ;;
|
|
--out-dir=*) OUT_DIR="${arg#--out-dir=}" ;;
|
|
-*)
|
|
echo "package-release: unknown option '$arg'. Please consult --help." >&2
|
|
exit 2
|
|
;;
|
|
*=*) MAKE_ARGS+=("$arg") ;;
|
|
*)
|
|
if [ -z "$GOOS" ]; then GOOS="$arg"
|
|
elif [ -z "$GOARCH" ]; then GOARCH="$arg"
|
|
else
|
|
echo "package-release: unexpected argument '$arg'. Please consult --help." >&2
|
|
exit 2
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
[ -n "$GOOS" ] && [ -n "$GOARCH" ] || { usage >&2; exit 2; }
|
|
case "$GOOS" in
|
|
linux | darwin | windows) ;;
|
|
*) echo "package-release: goos must be linux, darwin or windows." >&2; exit 2 ;;
|
|
esac
|
|
[ -n "$expect_value" ] && { echo "package-release: --$expect_value needs a value." >&2; exit 2; }
|
|
|
|
BUILD_DIR="${BUILD_DIR:-build/c}"
|
|
OUT_DIR="$(mkdir -p "$OUT_DIR" && cd "$OUT_DIR" && pwd)"
|
|
NAME="codebase-memory-mcp-${GOOS}-${GOARCH}"
|
|
|
|
# Ship every release binary stripped. Production already builds without -g, but
|
|
# the linker still keeps a ~536 KB .symtab, so releases carried their full
|
|
# symbol table to users: bigger downloads and a free map of the internals, with
|
|
# nothing gained. Nothing symbolizes at runtime (mem_profile.c is not in the
|
|
# production build and never calls backtrace_symbols), so this costs no
|
|
# diagnostics.
|
|
#
|
|
# A historical unstripped linux-amd64 artifact was the sole Microsoft detection
|
|
# in release run 30398064336, while related stripped artifacts later scanned
|
|
# clean. That is useful release evidence but not controlled feature attribution:
|
|
# engine state and other bytes can differ between observations. Independently
|
|
# of the opaque verdict, stripping removes an unnecessary symbol surface and
|
|
# does not change program behavior.
|
|
#
|
|
# macOS is ad-hoc signed by the build workflow BEFORE this script runs, and
|
|
# stripping invalidates that signature, so Mach-O is re-signed here. Skipping
|
|
# the re-sign ships a binary the kernel refuses to exec.
|
|
strip_release_binary() {
|
|
local binary="$1"
|
|
[ -f "$binary" ] || return 0
|
|
# The right flags differ per format, and the WRONG ones fail silently in
|
|
# the dangerous direction. Measured on the flagged darwin-arm64 artifact:
|
|
#
|
|
# llvm-strip --strip-all 373 symbols scanned CLEAN
|
|
# strip (no flags) 378 symbols equivalent
|
|
# strip -x -S 4058 symbols the state VirusTotal FLAGGED
|
|
# strip -X / -u -r 4058 symbols likewise
|
|
#
|
|
# Apple's strip returns success for `-x -S`, so a helper that just tries
|
|
# candidates until one exits 0 would quietly reship the flagged binary.
|
|
# GNU/LLVM `--strip-all` is not even accepted by Apple's strip, which is why
|
|
# generalising it to every platform broke the macOS build -- loudly, which
|
|
# was the lucky outcome.
|
|
#
|
|
# So: --strip-all where it is understood, plain `strip` for Mach-O, and a
|
|
# hard error when no candidate can do the job. Never a weaker fallback.
|
|
local stripped=""
|
|
for tool in "${STRIP:-}" llvm-strip strip; do
|
|
[ -n "$tool" ] || continue
|
|
command -v "$tool" >/dev/null 2>&1 || continue
|
|
if "$tool" --strip-all "$binary" 2>/dev/null; then
|
|
stripped="$tool --strip-all"
|
|
elif [ "$GOOS" = "darwin" ] && "$tool" "$binary" 2>/dev/null; then
|
|
stripped="$tool"
|
|
fi
|
|
[ -n "$stripped" ] && break
|
|
done
|
|
if [ -z "$stripped" ]; then
|
|
echo "package-release: no working strip for $binary" >&2
|
|
return 1
|
|
fi
|
|
if [ "$GOOS" = "darwin" ]; then
|
|
command -v codesign >/dev/null 2>&1 &&
|
|
codesign --sign - --force "$binary" 2>/dev/null
|
|
fi
|
|
echo "=== package-release: stripped $(basename "$binary") ==="
|
|
return 0
|
|
}
|
|
|
|
if [ "$GOOS" = "windows" ]; then
|
|
# Windows ships one executable, exactly like every other runtime set. There is no
|
|
# launcher stub: a small unsigned PE whose entire job is to verify and
|
|
# execute another binary adds loader-like behavior and another artifact to
|
|
# audit. Historical launcher builds received Microsoft Wacatac verdicts,
|
|
# but that observation does not identify a stable feature or establish
|
|
# causation. Self-update — the launcher's whole reason to exist — moves OUT
|
|
# of the running process into install.ps1: Windows' executable lock only
|
|
# blocks a process from replacing ITSELF.
|
|
PAYLOAD="$BUILD_DIR/codebase-memory-mcp"
|
|
[ -f "${PAYLOAD}.exe" ] && PAYLOAD="${PAYLOAD}.exe"
|
|
[ -f "$PAYLOAD" ] || { echo "package-release: build first; missing $PAYLOAD" >&2; exit 2; }
|
|
STAGED_BINARY_NAME="codebase-memory-mcp.exe"
|
|
INSTALLER="install.ps1"
|
|
else
|
|
PAYLOAD="$BUILD_DIR/codebase-memory-mcp"
|
|
[ -f "$PAYLOAD" ] || { echo "package-release: build first; missing $PAYLOAD" >&2; exit 2; }
|
|
STAGED_BINARY_NAME="codebase-memory-mcp"
|
|
INSTALLER="install.sh"
|
|
fi
|
|
|
|
# Work from one owner-private directory for every target. The binary is copied
|
|
# here BEFORE strip/re-sign and the archive is created from this same directory,
|
|
# so the executable that validates the adjacent sidecars is byte-for-byte the
|
|
# executable users receive. Keeping the stage beside the build also avoids a
|
|
# system /tmp mounted noexec: the validation probe must actually execute.
|
|
PACK_DIR="$(mktemp -d "$BUILD_DIR/.cbm-package.XXXXXX")"
|
|
trap 'rm -rf "$PACK_DIR"' EXIT
|
|
STAGED_BINARY="$PACK_DIR/$STAGED_BINARY_NAME"
|
|
cp "$PAYLOAD" "$STAGED_BINARY"
|
|
strip_release_binary "$STAGED_BINARY" || exit 2
|
|
|
|
# Gate the artifact AFTER strip/re-sign: this is the final executable image and
|
|
# no later step may mutate it.
|
|
bash scripts/ci/check-binary-composition.sh "$STAGED_BINARY" || exit 2
|
|
|
|
cp LICENSE "$INSTALLER" "$PACK_DIR/"
|
|
scripts/gen-third-party-notices.sh "$PACK_DIR/THIRD_PARTY_NOTICES.md"
|
|
|
|
if [ "$GOOS" = "windows" ]; then
|
|
(
|
|
cd "$PACK_DIR"
|
|
rm -f "$OUT_DIR/$NAME.zip"
|
|
ARCHIVE_MEMBERS=(
|
|
codebase-memory-mcp.exe LICENSE install.ps1
|
|
THIRD_PARTY_NOTICES.md
|
|
)
|
|
zip -q "$OUT_DIR/$NAME.zip" "${ARCHIVE_MEMBERS[@]}"
|
|
)
|
|
echo "=== package-release: $OUT_DIR/$NAME.zip ==="
|
|
else
|
|
ARCHIVE_MEMBERS=(
|
|
codebase-memory-mcp LICENSE install.sh
|
|
THIRD_PARTY_NOTICES.md
|
|
)
|
|
# BSD tar otherwise materializes macOS extended attributes as hidden
|
|
# AppleDouble `._*` members, violating the exact four-file inventory.
|
|
COPYFILE_DISABLE=1 tar -czf "$OUT_DIR/$NAME.tar.gz" -C "$PACK_DIR" \
|
|
"${ARCHIVE_MEMBERS[@]}"
|
|
echo "=== package-release: $OUT_DIR/$NAME.tar.gz ==="
|
|
fi
|