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

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