Repository: deislabs/ratify (go)

Issue:
Store plugins cannot be used from verifier plugins
When executing verifier plugins, Ratify will bundle up and pass all of the configuration needed about a store to a verifier plugin over STDIN. An important field in this flow is `pluginBinDirs`, as that is how Ratify knows where to find plugins - either in the default plugin dir, or a user-provided dir. 

Today, the verifier plugin skeleton ignores that STDIN input and uses an explicit `nil` and `""` as the `pluginBinDirs` paths for stores. The effect is that when an out of tree store (ex: anything not `oras`) is resolved, it fails at runtime with an error because the store can't be found under a blank subdir. Ex:

```
    {
      "isSuccess": false,
      "name": "sample",
      "message": "an error thrown by the verifier: plugin command VERIFY failed; failed to find plugin \"oras2\" in paths []",
      "artifactType": "application/spdx+json"
    },
```

Per some code comments nearby, it looks like this used to work, but there has been limited usage of plugin stores outside of the sample in the repo.

Pull request description:
Enable verifier plugins to work with store plugins
# Description

## What this PR does / why we need it:

- Enables verifier plugins to consume `pluginBinDirs` from STDIN and use them to resolve store plugins
- Adds tests to validate that the path is used
- Adds test coverage to ensure that builtin stores are correctly resolved

Fixes #492

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Please also list any relevant details for your test configuration

- [x] Added/updated unit tests
- [x] Manually built a store plugin and validated against a verifier plugin

# Checklist:

- [x] Does the affected code have corresponding tests?


Patch:
diff --git a/pkg/referrerstore/plugin/plugin.go b/pkg/referrerstore/plugin/plugin.go
index 5137061..83fe03c 100644
--- a/pkg/referrerstore/plugin/plugin.go
+++ b/pkg/referrerstore/plugin/plugin.go
@@ -201,3 +201,7 @@ func (sp *StorePlugin) GetConfig() *config.StoreConfig {
 		Store:         sp.rawConfig,
 	}
 }
+
+func (sp *StorePlugin) GetPath() []string {
+	return sp.path
+}
diff --git a/pkg/verifier/plugin/skel/skel.go b/pkg/verifier/plugin/skel/skel.go
index 9e24a39..2010e26 100644
--- a/pkg/verifier/plugin/skel/skel.go
+++ b/pkg/verifier/plugin/skel/skel.go
@@ -87,7 +87,7 @@ func (pc *pcontext) pluginMainCore(name, version string, verifyReference VerifyR
 	// The below is a workaround to be able to use built-in referrer store plugins from within verifier plugins
 	storeConfigs := storeConfig.StoresConfig{
 		Version:       version,
-		PluginBinDirs: nil,
+		PluginBinDirs: input.StoreConfig.PluginBinDirs,
 		Stores:        []storeConfig.StorePluginConfig{input.StoreConfig.Store},
 	}
 	stores, storeErr := factory.CreateStoresFromConfig(storeConfigs, "")


Test patch:
diff --git a/pkg/verifier/plugin/skel/skel_test.go b/pkg/verifier/plugin/skel/skel_test.go
index 7cd343e..ed2a2ed 100644
--- a/pkg/verifier/plugin/skel/skel_test.go
+++ b/pkg/verifier/plugin/skel/skel_test.go
@@ -18,17 +18,21 @@ package skel
 import (
 	"bytes"
 	"fmt"
+	"reflect"
 	"strings"
 	"testing"
 
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	"github.com/deislabs/ratify/pkg/referrerstore"
-
+	sp "github.com/deislabs/ratify/pkg/referrerstore/plugin"
 	"github.com/deislabs/ratify/pkg/verifier/plugin"
 	"github.com/deislabs/ratify/pkg/verifier/types"
 
 	"github.com/deislabs/ratify/pkg/verifier"
+
+	// This import is required to utilize the oras built-in referrer store
+	_ "github.com/deislabs/ratify/pkg/referrerstore/oras"
 )
 
 func TestPluginMain_VerifyReference_ReturnsExpected(t *testing.T) {
@@ -40,6 +44,15 @@ func TestPluginMain_VerifyReference_ReturnsExpected(t *testing.T) {
 		if referrerStore.Name() != "test-store" {
 			t.Fatalf("expected store name %s actual %s", "test-store", referrerStore.Name())
 		}
+
+		// the parsed pluginBinDirs should include the data that was provided by Ratify, plus the default (currently assumed to be "")
+		expectedPluginBinDirs := []string{"/tmp/ratify/plugins", ""}
+		pluginStore := referrerStore.(*sp.StorePlugin)
+		actualPluginBinDirs := pluginStore.GetPath()
+		if !reflect.DeepEqual(expectedPluginBinDirs, actualPluginBinDirs) {
+			t.Fatalf("expected plugin bin dirs %#v actual %#v", expectedPluginBinDirs, actualPluginBinDirs)
+		}
+
 		return &verifier.VerifierResult{IsSuccess: true}, nil
 	}
 
@@ -49,7 +62,44 @@ func TestPluginMain_VerifyReference_ReturnsExpected(t *testing.T) {
 		plugin.SubjectEnvKey: "localhost:5000/net-monitor:v1@sha256:a0fc570a245b09ed752c42d600ee3bb5b4f77bbd70d8898780b7ab43454530eb",
 	}
 
-	stdinData := `{ "storeConfig" : {"store": {"name":"test-store", "some": "config"}}, "config": {"name": "skel-test-case", "some":"config"}, "referenceDesc": {"artifactType": "test-type"}}`
+	stdinData := `{ "storeConfig" : {"store": {"name":"test-store", "some": "config"}, "pluginBinDirs": ["/tmp/ratify/plugins"]}, "config": {"name": "skel-test-case", "some":"config"}, "referenceDesc": {"artifactType": "test-type"}}`
+	stdout := &bytes.Buffer{}
+	stderr := &bytes.Buffer{}
+	pluginContext := &pcontext{
+		GetEnviron: func(key string) string { return environment[key] },
+		Stdin:      strings.NewReader(stdinData),
+		Stdout:     stdout,
+		Stderr:     stderr,
+	}
+
+	err := pluginContext.pluginMainCore("skel-test-case", "1.0.0", verifyReference, []string{"1.0.0"})
+	if err != nil {
+		t.Fatalf("plugin execution failed %v", err)
+	}
+
+	out := fmt.Sprintf("%s", stdout)
+	if !strings.Contains(out, `"isSuccess":true`) {
+		t.Fatalf("plugin execution failed. expected %v actual %v", "isSuccess: true", out)
+	}
+}
+
+func TestPluginMain_VerifyReference_CanUseBuiltinStores(t *testing.T) {
+	verifyReference := func(args *CmdArgs, subjectReference common.Reference, referenceDescriptor ocispecs.ReferenceDescriptor, referrerStore referrerstore.ReferrerStore) (*verifier.VerifierResult, error) {
+		// expect to find a builtin store and fail if it was configured as a plugin
+		if _, ok := referrerStore.(*sp.StorePlugin); ok {
+			t.Fatalf("expected store to be builtin")
+		}
+
+		return &verifier.VerifierResult{IsSuccess: true}, nil
+	}
+
+	environment := map[string]string{
+		plugin.CommandEnvKey: plugin.VerifyCommand,
+		plugin.VersionEnvKey: "1.0.0",
+		plugin.SubjectEnvKey: "localhost:5000/net-monitor:v1@sha256:a0fc570a245b09ed752c42d600ee3bb5b4f77bbd70d8898780b7ab43454530eb",
+	}
+
+	stdinData := `{ "storeConfig" : {"store": {"name":"oras"}}, "config": {"name": "skel-test-case", "some":"config"}, "referenceDesc": {"artifactType": "test-type"}}`
 	stdout := &bytes.Buffer{}
 	stderr := &bytes.Buffer{}
 	pluginContext := &pcontext{