From 0d54097d545058640e60d0d1df53d394b4317176 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Fri, 29 Aug 2025 22:53:41 -0500 Subject: [PATCH] Change behavior for installing plugin with missing .prov file (now warns and continues instead of failing) Signed-off-by: Scott Rigby --- internal/plugin/installer/http_installer.go | 21 +++++------ internal/plugin/installer/installer.go | 38 +++++++++++++------- internal/plugin/installer/local_installer.go | 13 ++++--- internal/plugin/installer/oci_installer.go | 23 ++++++------ 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/internal/plugin/installer/http_installer.go b/internal/plugin/installer/http_installer.go index f9fbee922..a4687d8c9 100644 --- a/internal/plugin/installer/http_installer.go +++ b/internal/plugin/installer/http_installer.go @@ -184,20 +184,15 @@ func (i *HTTPInstaller) PrepareForVerification() (string, func(), error) { return "", nil, fmt.Errorf("failed to write plugin file: %w", err) } - // Download signature file - provData, err := g.Get(i.Source+".prov", getter.WithURL(i.Source+".prov")) - if err != nil { - cleanup() - return "", nil, fmt.Errorf("failed to download plugin signature: %w", err) - } - - if err := os.WriteFile(pluginFile+".prov", provData.Bytes(), 0644); err != nil { - cleanup() - return "", nil, fmt.Errorf("failed to write signature file: %w", err) + // Try to download signature file - don't fail if it doesn't exist + if provData, err := g.Get(i.Source+".prov", getter.WithURL(i.Source+".prov")); err == nil { + if err := os.WriteFile(pluginFile+".prov", provData.Bytes(), 0644); err == nil { + // Store the provenance data so we can save it after installation + i.provData = provData.Bytes() + } } - - // Store the provenance data so we can save it after installation - i.provData = provData.Bytes() + // Note: We don't fail if .prov file can't be downloaded - the verification logic + // in InstallWithOptions will handle missing .prov files appropriately return pluginFile, cleanup, nil } diff --git a/internal/plugin/installer/installer.go b/internal/plugin/installer/installer.go index ad2a0e02d..dd169397e 100644 --- a/internal/plugin/installer/installer.go +++ b/internal/plugin/installer/installer.go @@ -100,20 +100,32 @@ func InstallWithOptions(i Installer, opts Options) (*VerificationResult, error) defer cleanup() } - // Verify the plugin - verification, err := plugin.VerifyPlugin(pluginPath, opts.Keyring) - if err != nil { - return nil, fmt.Errorf("plugin verification failed: %w", err) - } + // Check if provenance file exists + provFile := pluginPath + ".prov" + if _, err := os.Stat(provFile); err != nil { + if os.IsNotExist(err) { + // No .prov file found - emit warning but continue installation + fmt.Fprintf(os.Stderr, "WARNING: No provenance file found for plugin. Plugin is not signed and cannot be verified.\n") + } else { + // Other error accessing .prov file + return nil, fmt.Errorf("failed to access provenance file: %w", err) + } + } else { + // Provenance file exists - verify the plugin + verification, err := plugin.VerifyPlugin(pluginPath, opts.Keyring) + if err != nil { + return nil, fmt.Errorf("plugin verification failed: %w", err) + } - // Collect verification info - result = &VerificationResult{ - SignedBy: make([]string, 0), - Fingerprint: fmt.Sprintf("%X", verification.SignedBy.PrimaryKey.Fingerprint), - FileHash: verification.FileHash, - } - for name := range verification.SignedBy.Identities { - result.SignedBy = append(result.SignedBy, name) + // Collect verification info + result = &VerificationResult{ + SignedBy: make([]string, 0), + Fingerprint: fmt.Sprintf("%X", verification.SignedBy.PrimaryKey.Fingerprint), + FileHash: verification.FileHash, + } + for name := range verification.SignedBy.Identities { + result.SignedBy = append(result.SignedBy, name) + } } } diff --git a/internal/plugin/installer/local_installer.go b/internal/plugin/installer/local_installer.go index 5df6edb36..0e00c93d0 100644 --- a/internal/plugin/installer/local_installer.go +++ b/internal/plugin/installer/local_installer.go @@ -190,15 +190,14 @@ func (i *LocalInstaller) PrepareForVerification() (string, func(), error) { return "", nil, fmt.Errorf("verification not supported for directories") } - // For local files, we just need to check that the .prov file exists + // For local files, try to read the .prov file if it exists provFile := i.Source + ".prov" - provData, err := os.ReadFile(provFile) - if err != nil { - return "", nil, fmt.Errorf("signature file %s not found: %w", provFile, err) + if provData, err := os.ReadFile(provFile); err == nil { + // Store the provenance data so we can save it after installation + i.provData = provData } - - // Store the provenance data so we can save it after installation - i.provData = provData + // Note: We don't fail if .prov file doesn't exist - the verification logic + // in InstallWithOptions will handle missing .prov files appropriately // Return the source path directly, no cleanup needed return i.Source, nil, nil diff --git a/internal/plugin/installer/oci_installer.go b/internal/plugin/installer/oci_installer.go index e026f388d..c33ef13d5 100644 --- a/internal/plugin/installer/oci_installer.go +++ b/internal/plugin/installer/oci_installer.go @@ -288,21 +288,18 @@ func (i *OCIInstaller) PrepareForVerification() (pluginPath string, cleanup func return "", nil, fmt.Errorf("failed to save plugin tarball: %w", err) } - // Download the provenance file + // Try to download the provenance file - don't fail if it doesn't exist provSource := i.Source + ".prov" - provData, err := i.getter.Get(provSource) - if err != nil { - cleanup() - return "", nil, fmt.Errorf("failed to pull provenance from %s: %w", provSource, err) - } - - // Save provenance to temp directory - provFile := filepath.Join(tempDir, filename+".prov") - if err := os.WriteFile(provFile, provData.Bytes(), 0644); err != nil { - cleanup() - return "", nil, fmt.Errorf("failed to save provenance file: %w", err) + if provData, err := i.getter.Get(provSource); err == nil { + // Save provenance to temp directory + provFile := filepath.Join(tempDir, filename+".prov") + if err := os.WriteFile(provFile, provData.Bytes(), 0644); err == nil { + slog.Debug("prepared plugin for verification", "plugin", pluginTarball, "provenance", provFile) + } } + // Note: We don't fail if .prov file can't be downloaded - the verification logic + // in InstallWithOptions will handle missing .prov files appropriately - slog.Debug("prepared plugin for verification", "plugin", pluginTarball, "provenance", provFile) + slog.Debug("prepared plugin for verification", "plugin", pluginTarball) return pluginTarball, cleanup, nil }