Add GPG signing support for manifest generation

- Add --sign-key flag and MFER_SIGN_KEY env var to gen and freshen commands
- Sign inner message multihash with GPG detached signature
- Include signer fingerprint and public key in outer wrapper
- Add comprehensive tests with temporary GPG keyring
- Increase test timeout to 10s for GPG key generation
This commit is contained in:
2025-12-18 02:12:54 -08:00
parent 308c583d57
commit 778999a285
10 changed files with 415 additions and 13 deletions

View File

@@ -4,9 +4,11 @@ import (
"bytes"
"crypto/sha256"
"errors"
"fmt"
"time"
"github.com/klauspost/compress/zstd"
"github.com/multiformats/go-multihash"
"google.golang.org/protobuf/proto"
)
@@ -53,7 +55,10 @@ func (m *manifest) generateOuter() error {
}
h := sha256.New()
h.Write(innerData)
if _, err := h.Write(innerData); err != nil {
return err
}
sha256Hash := h.Sum(nil)
idc := new(bytes.Buffer)
zw, err := zstd.NewWriter(idc, zstd.WithEncoderLevel(zstd.SpeedBestCompression))
@@ -70,10 +75,38 @@ func (m *manifest) generateOuter() error {
o := &MFFileOuter{
InnerMessage: idc.Bytes(),
Size: int64(len(innerData)),
Sha256: h.Sum(nil),
Sha256: sha256Hash,
Version: MFFileOuter_VERSION_ONE,
CompressionType: MFFileOuter_COMPRESSION_ZSTD,
}
// Sign the manifest if signing options are provided
if m.signingOptions != nil && m.signingOptions.KeyID != "" {
// Encode hash as multihash for signing
mh, err := multihash.Encode(sha256Hash, multihash.SHA2_256)
if err != nil {
return fmt.Errorf("failed to encode multihash: %w", err)
}
sig, err := gpgSign(mh, m.signingOptions.KeyID)
if err != nil {
return fmt.Errorf("failed to sign manifest: %w", err)
}
o.Signature = sig
fingerprint, err := gpgGetKeyFingerprint(m.signingOptions.KeyID)
if err != nil {
return fmt.Errorf("failed to get key fingerprint: %w", err)
}
o.Signer = fingerprint
pubKey, err := gpgExportPublicKey(m.signingOptions.KeyID)
if err != nil {
return fmt.Errorf("failed to export public key: %w", err)
}
o.SigningPubKey = pubKey
}
m.pbOuter = o
return nil
}