fix: allow signing multiple charts with passphrase from stdin.

Cache the signing key passphrase. When signing multiple charts
with the passphrase from stdin, this allows signing all charts
instead of all but the first failing with an error about stdin
already having been closed.

Signed-off-by: Krisztian Litkey <krisztian.litkey@intel.com>
pull/30718/head
Krisztian Litkey 6 months ago
parent 0199b748aa
commit 3102c28804
No known key found for this signature in database
GPG Key ID: 637F2939D50AF85D

@ -39,6 +39,7 @@ type Package struct {
Key string
Keyring string
PassphraseFile string
cachedPassphrase []byte
Version string
AppVersion string
Destination string
@ -55,6 +56,10 @@ type Package struct {
InsecureSkipTLSverify bool
}
const (
passPhraseFileStdin = "-"
)
// NewPackage creates a new Package object with the given configuration.
func NewPackage() *Package {
return &Package{}
@ -128,7 +133,7 @@ func (p *Package) Clearsign(filename string) error {
passphraseFetcher := promptUser
if p.PassphraseFile != "" {
passphraseFetcher, err = passphraseFileFetcher(p.PassphraseFile, os.Stdin)
passphraseFetcher, err = p.passphraseFileFetcher(p.PassphraseFile, os.Stdin)
if err != nil {
return err
}
@ -156,7 +161,17 @@ func promptUser(name string) ([]byte, error) {
return pw, err
}
func passphraseFileFetcher(passphraseFile string, stdin *os.File) (provenance.PassphraseFetcher, error) {
func (p *Package) passphraseFileFetcher(passphraseFile string, stdin *os.File) (provenance.PassphraseFetcher, error) {
// When reading from stdin we cache the passphrase here. If we are
// packaging multiple charts, we reuse the cached passphrase. This
// allows giving the passphrase once on stdin without failing with
// complaints about stdin already being closed.
//
// An alternative to this would be to omit file.Close() for stdin
// below and require the user to provide the same passphrase once
// per chart on stdin, but that does not seem very user-friendly.
if p.cachedPassphrase == nil {
file, err := openPassphraseFile(passphraseFile, stdin)
if err != nil {
return nil, err
@ -168,13 +183,20 @@ func passphraseFileFetcher(passphraseFile string, stdin *os.File) (provenance.Pa
if err != nil {
return nil, err
}
p.cachedPassphrase = passphrase
return func(_ string) ([]byte, error) {
return passphrase, nil
}, nil
}
return func(_ string) ([]byte, error) {
return p.cachedPassphrase, nil
}, nil
}
func openPassphraseFile(passphraseFile string, stdin *os.File) (*os.File, error) {
if passphraseFile == "-" {
if passphraseFile == passPhraseFileStdin {
stat, err := stdin.Stat()
if err != nil {
return nil, err

@ -29,8 +29,9 @@ import (
func TestPassphraseFileFetcher(t *testing.T) {
secret := "secret"
directory := ensure.TempFile(t, "passphrase-file", []byte(secret))
testPkg := NewPackage()
fetcher, err := passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil)
fetcher, err := testPkg.passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil)
if err != nil {
t.Fatal("Unable to create passphraseFileFetcher", err)
}
@ -48,8 +49,9 @@ func TestPassphraseFileFetcher(t *testing.T) {
func TestPassphraseFileFetcher_WithLineBreak(t *testing.T) {
secret := "secret"
directory := ensure.TempFile(t, "passphrase-file", []byte(secret+"\n\n."))
testPkg := NewPackage()
fetcher, err := passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil)
fetcher, err := testPkg.passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil)
if err != nil {
t.Fatal("Unable to create passphraseFileFetcher", err)
}
@ -66,17 +68,48 @@ func TestPassphraseFileFetcher_WithLineBreak(t *testing.T) {
func TestPassphraseFileFetcher_WithInvalidStdin(t *testing.T) {
directory := t.TempDir()
testPkg := NewPackage()
stdin, err := os.CreateTemp(directory, "non-existing")
if err != nil {
t.Fatal("Unable to create test file", err)
}
if _, err := passphraseFileFetcher("-", stdin); err == nil {
if _, err := testPkg.passphraseFileFetcher("-", stdin); err == nil {
t.Error("Expected passphraseFileFetcher returning an error")
}
}
func TestPassphraseFileFetcher_WithStdinAndMultipleFetches(t *testing.T) {
testPkg := NewPackage()
stdin, w, err := os.Pipe()
if err != nil {
t.Fatal("Unable to create pipe", err)
}
passphrase := "secret-from-stdin"
go func() {
w.Write([]byte(passphrase + "\n"))
}()
for i := 0; i < 4; i++ {
fetcher, err := testPkg.passphraseFileFetcher("-", stdin)
if err != nil {
t.Errorf("Expected passphraseFileFetcher to not return an error, but got %v", err)
}
pass, err := fetcher("key")
if err != nil {
t.Errorf("Expected passphraseFileFetcher invocation to succeed, failed with %v", err)
}
if string(pass) != string(passphrase) {
t.Errorf("Expected multiple passphrase fetch to return %q, got %q", passphrase, pass)
}
}
}
func TestValidateVersion(t *testing.T) {
type args struct {
ver string

Loading…
Cancel
Save