From 2088ce0d9cc18f5f5961eedefd5a9b029ff04c61 Mon Sep 17 00:00:00 2001 From: Keegan Smith Date: Wed, 9 Sep 2026 08:35:18 +0000 Subject: [PATCH] feat/packaging: make forked Git installs reproducible and relocatable Sourcegraph needs a prebuilt Git with its practical feature set intact on Amp orbs and engineer Macs, without requiring Nix or native compilation on consuming machines. Pinning source and build environments, recording recipe provenance separately, and carrying redistributed dependency notices makes the manually produced archives reviewable and suitable for immutable publication after platform validation. Co-authored-by: Amp Amp-Thread-ID: https://ampcode.com/threads/T-01a081bc-ccc0-753b-9d0d-e27952625463 --- .../sourcegraph/packaging/Dockerfile.linux | 10 ++ contrib/sourcegraph/packaging/README.md | 105 +++++++++++++++++ contrib/sourcegraph/packaging/build-darwin.sh | 102 +++++++++++++++++ .../packaging/build-from-source.sh | 107 ++++++++++++++++++ contrib/sourcegraph/packaging/build-linux.sh | 46 ++++++++ .../packaging/bundle-linux-libraries.sh | 102 +++++++++++++++++ .../packaging/validate-linux-archive.sh | 101 +++++++++++++++++ .../packaging/verify-darwin-dependencies.sh | 41 +++++++ 8 files changed, 614 insertions(+) create mode 100644 contrib/sourcegraph/packaging/Dockerfile.linux create mode 100644 contrib/sourcegraph/packaging/README.md create mode 100755 contrib/sourcegraph/packaging/build-darwin.sh create mode 100755 contrib/sourcegraph/packaging/build-from-source.sh create mode 100755 contrib/sourcegraph/packaging/build-linux.sh create mode 100755 contrib/sourcegraph/packaging/bundle-linux-libraries.sh create mode 100755 contrib/sourcegraph/packaging/validate-linux-archive.sh create mode 100755 contrib/sourcegraph/packaging/verify-darwin-dependencies.sh diff --git a/contrib/sourcegraph/packaging/Dockerfile.linux b/contrib/sourcegraph/packaging/Dockerfile.linux new file mode 100644 index 00000000000000..f7e535c80ee932 --- /dev/null +++ b/contrib/sourcegraph/packaging/Dockerfile.linux @@ -0,0 +1,10 @@ +FROM debian:12@sha256:6ebd97fa83deb272194a2cf015b3d26a4d538e9ad3a7a79d544c8af5b0a01443 + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + build-essential ca-certificates cargo file gettext libcurl4-openssl-dev \ + libexpat1-dev libpcre2-dev libssl-dev patchelf perl tcl tk zlib1g-dev && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /src +ENTRYPOINT ["contrib/sourcegraph/packaging/build-from-source.sh", "linux-amd64"] diff --git a/contrib/sourcegraph/packaging/README.md b/contrib/sourcegraph/packaging/README.md new file mode 100644 index 00000000000000..fa752c9b8d88ac --- /dev/null +++ b/contrib/sourcegraph/packaging/README.md @@ -0,0 +1,105 @@ +# Sourcegraph Git archives + +These scripts produce full, relocatable Git installations for Sourcegraph +engineer Macs and Amp orbs. They do not change Git behavior. Both builders +export the exact upstream-compatible `v2.55.0` source at commit +`e9019fcafe0040228b8631c30f97ae1adb61bcdc`, regardless of the branch from +which the packaging script runs. + +The intended immutable downstream release is `sourcegraph/v2.55.0-1`. A +release consists of exactly these files: + +* `git-sourcegraph-v2.55.0-1-linux-amd64.tar.gz` +* `git-sourcegraph-v2.55.0-1-linux-amd64.tar.gz.sha256` +* `git-sourcegraph-v2.55.0-1-darwin-arm64.tar.gz` +* `git-sourcegraph-v2.55.0-1-darwin-arm64.tar.gz.sha256` + +Each archive has one `git-sourcegraph/` root. Stripping that directory exposes +`bin/`, `libexec/`, `share/`, optional `lib/`, and `BUILD-INFO`. The latter +records the source tag and commit, downstream version, build host, dependency +versions, recipe commit, and the identity embedded in Git. The source commit is +what was compiled; the recipe commit identifies the packaging implementation. +Consumers should verify the checksum sidecar before extracting. + +The source constants in both entry-point scripts move together. They currently +pin upstream `v2.55.0` because this experiment has no behavior patches. When a +future Sourcegraph behavior patch lands, update the source ref and commit to the +exact downstream revision containing that patch; never leave the builder +exporting an older upstream commit. + +## Linux AMD64 + +Install Docker, then run: + +```console +./contrib/sourcegraph/packaging/build-linux.sh +./contrib/sourcegraph/packaging/validate-linux-archive.sh \ + artifacts/git-sourcegraph-v2.55.0-1-linux-amd64.tar.gz +``` + +The builder image starts from Debian 12 at a pinned multi-platform image +digest. `BUILD-INFO` captures the selected amd64 image's installed package +versions. The archive bundles the non-glibc dynamic dependency closure and +uses relative ELF RPATHs; glibc itself remains at Debian 12's 2.36 baseline. +Installed executables are stripped without removing features. +Git's Rust components remain enabled and are built with Debian's Rust toolchain. +The build container uses the invoking user's numeric UID and GID so bind-mount +contents and resulting artifacts remain owned and removable by that user. +The validator moves the unpacked tree, checks source identity, templates, +PCRE2, user config, `/etc/gitconfig`, HTTPS, and all ELF dependencies. + +## macOS ARM64 + +The Mac artifact must be built and validated on a supported Apple Silicon Mac. +Install Xcode command-line tools, Rust, and GNU tar, then run: + +```console +xcode-select --install # if the tools are not already installed +brew install rust gnu-tar +./contrib/sourcegraph/packaging/build-darwin.sh +``` + +The script discards inherited Nix SDK, compiler, and library search settings; +uses an Apple Xcode SDK; and targets macOS 14 by default. If `xcode-select` +points outside the normal Apple developer directories, the script uses +`/Applications/Xcode.app` when available and otherwise stops before building. +Override Xcode with `SOURCEGRAPH_GIT_DEVELOPER_DIR` or the deployment floor with +`SOURCEGRAPH_GIT_DEPLOYMENT_TARGET` only when deliberately preparing a +different artifact. It downloads checksum-pinned PCRE2 10.48 source and builds +it statically for the same target. Git uses the macOS SDK's curl, iconv, and +system libraries. Localization is disabled because macOS has no system libintl +and linking an incidental Homebrew gettext would make the archive depend on +the build machine. Git still includes its English fallthrough messages. + +The full install includes `git-credential-osxkeychain`, rejects non-system +Mach-O dependencies (including `/opt/homebrew` and build paths), verifies +arm64 and the macOS 14 deployment floor, strips ephemeral source/staging paths, +and then ad-hoc signs unsigned installed binaries. Ad-hoc signatures are not +Apple notarization and do not establish publisher identity. + +Before an experimental service release, unpack the archive into two different +directories and run `bin/git version --build-options`, `bin/git init`, a PCRE2 +`git grep -P`, an HTTPS clone/fetch, and the team's normal SSH, GPG signing, and +Git LFS workflows. Inspect every Mach-O file with `otool -L` and +`codesign --verify --verbose`. Publish the checksummed archives only as an +opt-in prerelease under an immutable downstream tag; sign that tag separately +when signing infrastructure is available. Creating the tag or GitHub release +is intentionally outside these scripts. + +Validation on macOS 26.6.2 exercised those core workflows, but the locked +noninteractive login keychain prevented a `credential-osxkeychain` store/get/ +erase round trip. The macOS 14 deployment floor was inspected in Mach-O load +commands, not run on macOS 14. Complete both checks before describing this as a +fully supported everyday Git replacement. + +## License notices + +Both archives include Git's `COPYING` under `LICENSES/`. Darwin also includes +the pinned PCRE2 source's `LICENCE`. Linux includes Debian's copyright notice +for every package whose shared library is copied into `lib/`, while +`BUNDLED-LIBRARIES` records each library's exact binary and source package +versions and a Debian source-retrieval link. References to Debian's +`/usr/share/common-licenses` resolve within `LICENSES/debian/common-licenses`. +System libraries referenced by the Darwin archive are not redistributed. +Release notes should link the exact Git and PCRE2 sources; checksum sidecars +are checksums, not signatures. diff --git a/contrib/sourcegraph/packaging/build-darwin.sh b/contrib/sourcegraph/packaging/build-darwin.sh new file mode 100755 index 00000000000000..fe51c82efe341f --- /dev/null +++ b/contrib/sourcegraph/packaging/build-darwin.sh @@ -0,0 +1,102 @@ +#!/bin/sh +set -eu + +SOURCE_TAG=v2.55.0 +SOURCE_COMMIT=e9019fcafe0040228b8631c30f97ae1adb61bcdc +RELEASE_VERSION=v2.55.0-1 +PCRE2_VERSION=10.48 +PCRE2_SHA256=b6c68fdf6f3ac31388b50aa89ff0fc49c00c987c16e7b5146491d12003f2c8ed + +test "$(uname -s)" = Darwin && test "$(uname -m)" = arm64 || { + echo 'error: the Darwin archive must be built on an arm64 Mac' >&2 + exit 1 +} + +root=$(git rev-parse --show-toplevel) +output=${1:-"$root/artifacts"} +RECIPE_COMMIT=$(git -C "$root" rev-parse HEAD) +actual=$(git -C "$root" rev-parse "$SOURCE_TAG^{commit}") +test "$actual" = "$SOURCE_COMMIT" || { + echo "error: $SOURCE_TAG resolved to $actual, expected $SOURCE_COMMIT" >&2 + exit 1 +} + +mkdir -p "$output" +output=$(cd "$output" && pwd) +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT HUP INT TERM + +# Resolve the non-Apple tools before replacing the inherited PATH. Sourcegraph +# shells may export a Nix SDK and library search paths which must not influence +# a redistributable Mac build. +rust_dir=$(dirname "$(command -v rustc)") +cargo_dir=$(dirname "$(command -v cargo)") +gtar_dir=$(dirname "$(command -v gtar)") +unset SDKROOT CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH LIBRARY_PATH \ + LD_LIBRARY_PATH DYLD_LIBRARY_PATH PKG_CONFIG_PATH CFLAGS CPPFLAGS LDFLAGS \ + CC CXX AR RANLIB +if test -n "${SOURCEGRAPH_GIT_DEVELOPER_DIR:-}" +then + DEVELOPER_DIR=$SOURCEGRAPH_GIT_DEVELOPER_DIR +else + selected_developer_dir=$(/usr/bin/xcode-select -p) + case "$selected_developer_dir" in + /Applications/*.app/Contents/Developer|/Library/Developer/CommandLineTools) + DEVELOPER_DIR=$selected_developer_dir ;; + *) + if test -d /Applications/Xcode.app/Contents/Developer + then + DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer + else + echo "error: xcode-select resolved non-Apple developer directory: $selected_developer_dir" >&2 + echo 'set SOURCEGRAPH_GIT_DEVELOPER_DIR to an Apple Xcode or CommandLineTools directory' >&2 + exit 1 + fi ;; + esac +fi +export DEVELOPER_DIR +SDKROOT=$(/usr/bin/xcrun --sdk macosx --show-sdk-path) +export SDKROOT +MACOSX_DEPLOYMENT_TARGET=${SOURCEGRAPH_GIT_DEPLOYMENT_TARGET:-14.0} +export MACOSX_DEPLOYMENT_TARGET +CC=$(/usr/bin/xcrun --find clang) +AR=$(/usr/bin/xcrun --find ar) +RANLIB=$(/usr/bin/xcrun --find ranlib) +export CC AR RANLIB +PATH="$rust_dir:$cargo_dir:$gtar_dir:/usr/bin:/bin:/usr/sbin:/sbin" +export PATH + +# Detect an invalid or incomplete selected SDK before doing the dependency build. +printf '#include \n' | "$CC" -isysroot "$SDKROOT" -x c -fsyntax-only - || { + echo "error: selected Xcode SDK cannot compile against zlib: $SDKROOT" >&2 + exit 1 +} + +git -C "$root" archive "$SOURCE_COMMIT" | tar -x -C "$work" +mkdir -p "$work/contrib/sourcegraph" +cp -R "$root/contrib/sourcegraph/packaging" "$work/contrib/sourcegraph/" + +pcre_archive="$work/pcre2-$PCRE2_VERSION.tar.bz2" +/usr/bin/curl -fL --retry 3 \ + "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$PCRE2_VERSION/pcre2-$PCRE2_VERSION.tar.bz2" \ + -o "$pcre_archive" +printf '%s %s\n' "$PCRE2_SHA256" "$pcre_archive" | /usr/bin/shasum -a 256 -c - +tar -xjf "$pcre_archive" -C "$work" +pcre_prefix="$work/pcre2-install" +( + cd "$work/pcre2-$PCRE2_VERSION" + ./configure --prefix="$pcre_prefix" --disable-shared --enable-static --enable-jit + /usr/bin/make -j"$(getconf _NPROCESSORS_ONLN)" + /usr/bin/make install +) + +( + cd "$work" + SOURCE_DATE_EPOCH=$(git -C "$root" show -s --format=%ct "$SOURCE_COMMIT") \ + SOURCE_COMMIT="$SOURCE_COMMIT" SOURCE_TAG="$SOURCE_TAG" \ + RECIPE_COMMIT="$RECIPE_COMMIT" RELEASE_VERSION="$RELEASE_VERSION" \ + PCRE2_PREFIX="$pcre_prefix" \ + PCRE2_LICENSE="$work/pcre2-$PCRE2_VERSION/LICENCE.md" \ + SOURCE_BUILD_ROOT="$work" \ + contrib/sourcegraph/packaging/build-from-source.sh darwin-arm64 "$output" +) diff --git a/contrib/sourcegraph/packaging/build-from-source.sh b/contrib/sourcegraph/packaging/build-from-source.sh new file mode 100755 index 00000000000000..d04a12b4b14b22 --- /dev/null +++ b/contrib/sourcegraph/packaging/build-from-source.sh @@ -0,0 +1,107 @@ +#!/bin/sh +set -eu + +platform=${1:?usage: build-from-source.sh PLATFORM [OUTPUT]} +output=${2:-/out} +: "${SOURCE_COMMIT:?SOURCE_COMMIT is required}" +: "${SOURCE_TAG:?SOURCE_TAG is required}" +: "${RECIPE_COMMIT:?RECIPE_COMMIT is required}" +: "${RELEASE_VERSION:?RELEASE_VERSION is required}" +: "${SOURCE_DATE_EPOCH:?SOURCE_DATE_EPOCH is required}" + +stage=$(mktemp -d) +trap 'rm -rf "$stage"' EXIT HUP INT TERM + +case "$platform" in + linux-amd64) + test "$(uname -s)-$(uname -m)" = Linux-x86_64 + make_options='RUNTIME_PREFIX=YesPlease USE_LIBPCRE2=YesPlease INSTALL_STRIP=-s NO_INSTALL_HARDLINKS=YesPlease' + ;; + darwin-arm64) + test "$(uname -s)-$(uname -m)" = Darwin-arm64 + # Force the SDK-provided iconv instead of config.mak.uname's Homebrew + # workaround on recent Darwin. Expose only the locally built PCRE2 + # static archive so no package-manager path survives the installation. + pcre_prefix=${PCRE2_PREFIX:?PCRE2_PREFIX is required on Darwin} + test -f "$pcre_prefix/lib/libpcre2-8.a" + static_pcre="$stage/static-pcre2" + mkdir "$static_pcre" + ln -s "$pcre_prefix/include" "$static_pcre/include" + mkdir "$static_pcre/lib" + cp "$pcre_prefix/lib/libpcre2-8.a" "$static_pcre/lib/" + make_options="RUNTIME_PREFIX=YesPlease USE_LIBPCRE2=YesPlease \ + LIBPCREDIR=$static_pcre ICONVDIR=/usr \ + INSTALL_STRIP=-s NO_GETTEXT=YesPlease NO_INSTALL_HARDLINKS=YesPlease \ + USE_HOMEBREW_LIBICONV= NEEDS_GOOD_LIBICONV=" + ;; + *) echo "error: unsupported platform: $platform" >&2; exit 1 ;; +esac + +prefix="$stage/git-sourcegraph" +mkdir -p "$prefix" "$output" + +# Do not let a caller's prior build flags leak into the release artifact. +make clean +# shellcheck disable=SC2086 +make -j"$(getconf _NPROCESSORS_ONLN)" $make_options \ + prefix=/ sysconfdir=/etc GIT_VERSION=2.55.0 \ + GIT_BUILT_FROM_COMMIT="$SOURCE_COMMIT" all +# shellcheck disable=SC2086 +make $make_options prefix=/ sysconfdir=/etc GIT_VERSION=2.55.0 \ + GIT_BUILT_FROM_COMMIT="$SOURCE_COMMIT" DESTDIR="$prefix" install + +mkdir "$prefix/LICENSES" +cp COPYING "$prefix/LICENSES/Git-COPYING" + +if test "$platform" = darwin-arm64 +then + pcre2_license=${PCRE2_LICENSE:?PCRE2_LICENSE is required on Darwin} + test -f "$pcre2_license" || { + echo "error: PCRE2 license notice not found: $pcre2_license" >&2 + exit 1 + } + cp "$pcre2_license" "$prefix/LICENSES/PCRE2-LICENCE" + # The keychain helper is intentionally included in the full Mac install. + # shellcheck disable=SC2086 + make $make_options prefix=/ sysconfdir=/etc GIT_VERSION=2.55.0 \ + GIT_BUILT_FROM_COMMIT="$SOURCE_COMMIT" DESTDIR="$prefix" \ + install-git-credential-osxkeychain + contrib/sourcegraph/packaging/verify-darwin-dependencies.sh "$prefix" +else + contrib/sourcegraph/packaging/bundle-linux-libraries.sh "$prefix" +fi + +{ + echo "release_version=$RELEASE_VERSION" + echo "source_tag=$SOURCE_TAG" + echo "source_commit=$SOURCE_COMMIT" + echo "recipe_commit=$RECIPE_COMMIT" + echo "platform=$platform" + echo "source_date_epoch=$SOURCE_DATE_EPOCH" + echo "git_version=$($prefix/bin/git --version)" + echo "git_build_options=$($prefix/bin/git version --build-options | tr '\n' ';')" + echo "build_uname=$(uname -a)" + echo "cc_version=$(cc --version | head -1)" + echo "rustc_version=$(rustc --version)" + echo "cargo_version=$(cargo --version)" + if command -v dpkg-query >/dev/null 2>&1 + then + echo 'builder_image=debian:12@sha256:6ebd97fa83deb272194a2cf015b3d26a4d538e9ad3a7a79d544c8af5b0a01443' + echo 'build_packages_begin' + dpkg-query -W -f='${Package}=${Version}\n' | LC_ALL=C sort + echo 'build_packages_end' + else + echo "xcode_version=$(xcodebuild -version | tr '\n' ';')" + echo 'pcre2_version=10.48' + echo 'pcre2_source_sha256=b6c68fdf6f3ac31388b50aa89ff0fc49c00c987c16e7b5146491d12003f2c8ed' + echo "macosx_deployment_target=${MACOSX_DEPLOYMENT_TARGET:-unset}" + fi +} >"$prefix/BUILD-INFO" + +archive="git-sourcegraph-${RELEASE_VERSION}-${platform}.tar.gz" +tar_command=tar +test "$platform" != darwin-arm64 || tar_command=${GTAR:-gtar} +COPYFILE_DISABLE=1 TZ=UTC "$tar_command" --sort=name --mtime="@$SOURCE_DATE_EPOCH" \ + --owner=0 --group=0 --numeric-owner -czf "$output/$archive" -C "$stage" git-sourcegraph +(cd "$output" && shasum -a 256 "$archive" >"$archive.sha256") +echo "$output/$archive" diff --git a/contrib/sourcegraph/packaging/build-linux.sh b/contrib/sourcegraph/packaging/build-linux.sh new file mode 100755 index 00000000000000..891cd81b4d823f --- /dev/null +++ b/contrib/sourcegraph/packaging/build-linux.sh @@ -0,0 +1,46 @@ +#!/bin/sh +set -eu + +SOURCE_TAG=v2.55.0 +SOURCE_COMMIT=e9019fcafe0040228b8631c30f97ae1adb61bcdc +RELEASE_VERSION=v2.55.0-1 +IMAGE=git-sourcegraph-linux-builder:v2.55.0-1 + +root=$(git rev-parse --show-toplevel) +output=${1:-"$root/artifacts"} +RECIPE_COMMIT=$(git -C "$root" rev-parse HEAD) +actual=$(git -C "$root" rev-parse "$SOURCE_TAG^{commit}") +test "$actual" = "$SOURCE_COMMIT" || { + echo "error: $SOURCE_TAG resolved to $actual, expected $SOURCE_COMMIT" >&2 + exit 1 +} + +mkdir -p "$output" +output=$(cd "$output" && pwd) +work=$(mktemp -d) +cleanup() { + status=$? + trap - EXIT HUP INT TERM + rm -rf "$work" || : + exit "$status" +} +trap cleanup EXIT HUP INT TERM + +# Export the release source rather than building whichever fork branch happens +# to contain these packaging scripts. +git -C "$root" archive "$SOURCE_COMMIT" | tar -x -C "$work" +mkdir -p "$work/contrib/sourcegraph" +cp -R "$root/contrib/sourcegraph/packaging" "$work/contrib/sourcegraph/" + +docker build -f "$root/contrib/sourcegraph/packaging/Dockerfile.linux" -t "$IMAGE" "$root" +docker run --rm \ + --user "$(id -u):$(id -g)" \ + -e HOME=/tmp \ + -e SOURCE_DATE_EPOCH="$(git -C "$root" show -s --format=%ct "$SOURCE_COMMIT")" \ + -e SOURCE_COMMIT="$SOURCE_COMMIT" \ + -e SOURCE_TAG="$SOURCE_TAG" \ + -e RECIPE_COMMIT="$RECIPE_COMMIT" \ + -e RELEASE_VERSION="$RELEASE_VERSION" \ + -v "$work:/src" \ + -v "$output:/out" \ + "$IMAGE" diff --git a/contrib/sourcegraph/packaging/bundle-linux-libraries.sh b/contrib/sourcegraph/packaging/bundle-linux-libraries.sh new file mode 100755 index 00000000000000..e0c8fa41513169 --- /dev/null +++ b/contrib/sourcegraph/packaging/bundle-linux-libraries.sh @@ -0,0 +1,102 @@ +#!/bin/sh +set -eu + +prefix=${1:?usage: bundle-linux-libraries.sh PREFIX} +mkdir -p "$prefix/lib" +notices="$prefix/LICENSES/debian" +mkdir -p "$notices" +cp -R /usr/share/common-licenses "$notices/common-licenses" +cat >"$notices/README" <<'EOF' +Debian copyright notices in this directory may refer to license texts under +/usr/share/common-licenses. Their archived copies are in common-licenses/. +EOF +manifest="$prefix/BUNDLED-LIBRARIES" +printf 'library\tbinary_package\tbinary_version\tsource_package\tsource_version\tsource_retrieval\tcopyright_notice\n' >"$manifest" + +find_elfs() { + find "$prefix/bin" "$prefix/libexec" -type f -perm -111 -exec file {} + | + sed -n 's/: .*ELF .*//p' +} + +find_owning_package() { + library=$1 + canonical=$(readlink -f "$library") + for candidate in "$library" "$canonical" + do + case "$candidate" in + /lib/*) alternate=/usr$candidate ;; + /usr/lib/*) alternate=${candidate#/usr} ;; + *) alternate= ;; + esac + for path in "$candidate" "$alternate" + do + test -n "$path" || continue + if ownership=$(dpkg-query -S "$path" 2>/dev/null) + then + printf '%s\n' "$ownership" | sed -n '1{s/: \/.*//;p;}' + return 0 + fi + done + done + return 1 +} + +# ldd reports the complete transitive closure. Keep glibc, its loader, and the +# base POSIX libraries on the host so the archive retains Debian 12's glibc +# floor; bundle feature libraries such as curl, OpenSSL, PCRE2, and expat. +find_elfs | while IFS= read -r executable +do + ldd "$executable" +done | awk '/=> \// { print $3 } /^\// { print $1 }' | LC_ALL=C sort -u | +while IFS= read -r library +do + case "$(basename "$library")" in + ld-linux-*|libc.so.*|libdl.so.*|libm.so.*|libpthread.so.*|libresolv.so.*|librt.so.*|libutil.so.*) + continue ;; + esac + library_name=$(basename "$library") + cp -L "$library" "$prefix/lib/$library_name" + + if package_spec=$(find_owning_package "$library") + then + : + else + echo "error: no Debian package owns $library" >&2 + exit 1 + fi + package=${package_spec%%:*} + package_metadata=$(dpkg-query -W \ + -f='${binary:Package}\t${Version}\t${source:Package}\t${source:Version}' \ + "$package_spec") + tab=$(printf '\t') + IFS="$tab" read -r binary_package binary_version source_package source_version <&2 + exit 1 + } + copyright_name="$package.copyright" + cp -L "$copyright_source" "$notices/$copyright_name" + printf '%s\t%s\t%s\t%s\t%s\thttps://snapshot.debian.org/package/%s/\tLICENSES/debian/%s\n' \ + "$library_name" "$binary_package" "$binary_version" \ + "$source_package" "$source_version" "$source_package" \ + "$copyright_name" >>"$manifest" +done + +for library in "$prefix"/lib/* +do + patchelf --set-rpath '$ORIGIN' "$library" +done + +find_elfs | while IFS= read -r executable +do + relative=${executable#"$prefix"/} + case "$relative" in + bin/*) rpath='$ORIGIN/../lib' ;; + libexec/git-core/*) rpath='$ORIGIN/../../lib' ;; + *) echo "error: unknown executable location: $relative" >&2; exit 1 ;; + esac + patchelf --set-rpath "$rpath" "$executable" +done diff --git a/contrib/sourcegraph/packaging/validate-linux-archive.sh b/contrib/sourcegraph/packaging/validate-linux-archive.sh new file mode 100755 index 00000000000000..f97d9b9921c477 --- /dev/null +++ b/contrib/sourcegraph/packaging/validate-linux-archive.sh @@ -0,0 +1,101 @@ +#!/bin/sh +set -eu + +archive=${1:?usage: validate-linux-archive.sh ARCHIVE} +expected_commit=e9019fcafe0040228b8631c30f97ae1adb61bcdc +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT HUP INT TERM + +roots=$(tar -tzf "$archive" | sed 's,/.*,,' | LC_ALL=C sort -u) +test "$roots" = git-sourcegraph + +for location in first/a second/moved/prefix +do + mkdir -p "$work/$location" + tar -xzf "$archive" -C "$work/$location" --strip-components=1 + git="$work/$location/bin/git" + test -s "$work/$location/LICENSES/Git-COPYING" + test -s "$work/$location/BUNDLED-LIBRARIES" + test "$($git --version)" = 'git version 2.55.0' + $git version --build-options | grep -F "built from commit: $expected_commit" + test "$($git --exec-path)" = "$work/$location/libexec/git-core" + test "$($git --html-path)" = "$work/$location/share/doc/git-doc" + + home="$work/home" + mkdir -p "$home" + HOME="$home" "$git" config --global sourcegraph.archive-test true + test "$(HOME="$home" "$git" config --global --get sourcegraph.archive-test)" = true + GIT_CONFIG_SYSTEM=/dev/null HOME="$home" "$git" init -q "$work/repository" + test -f "$work/repository/.git/hooks/applypatch-msg.sample" + printf 'needle\n' >"$work/repository/content" + GIT_CONFIG_SYSTEM=/dev/null HOME="$home" "$git" -C "$work/repository" add content + GIT_CONFIG_SYSTEM=/dev/null HOME="$home" "$git" -C "$work/repository" grep -P 'n(?=eedle)' + rm -rf "$work/repository" +done + +# Every bundled shared library identifies its exact Debian binary/source +# package, source retrieval location, and included copyright notice. +prefix="$work/second/moved/prefix" +test -s "$prefix/LICENSES/debian/README" +test -s "$prefix/LICENSES/debian/common-licenses/GPL-2" +test -s "$prefix/LICENSES/debian/common-licenses/LGPL-2.1" +tab=$(printf '\t') +tail -n +2 "$prefix/BUNDLED-LIBRARIES" | while IFS="$tab" read -r \ + library binary_package binary_version source_package source_version source_url copyright_notice +do + test -n "$binary_package" && test -n "$binary_version" + test -n "$source_package" && test -n "$source_version" + test "$source_url" = "https://snapshot.debian.org/package/$source_package/" + test -s "$prefix/$copyright_notice" + test -f "$prefix/lib/$library" +done +for library in "$prefix"/lib/* +do + awk -F '\t' -v library="$(basename "$library")" \ + 'NR > 1 && $1 == library { found = 1 } END { exit !found }' \ + "$prefix/BUNDLED-LIBRARIES" +done + +# Exercise HTTPS with the packaged curl/SSL dependency closure. +GIT_CONFIG_SYSTEM=/dev/null HOME="$work/home" \ + "$work/second/moved/prefix/bin/git" ls-remote \ + https://github.com/git/git.git HEAD | grep -E '^[0-9a-f]{40}[[:space:]]+HEAD$' + +# The default remains host /etc/gitconfig; user config and external tools such +# as ssh, gpg, and git-lfs are deliberately discovered from the host PATH. +strings "$work/second/moved/prefix/bin/git" | grep -Fx /etc/gitconfig +test ! -e "$work/second/moved/prefix/etc/gitconfig" +if test -s /etc/gitconfig +then + "$work/second/moved/prefix/bin/git" config --system --show-origin --list | + awk -F '\t' '$1 != "file:/etc/gitconfig" { exit 1 } END { if (NR == 0) exit 1 }' +fi +GIT_CONFIG_NOSYSTEM=1 HOME="$work/home" \ + "$work/second/moved/prefix/bin/git" config --get sourcegraph.archive-test | grep -Fx true +mkdir "$work/isolated-home" +! GIT_CONFIG_NOSYSTEM=1 HOME="$work/isolated-home" \ + "$work/second/moved/prefix/bin/git" config --get commit.gpgsign + +# Dashed external integrations continue to resolve through PATH. This is the +# mechanism used by git-lfs; SSH and signing programs are likewise external. +mkdir "$work/external" +cat >"$work/external/git-lfs" <&2 + exit 1 + fi + readelf -d "$executable" | grep -E 'RPATH|RUNPATH' | grep -F '$ORIGIN' +done + +echo 'Linux archive validation passed.' diff --git a/contrib/sourcegraph/packaging/verify-darwin-dependencies.sh b/contrib/sourcegraph/packaging/verify-darwin-dependencies.sh new file mode 100755 index 00000000000000..259e3be3be33c2 --- /dev/null +++ b/contrib/sourcegraph/packaging/verify-darwin-dependencies.sh @@ -0,0 +1,41 @@ +#!/bin/sh +set -eu + +prefix=${1:?usage: verify-darwin-dependencies.sh PREFIX} +: "${MACOSX_DEPLOYMENT_TARGET:?MACOSX_DEPLOYMENT_TARGET is required}" +: "${SOURCE_BUILD_ROOT:?SOURCE_BUILD_ROOT is required}" +test -s "$prefix/LICENSES/Git-COPYING" +test -s "$prefix/LICENSES/PCRE2-LICENCE" +status_file=$(mktemp) +trap 'rm -f "$status_file"' EXIT HUP INT TERM +find "$prefix/bin" "$prefix/libexec" -type f -perm -111 | while IFS= read -r executable +do + file "$executable" | grep -q 'Mach-O' || continue + file "$executable" | grep -q 'arm64' || { + echo "error: non-arm64 executable: $executable" >&2 + echo failed >>"$status_file" + } + minos=$(otool -l "$executable" | awk \ + '/cmd LC_BUILD_VERSION/ { found = 1; next } found && $1 == "minos" { print $2; exit }') + test "$minos" = "$MACOSX_DEPLOYMENT_TARGET" || { + echo "error: $executable targets macOS $minos, expected $MACOSX_DEPLOYMENT_TARGET" >&2 + echo failed >>"$status_file" + } + for build_path in "$SOURCE_BUILD_ROOT" "$(dirname "$prefix")" + do + if strings "$executable" | grep -F "$build_path" >/dev/null + then + echo "error: build path embedded in $executable: $build_path" >&2 + echo failed >>"$status_file" + fi + done + otool -L "$executable" | tail -n +2 | awk '{ print $1 }' | while IFS= read -r library + do + case "$library" in + /System/Library/*|/usr/lib/*) ;; + *) echo "error: non-system dependency in $executable: $library" >&2; echo failed >>"$status_file" ;; + esac + done + codesign --verify --verbose "$executable" 2>/dev/null || codesign --force --sign - "$executable" +done +test ! -s "$status_file"