From d470fc68d32151004db1d74b0d1773cbaee67765 Mon Sep 17 00:00:00 2001 From: Ashutosh Narkar Date: Wed, 28 Oct 2020 00:21:10 -0700 Subject: [PATCH] plugins/bundle: Support for loading signed bundles from disk Earlier when loading bundles from disk, we weren't providing the bundle verification config that would be needed to read a signed bundle that may have been persisted to disk in the past. This changes adds support for loading signed bundles from disk by providing the bundle verification config (if any) to the bundle reader. Fixes: #2824 Signed-off-by: Ashutosh Narkar --- plugins/bundle/plugin.go | 15 ++++--- plugins/bundle/plugin_test.go | 77 +++++++++++++++++++++++++++++++---- 2 files changed, 79 insertions(+), 13 deletions(-) diff --git a/plugins/bundle/plugin.go b/plugins/bundle/plugin.go index 654a2cd8ee..ce4e57e951 100644 --- a/plugins/bundle/plugin.go +++ b/plugins/bundle/plugin.go @@ -264,9 +264,9 @@ func (p *Plugin) initDownloaders() { } func (p *Plugin) loadAndActivateBundlesFromDisk(ctx context.Context) error { - for name := range p.config.Bundles { + for name, src := range p.config.Bundles { if p.persistBundle(name) { - b, err := loadBundleFromDisk(p.bundlePersistPath, name) + b, err := loadBundleFromDisk(p.bundlePersistPath, name, src) if err != nil { p.logError(name, "Failed to load bundle from disk: %v", err) return err @@ -558,7 +558,7 @@ func saveCurrentBundleToDisk(path, filename string, b *bundle.Bundle) error { return nil } -func loadBundleFromDisk(path, name string) (*bundle.Bundle, error) { +func loadBundleFromDisk(path, name string, src *Source) (*bundle.Bundle, error) { bundlePath := filepath.Join(path, name, "bundle.tar.gz") if _, err := os.Stat(bundlePath); err == nil { @@ -568,12 +568,17 @@ func loadBundleFromDisk(path, name string) (*bundle.Bundle, error) { } defer f.Close() - b, err := bundle.NewReader(f).Read() + r := bundle.NewReader(f) + + if src != nil { + r = r.WithBundleVerificationConfig(src.Signing) + } + + b, err := r.Read() if err != nil { return nil, err } return &b, nil - } else if os.IsNotExist(err) { return nil, nil } else { diff --git a/plugins/bundle/plugin_test.go b/plugins/bundle/plugin_test.go index 3cf4053f02..fed2165cf4 100644 --- a/plugins/bundle/plugin_test.go +++ b/plugins/bundle/plugin_test.go @@ -161,7 +161,7 @@ func TestPluginOneShotBundlePersistence(t *testing.T) { ensurePluginState(t, plugin, plugins.StateOK) - result, err := loadBundleFromDisk(plugin.bundlePersistPath, bundleName) + result, err := loadBundleFromDisk(plugin.bundlePersistPath, bundleName, nil) if err != nil { t.Fatal("unexpected error:", err) } @@ -1632,7 +1632,7 @@ func TestSaveBundleToDiskOverWrite(t *testing.T) { t.Fatalf("unexpected error %v", err) } - b2 := writeTestBundleToDisk(t, bundleDir) + b2 := writeTestBundleToDisk(t, bundleDir, false) module := "package a.a1\n\nbar=1" @@ -1658,7 +1658,7 @@ func TestSaveBundleToDiskOverWrite(t *testing.T) { t.Fatalf("unexpected error %v", err) } - actual, err := loadBundleFromDisk(plugin.bundlePersistPath, "foo") + actual, err := loadBundleFromDisk(plugin.bundlePersistPath, "foo", nil) if err != nil { t.Fatalf("unexpected error %v", err) } @@ -1691,7 +1691,7 @@ func TestSaveCurrentBundleToDisk(t *testing.T) { func TestLoadBundleFromDisk(t *testing.T) { // no bundle on disk - _, err := loadBundleFromDisk("foo", "bar") + _, err := loadBundleFromDisk("foo", "bar", nil) if err != nil { t.Fatalf("unexpected error %v", err) } @@ -1712,9 +1712,9 @@ func TestLoadBundleFromDisk(t *testing.T) { t.Fatalf("unexpected error %v", err) } - b := writeTestBundleToDisk(t, bundleDir) + b := writeTestBundleToDisk(t, bundleDir, false) - result, err := loadBundleFromDisk(dir, bundleName) + result, err := loadBundleFromDisk(dir, bundleName, nil) if err != nil { t.Fatal("unexpected error:", err) } @@ -1724,6 +1724,50 @@ func TestLoadBundleFromDisk(t *testing.T) { } } +func TestLoadSignedBundleFromDisk(t *testing.T) { + + // no bundle on disk + _, err := loadBundleFromDisk("foo", "bar", nil) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + // create a test signed bundle and load it from disk + dir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + defer os.RemoveAll(dir) + + bundleName := "foo" + bundleDir := filepath.Join(dir, bundleName) + + err = os.MkdirAll(bundleDir, os.ModePerm) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + b := writeTestBundleToDisk(t, bundleDir, true) + + src := Source{ + Signing: bundle.NewVerificationConfig(map[string]*bundle.KeyConfig{"foo": {Key: "secret", Algorithm: "HS256"}}, "foo", "", nil), + } + + result, err := loadBundleFromDisk(dir, bundleName, &src) + if err != nil { + t.Fatal("unexpected error:", err) + } + + if !result.Equal(b) { + t.Fatal("expected the test bundle to be equal to the one loaded from disk") + } + + if !reflect.DeepEqual(result.Signatures, b.Signatures) { + t.Fatal("Expected signatures to be same") + } +} + func TestGetDefaultBundlePersistPath(t *testing.T) { path, err := getDefaultBundlePersistPath() if err != nil { @@ -1735,10 +1779,16 @@ func TestGetDefaultBundlePersistPath(t *testing.T) { } } -func writeTestBundleToDisk(t *testing.T, srcDir string) bundle.Bundle { +func writeTestBundleToDisk(t *testing.T, srcDir string, signed bool) bundle.Bundle { t.Helper() - b := getTestBundle(t) + var b bundle.Bundle + + if signed { + b = getTestSignedBundle(t) + } else { + b = getTestBundle(t) + } var buf bytes.Buffer if err := bundle.NewWriter(&buf).UseModulePath(true).Write(b); err != nil { @@ -1776,6 +1826,17 @@ func getTestBundle(t *testing.T) bundle.Bundle { return b } +func getTestSignedBundle(t *testing.T) bundle.Bundle { + t.Helper() + + b := getTestBundle(t) + + if err := b.GenerateSignature(bundle.NewSigningConfig("secret", "HS256", ""), "foo", false); err != nil { + t.Fatal("Unexpected error:", err) + } + return b +} + func validateStoreState(ctx context.Context, t *testing.T, store storage.Store, root string, expData interface{}, expIds []string, expBundleName string, expBundleRev string) { t.Helper() if err := storage.Txn(ctx, store, storage.TransactionParams{}, func(txn storage.Transaction) error {