SERVER-115285 Provide bazel mechanism for signing test extensions (#45997)
Co-authored-by: Daniel Moody <dmoody256@gmail.com> GitOrigin-RevId: 1377939ce9f1ef1269ec5dbddaa82d1376517fe9
This commit is contained in:
parent
c2ae2cefc9
commit
a0df8f66d5
@ -199,3 +199,7 @@ poetry(
|
||||
load("//bazel/format:shfmt.bzl", "shfmt")
|
||||
|
||||
shfmt()
|
||||
|
||||
load("//bazel/gpg:gpg.bzl", "gpg")
|
||||
|
||||
gpg()
|
||||
|
||||
@ -34,6 +34,13 @@ py_binary(
|
||||
],
|
||||
)
|
||||
|
||||
py_binary(
|
||||
name = "gpg_signer",
|
||||
srcs = ["gpg_signer.py"],
|
||||
main = "gpg_signer.py",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_wrapper",
|
||||
srcs = ["test_wrapper.sh"],
|
||||
|
||||
1
bazel/gpg/BUILD.bazel
Normal file
1
bazel/gpg/BUILD.bazel
Normal file
@ -0,0 +1 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
79
bazel/gpg/gpg.bzl
Normal file
79
bazel/gpg/gpg.bzl
Normal file
@ -0,0 +1,79 @@
|
||||
"""Repository rules for gpg bundle download"""
|
||||
|
||||
load("//bazel:utils.bzl", "retry_download_and_extract")
|
||||
load("@bazel_rules_mongo//utils:platforms_normalize.bzl", "ARCH_NORMALIZE_MAP", "OS_NORMALIZE_MAP")
|
||||
|
||||
URLS_MAP = {
|
||||
"linux_aarch64": {
|
||||
"sha": "d7197d8b8ad4dc4ef6c27eb03c6cc565e00f994b33011da89f37dacc92810228",
|
||||
"url": "https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/gpg_bundle-aarch64.tar.gz",
|
||||
},
|
||||
"linux_x86_64": {
|
||||
"sha": "66608c5dcfd4580ec7e7dfcf8dd16df73b563674222bf3b9785d853b3d2052ee",
|
||||
"url": "https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/gpg_bundle-x86_64.tar.gz",
|
||||
},
|
||||
"linux_s390x": {
|
||||
"sha": "1fff70fce14abfa83b08df7465929c0b98e5c12c7bff001c4fbd82adaf82c8bd",
|
||||
"url": "https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/gpg_bundle-s390x.tar.gz",
|
||||
},
|
||||
"linux_ppc64le": {
|
||||
"sha": "3f2ecdfb99c49d148f92973e5164821de663984e5a02cd6a1686ce32f1c1d9f9",
|
||||
"url": "https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/gpg_bundle-ppc64le.tar.gz",
|
||||
},
|
||||
}
|
||||
|
||||
def _gpg_bundle_repo_impl(ctx):
|
||||
os = ctx.os.name
|
||||
os_norm = OS_NORMALIZE_MAP.get(ctx.os.name)
|
||||
if os_norm != "linux":
|
||||
ctx.file(
|
||||
"BUILD.bazel",
|
||||
content = """package(default_visibility = ["//visibility:public"])
|
||||
filegroup(name = "gpg_bins", srcs = glob([]))
|
||||
filegroup(name = "gpg_libs", srcs = glob([]))
|
||||
""",
|
||||
)
|
||||
return
|
||||
|
||||
arch = ctx.os.arch
|
||||
os_constraint = OS_NORMALIZE_MAP[os]
|
||||
arch_constraint = ARCH_NORMALIZE_MAP[arch]
|
||||
platform_key = "{os}_{arch}".format(os = os_constraint, arch = arch_constraint)
|
||||
|
||||
if platform_key not in URLS_MAP:
|
||||
fail("Unsupported platform for gpg bundle: {k}. Supported: {supported}".format(
|
||||
k = platform_key,
|
||||
supported = ", ".join(sorted(URLS_MAP.keys())),
|
||||
))
|
||||
|
||||
platform_info = URLS_MAP[platform_key]
|
||||
ctx.report_progress("downloading gpg bundle")
|
||||
retry_download_and_extract(
|
||||
ctx = ctx,
|
||||
tries = 5,
|
||||
url = platform_info["url"],
|
||||
sha256 = platform_info["sha"],
|
||||
)
|
||||
|
||||
# BUILD file: include all bin/* and libs/** in runfiles
|
||||
ctx.file(
|
||||
"BUILD.bazel",
|
||||
content = """package(default_visibility = ["//visibility:public"])
|
||||
filegroup(
|
||||
name = "gpg_libs",
|
||||
srcs = glob(["gpg_bundle-*/libs/**"]),)
|
||||
|
||||
filegroup(
|
||||
name = "gpg_bins",
|
||||
srcs = glob(["gpg_bundle-*/bin/*"]),)
|
||||
|
||||
""",
|
||||
)
|
||||
|
||||
_gpg_bundle_repo = repository_rule(
|
||||
implementation = _gpg_bundle_repo_impl,
|
||||
attrs = {},
|
||||
)
|
||||
|
||||
def gpg():
|
||||
_gpg_bundle_repo(name = "gpg")
|
||||
132
bazel/gpg_signer.py
Normal file
132
bazel/gpg_signer.py
Normal file
@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Action helper to sign a file with a provided private key using GPG.
|
||||
|
||||
This replaces the inline `_gpg_sign.sh` that `bazel/signing.bzl` used to generate.
|
||||
|
||||
Args (positional):
|
||||
1) GPG: path to the gpg binary to execute
|
||||
2) KEY: path to the ascii-armored private key file to import
|
||||
3) PASSPHRASE: optional path to a file containing the passphrase (or "" if none)
|
||||
4) OUT: output signature path
|
||||
5) INP: input file path to sign
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
def _debug(msg: str) -> None:
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
|
||||
def _run(argv: List[str], *, capture_stdout: bool = False) -> subprocess.CompletedProcess:
|
||||
if capture_stdout:
|
||||
return subprocess.run(
|
||||
argv, check=True, text=True, stdout=subprocess.PIPE, stderr=sys.stderr
|
||||
)
|
||||
return subprocess.run(argv, check=True)
|
||||
|
||||
|
||||
def _extract_fingerprint(colons_output: str) -> Optional[str]:
|
||||
# gpg --with-colons output: lines like "fpr:::::::::FINGERPRINT:"
|
||||
for line in colons_output.splitlines():
|
||||
if not line.startswith("fpr:"):
|
||||
continue
|
||||
parts = line.split(":")
|
||||
if len(parts) > 9 and parts[9]:
|
||||
return parts[9]
|
||||
return None
|
||||
|
||||
|
||||
def main(argv: List[str]) -> int:
|
||||
_debug("Starting gpg_signer.py")
|
||||
|
||||
if len(argv) != 6:
|
||||
print(
|
||||
"usage: gpg_signer.py <gpg> <key> <passphrase_file_or_empty> <out> <inp>",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 2
|
||||
|
||||
gpg = argv[1]
|
||||
key = argv[2]
|
||||
passphrase_file = argv[3] or None
|
||||
out_path = argv[4]
|
||||
inp_path = argv[5]
|
||||
|
||||
# Use helpers from the same bundle as `gpg` to avoid accidentally picking up system gpg-agent/gpgconf,
|
||||
# especially under remote execution.
|
||||
bindir = os.path.dirname(gpg)
|
||||
gpg_agent = os.path.join(bindir, "gpg-agent")
|
||||
gpgconf = os.path.join(bindir, "gpgconf")
|
||||
|
||||
# Unique temp homedir for this action.
|
||||
base_tmp = os.environ.get("TMPDIR") or os.getcwd()
|
||||
gpgdir = tempfile.mkdtemp(prefix="gpg.", dir=base_tmp)
|
||||
os.chmod(gpgdir, 0o700)
|
||||
|
||||
try:
|
||||
# Disable agent caching for this home directory.
|
||||
with open(os.path.join(gpgdir, "gpg-agent.conf"), "w", encoding="utf-8") as fh:
|
||||
fh.write(
|
||||
"default-cache-ttl 0\n"
|
||||
"max-cache-ttl 0\n"
|
||||
"ignore-cache-for-signing\n"
|
||||
"allow-loopback-pinentry\n"
|
||||
)
|
||||
|
||||
_debug("Starting gpg-agent")
|
||||
# Inherit stdout/stderr so logs show up in action output (like the old shell script).
|
||||
_run([gpg_agent, "--homedir", gpgdir, "--daemon", "--verbose"])
|
||||
_debug("gpg-agent importing key to home dir")
|
||||
|
||||
# Import the private key into the temp homedir.
|
||||
_run([gpg, "--homedir", gpgdir, "--batch", "--import", key])
|
||||
|
||||
# Find fingerprint.
|
||||
cp = _run([gpg, "--homedir", gpgdir, "--list-keys", "--with-colons"], capture_stdout=True)
|
||||
fpr = _extract_fingerprint(cp.stdout)
|
||||
if not fpr:
|
||||
print(
|
||||
"Failed to determine key fingerprint from gpg --with-colons output", file=sys.stderr
|
||||
)
|
||||
return 1
|
||||
|
||||
# Build passphrase options if provided.
|
||||
pass_opts: List[str] = []
|
||||
if passphrase_file:
|
||||
pass_opts = ["--pinentry-mode", "loopback", "--passphrase-file", passphrase_file]
|
||||
|
||||
_run(
|
||||
[
|
||||
gpg,
|
||||
"--homedir",
|
||||
gpgdir,
|
||||
"--batch",
|
||||
"--yes",
|
||||
*pass_opts,
|
||||
"--detach-sign",
|
||||
"-u",
|
||||
fpr,
|
||||
"-o",
|
||||
out_path,
|
||||
inp_path,
|
||||
]
|
||||
)
|
||||
return 0
|
||||
finally:
|
||||
# Cleanup.
|
||||
try:
|
||||
subprocess.run([gpgconf, "--homedir", gpgdir, "--kill", "gpg-agent"], check=False)
|
||||
finally:
|
||||
shutil.rmtree(gpgdir, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main(sys.argv))
|
||||
191
bazel/signing.bzl
Normal file
191
bazel/signing.bzl
Normal file
@ -0,0 +1,191 @@
|
||||
"""Custom signing macros for test extensions."""
|
||||
|
||||
load("//bazel:mongo_src_rules.bzl", "mongo_cc_extension_shared_library")
|
||||
|
||||
def _gpg_sign_impl(ctx):
|
||||
outs = []
|
||||
|
||||
python = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"].py3_runtime
|
||||
|
||||
for src in ctx.files.srcs:
|
||||
out = ctx.actions.declare_file(src.basename + ".sig")
|
||||
outs.append(out)
|
||||
|
||||
# Inputs to this action
|
||||
inputs = [src, ctx.file.key, ctx.file._gpg_signer]
|
||||
pass_arg = ""
|
||||
if ctx.file.passphrase:
|
||||
inputs.append(ctx.file.passphrase)
|
||||
pass_arg = ctx.file.passphrase.path
|
||||
|
||||
dep_files = ctx.files.gpg_bins
|
||||
dep_dirs = [f.dirname for f in dep_files]
|
||||
|
||||
# Prefer explicit override (if provided). Otherwise, locate the real gpg binary from the bundle.
|
||||
gpg_file = ctx.file.gpg_main_script
|
||||
if gpg_file == None:
|
||||
for f in dep_files:
|
||||
if f.basename == "gpg" or f.basename == "gpg.exe":
|
||||
gpg_file = f
|
||||
break
|
||||
if gpg_file == None:
|
||||
fail("Unable to find gpg in gpg_bins. Ensure @gpg//:gpg_bins contains a 'gpg' binary.")
|
||||
|
||||
env = dict(ctx.configuration.default_shell_env)
|
||||
sep = ctx.configuration.host_path_separator # ":" or ";"
|
||||
base_path = env.get("PATH", "")
|
||||
env["PATH"] = sep.join(dep_dirs + ([base_path] if base_path else []))
|
||||
|
||||
inputs += dep_files
|
||||
|
||||
# Needed for remote execution: gpg binaries use RUNPATH=$ORIGIN/../libs.
|
||||
inputs += ctx.files.gpg_libs
|
||||
|
||||
inputs += python.files.to_list()
|
||||
|
||||
# Run the signer via the hermetic python toolchain (no shell involved)
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
outputs = [out],
|
||||
tools = [],
|
||||
executable = python.interpreter.path,
|
||||
env = env,
|
||||
arguments = [
|
||||
ctx.file._gpg_signer.path,
|
||||
gpg_file.path, # $1
|
||||
ctx.file.key.path, # $2
|
||||
pass_arg, # $3 (empty if none)
|
||||
out.path, # $4
|
||||
src.path, # $5,
|
||||
],
|
||||
progress_message = "Signing {}".format(src.basename),
|
||||
mnemonic = "GpgSign",
|
||||
)
|
||||
|
||||
return [
|
||||
DefaultInfo(files = depset(outs)),
|
||||
OutputGroupInfo(signatures = depset(outs), originals = depset(ctx.files.srcs)),
|
||||
]
|
||||
|
||||
gpg_sign = rule(
|
||||
implementation = _gpg_sign_impl,
|
||||
attrs = {
|
||||
"srcs": attr.label_list(allow_files = True),
|
||||
"key": attr.label(allow_single_file = True, mandatory = True),
|
||||
"passphrase": attr.label(allow_single_file = True),
|
||||
"gpg_main_script": attr.label(
|
||||
allow_single_file = True,
|
||||
doc = "Optional override for the gpg binary path. If unset, uses @gpg//:gpg_bins to locate 'gpg'.",
|
||||
),
|
||||
"gpg_bins": attr.label(default = Label("@gpg//:gpg_bins")),
|
||||
"gpg_libs": attr.label(default = Label("@gpg//:gpg_libs")),
|
||||
"_gpg_signer": attr.label(
|
||||
allow_single_file = True,
|
||||
default = Label("//bazel:gpg_signer.py"),
|
||||
),
|
||||
},
|
||||
toolchains = ["@bazel_tools//tools/python:toolchain_type"],
|
||||
fragments = ["py"],
|
||||
)
|
||||
|
||||
# Extensions must be signed in order to be loaded into the server. This macros allows users to build
|
||||
# the extension shared object, and sign it with the provided PGP key. The target for the packaged
|
||||
# output is name + "_signed_lib". It's necessary to reference this target as a dependency to ensure
|
||||
# the signed artifacts are generated.
|
||||
def signed_mongo_cc_extension_shared_library(
|
||||
name,
|
||||
srcs = [],
|
||||
deps = [],
|
||||
private_hdrs = [],
|
||||
visibility = None,
|
||||
data = [],
|
||||
tags = [],
|
||||
copts = [],
|
||||
linkopts = [],
|
||||
includes = [],
|
||||
linkstatic = False,
|
||||
local_defines = [],
|
||||
target_compatible_with = [],
|
||||
defines = [],
|
||||
additional_linker_inputs = [],
|
||||
features = [],
|
||||
exec_properties = {},
|
||||
# signing
|
||||
# path to the GPG key, we are currently going to get this from the mongo repo
|
||||
key = "//src/mongo/db/extension/test_examples/test_extensions_signing_keys:test_extensions_signing_private_key.asc",
|
||||
passphrase = None,
|
||||
sign_visibility = None,
|
||||
sign_tags = None,
|
||||
**kwargs):
|
||||
"""Build an extension shared library and sign it with a temporary GPG homedir.
|
||||
|
||||
Args:
|
||||
name: Name of the extension shared library target.
|
||||
srcs: Sources for the extension library.
|
||||
deps: Dependencies for the extension library.
|
||||
private_hdrs: Private headers for the extension library.
|
||||
visibility: Visibility for created targets.
|
||||
data: Runtime data deps for the extension library.
|
||||
tags: Tags for created targets.
|
||||
copts: C/C++ compile options for the extension library.
|
||||
linkopts: Link options for the extension library.
|
||||
includes: Include paths for the extension library.
|
||||
linkstatic: Whether to link statically (see underlying rule semantics).
|
||||
local_defines: Local preprocessor defines for the extension library.
|
||||
target_compatible_with: Platform constraints for created targets.
|
||||
defines: Preprocessor defines for the extension library.
|
||||
additional_linker_inputs: Extra linker inputs for the extension library.
|
||||
features: Bazel features to enable/disable on the extension library.
|
||||
exec_properties: Exec properties for created actions.
|
||||
key: Label of the signing key file (private key).
|
||||
passphrase: Optional label of a file containing the signing key passphrase.
|
||||
sign_visibility: Optional visibility override for signing targets.
|
||||
sign_tags: Optional tags for signing targets.
|
||||
**kwargs: Forwarded to the underlying extension rule.
|
||||
"""
|
||||
if key == None:
|
||||
fail("signed_mongo_cc_extension_shared_library requires a pgp key")
|
||||
|
||||
sig_name = name + "_sig"
|
||||
|
||||
# 1) Build the shared object
|
||||
mongo_cc_extension_shared_library(
|
||||
name = name,
|
||||
srcs = srcs,
|
||||
deps = deps,
|
||||
private_hdrs = private_hdrs,
|
||||
visibility = visibility,
|
||||
data = data,
|
||||
tags = tags,
|
||||
copts = copts,
|
||||
linkopts = linkopts,
|
||||
includes = includes,
|
||||
linkstatic = linkstatic,
|
||||
local_defines = local_defines,
|
||||
target_compatible_with = target_compatible_with,
|
||||
defines = defines,
|
||||
additional_linker_inputs = additional_linker_inputs,
|
||||
features = features,
|
||||
exec_properties = exec_properties,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
# 2) Sign the produced library (ctx.files.srcs for a rule label includes its default outputs)
|
||||
gpg_sign(
|
||||
name = sig_name,
|
||||
srcs = [":" + name],
|
||||
key = key,
|
||||
passphrase = passphrase,
|
||||
visibility = sign_visibility if sign_visibility != None else visibility,
|
||||
tags = (sign_tags if sign_tags != None else []),
|
||||
)
|
||||
|
||||
# 3) Aggregate both files under name + "_signed_lib" for consumption
|
||||
signed_bundle_name = name + "_signed_lib"
|
||||
|
||||
native.filegroup(
|
||||
name = signed_bundle_name,
|
||||
srcs = [":" + name, ":" + sig_name],
|
||||
visibility = visibility,
|
||||
tags = tags,
|
||||
)
|
||||
75
buildscripts/mongo_gpg_builds/README.md
Normal file
75
buildscripts/mongo_gpg_builds/README.md
Normal file
@ -0,0 +1,75 @@
|
||||
# mongo gpg builds
|
||||
|
||||
This directory contains a script to produce **portable `gpg` binaries** for all our supported linux platforms:
|
||||
|
||||
- **Linux** (`manylinux2014` glibc 2.17 baseline): `x86_64`, `aarch64`, `s390x`, `ppc64le`
|
||||
|
||||
In particular, it builds gnupg-2.5.16 from source.
|
||||
|
||||
This script is used to generate the binaries that we use bring into bazel as a dependency to sign test extensions.
|
||||
All artifacts are placed in the `dist/` directory.
|
||||
|
||||
---
|
||||
|
||||
## 📁 Contents
|
||||
|
||||
| Script | Platform | Output |
|
||||
| :----------------------- | :-------------------------------------- | :-------------------------- |
|
||||
| `build_gpg_manylinux.sh` | Linux (x86_64, aarch64, s390x, ppc64le) | `dist/gpg-manylinux-<arch>` |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 🐧 Linux (manylinux2014 glibc 2.17)
|
||||
|
||||
**Requirements:** Docker.
|
||||
To cross-build using QEMU (for aarch64/s390x/ppc64le), enable binfmt once:
|
||||
|
||||
```bash
|
||||
docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
```
|
||||
|
||||
#### Build native architecture
|
||||
|
||||
```bash
|
||||
./build_gpg_manylinux.sh
|
||||
```
|
||||
|
||||
#### Cross-build via QEMU
|
||||
|
||||
```bash
|
||||
ARCH=x86_64 PLATFORM=linux/amd64 ./build_gpg_manylinux.sh
|
||||
ARCH=aarch64 PLATFORM=linux/arm64 ./build_gpg_manylinux.sh
|
||||
ARCH=s390x PLATFORM=linux/s390x ./build_gpg_manylinux.sh
|
||||
ARCH=ppc64le PLATFORM=linux/ppc64le ./build_gpg_manylinux.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Build Behavior (All Platforms)
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Environment Variables
|
||||
|
||||
| Variable | Purpose | Default |
|
||||
| :--------- | :---------------- | :--------- |
|
||||
| `OUT_DIR` | Output directory | `./dist` |
|
||||
| `ARCH` | Linux target arch | `uname -m` |
|
||||
| `PLATFORM` | Docker platform | auto |
|
||||
|
||||
## 📜 License & Attribution
|
||||
|
||||
These scripts build **gpg** and its required dependencies from sources originally obtained from:
|
||||
👉 <https://www.gnupg.org/ftp/gcrypt/gnupg/> and <https://gnupg.org/download/index.html>
|
||||
|
||||
The exact sources can be obtained at the following URLs:
|
||||
|
||||
- https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/sources/gnupg-w32-2.5.16_20251230.tar.xz
|
||||
- https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/sources/libassuan-3.0.2.tar.bz2
|
||||
- https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/sources/libgcrypt-1.11.2.tar.bz2
|
||||
- https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/sources/libgpg-error-1.58.tar.bz2
|
||||
- https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/sources/libksba-1.6.7.tar.bz2
|
||||
- https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/sources/npth-1.8.tar.bz2
|
||||
- https://mdb-build-public.s3.us-east-1.amazonaws.com/gpg-binaries/SERVER-115285/sources/ntbtls-0.3.2.tar.bz2
|
||||
213
buildscripts/mongo_gpg_builds/build_gpg_manylinux.sh
Executable file
213
buildscripts/mongo_gpg_builds/build_gpg_manylinux.sh
Executable file
@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# -------- config (overridable via env) --------------------------------------
|
||||
ARCH="${ARCH:-$(uname -m)}" # x86_64 | aarch64 | s390x | ppc64le
|
||||
GPG_DIR="gnupg-2.5.16"
|
||||
OUT_DIR="${OUT_DIR:-$(pwd)/dist}"
|
||||
PLATFORM="${PLATFORM:-}" # e.g. linux/arm64 if you want to force
|
||||
DOCKER_IMAGE="" # filled below
|
||||
CPU_BASELINE="${CPU_BASELINE:-}" # default per-arch below
|
||||
|
||||
# Map arch -> image + defaults
|
||||
case "$ARCH" in
|
||||
x86_64 | amd64)
|
||||
ARCH=x86_64
|
||||
DOCKER_IMAGE="quay.io/pypa/manylinux2014_x86_64"
|
||||
CPU_BASELINE="${CPU_BASELINE:-x86-64}" # or x86-64-v2 / v3
|
||||
;;
|
||||
aarch64 | arm64)
|
||||
ARCH=aarch64
|
||||
DOCKER_IMAGE="quay.io/pypa/manylinux2014_aarch64"
|
||||
CPU_BASELINE="${CPU_BASELINE:-generic}"
|
||||
;;
|
||||
s390x | 390x)
|
||||
ARCH=s390x
|
||||
DOCKER_IMAGE="quay.io/pypa/manylinux2014_s390x"
|
||||
CPU_BASELINE="${CPU_BASELINE:-generic}"
|
||||
;;
|
||||
ppc64le | ppc)
|
||||
ARCH=ppc64le
|
||||
DOCKER_IMAGE="quay.io/pypa/manylinux2014_ppc64le"
|
||||
CPU_BASELINE="${CPU_BASELINE:-generic}"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported ARCH='$ARCH'. Expected x86_64|aarch64|s390x|ppc64le." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
echo "==> Build gpg for manylinux2014 ($ARCH)"
|
||||
echo " Image: $DOCKER_IMAGE"
|
||||
echo " CPU_BASELINE: $CPU_BASELINE"
|
||||
[ -n "$PLATFORM" ] && echo " docker --platform: $PLATFORM"
|
||||
|
||||
# Compose optional --platform flag
|
||||
PLATFORM_ARGS=()
|
||||
[ -n "$PLATFORM" ] && PLATFORM_ARGS=(--platform "$PLATFORM")
|
||||
|
||||
MY_LD_FLAGS="-Wl,-rpath,\$\$ORIGIN/../libs -Wl,--enable-new-dtags"
|
||||
|
||||
docker run --rm -t "${PLATFORM_ARGS[@]}" \
|
||||
-v "$OUT_DIR":/out \
|
||||
"$DOCKER_IMAGE" \
|
||||
bash -lc \
|
||||
'
|
||||
set -euo pipefail
|
||||
|
||||
echo "==> glibc baseline:"
|
||||
ldd --version > /tmp/lddv && head -1 /tmp/lddv
|
||||
|
||||
mkdir mongo_gpg
|
||||
cd mongo_gpg
|
||||
GPG_ROOT_DIR=$(pwd)
|
||||
mkdir gpg_bundle
|
||||
mkdir gpg_bundle/bin
|
||||
mkdir gpg_bundle/libs
|
||||
|
||||
GPG_BUNDLE_DIR=$GPG_ROOT_DIR/gpg_bundle
|
||||
|
||||
BUNDLE_BIN_DIR=$GPG_BUNDLE_DIR/bin
|
||||
BUNDLE_LIBS_DIR=$GPG_BUNDLE_DIR/libs
|
||||
|
||||
# download key
|
||||
echo "Downloading signing key"
|
||||
curl -fL -o signature_key.asc https://gnupg.org/signature_key.asc
|
||||
echo "Importing signing key"
|
||||
if ! out=$(gpg --batch --no-tty --import signature_key.asc 2>&1); then
|
||||
echo "Ignoring keys without valid self-signed UIDs during import"
|
||||
fi
|
||||
|
||||
verify_gpg_sig() {
|
||||
local artifact="$1" # e.g., libgpg-error-1.58.tar.bz2
|
||||
local sig_url="$2" # e.g., https://gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.58.tar.bz2.sig
|
||||
local sig_file="${3:-$(basename "$artifact").sig}" # optional override for sig filename
|
||||
echo "Verifying $sig_file"
|
||||
curl -fL -o "$sig_file" "$sig_url"
|
||||
if ! gpg --batch --no-tty --verify "$sig_file" "$artifact"; then
|
||||
echo "Signature verification failed for $artifact"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# libgpg-error
|
||||
echo "Downloading gpg-error"
|
||||
curl -fL -o libgpg-error-1.58.tar.bz2 https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.58.tar.bz2
|
||||
#verify_gpg_sig "libgpg-error-1.58.tar.bz2" "https://gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.58.tar.bz2.sig"
|
||||
|
||||
tar -xvf libgpg-error-1.58.tar.bz2
|
||||
echo "Making gpg-error"
|
||||
|
||||
cd libgpg-error-1.58
|
||||
./configure
|
||||
make -j20
|
||||
make install
|
||||
cp src/.libs/libgpg-error.so.0.41.1 $BUNDLE_LIBS_DIR/libgpg-error.so.0
|
||||
|
||||
# libgpgcrypt
|
||||
cd $GPG_ROOT_DIR
|
||||
echo "Downloading gpgcrypt"
|
||||
|
||||
curl -fL -o libgcrypt-1.11.2.tar.bz2 https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.11.2.tar.bz2
|
||||
#verify_gpg_sig "libgcrypt-1.11.2.tar.bz2" "https://gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.11.2.tar.bz2.sig"
|
||||
|
||||
tar -xvf libgcrypt-1.11.2.tar.bz2
|
||||
cd libgcrypt-1.11.2
|
||||
./configure
|
||||
make -j20
|
||||
make install
|
||||
cp src/.libs/libgcrypt.so.20.6.0 $BUNDLE_LIBS_DIR/libgcrypt.so.20
|
||||
|
||||
echo "Downloading libksba"
|
||||
|
||||
# libksba
|
||||
cd $GPG_ROOT_DIR
|
||||
curl -fL -o libksba-1.6.7.tar.bz2 https://www.gnupg.org/ftp/gcrypt/libksba/libksba-1.6.7.tar.bz2
|
||||
#verify_gpg_sig "libksba-1.6.7.tar.bz2" "https://gnupg.org/ftp/gcrypt/libksba/libksba-1.6.7.tar.bz2.sig"
|
||||
|
||||
tar -xvf libksba-1.6.7.tar.bz2
|
||||
cd libksba-1.6.7
|
||||
./configure
|
||||
make -j20
|
||||
make install
|
||||
cp src/.libs/libksba.so.8.14.7 $BUNDLE_LIBS_DIR/libksba.so.8
|
||||
|
||||
# libassuan
|
||||
cd $GPG_ROOT_DIR
|
||||
echo "Downloading libassuan"
|
||||
|
||||
curl -fL -o libassuan-3.0.2.tar.bz2 https://www.gnupg.org/ftp/gcrypt/libassuan/libassuan-3.0.2.tar.bz2
|
||||
#verify_gpg_sig "libassuan-3.0.2.tar.bz2" "https://gnupg.org/ftp/gcrypt/libassuan/libassuan-3.0.2.tar.bz2.sig"
|
||||
|
||||
tar -xvf libassuan-3.0.2.tar.bz2
|
||||
cd libassuan-3.0.2
|
||||
./configure
|
||||
make -j20
|
||||
make install
|
||||
cp src/.libs/libassuan.so.9.0.2 $BUNDLE_LIBS_DIR/libassuan.so.9
|
||||
|
||||
# ntbtls
|
||||
echo "Downloading ntbtls"
|
||||
cd $GPG_ROOT_DIR
|
||||
curl -fL -o ntbtls-0.3.2.tar.bz2 https://www.gnupg.org/ftp/gcrypt/ntbtls/ntbtls-0.3.2.tar.bz2
|
||||
#verify_gpg_sig "ntbtls-0.3.2.tar.bz2" "https://gnupg.org/ftp/gcrypt/ntbtls/ntbtls-0.3.2.tar.bz2.sig"
|
||||
|
||||
tar -xvf ntbtls-0.3.2.tar.bz2
|
||||
cd ntbtls-0.3.2
|
||||
./configure
|
||||
make -j20
|
||||
make install
|
||||
cp src/.libs/libntbtls.so.0.1.3 $BUNDLE_LIBS_DIR/libntbtls.so.0
|
||||
|
||||
# npth
|
||||
echo "Downloading npth"
|
||||
cd $GPG_ROOT_DIR
|
||||
curl -fL -o npth-1.8.tar.bz2 https://www.gnupg.org/ftp/gcrypt/npth/npth-1.8.tar.bz2
|
||||
#verify_gpg_sig "npth-1.8.tar.bz2" "https://gnupg.org/ftp/gcrypt/npth/npth-1.8.tar.bz2.sig"
|
||||
|
||||
tar -xvf npth-1.8.tar.bz2
|
||||
cd npth-1.8
|
||||
./configure
|
||||
make -j20
|
||||
make install
|
||||
cp src/.libs/libnpth.so.0.3.0 $BUNDLE_LIBS_DIR/libnpth.so.0
|
||||
|
||||
# gpg
|
||||
cd $GPG_ROOT_DIR
|
||||
echo "Downloading gpg"
|
||||
curl -fL -o gnupg-w32-2.5.16_20251230.tar.xz https://www.gnupg.org/ftp/gcrypt/gnupg/gnupg-w32-2.5.16_20251230.tar.xz
|
||||
# verify_gpg_sig "gnupg-w32-2.5.16_20251230.tar.xz" "https://gnupg.org/ftp/gcrypt/gnupg/gnupg-w32-2.5.16_20251230.tar.xz.sig"
|
||||
|
||||
tar -xvf gnupg-w32-2.5.16_20251230.tar.xz
|
||||
echo "making gpg"
|
||||
|
||||
cd gnupg-w32-2.5.16
|
||||
echo "Currently in path $(pwd)"
|
||||
GPG_SRC_DIR=$(pwd)
|
||||
echo $GPG_SRC_DIR
|
||||
mkdir build
|
||||
cd build
|
||||
echo "Currently in path $(pwd)"
|
||||
echo "running configure on path $GPG_SRC_DIR"
|
||||
|
||||
$GPG_SRC_DIR/configure --disable-sqlite
|
||||
|
||||
make -j20 LDFLAGS='"'"'-Wl,-rpath,\$$ORIGIN/../libs -Wl,--enable-new-dtags'"'"'
|
||||
|
||||
cp -L bin/gpg $BUNDLE_BIN_DIR/gpg
|
||||
cp -L bin/gpg-agent $BUNDLE_BIN_DIR/gpg-agent
|
||||
cp -L bin/gpg-card $BUNDLE_BIN_DIR/gpg-card
|
||||
cp -L bin/gpgconf $BUNDLE_BIN_DIR/gpgconf
|
||||
cp -L bin/gpgconf.ctl $BUNDLE_BIN_DIR/gpgconf.ctl
|
||||
cp -L bin/gpg-connect-agent $BUNDLE_BIN_DIR/gpg-connect-agent
|
||||
cp -L bin/gpgsm $BUNDLE_BIN_DIR/gpgsm
|
||||
cp -L bin/gpgtar $BUNDLE_BIN_DIR/gpgtar
|
||||
cp -L bin/gpgv $BUNDLE_BIN_DIR/gpgv
|
||||
|
||||
OUT_NAME=gpg_bundle-'"$ARCH"'
|
||||
cp -r $GPG_BUNDLE_DIR /out/$OUT_NAME
|
||||
'
|
||||
|
||||
echo "Built: $OUT_DIR/gpg_bundle-$ARCH"
|
||||
@ -1,7 +1,7 @@
|
||||
load("//bazel/install_rules:install_rules.bzl", "extensions_with_config")
|
||||
load("//bazel:mongo_src_rules.bzl", "mongo_cc_extension_shared_library")
|
||||
load("@poetry//:dependencies.bzl", "dependency")
|
||||
load("//bazel/config:render_template.bzl", "render_template")
|
||||
load("//bazel:signing.bzl", "signed_mongo_cc_extension_shared_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
@ -31,34 +31,34 @@ extensions_with_config(
|
||||
# null_chars_string_input.js will break as not all stages from $listMqlEntities
|
||||
# will have a null character test. To resolve this, ensure that these new stages
|
||||
# are added to the "skips" list in that test.
|
||||
":bar_mongo_extension",
|
||||
":foo_mongo_extension",
|
||||
":limit_mongo_extension",
|
||||
":logging_mongo_extension",
|
||||
":debug_logging_mongo_extension",
|
||||
":parse_options_mongo_extension",
|
||||
":test_options_mongo_extension",
|
||||
":toaster_mongo_extension",
|
||||
":extension_errors_mongo_extension",
|
||||
":shapify_mongo_extension",
|
||||
":sharded_execution_serialization_mongo_extension",
|
||||
":read_n_documents_mongo_extension",
|
||||
":explain_mongo_extension",
|
||||
":metadata_mongo_extension",
|
||||
":idle_threads_mongo_extension",
|
||||
":interrupt_mongo_extension",
|
||||
":match_topN_mongo_extension",
|
||||
":native_vector_search_mongo_extension",
|
||||
":metrics_mongo_extension",
|
||||
":other_metrics_mongo_extension",
|
||||
":bar_mongo_extension_signed_lib",
|
||||
":foo_mongo_extension_signed_lib",
|
||||
":limit_mongo_extension_signed_lib",
|
||||
":logging_mongo_extension_signed_lib",
|
||||
":debug_logging_mongo_extension_signed_lib",
|
||||
":parse_options_mongo_extension_signed_lib",
|
||||
":test_options_mongo_extension_signed_lib",
|
||||
":toaster_mongo_extension_signed_lib",
|
||||
":extension_errors_mongo_extension_signed_lib",
|
||||
":shapify_mongo_extension_signed_lib",
|
||||
":sharded_execution_serialization_mongo_extension_signed_lib",
|
||||
":read_n_documents_mongo_extension_signed_lib",
|
||||
":explain_mongo_extension_signed_lib",
|
||||
":metadata_mongo_extension_signed_lib",
|
||||
":idle_threads_mongo_extension_signed_lib",
|
||||
":interrupt_mongo_extension_signed_lib",
|
||||
":match_topN_mongo_extension_signed_lib",
|
||||
":native_vector_search_mongo_extension_signed_lib",
|
||||
":metrics_mongo_extension_signed_lib",
|
||||
":other_metrics_mongo_extension_signed_lib",
|
||||
|
||||
#################### EXTENSIONS FOR NO-PASSTHROUGH TESTS ####################
|
||||
# Any extension that is just loaded in a no-passthrough test MUST NOT have the
|
||||
# "_mongo_extension" suffix.
|
||||
":no_symbol_bad_extension",
|
||||
":duplicate_stage_descriptor_bad_extension",
|
||||
":foo_extension_v2",
|
||||
":vector_search_extension",
|
||||
":no_symbol_bad_extension_signed_lib",
|
||||
":duplicate_stage_descriptor_bad_extension_signed_lib",
|
||||
":foo_extension_v2_signed_lib",
|
||||
":vector_search_extension_signed_lib",
|
||||
],
|
||||
)
|
||||
|
||||
@ -71,7 +71,7 @@ pkg_name = "//" + package_name() + "/"
|
||||
|
||||
# Extensions under test_examples/
|
||||
[
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = extension_name + "_mongo_extension",
|
||||
srcs = [extension_name + ".cpp"],
|
||||
)
|
||||
@ -86,7 +86,7 @@ pkg_name = "//" + package_name() + "/"
|
||||
|
||||
# Extensions under test_examples/desugar/
|
||||
[
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = extension_name + "_mongo_extension",
|
||||
srcs = [pkg_name + "desugar:" + extension_name + ".cpp"],
|
||||
)
|
||||
@ -137,7 +137,7 @@ filegroup(
|
||||
|
||||
# Extensions under test_examples/extension_options/
|
||||
[
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = extension_name + "_mongo_extension",
|
||||
srcs = [pkg_name + "extension_options:" + extension_name + ".cpp"],
|
||||
)
|
||||
@ -150,7 +150,7 @@ filegroup(
|
||||
|
||||
# Extensions under test_examples/loading/
|
||||
[
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = extension_name + "_mongo_extension",
|
||||
srcs = [pkg_name + "loading:" + extension_name + ".cpp"],
|
||||
)
|
||||
@ -163,7 +163,7 @@ filegroup(
|
||||
|
||||
# Extensions under test_examples/host_services/
|
||||
[
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = extension_name + "_mongo_extension",
|
||||
srcs = [pkg_name + "host_services:" + extension_name + ".cpp"],
|
||||
)
|
||||
@ -177,7 +177,7 @@ filegroup(
|
||||
|
||||
# Extensions under test_examples/observability/
|
||||
[
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = extension_name + "_mongo_extension",
|
||||
srcs = [pkg_name + "observability:" + extension_name + ".cpp"],
|
||||
)
|
||||
@ -200,7 +200,7 @@ filegroup(
|
||||
# Extensions under test_examples/fail_to_load/
|
||||
# Each of these should fail startup.
|
||||
[
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = extension_name + "_bad_extension",
|
||||
srcs = [pkg_name + "fail_to_load:" + extension_name + ".cpp"],
|
||||
)
|
||||
@ -224,7 +224,7 @@ filegroup(
|
||||
# "foo_v2" is used for testing upgrade scenarios as the upgrade of "foo" from above. We cannot use
|
||||
# the "mongo_extension" suffix since loading this extension in passthroughs with "foo" V1 should
|
||||
# cause duplicate stage errors.
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = "foo_extension_v2",
|
||||
srcs = ["foo_v2.cpp"],
|
||||
)
|
||||
@ -232,12 +232,12 @@ mongo_cc_extension_shared_library(
|
||||
# "vector_search" is used to test that we can override the existing $vectorSearch implementation.
|
||||
# It must not have the _mongo_extension suffix so that it doesn't get loaded in the
|
||||
# Extensions-enabled variant since that would break real $vectorSearch tests.
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = "vector_search_extension",
|
||||
srcs = ["vector_search.cpp"],
|
||||
)
|
||||
|
||||
mongo_cc_extension_shared_library(
|
||||
signed_mongo_cc_extension_shared_library(
|
||||
name = "mongothost_extension",
|
||||
srcs = [pkg_name + "extension_options:mongothost.cpp"],
|
||||
)
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
exports_files(
|
||||
["test_extensions_signing_private_key.asc"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
@ -0,0 +1,106 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
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
|
||||
TNkpqaN9Bduv8xozbFUitHNTPTplns4uPF9Q
|
||||
=SAT8
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
@ -0,0 +1,52 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=Fjw3
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
Loading…
Reference in New Issue
Block a user