mirror of https://github.com/helm/helm
commit
4758d8dba9
@ -1,2 +1,2 @@
|
|||||||
GOLANG_VERSION=1.26
|
GOLANG_VERSION=1.27
|
||||||
GOLANGCI_LINT_VERSION=v2.12.2
|
GOLANGCI_LINT_VERSION=v2.13.1
|
||||||
|
|||||||
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Helm Authors.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package provenance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GnuPG 2.1+ can store file-backed public keys in a "keybox" (pubring.kbx),
|
||||||
|
// a container that interleaves OpenPGP keyblocks with GnuPG-specific
|
||||||
|
// metadata. It is not an OpenPGP packet stream, so it cannot be handed to
|
||||||
|
// openpgp.ReadKeyRing directly. A keybox is a sequence of blobs, each starting
|
||||||
|
// with:
|
||||||
|
//
|
||||||
|
// byte 0..3 u32 blob length, big endian, including this header
|
||||||
|
// byte 4 u8 blob type (0 empty, 1 header, 2 OpenPGP, 3 X.509)
|
||||||
|
// byte 5 u8 blob version
|
||||||
|
//
|
||||||
|
// The first blob is a header carrying the "KBXf" magic at offset 8. OpenPGP
|
||||||
|
// blobs (type 2) record where the raw keyblock lives inside the blob:
|
||||||
|
//
|
||||||
|
// byte 8..11 u32 keyblock offset, relative to the blob start
|
||||||
|
// byte 12..15 u32 keyblock length
|
||||||
|
//
|
||||||
|
// Reference: kbx/keybox-blob.c in the GnuPG source tree.
|
||||||
|
const (
|
||||||
|
kbxBlobTypeHeader = 1
|
||||||
|
kbxBlobTypeOpenPGP = 2
|
||||||
|
|
||||||
|
// kbxBlobFlagEphemeral marks a blob GnuPG considers not (yet) part of
|
||||||
|
// the keyring, e.g. written during an interrupted keyserver operation
|
||||||
|
// (KEYBOX_FLAG_BLOB_EPHEMERAL in kbx/keybox.h). GnuPG skips such blobs
|
||||||
|
// on every normal read (kbx/keybox-search.c), and so do we.
|
||||||
|
kbxBlobFlagEphemeral = 0x0002
|
||||||
|
|
||||||
|
// kbxMinBlobLen covers the length and type fields present in every blob.
|
||||||
|
kbxMinBlobLen = 5
|
||||||
|
|
||||||
|
// kbxOpenPGPHeaderLen is how much of an OpenPGP blob header must be
|
||||||
|
// present for the flags, keyblock offset and keyblock length fields to
|
||||||
|
// be readable.
|
||||||
|
kbxOpenPGPHeaderLen = 16
|
||||||
|
)
|
||||||
|
|
||||||
|
// isKeybox reports whether data looks like a GnuPG keybox (pubring.kbx)
|
||||||
|
// image, identified by the "KBXf" magic in the mandatory first header blob.
|
||||||
|
func isKeybox(data []byte) bool {
|
||||||
|
return len(data) >= 12 && data[4] == kbxBlobTypeHeader && string(data[8:12]) == "KBXf"
|
||||||
|
}
|
||||||
|
|
||||||
|
// isArmored reports whether data looks like an ASCII-armored keyring, as
|
||||||
|
// produced by `gpg --export --armor`.
|
||||||
|
func isArmored(data []byte) bool {
|
||||||
|
return bytes.HasPrefix(bytes.TrimSpace(data), []byte("-----BEGIN PGP"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyboxPublicKeys extracts the OpenPGP keyblocks embedded in a keybox image
|
||||||
|
// and returns them concatenated, ready for openpgp.ReadKeyRing. Blobs of any
|
||||||
|
// other type (header, X.509, empty) are skipped, as are blobs flagged
|
||||||
|
// ephemeral, which GnuPG itself ignores when reading the keyring. Malformed
|
||||||
|
// input yields an error, never a panic.
|
||||||
|
func keyboxPublicKeys(data []byte) ([]byte, error) {
|
||||||
|
var keyblocks bytes.Buffer
|
||||||
|
for offset := 0; offset < len(data); {
|
||||||
|
rest := data[offset:]
|
||||||
|
if len(rest) < kbxMinBlobLen {
|
||||||
|
return nil, fmt.Errorf("truncated blob header at offset %d", offset)
|
||||||
|
}
|
||||||
|
blobLen := binary.BigEndian.Uint32(rest)
|
||||||
|
if blobLen < kbxMinBlobLen {
|
||||||
|
return nil, fmt.Errorf("invalid blob length %d at offset %d", blobLen, offset)
|
||||||
|
}
|
||||||
|
if uint64(blobLen) > uint64(len(rest)) {
|
||||||
|
return nil, fmt.Errorf("blob at offset %d has length %d exceeding the %d remaining bytes", offset, blobLen, len(rest))
|
||||||
|
}
|
||||||
|
blob := rest[:blobLen]
|
||||||
|
if blob[4] == kbxBlobTypeOpenPGP {
|
||||||
|
if len(blob) < kbxOpenPGPHeaderLen {
|
||||||
|
return nil, fmt.Errorf("OpenPGP blob at offset %d is too short", offset)
|
||||||
|
}
|
||||||
|
flags := binary.BigEndian.Uint16(blob[6:])
|
||||||
|
keyblockOffset := binary.BigEndian.Uint32(blob[8:])
|
||||||
|
keyblockLen := binary.BigEndian.Uint32(blob[12:])
|
||||||
|
if uint64(keyblockOffset)+uint64(keyblockLen) > uint64(len(blob)) {
|
||||||
|
return nil, fmt.Errorf("OpenPGP blob at offset %d has an out-of-range keyblock", offset)
|
||||||
|
}
|
||||||
|
if flags&kbxBlobFlagEphemeral == 0 {
|
||||||
|
keyblocks.Write(blob[keyblockOffset : keyblockOffset+keyblockLen])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += int(blobLen)
|
||||||
|
}
|
||||||
|
if keyblocks.Len() == 0 {
|
||||||
|
return nil, errors.New("keybox contains no OpenPGP keys")
|
||||||
|
}
|
||||||
|
return keyblocks.Bytes(), nil
|
||||||
|
}
|
||||||
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Helm Authors.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package provenance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// testKeybox is a GnuPG keybox (pubring.kbx) containing the helm-test
|
||||||
|
// public key. Regenerate with testdata/regen-keyring-formats.sh.
|
||||||
|
testKeybox = "testdata/helm-test-key.kbx"
|
||||||
|
|
||||||
|
// testMixedKeybox is a keybox containing the RSA and Ed25519 test keys.
|
||||||
|
testMixedKeybox = "testdata/helm-mixed-keyring.kbx"
|
||||||
|
|
||||||
|
// testArmoredPubfile is the ASCII-armored export of the helm-test key.
|
||||||
|
testArmoredPubfile = "testdata/helm-test-key.asc"
|
||||||
|
|
||||||
|
// testMultiBlockArmored is two concatenated single-key armored exports
|
||||||
|
// (cat key1.asc key2.asc), covering the RSA and Ed25519 test keys.
|
||||||
|
testMultiBlockArmored = "testdata/helm-mixed-keyring.asc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsKeybox(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
file string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{"keybox", testKeybox, true},
|
||||||
|
{"mixed keybox", testMixedKeybox, true},
|
||||||
|
{"legacy binary keyring", testPubfile, false},
|
||||||
|
{"armored keyring", testArmoredPubfile, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
data, err := os.ReadFile(tt.file)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, isKeybox(data))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("degenerate inputs", func(t *testing.T) {
|
||||||
|
assert.False(t, isKeybox(nil))
|
||||||
|
assert.False(t, isKeybox([]byte{}))
|
||||||
|
assert.False(t, isKeybox([]byte("KBXf")))
|
||||||
|
assert.False(t, isKeybox([]byte("garbage that is longer than twelve bytes")))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsArmored(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
file string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{"armored keyring", testArmoredPubfile, true},
|
||||||
|
{"legacy binary keyring", testPubfile, false},
|
||||||
|
{"keybox", testKeybox, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
data, err := os.ReadFile(tt.file)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, isArmored(data))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("degenerate inputs", func(t *testing.T) {
|
||||||
|
assert.False(t, isArmored(nil))
|
||||||
|
assert.False(t, isArmored([]byte("not a key")))
|
||||||
|
assert.True(t, isArmored([]byte("\n\t -----BEGIN PGP PUBLIC KEY BLOCK-----")))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyboxPublicKeys(t *testing.T) {
|
||||||
|
data, err := os.ReadFile(testKeybox)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
keys, err := keyboxPublicKeys(data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ring, err := openpgp.ReadKeyRing(bytes.NewReader(keys))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Len(t, ring, 1)
|
||||||
|
_, ok := ring[0].Identities[testKeyName]
|
||||||
|
assert.True(t, ok, "expected keybox to contain %q", testKeyName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyboxPublicKeysEphemeral(t *testing.T) {
|
||||||
|
// GnuPG flags in-progress key material as ephemeral (bit 0x0002 of the
|
||||||
|
// blob flags at blob offset 6) and hides it from every normal read; the
|
||||||
|
// parser must do the same.
|
||||||
|
setFlags := func(t *testing.T, data []byte, blobStart int, flags uint16) []byte {
|
||||||
|
t.Helper()
|
||||||
|
require.Equal(t, byte(kbxBlobTypeOpenPGP), data[blobStart+4])
|
||||||
|
mutated := bytes.Clone(data)
|
||||||
|
binary.BigEndian.PutUint16(mutated[blobStart+6:], flags)
|
||||||
|
return mutated
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("all blobs ephemeral means no keys", func(t *testing.T) {
|
||||||
|
valid, err := os.ReadFile(testKeybox)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = keyboxPublicKeys(setFlags(t, valid, 32, kbxBlobFlagEphemeral))
|
||||||
|
assert.ErrorContains(t, err, "no OpenPGP keys")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ephemeral blob is skipped, others kept", func(t *testing.T) {
|
||||||
|
valid, err := os.ReadFile(testMixedKeybox)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Flag only the first OpenPGP blob (the RSA helm-test key).
|
||||||
|
keys, err := keyboxPublicKeys(setFlags(t, valid, 32, kbxBlobFlagEphemeral))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ring, err := openpgp.ReadKeyRing(bytes.NewReader(keys))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Len(t, ring, 1)
|
||||||
|
_, ok := ring[0].Identities[testKeyName]
|
||||||
|
assert.False(t, ok, "expected the ephemeral-flagged %q blob to be skipped", testKeyName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyboxPublicKeysMalformed(t *testing.T) {
|
||||||
|
valid, err := os.ReadFile(testKeybox)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// The mutations below rely on the fixture layout: a 32-byte header blob
|
||||||
|
// followed by an OpenPGP blob.
|
||||||
|
const blobStart = 32
|
||||||
|
require.Greater(t, len(valid), blobStart+16)
|
||||||
|
require.Equal(t, byte(kbxBlobTypeOpenPGP), valid[blobStart+4])
|
||||||
|
|
||||||
|
mutate := func(offset int, value uint32) []byte {
|
||||||
|
data := bytes.Clone(valid)
|
||||||
|
binary.BigEndian.PutUint32(data[offset:], value)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
data []byte
|
||||||
|
}{
|
||||||
|
{"header only, no keys", valid[:blobStart]},
|
||||||
|
{"truncated inside blob header", valid[:blobStart+2]},
|
||||||
|
{"truncated inside blob body", valid[:blobStart+16]},
|
||||||
|
{"zero blob length", mutate(blobStart, 0)},
|
||||||
|
{"blob length below minimum", mutate(blobStart, 4)},
|
||||||
|
{"blob length past end of data", mutate(blobStart, uint32(len(valid))+1)},
|
||||||
|
{"keyblock offset out of range", mutate(blobStart+8, uint32(len(valid)))},
|
||||||
|
{"keyblock length out of range", mutate(blobStart+12, uint32(len(valid)))},
|
||||||
|
{"keyblock offset overflow", mutate(blobStart+8, ^uint32(0))},
|
||||||
|
{"keyblock length overflow", mutate(blobStart+12, ^uint32(0))},
|
||||||
|
{"openpgp blob shorter than its header", append(bytes.Clone(valid[:blobStart]), 0, 0, 0, 8, kbxBlobTypeOpenPGP, 1, 0, 0)},
|
||||||
|
{"empty input", nil},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
_, err := keyboxPublicKeys(tt.data)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mQENBFeWbZ4BCADIsgNRyVBSWJkbH6h3UWWXsA9ce1u+YKvaCYFSjIujKycTAqCC
|
||||||
|
P7qUV2Oj/4E2zUcOD1/8/meDwuTnNTLzdSw4ujtFlKRSw7zelQE6sxvID0KM0pQK
|
||||||
|
7AxDTXsm/7Afd/fg4WNW0/hcbeiNz4TVmSWAnbqeLg8o8eljR5QhTk47H6Glo4hV
|
||||||
|
raeLCKG77qm2qOQ/m38ec+L5n9iUpoZZu1S5RXPUIanV5pLlx2rQsooIQEdJbTRF
|
||||||
|
Iv3+2Nj/56PFVdrw7E5ARqCD4PpzzYV7uj8vKumOp+VivFj95Ze6DFENh1WWy336
|
||||||
|
jQEj0uTolgOYeQ6AdJobwSPUeYXGV6Sf2vwXABEBAAG0XUhlbG0gVGVzdGluZyAo
|
||||||
|
VGhpcyBrZXkgc2hvdWxkIG9ubHkgYmUgdXNlZCBmb3IgdGVzdGluZy4gRE8gTk9U
|
||||||
|
IFRSVVNULikgPGhlbG0tdGVzdGluZ0BoZWxtLnNoPokBNwQTAQoAIQUCV5ZtngIb
|
||||||
|
AwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRCEO7+YH8GHYolFCAC0+ejT5dIX
|
||||||
|
0juRl5AdG6XAlEf9IrehkVlo0s5bG1Ucea9jjNRafmmHyMravrxZVI9zGFhaNpxA
|
||||||
|
+McnnWAO8lx5yTgnGW269qvFBsj5n0ItPewILQZjTEgwLYf1oc2qCFpk+8ovBnxZ
|
||||||
|
Kaz3J5QKqU09zLO2yALuI5FTCCUupJ3OGIrKvLJ4H2jsRk/5jgqIgqJotW/4Baza
|
||||||
|
4zemFdQHj9FPvq9sVeW5lyxM48i638GtslIgc0y2Yd/bfiy0tfIkskWz/kS1U6c9
|
||||||
|
Utr3UPwpBqHjXnakmpK7GMGlp5eDXgr63BEdLKxJJWWxIys35fR19XZXcAELrwMh
|
||||||
|
zkTzB/dvI375uQENBFeWbZ4BCADB6a8oiF2royWbvwmujBxSmD68QWziNZbSCuRs
|
||||||
|
M4WM1iy69kspJHRwJEVIE5pkoVfV6tIcwQQ0VkJmq6Pf/pyKeMAXp0u8bp5K0mVE
|
||||||
|
Yio1/adiLM3kX1yleoXLNUb1gNvsk6Kp6BZCUNRmjKlbKxapJKHmL+opX8UoeLeE
|
||||||
|
KSgJNL8jvo3nRgg+wIPnVDoizz7y03F0k4SbgNGdoA/FtZs/vcSrEfzOLgI2RxQS
|
||||||
|
dj/ePkxg9TvQygUSYgAVbYlASw6XMmd/zTjkfD9qa0l3WSejTisn85b611WryDpA
|
||||||
|
iYkYC3GzK8g7S9VwkAbtr79cbG+1djlA4aHASpil+zR12yEhABEBAAGJAR8EGAEK
|
||||||
|
AAkFAleWbZ4CGwwACgkQhDu/mB/Bh2LbNQgAiOOMNzmKzY4A7/ra8ppaH9oL8XIa
|
||||||
|
WvInivOsx22K09PPuPVqi/ooBiRGyRqhdVS4ShPOoOTR5tOsdfPpEMTHnGQ1+jW+
|
||||||
|
Tw5MXv3oMckWw3YEYptnuvon3wT4bOXLr+eYlY4Z1ONs+pAXwMiQ2zXNuKHpA2fR
|
||||||
|
HsF8Wyw57rCVn7K5nQgZCbVxasYlzvFGnmt/itSC5w/AnIvICDOWcoGFKTieqhME
|
||||||
|
IkCyvu+DNrMAumnD2fqF2olsM4IzCEPSMEQqJIGzZTtQTseS8NSDioRGnG1AJQ94
|
||||||
|
BssQVmTh0/hlpoTqXY803lR5wb1fr3RRnkOu+lbEI6AAUj51j5TAAo/1dA==
|
||||||
|
=bvcV
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mDMEaMzP2xYJKwYBBAHaRw8BAQdAXkL0KKTOZoMaM+6HsrkWv93zmLmnMiIoQvR2
|
||||||
|
F+bjx7G0KEhlbG0gRWQyNTUxOSBUZXN0IDxoZWxtLWVkMjU1MTlAaGVsbS5zaD6I
|
||||||
|
mQQTFgoAQRYhBEy+dUwlWAxsh43nEfuFaBLOL8tkBQJozM/bAhsDBQkFo5qABQsJ
|
||||||
|
CAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEPuFaBLOL8tktBYA/2cclE0N+BZV
|
||||||
|
Wymk6XfwFMjErM6olWAfwA8DfAGQ55+lAQCqSa+Tkjd4dmToVHcb0QAm+zwklAY4
|
||||||
|
e6qWgGiivn77AA==
|
||||||
|
=wJ7K
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
Binary file not shown.
@ -0,0 +1,30 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mQENBFeWbZ4BCADIsgNRyVBSWJkbH6h3UWWXsA9ce1u+YKvaCYFSjIujKycTAqCC
|
||||||
|
P7qUV2Oj/4E2zUcOD1/8/meDwuTnNTLzdSw4ujtFlKRSw7zelQE6sxvID0KM0pQK
|
||||||
|
7AxDTXsm/7Afd/fg4WNW0/hcbeiNz4TVmSWAnbqeLg8o8eljR5QhTk47H6Glo4hV
|
||||||
|
raeLCKG77qm2qOQ/m38ec+L5n9iUpoZZu1S5RXPUIanV5pLlx2rQsooIQEdJbTRF
|
||||||
|
Iv3+2Nj/56PFVdrw7E5ARqCD4PpzzYV7uj8vKumOp+VivFj95Ze6DFENh1WWy336
|
||||||
|
jQEj0uTolgOYeQ6AdJobwSPUeYXGV6Sf2vwXABEBAAG0XUhlbG0gVGVzdGluZyAo
|
||||||
|
VGhpcyBrZXkgc2hvdWxkIG9ubHkgYmUgdXNlZCBmb3IgdGVzdGluZy4gRE8gTk9U
|
||||||
|
IFRSVVNULikgPGhlbG0tdGVzdGluZ0BoZWxtLnNoPokBNwQTAQoAIQUCV5ZtngIb
|
||||||
|
AwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRCEO7+YH8GHYolFCAC0+ejT5dIX
|
||||||
|
0juRl5AdG6XAlEf9IrehkVlo0s5bG1Ucea9jjNRafmmHyMravrxZVI9zGFhaNpxA
|
||||||
|
+McnnWAO8lx5yTgnGW269qvFBsj5n0ItPewILQZjTEgwLYf1oc2qCFpk+8ovBnxZ
|
||||||
|
Kaz3J5QKqU09zLO2yALuI5FTCCUupJ3OGIrKvLJ4H2jsRk/5jgqIgqJotW/4Baza
|
||||||
|
4zemFdQHj9FPvq9sVeW5lyxM48i638GtslIgc0y2Yd/bfiy0tfIkskWz/kS1U6c9
|
||||||
|
Utr3UPwpBqHjXnakmpK7GMGlp5eDXgr63BEdLKxJJWWxIys35fR19XZXcAELrwMh
|
||||||
|
zkTzB/dvI375uQENBFeWbZ4BCADB6a8oiF2royWbvwmujBxSmD68QWziNZbSCuRs
|
||||||
|
M4WM1iy69kspJHRwJEVIE5pkoVfV6tIcwQQ0VkJmq6Pf/pyKeMAXp0u8bp5K0mVE
|
||||||
|
Yio1/adiLM3kX1yleoXLNUb1gNvsk6Kp6BZCUNRmjKlbKxapJKHmL+opX8UoeLeE
|
||||||
|
KSgJNL8jvo3nRgg+wIPnVDoizz7y03F0k4SbgNGdoA/FtZs/vcSrEfzOLgI2RxQS
|
||||||
|
dj/ePkxg9TvQygUSYgAVbYlASw6XMmd/zTjkfD9qa0l3WSejTisn85b611WryDpA
|
||||||
|
iYkYC3GzK8g7S9VwkAbtr79cbG+1djlA4aHASpil+zR12yEhABEBAAGJAR8EGAEK
|
||||||
|
AAkFAleWbZ4CGwwACgkQhDu/mB/Bh2LbNQgAiOOMNzmKzY4A7/ra8ppaH9oL8XIa
|
||||||
|
WvInivOsx22K09PPuPVqi/ooBiRGyRqhdVS4ShPOoOTR5tOsdfPpEMTHnGQ1+jW+
|
||||||
|
Tw5MXv3oMckWw3YEYptnuvon3wT4bOXLr+eYlY4Z1ONs+pAXwMiQ2zXNuKHpA2fR
|
||||||
|
HsF8Wyw57rCVn7K5nQgZCbVxasYlzvFGnmt/itSC5w/AnIvICDOWcoGFKTieqhME
|
||||||
|
IkCyvu+DNrMAumnD2fqF2olsM4IzCEPSMEQqJIGzZTtQTseS8NSDioRGnG1AJQ94
|
||||||
|
BssQVmTh0/hlpoTqXY803lR5wb1fr3RRnkOu+lbEI6AAUj51j5TAAo/1dA==
|
||||||
|
=bvcV
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
Binary file not shown.
@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Regenerate the file-backed keyring fixtures from the committed binary
|
||||||
|
# keyrings. Requires GnuPG 2.1+ (keybox support).
|
||||||
|
#
|
||||||
|
# helm-test-key.kbx keybox (pubring.kbx) containing the helm-test key
|
||||||
|
# helm-mixed-keyring.kbx keybox containing the RSA and Ed25519 test keys
|
||||||
|
# helm-test-key.asc ASCII-armored export of the helm-test key
|
||||||
|
# helm-mixed-keyring.asc two concatenated single-key armored exports
|
||||||
|
set -e
|
||||||
|
|
||||||
|
GNUPGHOME=$(mktemp -d)
|
||||||
|
export GNUPGHOME
|
||||||
|
chmod 700 "$GNUPGHOME"
|
||||||
|
gpg --batch --no-tty --quiet --import helm-test-key.pub
|
||||||
|
cp "$GNUPGHOME/pubring.kbx" helm-test-key.kbx
|
||||||
|
gpg --batch --no-tty --export --armor helm-testing@helm.sh > helm-test-key.asc
|
||||||
|
rm -rf "$GNUPGHOME"
|
||||||
|
|
||||||
|
GNUPGHOME=$(mktemp -d)
|
||||||
|
export GNUPGHOME
|
||||||
|
chmod 700 "$GNUPGHOME"
|
||||||
|
gpg --batch --no-tty --quiet --import helm-mixed-keyring.pub
|
||||||
|
cp "$GNUPGHOME/pubring.kbx" helm-mixed-keyring.kbx
|
||||||
|
gpg --batch --no-tty --export --armor helm-testing@helm.sh > helm-mixed-keyring.asc
|
||||||
|
gpg --batch --no-tty --export --armor helm-ed25519@helm.sh >> helm-mixed-keyring.asc
|
||||||
|
rm -rf "$GNUPGHOME"
|
||||||
Loading…
Reference in new issue