Files
bible/rules/patterns/release-signing/README.md
2026-04-02 13:48:36 +03:00

1.8 KiB

Release Signing Pattern Notes

This file keeps examples and rationale. The normative rules live in contract.md.

Keys Repository Shape

keys/
  developers/
    <name>.pub
  scripts/
    keygen.sh
    sign-release.sh
    verify-signature.sh

Runtime Trust Loader

// trustedKeysRaw is injected via -ldflags.
// Format: base64(key1):base64(key2):...
var trustedKeysRaw string

Typical parsing pattern:

func trustedKeys() ([]ed25519.PublicKey, error) {
    if trustedKeysRaw == "" {
        return nil, fmt.Errorf("dev build: trusted keys not embedded, updates disabled")
    }
    var keys []ed25519.PublicKey
    for _, enc := range strings.Split(trustedKeysRaw, ":") {
        b, err := base64.StdEncoding.DecodeString(strings.TrimSpace(enc))
        if err != nil || len(b) != ed25519.PublicKeySize {
            return nil, fmt.Errorf("invalid trusted key: %w", err)
        }
        keys = append(keys, ed25519.PublicKey(b))
    }
    return keys, nil
}

Build Example

KEYS=$(paste -sd: /path/to/keys/developers/*.pub)
go build \
  -ldflags "-s -w -X <module>/internal/updater.trustedKeysRaw=${KEYS}" \
  -o dist/<binary>-linux-amd64 \
  ./cmd/<binary>

Verification Sketch

func verifySignature(binaryPath, sigPath string) error {
    keys, err := trustedKeys()
    if err != nil {
        return err
    }
    data, err := os.ReadFile(binaryPath)
    if err != nil {
        return fmt.Errorf("read binary: %w", err)
    }
    sig, err := os.ReadFile(sigPath)
    if err != nil {
        return fmt.Errorf("read signature: %w", err)
    }
    for _, key := range keys {
        if ed25519.Verify(key, data, sig) {
            return nil
        }
    }
    return fmt.Errorf("signature verification failed: no trusted key matched")
}

Release Assets

<binary>-linux-amd64
<binary>-linux-amd64.sig