feat: bind each node to the binary it runs at its first handshake; refuse changes that are not in a CI-signed manifest [CI]
ci/woodpecker/push/main-amd64-build Pipeline failed

This commit is contained in:
justme committed 2026-10-08 05:39:13 +08:00
1 parent 117d34a2af
commit 4841f7b15b
40 files changed
+1011 -21

No files matched your search

+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# 镜像里某个可执行文件的 SHA-256:ci/binary-hash.sh <镜像> <镜像里的路径>
# 节点握手时上报的就是它正在运行的那个文件的哈希,CI 把这个哈希写进签名的清单(binaries),Backend 据此认「官方二进制」。
# 先试在镜像里运行 sha256sum(同架构),不行再挂载镜像文件系统直接读。
set -euo pipefail
image="${1:?usage: binary-hash.sh <image> <path>}"; path="${2:?path in the image}"
container="$(buildah from "$image")"
trap 'buildah rm "$container" >/dev/null 2>&1 || true' EXIT
if out="$(buildah run "$container" -- sha256sum "$path" 2>/dev/null)" && [[ "$out" =~ ^([0-9a-f]{64})[[:space:]] ]]; then
echo "${BASH_REMATCH[1]}"
exit 0
fi
buildah unshare bash -c '
set -euo pipefail
mount="$(buildah mount "$1")"
sha256sum "$mount$2" | cut -d" " -f1
buildah umount "$1" >/dev/null
' _ "$container" "$path"
+6 -1
View File
@@ -54,6 +54,11 @@ buildah bud --layers --network host --tls-verify=true --arch amd64 \
-f "$context/Containerfile" \
-t "$local_image" "$context"
# 镜像里节点二进制的哈希:写进签名的清单(binaries),Backend 凭它认「官方二进制」,节点握手时上报的就是它正在运行的这个文件的哈希
binary_sha256="$(bash "$root/ci/binary-hash.sh" "$local_image" "/usr/local/bin/moshiro-$component")"
[[ "$binary_sha256" =~ ^[0-9a-f]{64}$ ]] || { echo "could not hash the $component binary in the image" >&2; exit 1; }
echo "$component binary sha256: $binary_sha256"
logged_in=false
for attempt in 1 2 3 4; do
if buildah login --tls-verify=true --username "$ZOT_USERNAME" --password-stdin "$registry" <<< "$ZOT_SECRET" >/dev/null; then
@@ -86,5 +91,5 @@ done
# 发布清单:给镜像的 digest 签名(私钥只在 CI 密钥里),放进镜像仓库(<仓库>-manifest:dev),面板在线时再登记一份加速。
# 没有配置签名密钥(例如 fork)就只构建镜像、不发清单。
if [[ -n "${RELEASE_SIGNING_KEY:-}" ]]; then
bash "$root/ci/publish-release-offer.sh" "$component" "$repository" "$(cat "$work/$component.digest")" "$dev_tag" dev "$work/$component-release"
RELEASE_BINARIES="$binary_sha256" bash "$root/ci/publish-release-offer.sh" "$component" "$repository" "$(cat "$work/$component.digest")" "$dev_tag" dev "$work/$component-release"
fi
+9 -2
View File
@@ -28,9 +28,16 @@ if [[ -n "${RELEASE_NEXT_KEY:-}" ]]; then
[[ -n "$next_key" ]] || { echo "RELEASE_NEXT_KEY is not a public key" >&2; exit 2; }
fi
# 官方二进制的哈希(逗号分隔的小写十六进制):节点握手时上报正在运行的二进制的哈希,Backend 用这份签名的清单认「官方」
binaries=""
if [[ -n "${RELEASE_BINARIES:-}" ]]; then
[[ "$RELEASE_BINARIES" =~ ^[0-9a-f]{64}(,[0-9a-f]{64})*$ ]] || { echo "RELEASE_BINARIES must be comma-separated sha256 hashes" >&2; exit 2; }
binaries=",\"binaries\":\"$RELEASE_BINARIES\""
fi
mkdir -p "$outdir"
printf '{"schema":1,"component":"%s","channel":"%s","image":"%s","digest":"%s","tag":"%s","version":"%s","commit":"%s","built_at":"%s","seq":%s,"install_sh":"%s","install_ps1":"%s"%s}' \
"$component" "$channel" "$repository" "$digest" "$tag" "$version" "$commit" "$built_at" "$seq" "$install_sh" "$install_ps1" "${next_key:+,\"next_key\":\"$next_key\"}" > "$outdir/manifest.json"
printf '{"schema":1,"component":"%s","channel":"%s","image":"%s","digest":"%s","tag":"%s","version":"%s","commit":"%s","built_at":"%s","seq":%s,"install_sh":"%s","install_ps1":"%s"%s%s}' \
"$component" "$channel" "$repository" "$digest" "$tag" "$version" "$commit" "$built_at" "$seq" "$install_sh" "$install_ps1" "${next_key:+,\"next_key\":\"$next_key\"}" "$binaries" > "$outdir/manifest.json"
key="$(mktemp)"
trap 'rm -f "$key" "$outdir/manifest.sig.bin"' EXIT