You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
helm/internal/plugin/verify_test.go

215 lines
5.2 KiB

/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package plugin
import (
"os"
"path/filepath"
"testing"
"helm.sh/helm/v4/pkg/provenance"
)
const testKeyFile = "../../pkg/cmd/testdata/helm-test-key.secret"
const testPubFile = "../../pkg/cmd/testdata/helm-test-key.pub"
const testPluginYAML = `apiVersion: v1
name: test-plugin
type: cli/v1
runtime: subprocess
version: 1.0.0
runtimeConfig:
platformCommand:
- command: echo`
func TestVerifyPlugin(t *testing.T) {
// Create a test plugin and sign it
tempDir := t.TempDir()
// Create plugin directory
pluginDir := filepath.Join(tempDir, "verify-test-plugin")
if err := os.MkdirAll(pluginDir, 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0644); err != nil {
t.Fatal(err)
}
// Create tarball
tarballPath := filepath.Join(tempDir, "verify-test-plugin.tar.gz")
tarFile, err := os.Create(tarballPath)
if err != nil {
t.Fatal(err)
}
if err := CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil {
tarFile.Close()
t.Fatal(err)
}
tarFile.Close()
// Sign the plugin with source directory
signer, err := provenance.NewFromKeyring(testKeyFile, "helm-test")
if err != nil {
t.Fatal(err)
}
if err := signer.DecryptKey(func(_ string) ([]byte, error) {
return []byte(""), nil
}); err != nil {
t.Fatal(err)
}
// Read the tarball data
tarballData, err := os.ReadFile(tarballPath)
if err != nil {
t.Fatal(err)
}
sig, err := SignPlugin(tarballData, filepath.Base(tarballPath), signer)
if err != nil {
t.Fatal(err)
}
// Write the signature to .prov file
provFile := tarballPath + ".prov"
if err := os.WriteFile(provFile, []byte(sig), 0644); err != nil {
t.Fatal(err)
}
// Read the files for verification
archiveData, err := os.ReadFile(tarballPath)
if err != nil {
t.Fatal(err)
}
provData, err := os.ReadFile(provFile)
if err != nil {
t.Fatal(err)
}
// Now verify the plugin
verification, err := VerifyPlugin(archiveData, provData, filepath.Base(tarballPath), testPubFile)
if err != nil {
t.Fatalf("Failed to verify plugin: %v", err)
}
// Check verification results
if verification.SignedBy == nil {
t.Error("SignedBy is nil")
}
if verification.FileName != "verify-test-plugin.tar.gz" {
t.Errorf("Expected filename 'verify-test-plugin.tar.gz', got %s", verification.FileName)
}
if verification.FileHash == "" {
t.Error("FileHash is empty")
}
}
func TestVerifyPluginBadSignature(t *testing.T) {
tempDir := t.TempDir()
// Create a plugin tarball
pluginDir := filepath.Join(tempDir, "bad-plugin")
if err := os.MkdirAll(pluginDir, 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0644); err != nil {
t.Fatal(err)
}
tarballPath := filepath.Join(tempDir, "bad-plugin.tar.gz")
tarFile, err := os.Create(tarballPath)
if err != nil {
t.Fatal(err)
}
if err := CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil {
tarFile.Close()
t.Fatal(err)
}
tarFile.Close()
// Create a bad signature (just some text)
badSig := `-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
This is not a real signature
-----BEGIN PGP SIGNATURE-----
InvalidSignatureData
-----END PGP SIGNATURE-----`
provFile := tarballPath + ".prov"
if err := os.WriteFile(provFile, []byte(badSig), 0644); err != nil {
t.Fatal(err)
}
// Read the files
archiveData, err := os.ReadFile(tarballPath)
if err != nil {
t.Fatal(err)
}
provData, err := os.ReadFile(provFile)
if err != nil {
t.Fatal(err)
}
// Try to verify - should fail
_, err = VerifyPlugin(archiveData, provData, filepath.Base(tarballPath), testPubFile)
if err == nil {
t.Error("Expected verification to fail with bad signature")
}
}
func TestVerifyPluginMissingProvenance(t *testing.T) {
tempDir := t.TempDir()
tarballPath := filepath.Join(tempDir, "no-prov.tar.gz")
// Create a minimal tarball
if err := os.WriteFile(tarballPath, []byte("dummy"), 0644); err != nil {
t.Fatal(err)
}
// Read the tarball data
archiveData, err := os.ReadFile(tarballPath)
if err != nil {
t.Fatal(err)
}
// Try to verify with empty provenance data
_, err = VerifyPlugin(archiveData, nil, filepath.Base(tarballPath), testPubFile)
if err == nil {
t.Error("Expected verification to fail with empty provenance data")
}
}
func TestVerifyPluginMalformedData(t *testing.T) {
// Test with malformed tarball data - should fail
malformedData := []byte("not a tarball")
provData := []byte("fake provenance")
_, err := VerifyPlugin(malformedData, provData, "malformed.tar.gz", testPubFile)
if err == nil {
t.Error("Expected malformed data verification to fail, but it succeeded")
}
}