diff --git a/audit/internal/updater/trust.go b/audit/internal/updater/trust.go deleted file mode 100644 index d0d75cd..0000000 --- a/audit/internal/updater/trust.go +++ /dev/null @@ -1,59 +0,0 @@ -// Package updater handles binary self-update with Ed25519 signature verification. -// See bible/rules/patterns/release-signing/contract.md for the full contract. -package updater - -import ( - "crypto/ed25519" - "encoding/base64" - "fmt" - "strings" -) - -// trustedKeysRaw is injected at release build time via: -// -// -ldflags "-X bee/audit/internal/updater.trustedKeysRaw=base64key1:base64key2" -// -// Empty in dev builds — updates are disabled when empty. -var trustedKeysRaw string - -// TrustedKeys decodes the embedded public keys. -// Returns an error if the binary was built without key injection (dev build). -func TrustedKeys() ([]ed25519.PublicKey, error) { - if strings.TrimSpace(trustedKeysRaw) == "" { - return nil, fmt.Errorf("dev build: trusted keys not embedded, updates disabled") - } - var keys []ed25519.PublicKey - for _, enc := range strings.Split(trustedKeysRaw, ":") { - enc = strings.TrimSpace(enc) - if enc == "" { - continue - } - b, err := base64.StdEncoding.DecodeString(enc) - if err != nil { - return nil, fmt.Errorf("decode trusted key: %w", err) - } - if len(b) != ed25519.PublicKeySize { - return nil, fmt.Errorf("trusted key has wrong size: got %d, want %d", len(b), ed25519.PublicKeySize) - } - keys = append(keys, ed25519.PublicKey(b)) - } - if len(keys) == 0 { - return nil, fmt.Errorf("no valid trusted keys found in build") - } - return keys, nil -} - -// VerifySignature returns nil if sig was produced by any trusted key over data. -// Returns an error (never panics) on any failure — caller logs and continues. -func VerifySignature(data, sig []byte) error { - keys, err := TrustedKeys() - if err != nil { - return err - } - for _, key := range keys { - if ed25519.Verify(key, data, sig) { - return nil - } - } - return fmt.Errorf("signature verification failed: no trusted key matched") -} diff --git a/audit/internal/updater/trust_test.go b/audit/internal/updater/trust_test.go deleted file mode 100644 index 10e889b..0000000 --- a/audit/internal/updater/trust_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package updater - -import ( - "crypto/ed25519" - "crypto/rand" - "encoding/base64" - "testing" -) - -func TestVerifySignature_valid(t *testing.T) { - pub, priv, err := ed25519.GenerateKey(rand.Reader) - if err != nil { - t.Fatal(err) - } - - data := []byte("release binary content") - sig := ed25519.Sign(priv, data) - - trustedKeysRaw = base64.StdEncoding.EncodeToString(pub) - t.Cleanup(func() { trustedKeysRaw = "" }) - - if err := VerifySignature(data, sig); err != nil { - t.Fatalf("expected valid signature to pass: %v", err) - } -} - -func TestVerifySignature_tampered(t *testing.T) { - pub, priv, err := ed25519.GenerateKey(rand.Reader) - if err != nil { - t.Fatal(err) - } - _ = pub - - data := []byte("original content") - sig := ed25519.Sign(priv, data) - - // different key embedded - pub2, _, _ := ed25519.GenerateKey(rand.Reader) - trustedKeysRaw = base64.StdEncoding.EncodeToString(pub2) - t.Cleanup(func() { trustedKeysRaw = "" }) - - if err := VerifySignature(data, sig); err == nil { - t.Fatal("expected tampered signature to fail") - } -} - -func TestVerifySignature_multiKey_anyMatches(t *testing.T) { - pub1, _, _ := ed25519.GenerateKey(rand.Reader) - pub2, priv2, _ := ed25519.GenerateKey(rand.Reader) - - data := []byte("signed by developer 2") - sig := ed25519.Sign(priv2, data) - - trustedKeysRaw = base64.StdEncoding.EncodeToString(pub1) + ":" + - base64.StdEncoding.EncodeToString(pub2) - t.Cleanup(func() { trustedKeysRaw = "" }) - - if err := VerifySignature(data, sig); err != nil { - t.Fatalf("expected any-key match to pass: %v", err) - } -} - -func TestVerifySignature_devBuild(t *testing.T) { - trustedKeysRaw = "" - _, priv, _ := ed25519.GenerateKey(rand.Reader) - data := []byte("content") - sig := ed25519.Sign(priv, data) - - if err := VerifySignature(data, sig); err == nil { - t.Fatal("expected dev build (no keys) to fail") - } -} diff --git a/iso/builder/build-in-container.sh b/iso/builder/build-in-container.sh index 842106d..d90d4ec 100755 --- a/iso/builder/build-in-container.sh +++ b/iso/builder/build-in-container.sh @@ -124,66 +124,41 @@ else echo "=== using existing builder image ${IMAGE_REF} (${BUILDER_PLATFORM}) ===" fi -# Build base docker run args (without --authorized-keys) -build_run_args() { - _variant="$1" - _auth_arg="" - if [ -n "$AUTH_KEYS" ]; then - _auth_arg="--authorized-keys /tmp/bee-authkeys/${AUTH_KEYS_BASE}" - fi - echo "run --rm --privileged \ - --platform ${BUILDER_PLATFORM} \ - -v ${REPO_ROOT}:/work \ - -v ${CACHE_DIR}:/cache \ - ${AUTH_KEYS:+-v ${AUTH_KEYS_DIR}:/tmp/bee-authkeys:ro} \ +run_variant() { + _v="$1" + echo "=== building variant: ${_v} ===" + + set -- \ + --rm \ + --privileged \ + --platform "${BUILDER_PLATFORM}" \ + -v "${REPO_ROOT}:/work" \ + -v "${CACHE_DIR}:/cache" \ -e BEE_CONTAINER_BUILD=1 \ -e GOCACHE=/cache/go-build \ -e GOMODCACHE=/cache/go-mod \ -e TMPDIR=/cache/tmp \ -e BEE_CACHE_DIR=/cache/bee \ - -w /work \ - ${IMAGE_REF} \ - sh /work/iso/builder/build.sh --variant ${_variant} ${_auth_arg}" -} + -e BEE_REQUIRE_MEMTEST=1 -run_variant() { - _v="$1" - echo "=== building variant: ${_v} ===" if [ -n "$AUTH_KEYS" ]; then - "$CONTAINER_TOOL" run --rm --privileged \ - --platform "${BUILDER_PLATFORM}" \ - -v "${REPO_ROOT}:/work" \ - -v "${CACHE_DIR}:/cache" \ - -v "${AUTH_KEYS_DIR}:/tmp/bee-authkeys:ro" \ - -e BEE_CONTAINER_BUILD=1 \ - -e GOCACHE=/cache/go-build \ - -e GOMODCACHE=/cache/go-mod \ - -e TMPDIR=/cache/tmp \ - -e BEE_CACHE_DIR=/cache/bee \ - -e BEE_REQUIRE_MEMTEST=1 \ - ${MIRROR:+-e "BEE_MIRROR=${MIRROR}"} \ - -w /work \ - "${IMAGE_REF}" \ - sh /work/iso/builder/build.sh --variant "${_v}" \ - --authorized-keys "/tmp/bee-authkeys/${AUTH_KEYS_BASE}" \ - ${MIRROR:+--mirror "${MIRROR}"} - else - "$CONTAINER_TOOL" run --rm --privileged \ - --platform "${BUILDER_PLATFORM}" \ - -v "${REPO_ROOT}:/work" \ - -v "${CACHE_DIR}:/cache" \ - -e BEE_CONTAINER_BUILD=1 \ - -e GOCACHE=/cache/go-build \ - -e GOMODCACHE=/cache/go-mod \ - -e TMPDIR=/cache/tmp \ - -e BEE_CACHE_DIR=/cache/bee \ - -e BEE_REQUIRE_MEMTEST=1 \ - ${MIRROR:+-e "BEE_MIRROR=${MIRROR}"} \ - -w /work \ - "${IMAGE_REF}" \ - sh /work/iso/builder/build.sh --variant "${_v}" \ - ${MIRROR:+--mirror "${MIRROR}"} + set -- "$@" -v "${AUTH_KEYS_DIR}:/tmp/bee-authkeys:ro" fi + + if [ -n "$MIRROR" ]; then + set -- "$@" -e "BEE_MIRROR=${MIRROR}" + fi + + set -- "$@" -w /work "${IMAGE_REF}" \ + sh /work/iso/builder/build.sh --variant "${_v}" + if [ -n "$AUTH_KEYS" ]; then + set -- "$@" --authorized-keys "/tmp/bee-authkeys/${AUTH_KEYS_BASE}" + fi + if [ -n "$MIRROR" ]; then + set -- "$@" --mirror "${MIRROR}" + fi + + "$CONTAINER_TOOL" run "$@" } case "$VARIANT" in diff --git a/iso/builder/test-squashfs-layers.sh b/iso/builder/test-squashfs-layers.sh index e29f8a2..eb89ad8 100644 --- a/iso/builder/test-squashfs-layers.sh +++ b/iso/builder/test-squashfs-layers.sh @@ -16,6 +16,11 @@ for tool in mksquashfs unsquashfs rsync; do } done +find . -maxdepth 0 -printf '' >/dev/null 2>&1 || { + echo "test-squashfs-layers: GNU find not available, skipping" + exit 0 +} + T="$(mktemp -d)" trap 'rm -rf "$T"' EXIT INT TERM HUP ROOT="$T/root"