mirror of https://github.com/helm/helm
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.
215 lines
5.2 KiB
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")
|
|
}
|
|
}
|