fix(provenance): treat only not-exist as keyring absence in defaultKeyring

A stat error other than 'not exist' (e.g. a permission problem) meant
the file may well be present, but defaultKeyring() skipped past it: an
unreadable pubring.gpg silently lost precedence to pubring.kbx, and the
surfaced error could point at the wrong file. Treat only fs.ErrNotExist
as absence. For any other stat error, return that path unchanged so the
real error surfaces when the keyring is opened.

Signed-off-by: Ruslan Shaydullin <shaydullin.r.d@outlook.com>
pull/32281/head
Ruslan Shaydullin 3 weeks ago
parent bfc606f7ca
commit 72dc18fe19

@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
@ -98,21 +99,23 @@ func newDependencyBuildCmd(out io.Writer) *cobra.Command {
// defaultKeyring returns the expanded path to the default keyring.
//
// The legacy pubring.gpg file is preferred when present. If it is absent and
// the file-backed pubring.kbx exists, that is used instead. When neither
// exists, the legacy path is returned so that error messages keep pointing
// at the traditional default.
// The legacy pubring.gpg file is preferred and treated as absent only when
// stat fails with "not exist" — any other stat error (e.g. permissions)
// keeps the legacy path so the real error surfaces when the file is opened.
// If the legacy file is absent, the file-backed pubring.kbx path takes over
// under the same rule. When neither exists, the legacy path is returned so
// error messages keep pointing at the traditional default.
func defaultKeyring() string {
gnupgHome := filepath.Join(homedir.HomeDir(), ".gnupg")
if v, ok := os.LookupEnv("GNUPGHOME"); ok {
gnupgHome = v
}
legacy := filepath.Join(gnupgHome, "pubring.gpg")
if _, err := os.Stat(legacy); err == nil {
if _, err := os.Stat(legacy); !errors.Is(err, fs.ErrNotExist) {
return legacy
}
keybox := filepath.Join(gnupgHome, "pubring.kbx")
if _, err := os.Stat(keybox); err == nil {
if _, err := os.Stat(keybox); !errors.Is(err, fs.ErrNotExist) {
return keybox
}
return legacy

@ -19,6 +19,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/stretchr/testify/assert"
@ -147,9 +148,7 @@ func TestDependencyBuildCmdWithHelmV2Hash(t *testing.T) {
func TestDefaultKeyring(t *testing.T) {
touch := func(t *testing.T, path string) {
t.Helper()
if err := os.WriteFile(path, []byte("test"), 0o644); err != nil {
t.Fatal(err)
}
require.NoError(t, os.WriteFile(path, []byte("test"), 0o644))
}
tests := []struct {
@ -169,30 +168,44 @@ func TestDefaultKeyring(t *testing.T) {
for _, f := range tt.files {
touch(t, filepath.Join(dir, f))
}
if got, want := defaultKeyring(), filepath.Join(dir, tt.want); got != want {
t.Errorf("expected %q, got %q", want, got)
}
assert.Equal(t, filepath.Join(dir, tt.want), defaultKeyring())
})
}
t.Run("stat error other than not-exist keeps the legacy path", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("directory permissions are not enforced on Windows")
}
if os.Geteuid() == 0 {
t.Skip("root bypasses directory permissions")
}
parent := t.TempDir()
dir := filepath.Join(parent, ".gnupg")
require.NoError(t, os.MkdirAll(dir, 0o700))
touch(t, filepath.Join(dir, "pubring.kbx"))
t.Setenv("GNUPGHOME", dir)
// Make the directory unsearchable so stat on both keyrings fails
// with a permission error rather than "not exist".
require.NoError(t, os.Chmod(dir, 0o000))
t.Cleanup(func() { require.NoError(t, os.Chmod(dir, 0o700)) })
assert.Equal(t, filepath.Join(dir, "pubring.gpg"), defaultKeyring())
})
t.Run("no GNUPGHOME falls back to the home directory", func(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("GNUPGHOME", home) // register restoration before unsetting
os.Unsetenv("GNUPGHOME")
require.NoError(t, os.Unsetenv("GNUPGHOME"))
gnupgDir := filepath.Join(home, ".gnupg")
if err := os.MkdirAll(gnupgDir, 0o700); err != nil {
t.Fatal(err)
}
require.NoError(t, os.MkdirAll(gnupgDir, 0o700))
if got, want := defaultKeyring(), filepath.Join(gnupgDir, "pubring.gpg"); got != want {
t.Errorf("expected %q, got %q", want, got)
}
assert.Equal(t, filepath.Join(gnupgDir, "pubring.gpg"), defaultKeyring())
touch(t, filepath.Join(gnupgDir, "pubring.kbx"))
if got, want := defaultKeyring(), filepath.Join(gnupgDir, "pubring.kbx"); got != want {
t.Errorf("expected %q, got %q", want, got)
}
assert.Equal(t, filepath.Join(gnupgDir, "pubring.kbx"), defaultKeyring())
})
}

Loading…
Cancel
Save