☰
Bisq 可复现发布构建(Reproducible Release Builds)完全指南:从证据生成、A/B 对比到签名验证
2026/10/13 6:34:47 网站建设 项目流程
  • 区块链
  • DeFi
  • 金融科技

【免费下载链接】bisq

A decentralized bitcoin exchange network

项目地址:https://gitcode.com/gh_mirrors/bi/bisq
点击查看免费下载

Bisq(一个去中心化比特币交易网络,仓库根目录见 README.md)在docs/reproducible-builds/下维护了一套完整的可复现发布构建体系。本文以 可复现构建文档入口 为骨架,融合 使用指南、技术细节、Linux、macOS、Windows 与 背书(Attestation)计划,并结合仓库中的 Gradle 任务实现(build.gradle)、Linux 发布构建镜像(Dockerfile)与 GitHub Actions 工作流(build.yml、installer-evidence.yml、release-builder.yml)逐层展开。读完本文,你将掌握:如何生成并校验 Java 发布负载证据、如何生成并对比 Linux/macOS/Windows 安装包证据、如何在固定 Docker 镜像中做双 worktree A/B 复现比对、如何按发布经理与独立验证者的角色完成证据签名与背书验证。

一、项目目标:一个证据驱动的可信发布模型

可复现发布构建要回答的核心问题是:发布经理、CI 运行器或独立验证者重新构建同一个发布提交后,能否得到与已发布证据完全一致的产物。具体细化为三个问题:

  1. Java 发布负载是否与已发布的证据匹配?
  2. 每个操作系统的安装器是否与同一操作系统已发布的证据匹配?
  3. 构建是否在一个"重要输入可被记录和审查"的发布环境中完成?

1.1 规范的对比工件:Manifest

整套体系的权威对比工件是 Manifest(清单文件),它记录每个文件的三要素:SHA-256哈希、字节大小、以及仓库相对路径(repo-relative path)。它不依赖"信任构建日志",而是靠逐字节哈希对比来证明可复现性——这是与"看日志靠不靠谱"的信任模型本质区别。

证据 ZIP(Evidence ZIP)则把这些 Manifest 与诊断性构建信息打包在一起,供签名、发布与后续独立核验。安装器证据还会额外附带"包结构报告"(package structure reports),用于解释安装包内部差异。

从源码看,这一对比逻辑实现在 build.gradle 的compareReleaseEvidenceBundles任务中:它解析左右两个 manifest,计算三类差异集——missingFromRight(左侧独有)、extraInRight(右侧独有)、changedPaths(两侧均存在但 SHA-256 或 size 不同),任一差异非空即抛异常,并在失败信息中列出左右两侧各自的哈希与大小,供定位问题。

1.2 当前覆盖范围

Java 发布负载检查覆盖以下输入:

  • 各子项目 GradleJar任务启用的输出;
  • desktop 运行时库,即desktop/build/install/desktop/lib;
  • Gradle wrapper 文件与 wrapper 发行版元数据;
  • 固定的 Gradle 与 Java 运行时版本;
  • Gradle 依赖验证元数据(gradle/verification-metadata.xml)与纯校验和 allowlist;
  • 可复现的 ZIP/JAR 归档元数据。

安装器证据则覆盖:desktop:generateInstallers生成的各 OS 安装包:

  • Linux:.deb与.rpm;
  • macOS:.dmg;
  • Windows:.exe。

安装器 manifest 证明"产出的二进制安装文件"与"同一 OS 的已发布或 CI 生成目标"一致;结构报告则用于解释安装包内部差异。

1.3 当前状态与限制

各平台成熟度不同(详见下文三、四节),当前真实状态为:

  • Linux 支持最强:固定发布构建镜像可构建同一提交的两个干净 worktree,验证 Java 证据与 Linux 安装器证据并对比两者,且已接入手动 GitHub Actions 工作流Linux Release Builder(release-builder.yml)。
  • 标准Build Bisq工作流在 Linux、macOS、Windows 上运行verifyReleaseBuild(push 与 PR 构建均触发),验证 Java 负载与策略门,但它不是Linux 发布构建器的完整双 worktree 对比。
  • 手动Installer Evidence工作流可在三个 OS 上生成安装器证据,记录各 OS 诊断信息;但 macOS 与 Windows 目前还没有与 Linux 对等的固定双 worktree 发布构建环境。

限制必须如实承认:

  • 可复现性靠"对比 Manifest"证明,而非信任构建日志;
  • Java 负载证据可跨构建环境对比,但平台特有的运行时依赖差异仍须解释;安装器证据只与同 OS 的安装器格式对比;
  • Linux 有固定发布构建镜像;macOS 与 Windows 当前依赖 GitHub 托管 runner 或本地机器;
  • macOS.dmg与 Windows.exe的安装器内部结构目前属于"诊断性证据",确定性平台发布构建器仍是未来工作;
  • 已发布证据只有在发布经理签名、验证者核验签名后才真正有用。

1.4 项目方向

  1. 保持 Linux 作为"固定、隔离、双 worktree 可复现发布构建器"的参考实现;
  2. 在发布产物旁发布签名的 Java 证据与各 OS 安装器证据;
  3. 将"无法解释的 Java 负载不匹配"视为发布阻断项(release blocker);
  4. 将"安装器不匹配"视为受影响安装器工件的 OS 级阻断项;
  5. 通过增加"固定或可审查的发布构建环境 + A/B 对比",把 Linux 模型扩展到 macOS 与 Windows;
  6. 依赖验证维护与普通代码改动分离,使新增纯校验和工件获得显式审查。

二、如何生成与对比证据(实操)

本节为实际执行手册,对应官方 使用指南。所有路径均在仓库根目录下执行。

2.1 准备干净的检出

使用发布 tag 或发布提交的干净检出:

git submodule update --init --recursive shasum -a 256 -c gradle/wrapper/gradle-wrapper.sha256

第一行初始化全部子模块;第二行校验 Gradle wrapper 的 SHA-256 清单(清单文件见 gradle/wrapper/gradle-wrapper.sha256,内含gradlew、gradlew.bat、gradle-wrapper.jar、gradle-wrapper.properties四个文件的固定哈希)。在 Linux 上建议优先使用下文第三节的固定发布构建镜像。

2.2 构建 Java 发布证据

运行发布负载与策略门:

./gradlew clean verifyReleaseBuild

主要输出(位于build/reports/release/与build/reports/checksums/):

文件作用
release-evidence.zip可签名的证据压缩包
release-manifest.tsv权威 Java 负载对比清单(SHA-256、size、仓库相对路径)
SHA256SUMS校验和文件
build-info.json诊断性构建信息
checksums/jars.sha256各 jar 的 SHA-256

验证生成的校验和文件:

shasum -a 256 -c build/reports/release/SHA256SUMS

将本地重建与已发布或 CI 生成的 manifest 对比:

./gradlew verifyReleaseManifest \ -PreleaseManifest=/path/to/release-manifest.tsv

-PreleaseManifest可以指向:manifest 文件、解压后的证据目录、下载的 GitHub Actions artifact 目录,或release-evidence.zip本身。从源码(build.gradle)看,该任务先依赖generateReleaseManifest与verifyReleaseEnvironment,再通过verifyManifestMatches比较期望与实际的 manifest。

无需重建即可对比两个证据包:

./gradlew compareReleaseEvidenceBundles \ -PleftReleaseEvidence=/path/to/local/release-evidence.zip \ -PrightReleaseEvidence=/path/to/ci/release-evidence.zip

2.3 构建安装器证据

./gradlew verifyInstallerEvidenceBundle

该任务构建当前 OS 的安装器工件并写出:

文件作用
installer-evidence.zip可签名的安装器证据包
installer-manifest.tsv权威安装器工件对比清单
INSTALLER-SHA256SUMS校验和文件
installer-build-info.json构建信息
installer-structure-summary.txt结构报告摘要
installer-structure-report.tsv各工件结构报告生成/失败/跳过状态
installer-structure/各工件的结构报告明细

验证安装器校验和:

shasum -a 256 -c build/reports/release/INSTALLER-SHA256SUMS

对比本地安装器重建与已发布/CI 证据:

./gradlew verifyInstallerManifest \ -PinstallerManifest=/path/to/installer-evidence.zip

对比两个安装器证据包:

./gradlew compareInstallerEvidenceBundles \ -PleftInstallerEvidence=/path/to/local/installer-evidence.zip \ -PrightInstallerEvidence=/path/to/ci/installer-evidence.zip

安装器证据是 OS 特定的:Linux 只能对比 Linux,macOS 对比 macOS,Windows 对比 Windows,且应为同一发布提交。

2.4 使用 GitHub Actions

  • Build Bisq(build.yml):push 与 pull_request 自动触发,在ubuntu-24.04、macos-15、windows-2025三平台矩阵(Java 21.0.6)上运行verifyReleaseBuild --scan,并上传 Java 发布证据(artifact 名为release-manifests-<os>-java-21.0.6)。
  • Installer Evidence(installer-evidence.yml):手动触发(workflow_dispatch),在三个 OS 上运行verifyInstallerEvidenceBundle --scan并上传各 OS 安装器证据(artifact 分别为installer-evidence-ubuntu-24.04-java-21.0.6、installer-evidence-macos-15-java-21.0.6、installer-evidence-windows-2025-java-21.0.6;Windows 作业会先用 Chocolatey 安装 WiX Toolset)。
  • Linux Release Builder(release-builder.yml):手动触发,是目前最强的可复现性检查。流程为:检出所选提交(含子模块)→ 构建bisq-release-builder-linux:java-21.0.6镜像 → 在$GITHUB_SHA创建干净 worktreea、b→ 在两个 worktree 的 Docker 镜像内分别运行./gradlew clean verifyReleaseBuild verifyInstallerEvidenceBundle→ 运行compareReleaseEvidenceBundles与compareInstallerEvidenceBundles→ 上传release-builder-linux-java-21.0.6与release-builder-linux-installers-java-21.0.6两个 artifact。

手动触发方式:打开仓库的 GitHub Actions 标签页,选择工作流,点击Run workflow,选择要验证的分支或 tag。

2.5 发布经理政策

签名发布工件前应依次完成:

  1. 从发布 tag 或发布提交构建;
  2. 校验 Gradle wrapper 校验和清单;
  3. 生成 Java 发布证据;
  4. 将 Java 证据与同一提交、同一 Java 版本的 Linux CI 或 release-builder 证据对比;
  5. 可用时对比 macOS 与 Windows 的 Java 证据;
  6. 为每个将要发布的 OS 工件生成或下载安装器证据;
  7. 每个安装器只与同一 OS、同一提交的证据对比;
  8. 在签名前解释每一个不匹配项。

无法解释的 Java 负载不匹配 = 发布阻断项;无法解释的安装器不匹配 = 阻断该 OS 安装器的发布。

2.6 签名证据

用发布签名密钥对证据包与权威 manifest 文件做分离式装甲签名:

gpg --digest-algo SHA256 --armor --detach-sign build/reports/release/release-evidence.zip gpg --digest-algo SHA256 --armor --detach-sign build/reports/release/release-manifest.tsv gpg --digest-algo SHA256 --armor --detach-sign build/reports/release/SHA256SUMS gpg --digest-algo SHA256 --armor --detach-sign build/reports/release/installer-evidence.zip gpg --digest-algo SHA256 --armor --detach-sign build/reports/release/installer-manifest.tsv gpg --digest-algo SHA256 --armor --detach-sign build/reports/release/INSTALLER-SHA256SUMS

随后将签名证据发布到发布产物旁。

2.7 独立验证者工作流

独立验证者应:

  1. 检出发布 tag;
  2. 初始化子模块;
  3. 校验 Gradle wrapper 校验和文件;
  4. 重建 Java 发布证据;
  5. 核验已发布证据的签名;
  6. 将本地证据与签名的已发布证据对比。
git submodule update --init --recursive shasum -a 256 -c gradle/wrapper/gradle-wrapper.sha256 ./gradlew clean verifyReleaseBuild gpg --verify /path/to/release-evidence.zip.asc /path/to/release-evidence.zip ./gradlew verifyReleaseManifest \ -PreleaseManifest=/path/to/release-evidence.zip

验证安装器时,还需在同一 OS 重建或下载安装器证据并与签名安装器证据对比:

gpg --verify /path/to/installer-evidence.zip.asc /path/to/installer-evidence.zip ./gradlew verifyInstallerManifest \ -PinstallerManifest=/path/to/installer-evidence.zip

三、技术细节:任务模型、证据格式与确定性构建

本节对应官方 技术细节文档,并结合 build.gradle 源码逐项印证。

3.1 Gradle 任务模型

verifyReleaseBuild是主 Java 负载门(build.gradle),依赖:

  • verifyReleaseEnvironment——校验本地 Gradle 与 Java 运行时与固定环境一致(比较java.version、java.vendor、gradle.gradleVersion,见 build.gradle);
  • verifyGradleWrapperSecurity——校验 wrapper 四个文件的校验和、distributionUrl必须来自services.gradle.org且distributionSha256Sum为固定的 64 位小写 SHA-256(见 build.gradle);
  • verifyReleaseBuilderImage——静态检查 Linux release-builder Dockerfile 是否保持关键选择固定(如默认命令必须是./gradlew verifyReleaseBuild、base image 按 digest 固定,见 build.gradle);
  • verifyGithubActionsSecurity——检查工作流脚本中的命令是否为期望形式(例如 release-builder 工作流必须在两个 worktree 内运行./gradlew clean verifyReleaseBuild verifyInstallerEvidenceBundle);
  • verifyDependencySignaturePolicy——依赖签名策略门;
  • verifyReleaseEvidenceBundle——校验生成的证据 ZIP 是否包含必需文件;
  • 每个子项目的build任务;
  • 每个子项目的verifyReproducibleArchives任务。

verifyInstallerEvidenceBundle是主安装器证据门(build.gradle),依赖generateInstallerEvidenceBundle,后者又依赖安装器 manifest 与结构报告生成。

对比任务是只读的:

  • compareReleaseEvidenceBundles
  • compareInstallerEvidenceBundles

两者都接受 ZIP 包或已解压的证据目录。

3.2 Java 发布证据格式

  • release-manifest.tsv:权威 Java 负载对比文件,记录 SHA-256、字节大小、规范化的仓库相对路径。
  • release-evidence.zip包含:release-manifest.tsv、SHA256SUMS、build-info.json、checksums/jars.sha256。从源码(build.gradle)可见其构建为preserveFileTimestamps = false+reproducibleFileOrder = true的可复现 ZIP,保证证据包本身也确定性。
  • build-info.json:诊断性元数据,记录 Gradle/Java 运行时细节、OS 细节、选定的环境变量、存在时的 release-builder Dockerfile 标识、可用的安装器相关工具版本。它用于解释差异,不是权威对比文件。
  • compareReleaseEvidenceBundles只对比 manifest 条目;不匹配时报告缺失、多余、变更的路径及左右两侧的哈希与大小。

3.3 安装器证据格式

  • installer-manifest.tsv:权威安装器工件对比文件,记录:desktop:generateInstallers产物的 SHA-256、size、仓库相对路径。期望格式按 OS 区分:Linux.deb/.rpm、macOS.dmg、Windows.exe。
  • installer-evidence.zip包含:installer-manifest.tsv、INSTALLER-SHA256SUMS、installer-build-info.json、installer-structure-summary.txt、installer-structure-report.tsv、引用的installer-structure/*.txt报告。
  • installer-structure-report.tsv记录每个工件的结构报告是"已生成 / 失败 / 跳过"。结构报告是诊断性的,用于解释安装器差异,而installer-manifest.tsv仍为权威对比输入。
  • compareInstallerEvidenceBundles对比安装器 manifest;当被更改的工件带有结构报告行时,失败输出会指向对应结构报告,加速排查。

3.4 归档确定性

Gradle 归档输出必须使用确定性元数据:

  • preserveFileTimestamps = false(不保留文件时间戳);
  • reproducibleFileOrder = true(可复现文件顺序)。

同样的规则适用于bitcoind子模块,避免嵌入式 bitcoind jar 仅因 ZIP 元数据不同而产生差异(两处设置分别见 build.gradle 与 build.gradle)。

3.5 依赖验证维护

刷新依赖验证元数据,且应与普通代码改动分开提交:

./gradlew refreshDependencyVerificationKeyring ./gradlew resolveAndVerifyDependencies --write-verification-metadata pgp,sha256 ./gradlew verifyDependencySignaturePolicy ./gradlew dependencySignatureReport

新增纯校验和工件必须经过审查后才能写入 gradle/dependency-checksum-fallback-allowlist.tsv。该文件的格式为group:name:version<TAB>artifact-file-name<TAB>review-rationale(条目需按依赖与工件名排序),例如aopalliance:aopalliance:1.0的条目注明"Legacy Maven Central artifact without published detached signatures",Bisq 自维护的 JitPack 依赖(bitcoinj、jsocks、jsonrpc4j、netlayer、tor-binary 等)则注明"pinned to an immutable commit"。

3.6 差异排查顺序

证据不一致时:

  1. 先对比 manifest 行;
  2. 确认两次构建使用相同提交、子模块提交、Gradle 版本、Java 版本、时区、locale、OS/工具版本;
  3. Java 负载不匹配:检查compareReleaseEvidenceBundles指出的变更 jar 或运行时库路径;
  4. 安装器不匹配:检查installer-build-info.json、installer-structure-summary.txt、installer-structure-report.tsv与installer-structure/下对应工件报告;
  5. 仅在定位到差异字段后再修改构建逻辑。

四、分平台现状与操作:Linux / macOS / Windows

4.1 Linux:参考实现

Linux 是 Bisq 可复现发布构建的参考实现,对应 Linux 文档。

状态:已支持 Java 负载证据、.deb与.rpm安装器证据、确定性 RPM 重打包、固定镜像内的双干净 worktree 对比、手动 CI 工作流的证据上传。缺口为:Linux release-builder 是手动 CI(非 push/PR 自动);证据仍需发布经理签名发布。

构建 release-builder 镜像(Dockerfile 见 docker/release-builder/linux/Dockerfile):

docker build --pull=false \ -t bisq-release-builder-linux:java-21.0.6 \ docker/release-builder/linux

要测试更新的 Ubuntu 包快照再改动 Dockerfile 默认值:

docker build --pull=false \ --build-arg UBUNTU_APT_SNAPSHOT=20260501T000000Z \ -t bisq-release-builder-linux:java-21.0.6 \ docker/release-builder/linux

镜像固定的关键输入(来自 Dockerfile):

  • linux/amd64的 Azul Zulu OpenJDK 21.0.6 基础镜像,按 digest 固定:azul/zulu-openjdk:21.0.6@sha256:00a833d7f0...;
  • Ubuntu apt 快照时间戳(ARG UBUNTU_APT_SNAPSHOT=20260501T000000Z,构建时对 apt 源注入Snapshot: yes/APT::Snapshot配置);
  • SOURCE_DATE_EPOCH=0、TZ=UTC、LANG=C.UTF-8、LC_ALL=C.UTF-8、HOME=/tmp/bisq-home、GRADLE_USER_HOME=/tmp/bisq-home/.gradle;
  • 安装用于发布与安装器证据的 Linux 工具:binutils、coreutils、cpio、dpkg、dpkg-dev、fakeroot、file、git、gnupg、gzip、rpm、tar、unzip、xz-utils、zip(含locales、openssh-client、findutils、ca-certificates);
  • 默认命令CMD ["./gradlew", "verifyReleaseBuild"]。

运行单次 Linux 验证(从发布 tag/提交的干净检出):

docker run --rm --platform linux/amd64 \ --user "$(id -u):$(id -g)" \ -v "$PWD:/workspace" \ -w /workspace \ bisq-release-builder-linux:java-21.0.6 \ ./gradlew clean verifyReleaseBuild verifyInstallerEvidenceBundle

这会向build/reports/release/写入 Java 证据与 Linux 安装器证据。

本地运行完整 A/B 对比(两个同一提交的隔离 worktree):

RELEASE_REF=HEAD git worktree add --detach ../bisq-release-a "$RELEASE_REF" git worktree add --detach ../bisq-release-b "$RELEASE_REF" git -C ../bisq-release-a submodule update --init --recursive git -C ../bisq-release-b submodule update --init --recursive REPO_PARENT="$(cd .. && pwd)" docker run --rm --platform linux/amd64 \ --user "$(id -u):$(id -g)" \ -v "$REPO_PARENT:$REPO_PARENT" \ -w "$REPO_PARENT/bisq-release-a" \ bisq-release-builder-linux:java-21.0.6 \ ./gradlew clean verifyReleaseBuild verifyInstallerEvidenceBundle docker run --rm --platform linux/amd64 \ --user "$(id -u):$(id -g)" \ -v "$REPO_PARENT:$REPO_PARENT" \ -w "$REPO_PARENT/bisq-release-b" \ bisq-release-builder-linux:java-21.0.6 \ ./gradlew clean verifyReleaseBuild verifyInstallerEvidenceBundle

对比输出:

( cd ../bisq-release-a ./gradlew compareReleaseEvidenceBundles compareInstallerEvidenceBundles \ -PleftReleaseEvidence=build/reports/release/release-evidence.zip \ -PrightReleaseEvidence=../bisq-release-b/build/reports/release/release-evidence.zip \ -PleftInstallerEvidence=build/reports/release/installer-evidence.zip \ -PrightInstallerEvidence=../bisq-release-b/build/reports/release/installer-evidence.zip )

CI 工作流Linux Release Builder(release-builder.yml,仅workflow_dispatch):检出所选提交(含子模块)→ 构建镜像 → 在$GITHUB_SHA创建干净 worktreea/b→ 两个 worktree 均在镜像内运行clean verifyReleaseBuild verifyInstallerEvidenceBundle→ 分别运行compareReleaseEvidenceBundles与compareInstallerEvidenceBundles→ 上传两个 evidence artifact。这是当前 Linux 可复现性最强的 CI 信号。

Linux 安装器诊断:.deb差异检查ar外层成员元数据、debian-binary/control.tar.*/data.tar.*哈希、control.tar与data.tar清单;.rpm差异检查包校验与 digest 输出、构建日期与构建主机、负载归档清单、rpm -q包转储。排查起点是installer-build-info.json,确认 Java、Gradle、时区、locale、Dockerfile、apt 快照与 Linux 包工具版本一致。

Linux RPM 归一化:Linux RPM 安装器由jpackage生成后会被确定性重打包——解出 jpackage RPM 负载,再用rpmbuild以固定 RPM 宏重建:以 source date epoch 作为构建时间、钳制负载 mtime、固定构建主机、确定性 gzip 负载、禁用生成的 build-id 符号链接项、禁用安装后 buildroot 处理。生成的 spec 保留 Bisq 包元数据与桌面菜单安装/卸载脚本行为,使可安装负载与 jpackage 一致,同时去除不确定的 RPM 头与负载元数据。

4.2 macOS:Java 证据与.dmg诊断证据

对应 macOS 文档。当前支持verifyReleaseBuild生成 Java 负载证据、verifyInstallerEvidenceBundle生成.dmg安装器证据、手动Installer Evidence工作流上传证据、以及用hdiutil/pkgutil等工具的安装器诊断。缺口:无固定 macOS 发布构建镜像、无与 Linux 对等的双 worktree 工作流、.dmg内部结构目前只是诊断证据而非确定性保证。

本地操作:

git submodule update --init --recursive shasum -a 256 -c gradle/wrapper/gradle-wrapper.sha256 ./gradlew clean verifyReleaseBuild ./gradlew verifyInstallerEvidenceBundle ./gradlew compareReleaseEvidenceBundles \ -PleftReleaseEvidence=build/reports/release/release-evidence.zip \ -PrightReleaseEvidence=/path/to/ci/release-evidence.zip ./gradlew compareInstallerEvidenceBundles \ -PleftInstallerEvidence=build/reports/release/installer-evidence.zip \ -PrightInstallerEvidence=/path/to/macos/installer-evidence.zip

CI 层面:Build Bisq在macos-15运行verifyReleaseBuild --scan(push/PR);手动Installer Evidence有macos-15作业,运行verifyInstallerEvidenceBundle --scan并上传installer-evidence-macos-15-java-21.0.6。

.dmg差异排查:对比installer-build-info.json、hdiutil imageinfo、分区表输出、hdiutil verify、hdiutilSHA-256 校验和输出;macOS 结构报告使用的工具包括file、hdiutil、pkgutil、以及适用时的xar。若未来出现.pkg,再对比签名输出、负载文件清单与原始xar归档成员诊断。方向:一旦具备合适的固定或可审查 macOS 构建策略,就照搬 Linux 模型(双 worktree → 双证据 → 对比 → 上传第一个 worktree 的签名证据候选)。

4.3 Windows:Java 证据与.exe诊断证据

对应 Windows 文档。当前支持verifyReleaseBuild的 Java 负载证据、verifyInstallerEvidenceBundle的.exe安装器证据、手动 CI 上传、以及 PowerShell 与 WiX 相关工具的安装器诊断。Windows 安装器生成要求 WiX Toolset 位于PATH。

本地操作(wrapper 校验需在 Git Bash 等带shasum的 shell 中进行):

git submodule update --init --recursive shasum -a 256 -c gradle/wrapper/gradle-wrapper.sha256

然后:

./gradlew clean verifyReleaseBuild ./gradlew verifyInstallerEvidenceBundle ./gradlew compareReleaseEvidenceBundles ` -PleftReleaseEvidence=build/reports/release/release-evidence.zip ` -PrightReleaseEvidence=C:\path\to\ci\release-evidence.zip ./gradlew compareInstallerEvidenceBundles ` -PleftInstallerEvidence=build/reports/release/installer-evidence.zip ` -PrightInstallerEvidence=C:\path\to\windows\installer-evidence.zip

CI 层面:Build Bisq在windows-2025运行verifyReleaseBuild --scan;手动Installer Evidence的 Windows 作业在windows-2025上先用 Chocolatey 安装 WiX Toolset,再运行verifyInstallerEvidenceBundle --scan,上传installer-evidence-windows-2025-java-21.0.6。

.exe差异排查:对比installer-build-info.json、文件元数据、版本信息、Authenticode 签名输出、PE/COFF 头时间戳元数据。Windows 结构报告优先使用 Windows PowerShell,不可用时回退到 PowerShell Core(pwsh)。若未来加入.msi工件,还需对比 MSI Property 表条目。方向与 macOS 相同:沿 Linux 模型推进双 worktree A/B 对比。

五、背书(Attestation)计划:多独立构建者签名模型

对应 背书计划文档。其目标是让用户或维护者无需信任单台机器或单个人即可回答:

多个独立构建者是否从相同源码、构建指令与发布环境重现了相同的发布工件?

现有 Bisq 输出仍是权威对比工件:release-evidence.zip、release-manifest.tsv、SHA256SUMS、installer-evidence.zip、installer-manifest.tsv、INSTALLER-SHA256SUMS。背书(attestation)应描述并签名对比结果,不应替代安装器签名或发布签名。

5.1 推荐模型:阈值制

  1. CI 构建发布提交并上传证据;
  2. 至少三位独立构建者重建同一发布提交或 tag;
  3. 每位构建者将本地证据与 CI 或发布经理证据对比,并签署机器可读背书;
  4. 发布经理执行同样的重建与对比;
  5. 发布经理核验独立背书、签署最终发布工件、签署发布背书索引;
  6. 公开验证者可核验发布签名、证据签名、独立构建者签名与背书索引。

CI 证据有用,但不应计入独立构建者阈值;发布经理背书有用,但不应替代独立构建者阈值。推荐的发布最低政策:至少 3 个独立成功构建者背书;至少 1 个发布经理背书;所有背书引用精确的发布 tag、commit 哈希、工件名、工件 SHA-256 与证据包 SHA-256;Java 负载不匹配阻断发布(除非完整解释);安装器不匹配阻断受影响 OS/架构工件(除非完整解释);macOS Intel 与 Apple Silicon 的 DMG 视为不同工件。

5.2 角色与命令

独立构建者:干净检出 → 校验 wrapper → 运行证据任务 → 对比本地与目标证据 → 签名:

git submodule update --init --recursive shasum -a 256 -c gradle/wrapper/gradle-wrapper.sha256 ./gradlew clean verifyReleaseBuild ./gradlew verifyInstallerEvidenceBundle ./gradlew compareReleaseEvidenceBundles \ -PleftReleaseEvidence=build/reports/release/release-evidence.zip \ -PrightReleaseEvidence=/path/to/reference/release-evidence.zip ./gradlew compareInstallerEvidenceBundles \ -PleftInstallerEvidence=build/reports/release/installer-evidence.zip \ -PrightInstallerEvidence=/path/to/reference/installer-evidence.zip

随后生成rebuild-attestation.json并做分离 GPG 签名:

gpg --digest-algo SHA256 --armor --detach-sign rebuild-attestation.json

发布经理:核验每个构建者签名与密钥是否属于预期 Bisq 背书密钥、背书是否引用正确的 tag/commit/哈希、独立构建者阈值是否满足、本地重建并对比、创建并签名release-attestation-index.json、将索引、索引签名、构建者背书与签名发布到发布资产旁。

公开验证者:下载发布资产与背书包,核验发布工件签名、发布证据签名、构建者背书签名、发布背书索引签名、阈值策略与精确的工件/证据哈希。

5.3 背书格式与索引

背书格式采用小型 JSON,遵循 in-toto Statement 形状(示例 JSON 中给出了完整结构),建议 predicate 类型为https://bisq.network/reproducible-builds/rebuild-attestation/v1。JSON 的精确字节用分离 GPG 签名;未来工具应以排序键生成确定性 JSON 便于审查。

发布背书索引是发布经理签名的"已接受背书摘要",应包含:发布版本、tag、commit、工件列表(SHA-256 与 size)、证据包列表、已接受构建者背书(文件名、SHA-256、签名者指纹)、被拒绝/忽略的背书与理由、本发布使用的阈值政策、发布经理指纹、创建时间戳。索引也需签名:

gpg --digest-algo SHA256 --armor --detach-sign release-attestation-index.json

发布位置建议:短期把单一背书包附加到 GitHub release(建议资产Bisq-${VERSION}-reproducible-builds.zip与.asc,包内布局为release-attestation-index.json+attestations/<builder-fingerprint>/+evidence/),并在 Bisq 下载页镜像;中期建立专门的背书仓库(如bisq-network/bisq-rebuild-attestations),构建者以 PR 提交签名背书,发布经理核验后合入并打包进 release 背书包。选择独立仓库的原因:发布证据生成于发布源码提交之后,不应改写该发布的源码树,也不应把生成的发布数据塞进主仓库历史。

5.4 密钥管理与应用内展示

维护一个与发布签名密钥分离的小型 Bisq 背书密钥环,定义:接受的独立构建者指纹、发布经理指纹、密钥过期日期、撤销流程、密钥可签的背书类型(独立构建者/发布经理/两者)。应用与验证工具不应依赖在线 keyserver 查询——keyserver 只用于人工审计,自动化验证应使用项目发布的密钥环与精确指纹。

应用内下载流程应继续把"分离安装器签名验证"作为硬安全门,背书展示作为附加透明信号:下载紧凑背书索引 → 用内置密钥核验索引签名 → 用内置背书密钥环核验构建者签名 → 校验被背书工件名与 SHA-256 是否匹配所选安装器(含所选 macOS 架构)→ 显示类似Reproduced by 3 independent builders的状态并提供详情。应用不应因背书元数据临时不可用而失败更新(首批 rollout 阶段);待流程成熟后可决定缺失背书是警告还是硬阻断。隐私要求:不从应用查询第三方 keyserver、不上报用户下载或验证结果、背书下载仅限更新器已使用的发布元数据/下载源。

5.5 待添加的 Gradle 工具与分阶段落地

计划新增任务:generateRebuildAttestation(读取本地证据 manifest 与对比目标元数据,写确定性rebuild-attestation.json)、verifyRebuildAttestation(校验 JSON 形状、工件与证据哈希、分离 GPG 签名、签名者指纹)、collectReleaseAttestations(核验所有提交的背书、检查阈值、写release-attestation-index.json)、verifyReleaseAttestationIndex、packageReleaseAttestations(构建Bisq-${VERSION}-reproducible-builds.zip)、verifyGithubReleaseReadiness。

分阶段落地:

  • Phase 1 手动背书:定义 JSON schema 与接受密钥环;三位构建者手动产出并签名;与发布工件一起发布;文档保留验证说明。
  • Phase 2 Gradle 生成与验证:加入上述任务与发布就绪检查。
  • Phase 3 独立背书仓库:建小型仓库,背书走 PR,发布经理核验后打包进 release 资产。
  • Phase 4 应用内透明:下载窗口加背书摘要,对选定安装器核验背书索引,安装器签名验证仍为硬门。
  • Phase 5 更严格发布政策:决定缺失有效背书索引是否阻断最终发布、应用是否提示或阻断更新。

开放决策包括:独立构建者最低数量(建议默认 3);发布经理是否可兼任一名独立构建者(建议默认:否);是否所有 OS/架构工件在发布时都需要同一阈值(建议默认:先从 Java 负载与受支持的安装器证据开始,随确定性构建器成熟逐步收紧各 OS/架构阈值);背书仓库确切名称;密钥环文件位置与治理;是否在 GPG 签名之外为 CI 证据增加 GitHub artifact attestations。

六、结论与自检清单

Bisq 的可复现发布体系已经形成"固定环境 + 证据生成 + 权威 Manifest 对比 + 签名背书"的完整闭环:Linux 作为参考实现率先具备固定镜像与双 worktree A/B 对比(release-builder.yml);Java 负载证据在三平台 CI 上常态化生成(build.yml);安装器证据三平台可用但 macOS/Windows 尚属诊断证据;背书计划则把"至少三名独立构建者 + 发布经理"的阈值模型落成可执行的签名与发布流程。

无论你是发布经理、独立验证者,还是希望为 Bisq 贡献可复现性改进的开发者,建议的自检清单为:

  1. 每次构建前先跑git submodule update --init --recursive与shasum -a 256 -c gradle/wrapper/gradle-wrapper.sha256;
  2. 用./gradlew clean verifyReleaseBuild生成 Java 证据,用./gradlew verifyInstallerEvidenceBundle生成当前 OS 安装器证据;
  3. 对任何"已发布 vs 本地"对比使用verifyReleaseManifest/verifyInstallerManifest,对"两份本地证据"使用compareReleaseEvidenceBundles/compareInstallerEvidenceBundles;
  4. 排查差异时严格遵循"先 Manifest 行 → 再环境要素(commit、Gradle、Java、时区、locale、OS/工具版本)→ 再具体工件路径与结构报告"的顺序;
  5. 涉及发布时,未解释的 Java 负载不匹配与安装器不匹配分别是不同层级的阻断项;
  6. 签名统一使用gpg --digest-algo SHA256 --armor --detach-sign,并确保证据签名、发布签名、背书签名均可被公开验证者独立核验。

可复现构建的最终价值在于:任何人都不必"信任某个人的某台机器",而只需校验哈希、签名与背书,即可确认你拿到的 Bisq 安装包确实来自公开源码。

  • 区块链
  • DeFi
  • 金融科技

【免费下载链接】bisq

A decentralized bitcoin exchange network

项目地址:https://gitcode.com/gh_mirrors/bi/bisq
点击查看免费下载
上一篇:League Akari 英雄联盟工具包:新手快速上手指南与常见问题解决方案
下一篇:Voron 2.4专业调试实战:5个提升打印质量的核心技巧深度解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询