Skip to content

Commit 29bf2d6

Browse files
committed
Set up gitconfig extra properties from the specified secret
1 parent 847cb6d commit 29bf2d6

File tree

4 files changed

+75
-15
lines changed

4 files changed

+75
-15
lines changed

pkg/constants/metadata.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ const (
9393
// to detect if the user has provided an SSH key with a passhprase.
9494
SSHSecretName = "git-ssh-key"
9595

96+
// DevWorkspaceGitconfigExtraPropertiesSecretName is the name of the secret that is used to define custom gitconfig
97+
// properties that will be mounted to the /etc/gitconfig file. The secret's data map is parsed as a key value structure,
98+
// where each key is a gitconfig section, and value is a property definition. For example, secret's data map is set to
99+
// key:"http", value:"extraHeader = Basic token-content", so the gitconfig file will include next content:
100+
// [http]
101+
// extraHeader = Basic token-content
102+
// The 'git config list' command will reveal the property as: http.extraheader=Basic token-content.
103+
// The secret's data map key must not contain any special characters and whitespaces, and the value must match the
104+
// format: <property> = <value>, otherwise the custom property will be ignored.
105+
// Multiple properties per section are supported, each property set must start from the new line in this case.
106+
DevWorkspaceGitconfigExtraPropertiesSecretName = "devworkspace-gitconfig-extra-properties"
107+
96108
// SSHSecretPassphraseKey is the key used to retrieve the optional passphrase stored inside the SSH secret.
97109
SSHSecretPassphraseKey = "passphrase"
98110

pkg/provision/automount/gitconfig.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const mergedGitCredentialsMountPath = "/.git-credentials/"
2727

2828
// ProvisionGitConfiguration takes care of mounting git credentials and a gitconfig into a devworkspace.
2929
func ProvisionGitConfiguration(api sync.ClusterAPI, namespace string) (*Resources, error) {
30-
credentialsSecrets, tlsConfigMaps, err := getGitResources(api, namespace)
30+
credentialsSecrets, extraPropertySecret, tlsConfigMaps, err := getGitResources(api, namespace)
3131
if err != nil {
3232
return nil, err
3333
}
@@ -48,7 +48,7 @@ func ProvisionGitConfiguration(api sync.ClusterAPI, namespace string) (*Resource
4848
return nil, &dwerrors.FailError{Message: "Failed to collect git credentials secrets", Err: err}
4949
}
5050

51-
gitConfigMap, err := constructGitConfig(namespace, mergedGitCredentialsMountPath, tlsConfigMaps, baseGitConfig)
51+
gitConfigMap, err := constructGitConfig(namespace, mergedGitCredentialsMountPath, tlsConfigMaps, extraPropertySecret, baseGitConfig)
5252
if err != nil {
5353
return nil, &dwerrors.FailError{Message: "Failed to prepare git config for workspace", Err: err}
5454
}
@@ -69,7 +69,7 @@ func ProvisionGitConfiguration(api sync.ClusterAPI, namespace string) (*Resource
6969
return &resources, nil
7070
}
7171

72-
func getGitResources(api sync.ClusterAPI, namespace string) (credentialSecrets []corev1.Secret, tlsConfigMaps []corev1.ConfigMap, err error) {
72+
func getGitResources(api sync.ClusterAPI, namespace string) (credentialSecrets []corev1.Secret, extraPropertiesSecret *corev1.Secret, tlsConfigMaps []corev1.ConfigMap, err error) {
7373
credentialsLabelSelector := k8sclient.MatchingLabels{
7474
constants.DevWorkspaceGitCredentialLabel: "true",
7575
}
@@ -79,7 +79,7 @@ func getGitResources(api sync.ClusterAPI, namespace string) (credentialSecrets [
7979

8080
secretList := &corev1.SecretList{}
8181
if err := api.Client.List(api.Ctx, secretList, k8sclient.InNamespace(namespace), credentialsLabelSelector); err != nil {
82-
return nil, nil, err
82+
return nil, nil, nil, err
8383
}
8484
var secrets []corev1.Secret
8585
if len(secretList.Items) > 0 {
@@ -89,15 +89,23 @@ func getGitResources(api sync.ClusterAPI, namespace string) (credentialSecrets [
8989

9090
configmapList := &corev1.ConfigMapList{}
9191
if err := api.Client.List(api.Ctx, configmapList, k8sclient.InNamespace(namespace), tlsLabelSelector); err != nil {
92-
return nil, nil, err
92+
return nil, nil, nil, err
9393
}
9494
var configmaps []corev1.ConfigMap
9595
if len(configmapList.Items) > 0 {
9696
configmaps = configmapList.Items
9797
}
9898
sortConfigmaps(configmaps)
9999

100-
return secrets, configmaps, nil
100+
secretNN := types.NamespacedName{
101+
Name: constants.DevWorkspaceGitconfigExtraPropertiesSecretName,
102+
Namespace: namespace,
103+
}
104+
secret := &corev1.Secret{}
105+
if err := api.Client.Get(api.Ctx, secretNN, secret); err != nil {
106+
return secrets, nil, configmaps, nil
107+
}
108+
return secrets, secret, configmaps, nil
101109
}
102110

103111
func cleanupGitConfig(api sync.ClusterAPI, namespace string) error {

pkg/provision/automount/gitconfig_test.go

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func TestOneConfigMapWithNoUserMountPath(t *testing.T) {
114114
buildConfig(defaultName, mountPath, defaultData),
115115
}
116116

117-
gitconfig, err := constructGitConfig(testNamespace, mountPath, configmaps, nil)
117+
gitconfig, err := constructGitConfig(testNamespace, mountPath, configmaps, nil, nil)
118118
if !assert.NoError(t, err, "Should not return error") {
119119
return
120120
}
@@ -127,7 +127,7 @@ func TestOneConfigMapWithMountPathAndHostAndCert(t *testing.T) {
127127
buildConfig(defaultName, mountPath, defaultData),
128128
}
129129

130-
gitconfig, err := constructGitConfig(testNamespace, mountPath, configmaps, nil)
130+
gitconfig, err := constructGitConfig(testNamespace, mountPath, configmaps, nil, nil)
131131
if !assert.NoError(t, err, "Should not return error") {
132132
return
133133
}
@@ -140,7 +140,7 @@ func TestOneConfigMapWithMountPathAndWithoutHostAndWithoutCert(t *testing.T) {
140140
buildConfig(defaultName, mountPath, map[string]string{}),
141141
}
142142

143-
_, err := constructGitConfig(testNamespace, mountPath, configmaps, nil)
143+
_, err := constructGitConfig(testNamespace, mountPath, configmaps, nil, nil)
144144
assert.Equal(t, err.Error(), fmt.Sprintf("could not find certificate field in configmap %s", defaultName))
145145
}
146146

@@ -152,7 +152,7 @@ func TestOneConfigMapWithMountPathAndWithoutHostAndWithCert(t *testing.T) {
152152
}),
153153
}
154154

155-
gitconfig, err := constructGitConfig(testNamespace, mountPath, configmaps, nil)
155+
gitconfig, err := constructGitConfig(testNamespace, mountPath, configmaps, nil, nil)
156156
if !assert.NoError(t, err, "Should not return error") {
157157
return
158158
}
@@ -167,7 +167,7 @@ func TestOneConfigMapWithMountPathAndWithHostAndWithoutCert(t *testing.T) {
167167
}),
168168
}
169169

170-
_, err := constructGitConfig(testNamespace, mountPath, configmaps, nil)
170+
_, err := constructGitConfig(testNamespace, mountPath, configmaps, nil, nil)
171171
assert.Equal(t, err.Error(), fmt.Sprintf("could not find certificate field in configmap %s", defaultName))
172172
}
173173

@@ -177,7 +177,7 @@ func TestTwoConfigMapWithNoDefinedMountPathInAnnotation(t *testing.T) {
177177
buildConfig("configmap2", "/folder2", defaultData),
178178
}
179179

180-
gitconfig, err := constructGitConfig(testNamespace, "", configmaps, nil)
180+
gitconfig, err := constructGitConfig(testNamespace, "", configmaps, nil, nil)
181181
if !assert.NoError(t, err, "Should not return error") {
182182
return
183183
}
@@ -196,7 +196,7 @@ func TestTwoConfigMapWithOneDefaultTLSAndOtherGithubTLS(t *testing.T) {
196196
}),
197197
}
198198

199-
gitconfig, err := constructGitConfig(testNamespace, "", configmaps, nil)
199+
gitconfig, err := constructGitConfig(testNamespace, "", configmaps, nil, nil)
200200
if !assert.NoError(t, err, "Should not return error") {
201201
return
202202
}
@@ -214,10 +214,32 @@ func TestTwoConfigMapWithBothMissingHost(t *testing.T) {
214214
}),
215215
}
216216

217-
_, err := constructGitConfig(testNamespace, "", configmaps, nil)
217+
_, err := constructGitConfig(testNamespace, "", configmaps, nil, nil)
218218
assert.Equal(t, err.Error(), "multiple git tls credentials do not have host specified")
219219
}
220220

221+
func TestExtraProperties(t *testing.T) {
222+
mountPath := "/sample/test"
223+
secret := corev1.Secret{
224+
ObjectMeta: metav1.ObjectMeta{
225+
Name: constants.DevWorkspaceGitconfigExtraPropertiesSecretName,
226+
Namespace: testNamespace,
227+
},
228+
Data: map[string][]byte{
229+
"section": []byte("property1 = value1\nproperty2 = value2\ninvalidPropertySet"),
230+
},
231+
}
232+
233+
gitconfig, err := constructGitConfig(testNamespace, mountPath, []corev1.ConfigMap{}, &secret, nil)
234+
if !assert.NoError(t, err, "Should not return error") {
235+
return
236+
}
237+
assert.Contains(t, gitconfig.Data[gitConfigName], `[section]
238+
property1 = value1
239+
property2 = value2`)
240+
assert.NotContains(t, gitconfig.Data[gitConfigName], `invalidPropertySet`)
241+
}
242+
221243
func buildConfig(name string, mountPath string, data map[string]string) corev1.ConfigMap {
222244
return corev1.ConfigMap{
223245
ObjectMeta: metav1.ObjectMeta{

pkg/provision/automount/templates.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package automount
1616
import (
1717
"fmt"
1818
"path"
19+
"regexp"
1920
"strings"
2021

2122
"github.com/devfile/devworkspace-operator/pkg/constants"
@@ -57,7 +58,10 @@ const defaultGitServerTemplate = `[http]
5758
sslCAInfo = %s
5859
`
5960

60-
func constructGitConfig(namespace, credentialMountPath string, certificatesConfigMaps []corev1.ConfigMap, baseGitConfig *string) (*corev1.ConfigMap, error) {
61+
var GitconfigSectionRegexp = regexp.MustCompile(`^[a-zA-Z0-9]*$`)
62+
var GitconfigPropertySetRegexp = regexp.MustCompile(`^.*=.*$`)
63+
64+
func constructGitConfig(namespace, credentialMountPath string, certificatesConfigMaps []corev1.ConfigMap, extraPropertiesSecret *corev1.Secret, baseGitConfig *string) (*corev1.ConfigMap, error) {
6165
var configSettings []string
6266
configSettings = append(configSettings, gitLFSConfig)
6367

@@ -93,6 +97,20 @@ func constructGitConfig(namespace, credentialMountPath string, certificatesConfi
9397
}
9498
}
9599

100+
if extraPropertiesSecret != nil {
101+
for key, value := range extraPropertiesSecret.Data {
102+
if GitconfigSectionRegexp.MatchString(key) {
103+
configSettings = append(configSettings, fmt.Sprintf(`[%s]`, key))
104+
split := strings.Split(string(value), "\n")
105+
for _, element := range split {
106+
if GitconfigPropertySetRegexp.MatchString(element) {
107+
configSettings = append(configSettings, fmt.Sprintf(` %s`, element))
108+
}
109+
}
110+
}
111+
}
112+
}
113+
96114
gitConfig := strings.Join(configSettings, "\n")
97115

98116
gitConfigMap := &corev1.ConfigMap{

0 commit comments

Comments
 (0)