mirror of
https://github.com/helm/helm.git
synced 2026-05-28 04:35:48 -04:00
fix: Plugin missing provenance bypass
Signed-off-by: George Jenkins <gvjenkins@gmail.com>
This commit is contained in:
parent
4e7994d446
commit
05fa37973d
3 changed files with 55 additions and 42 deletions
|
|
@ -98,24 +98,23 @@ func InstallWithOptions(i Installer, opts Options) (*VerificationResult, error)
|
|||
|
||||
// Check if provenance data exists
|
||||
if len(provData) == 0 {
|
||||
// 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 {
|
||||
// Provenance data exists - verify the plugin
|
||||
verification, err := plugin.VerifyPlugin(archiveData, provData, filename, opts.Keyring)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("plugin verification failed: %w", err)
|
||||
}
|
||||
return nil, fmt.Errorf("plugin verification failed: no provenance file (.prov) found")
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
// Provenance data exists - verify the plugin
|
||||
verification, err := plugin.VerifyPlugin(archiveData, provData, filename, 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@ limitations under the License.
|
|||
package installer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
@ -44,33 +42,49 @@ func TestInstallWithOptions_VerifyMissingProvenance(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(installer.Path())
|
||||
|
||||
// Capture stderr to check warning message
|
||||
oldStderr := os.Stderr
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stderr = w
|
||||
|
||||
// Install with verification enabled (should warn but succeed)
|
||||
// Install with verification enabled should fail when .prov is missing
|
||||
result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: "dummy"})
|
||||
|
||||
// Restore stderr and read captured output
|
||||
w.Close()
|
||||
os.Stderr = oldStderr
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
output := buf.String()
|
||||
|
||||
// Should succeed with nil result (no verification performed)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected installation to succeed despite missing .prov file, got error: %v", err)
|
||||
// Should fail with a missing provenance error
|
||||
if err == nil {
|
||||
t.Fatal("Expected installation to fail when .prov file is missing and verification is enabled")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "no provenance file") {
|
||||
t.Errorf("Expected 'no provenance file' in error message, got: %v", err)
|
||||
}
|
||||
if result != nil {
|
||||
t.Errorf("Expected nil verification result when .prov file is missing, got: %+v", result)
|
||||
}
|
||||
|
||||
// Should contain warning message
|
||||
expectedWarning := "WARNING: No provenance file found for plugin"
|
||||
if !strings.Contains(output, expectedWarning) {
|
||||
t.Errorf("Expected warning message '%s' in output, got: %s", expectedWarning, output)
|
||||
// Plugin should NOT be installed
|
||||
if _, err := os.Stat(installer.Path()); !os.IsNotExist(err) {
|
||||
t.Errorf("Plugin should not be installed when verification fails due to missing .prov")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallWithOptions_NoVerifyMissingProvenance(t *testing.T) {
|
||||
ensure.HelmHome(t)
|
||||
|
||||
// Create a temporary plugin tarball without .prov file
|
||||
pluginDir := createTestPluginDir(t)
|
||||
pluginTgz := createTarballFromPluginDir(t, pluginDir)
|
||||
defer os.Remove(pluginTgz)
|
||||
|
||||
// Create local installer
|
||||
installer, err := NewLocalInstaller(pluginTgz)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create installer: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(installer.Path())
|
||||
|
||||
// Install with verification explicitly disabled should succeed without .prov
|
||||
result, err := InstallWithOptions(installer, Options{Verify: false})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected installation to succeed with --verify=false, got error: %v", err)
|
||||
}
|
||||
if result != nil {
|
||||
t.Errorf("Expected nil verification result when verification is disabled, got: %+v", result)
|
||||
}
|
||||
|
||||
// Plugin should be installed
|
||||
|
|
|
|||
|
|
@ -50,11 +50,11 @@ const pluginInstallDesc = `
|
|||
This command allows you to install a plugin from a url to a VCS repo or a local path.
|
||||
|
||||
By default, plugin signatures are verified before installation when installing from
|
||||
tarballs (.tgz or .tar.gz). This requires a corresponding .prov file to be available
|
||||
alongside the tarball.
|
||||
tarballs (.tgz or .tar.gz). A corresponding .prov file must be available alongside
|
||||
the tarball; installation will fail if it is missing or invalid.
|
||||
For local development, plugins installed from local directories are automatically
|
||||
treated as "local dev" and do not require signatures.
|
||||
Use --verify=false to skip signature verification for remote plugins.
|
||||
Use --verify=false to explicitly skip signature verification (NOT recommended).
|
||||
`
|
||||
|
||||
func newPluginInstallCmd(out io.Writer) *cobra.Command {
|
||||
|
|
|
|||
Loading…
Reference in a new issue