github.com/argoproj/argo-cd@v1.8.7/util/db/gpgkeys_test.go (about)

     1  package db
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	v1 "k8s.io/api/core/v1"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/apimachinery/pkg/runtime"
    12  	"k8s.io/client-go/kubernetes/fake"
    13  
    14  	"github.com/argoproj/argo-cd/common"
    15  	"github.com/argoproj/argo-cd/test"
    16  	"github.com/argoproj/argo-cd/util/settings"
    17  )
    18  
    19  // GPG config map with a single key and good mapping
    20  var gpgCMEmpty = v1.ConfigMap{
    21  	ObjectMeta: metav1.ObjectMeta{
    22  		Name:      common.ArgoCDGPGKeysConfigMapName,
    23  		Namespace: testNamespace,
    24  		Labels: map[string]string{
    25  			"app.kubernetes.io/part-of": "argocd",
    26  		},
    27  	},
    28  }
    29  
    30  // GPG config map with a single key and good mapping
    31  var gpgCMSingleGoodPubkey = v1.ConfigMap{
    32  	ObjectMeta: metav1.ObjectMeta{
    33  		Name:      common.ArgoCDGPGKeysConfigMapName,
    34  		Namespace: testNamespace,
    35  		Labels: map[string]string{
    36  			"app.kubernetes.io/part-of": "argocd",
    37  		},
    38  	},
    39  	Data: map[string]string{
    40  		"4AEE18F83AFDEB23": test.MustLoadFileToString("../gpg/testdata/github.asc"),
    41  	},
    42  }
    43  
    44  // GPG config map with two keys and good mapping
    45  var gpgCMMultiGoodPubkey = v1.ConfigMap{
    46  	ObjectMeta: metav1.ObjectMeta{
    47  		Name:      common.ArgoCDGPGKeysConfigMapName,
    48  		Namespace: testNamespace,
    49  		Labels: map[string]string{
    50  			"app.kubernetes.io/part-of": "argocd",
    51  		},
    52  	},
    53  	Data: map[string]string{
    54  		"FDC79815400D88A9": test.MustLoadFileToString("../gpg/testdata/johndoe.asc"),
    55  		"F7842A5CEAA9C0B1": test.MustLoadFileToString("../gpg/testdata/janedoe.asc"),
    56  	},
    57  }
    58  
    59  // GPG config map with a single key and bad mapping
    60  var gpgCMSingleKeyWrongId = v1.ConfigMap{
    61  	ObjectMeta: metav1.ObjectMeta{
    62  		Name:      common.ArgoCDGPGKeysConfigMapName,
    63  		Namespace: testNamespace,
    64  		Labels: map[string]string{
    65  			"app.kubernetes.io/part-of": "argocd",
    66  		},
    67  	},
    68  	Data: map[string]string{
    69  		"5AEE18F83AFDEB23": test.MustLoadFileToString("../gpg/testdata/github.asc"),
    70  	},
    71  }
    72  
    73  // GPG config map with a garbage pub key
    74  var gpgCMGarbagePubkey = v1.ConfigMap{
    75  	ObjectMeta: metav1.ObjectMeta{
    76  		Name:      common.ArgoCDGPGKeysConfigMapName,
    77  		Namespace: testNamespace,
    78  		Labels: map[string]string{
    79  			"app.kubernetes.io/part-of": "argocd",
    80  		},
    81  	},
    82  	Data: map[string]string{
    83  		"4AEE18F83AFDEB23": test.MustLoadFileToString("../gpg/testdata/garbage.asc"),
    84  	},
    85  }
    86  
    87  // GPG config map with a wrong key
    88  var gpgCMGarbageCMKey = v1.ConfigMap{
    89  	ObjectMeta: metav1.ObjectMeta{
    90  		Name:      common.ArgoCDGPGKeysConfigMapName,
    91  		Namespace: testNamespace,
    92  		Labels: map[string]string{
    93  			"app.kubernetes.io/part-of": "argocd",
    94  		},
    95  	},
    96  	Data: map[string]string{
    97  		"wullerosekaufe": test.MustLoadFileToString("../gpg/testdata/github.asc"),
    98  	},
    99  }
   100  
   101  // Returns a fake client set for use in tests
   102  func getGPGKeysClientset(gpgCM v1.ConfigMap) *fake.Clientset {
   103  	cm := v1.ConfigMap{
   104  		ObjectMeta: metav1.ObjectMeta{
   105  			Name:      "argocd-cm",
   106  			Namespace: testNamespace,
   107  			Labels: map[string]string{
   108  				"app.kubernetes.io/part-of": "argocd",
   109  			},
   110  		},
   111  		Data: nil,
   112  	}
   113  
   114  	return fake.NewSimpleClientset([]runtime.Object{&cm, &gpgCM}...)
   115  }
   116  
   117  func Test_ValidatePGPKey(t *testing.T) {
   118  	// Good case - single PGP key
   119  	{
   120  		key, err := validatePGPKey(test.MustLoadFileToString("../gpg/testdata/github.asc"))
   121  		assert.NoError(t, err)
   122  		assert.NotNil(t, key)
   123  		assert.Equal(t, "4AEE18F83AFDEB23", key.KeyID)
   124  		assert.NotEmpty(t, key.Owner)
   125  		assert.NotEmpty(t, key.KeyData)
   126  		assert.NotEmpty(t, key.SubType)
   127  	}
   128  	// Bad case - Garbage
   129  	{
   130  		key, err := validatePGPKey(test.MustLoadFileToString("../gpg/testdata/garbage.asc"))
   131  		assert.Error(t, err)
   132  		assert.Nil(t, key)
   133  	}
   134  	// Bad case - more than one key
   135  	{
   136  		key, err := validatePGPKey(test.MustLoadFileToString("../gpg/testdata/multi.asc"))
   137  		assert.Error(t, err)
   138  		assert.Nil(t, key)
   139  	}
   140  }
   141  
   142  func Test_ListConfiguredGPGPublicKeys(t *testing.T) {
   143  	// Good case. Single key in input, right mapping to Key ID in CM
   144  	{
   145  		clientset := getGPGKeysClientset(gpgCMSingleGoodPubkey)
   146  		settings := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
   147  		db := NewDB(testNamespace, settings, clientset)
   148  		if db == nil {
   149  			panic("could not get database")
   150  		}
   151  		keys, err := db.ListConfiguredGPGPublicKeys(context.Background())
   152  		assert.NoError(t, err)
   153  		assert.Len(t, keys, 1)
   154  	}
   155  	// Good case. No certificates in ConfigMap
   156  	{
   157  		clientset := getGPGKeysClientset(gpgCMEmpty)
   158  		settings := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
   159  		db := NewDB(testNamespace, settings, clientset)
   160  		if db == nil {
   161  			panic("could not get database")
   162  		}
   163  		keys, err := db.ListConfiguredGPGPublicKeys(context.Background())
   164  		assert.NoError(t, err)
   165  		assert.Len(t, keys, 0)
   166  	}
   167  	// Bad case. Single key in input, wrong mapping to Key ID in CM
   168  	{
   169  		clientset := getGPGKeysClientset(gpgCMSingleKeyWrongId)
   170  		settings := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
   171  		db := NewDB(testNamespace, settings, clientset)
   172  		if db == nil {
   173  			panic("could not get database")
   174  		}
   175  		keys, err := db.ListConfiguredGPGPublicKeys(context.Background())
   176  		assert.Error(t, err)
   177  		assert.Len(t, keys, 0)
   178  	}
   179  	// Bad case. Garbage public key
   180  	{
   181  		clientset := getGPGKeysClientset(gpgCMGarbagePubkey)
   182  		settings := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
   183  		db := NewDB(testNamespace, settings, clientset)
   184  		if db == nil {
   185  			panic("could not get database")
   186  		}
   187  		keys, err := db.ListConfiguredGPGPublicKeys(context.Background())
   188  		assert.Error(t, err)
   189  		assert.Len(t, keys, 0)
   190  	}
   191  	// Bad case. Garbage ConfigMap key in data
   192  	{
   193  		clientset := getGPGKeysClientset(gpgCMGarbageCMKey)
   194  		settings := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
   195  		db := NewDB(testNamespace, settings, clientset)
   196  		if db == nil {
   197  			panic("could not get database")
   198  		}
   199  		keys, err := db.ListConfiguredGPGPublicKeys(context.Background())
   200  		assert.Error(t, err)
   201  		assert.Len(t, keys, 0)
   202  	}
   203  }
   204  
   205  func Test_AddGPGPublicKey(t *testing.T) {
   206  	// Good case
   207  	{
   208  		clientset := getGPGKeysClientset(gpgCMEmpty)
   209  		settings := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
   210  		db := NewDB(testNamespace, settings, clientset)
   211  
   212  		// Key should be added
   213  		new, skipped, err := db.AddGPGPublicKey(context.Background(), test.MustLoadFileToString("../gpg/testdata/github.asc"))
   214  		assert.NoError(t, err)
   215  		assert.Len(t, new, 1)
   216  		assert.Len(t, skipped, 0)
   217  		cm, err := settings.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
   218  		assert.NoError(t, err)
   219  		assert.Len(t, cm.Data, 1)
   220  
   221  		// Same key should not be added, but skipped
   222  		new, skipped, err = db.AddGPGPublicKey(context.Background(), test.MustLoadFileToString("../gpg/testdata/github.asc"))
   223  		assert.NoError(t, err)
   224  		assert.Len(t, new, 0)
   225  		assert.Len(t, skipped, 1)
   226  		cm, err = settings.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
   227  		assert.NoError(t, err)
   228  		assert.Len(t, cm.Data, 1)
   229  
   230  		// New keys should be added
   231  		new, skipped, err = db.AddGPGPublicKey(context.Background(), test.MustLoadFileToString("../gpg/testdata/multi.asc"))
   232  		assert.NoError(t, err)
   233  		assert.Len(t, new, 2)
   234  		assert.Len(t, skipped, 0)
   235  		cm, err = settings.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
   236  		assert.NoError(t, err)
   237  		assert.Len(t, cm.Data, 3)
   238  
   239  		// Same new keys should be skipped
   240  		new, skipped, err = db.AddGPGPublicKey(context.Background(), test.MustLoadFileToString("../gpg/testdata/multi.asc"))
   241  		assert.NoError(t, err)
   242  		assert.Len(t, new, 0)
   243  		assert.Len(t, skipped, 2)
   244  		cm, err = settings.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
   245  		assert.NoError(t, err)
   246  		assert.Len(t, cm.Data, 3)
   247  
   248  		// Garbage input should result in error
   249  		new, skipped, err = db.AddGPGPublicKey(context.Background(), test.MustLoadFileToString("../gpg/testdata/garbage.asc"))
   250  		assert.Error(t, err)
   251  		assert.Nil(t, new)
   252  		assert.Nil(t, skipped)
   253  		cm, err = settings.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
   254  		assert.NoError(t, err)
   255  		assert.Len(t, cm.Data, 3)
   256  	}
   257  }
   258  
   259  func Test_DeleteGPGPublicKey(t *testing.T) {
   260  	defer os.Setenv("GNUPGHOME", "")
   261  	// Good case
   262  	{
   263  		clientset := getGPGKeysClientset(gpgCMMultiGoodPubkey)
   264  		settings := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
   265  		db := NewDB(testNamespace, settings, clientset)
   266  
   267  		// Key should be removed
   268  		err := db.DeleteGPGPublicKey(context.Background(), "FDC79815400D88A9")
   269  		assert.NoError(t, err)
   270  
   271  		// Key should not exist anymore, therefore can't be deleted again
   272  		err = db.DeleteGPGPublicKey(context.Background(), "FDC79815400D88A9")
   273  		assert.Error(t, err)
   274  
   275  		// One key left in configuration
   276  		n, err := db.ListConfiguredGPGPublicKeys(context.Background())
   277  		assert.NoError(t, err)
   278  		assert.Len(t, n, 1)
   279  
   280  		// Key should be removed
   281  		err = db.DeleteGPGPublicKey(context.Background(), "F7842A5CEAA9C0B1")
   282  		assert.NoError(t, err)
   283  
   284  		// Key should not exist anymore, therefore can't be deleted again
   285  		err = db.DeleteGPGPublicKey(context.Background(), "F7842A5CEAA9C0B1")
   286  		assert.Error(t, err)
   287  
   288  		// No key left in configuration
   289  		n, err = db.ListConfiguredGPGPublicKeys(context.Background())
   290  		assert.NoError(t, err)
   291  		assert.Len(t, n, 0)
   292  
   293  	}
   294  	// Bad case - empty ConfigMap
   295  	{
   296  		clientset := getGPGKeysClientset(gpgCMEmpty)
   297  		settings := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
   298  		db := NewDB(testNamespace, settings, clientset)
   299  
   300  		// Key should be removed
   301  		err := db.DeleteGPGPublicKey(context.Background(), "F7842A5CEAA9C0B1")
   302  		assert.Error(t, err)
   303  	}
   304  }