(chore): adds tls config for GitHub App auth

this commit ensures that if ca.crt or caFile is available in the github app secret, a tls config with user provided certs is appended to system cert pool and passed to the underlying http transport

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): update target URL for TLSConfigFromSecret

this commit ensures that the target URL for runtime/secrets.TLSConfigFromSecret has the scheme and host

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): adds test scenarios

this commit adds test scenarios for mTLS GitHub app in reconcile source auth strategy

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): use runtime/secrets authMethods

this commit ensures that GitHubApp secret resolution happens via pkg/runtime/secrets

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): update docs

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): adds github app data check

this commit ensures that when provider is github and no github app data is present in the secret, it will error out with invalid configuration

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): removes getProxyOpts helper func

this commit removes the helper method getProxyOpts and uses the standardized pkg/runtime/secrets APIs to get proxy options.

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): removes getProxyOpts test

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): improves test coverage

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): do not stall on missing github app data

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>

(chore): adds a note on mTLS configuration in docs

This commit mentions in the docs that if tls.crt and tls.key is part of the secret then mutual TLS configuration will be automatically enabled and should be used optionally.

Signed-off-by: abhijith-darshan <abhijith.darshan@hotmail.com>
This commit is contained in:
abhijith-darshan 2025-08-04 16:57:13 +02:00
parent bd6d090ef0
commit 46522f9815
No known key found for this signature in database
GPG Key ID: D46C33C884B83DD3
5 changed files with 193 additions and 141 deletions

View File

@ -357,6 +357,11 @@ same pattern.
- The private key that was generated in the pre-requisites.
- (Optional) GitHub Enterprise Server users can set the base URL to
`http(s)://HOSTNAME/api/v3`.
- (Optional) If GitHub Enterprise Server uses a private CA, include its bundle (root and any intermediates) in `ca.crt`.
If the `ca.crt` is specified, then it will be used for TLS verification for all API / Git over `HTTPS` requests to the GitHub Enterprise Server.
**NOTE:** If the secret contains `tls.crt`, `tls.key` then [mutual TLS configuration](#https-mutual-tls-authentication) will be automatically enabled.
Omit these keys if the GitHub server does not support mutual TLS.
```yaml
apiVersion: v1
@ -372,6 +377,10 @@ stringData:
...
-----END RSA PRIVATE KEY-----
githubAppBaseURL: "<github-enterprise-api-url>" #optional, required only for GitHub Enterprise Server users
ca.crt: | #optional, for GitHub Enterprise Server users
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
```
Alternatively, the Flux CLI can be used to automatically create the secret with

6
go.mod
View File

@ -30,15 +30,15 @@ require (
github.com/fluxcd/pkg/apis/meta v1.18.0
github.com/fluxcd/pkg/auth v0.21.0
github.com/fluxcd/pkg/cache v0.10.0
github.com/fluxcd/pkg/git v0.34.0
github.com/fluxcd/pkg/git/gogit v0.37.0
github.com/fluxcd/pkg/git v0.35.0
github.com/fluxcd/pkg/git/gogit v0.38.0
github.com/fluxcd/pkg/gittestserver v0.18.0
github.com/fluxcd/pkg/helmtestserver v0.26.0
github.com/fluxcd/pkg/http/transport v0.6.0
github.com/fluxcd/pkg/lockedfile v0.6.0
github.com/fluxcd/pkg/masktoken v0.7.0
github.com/fluxcd/pkg/oci v0.52.0
github.com/fluxcd/pkg/runtime v0.78.0
github.com/fluxcd/pkg/runtime v0.79.0
github.com/fluxcd/pkg/sourceignore v0.13.0
github.com/fluxcd/pkg/ssh v0.20.0
github.com/fluxcd/pkg/tar v0.13.0

12
go.sum
View File

@ -382,10 +382,10 @@ github.com/fluxcd/pkg/auth v0.21.0 h1:ckAQqP12wuptXEkMY18SQKWEY09m9e6yI0mEMsDV15
github.com/fluxcd/pkg/auth v0.21.0/go.mod h1:MXmpsXT97c874HCw5hnfqFUP7TsG8/Ss1vFrk8JccfM=
github.com/fluxcd/pkg/cache v0.10.0 h1:M+OGDM4da1cnz7q+sZSBtkBJHpiJsLnKVmR9OdMWxEY=
github.com/fluxcd/pkg/cache v0.10.0/go.mod h1:pPXRzQUDQagsCniuOolqVhnAkbNgYOg8d2cTliPs7ME=
github.com/fluxcd/pkg/git v0.34.0 h1:qTViWkfpEDnjzySyKRKliqUeGj/DznqlkmPhaDNIsFY=
github.com/fluxcd/pkg/git v0.34.0/go.mod h1:F9Asm3MlLW4uZx3FF92+bqho+oktdMdnTn/QmXe56NE=
github.com/fluxcd/pkg/git/gogit v0.37.0 h1:JINylFYpwrxS3MCu5Ei+g6XPgxbs5lv9PppIYYr07KY=
github.com/fluxcd/pkg/git/gogit v0.37.0/go.mod h1:X7YzW5mb4srA05h4SpL2OEGEHq02tbXQF5DPJen9hlc=
github.com/fluxcd/pkg/git v0.35.0 h1:mAauhsdfxNW4yQdXviVlvcN/uCGGG0+6p5D1+HFZI9w=
github.com/fluxcd/pkg/git v0.35.0/go.mod h1:F9Asm3MlLW4uZx3FF92+bqho+oktdMdnTn/QmXe56NE=
github.com/fluxcd/pkg/git/gogit v0.38.0 h1:222KmjpKf9pxqi8rAtm1omDcpGTY4JkahLrAwZ3AcwU=
github.com/fluxcd/pkg/git/gogit v0.38.0/go.mod h1:kHStdfd/AtkH5ED0UEWP2tmMGnfxg1GG92D29M+lRJ0=
github.com/fluxcd/pkg/gittestserver v0.18.0 h1:jkuLmzWFfq+v1ziI0LspZrUzc5WzCO98BaWb8OVRPtk=
github.com/fluxcd/pkg/gittestserver v0.18.0/go.mod h1:2wDLqUkPuixk/8pGQdef9ewaGJXf7Z+xHDVq8PIFG4E=
github.com/fluxcd/pkg/helmtestserver v0.26.0 h1:gKw1MGqWwN94nzs2yg3WKgMxi1RqqlDZXlGziaNCcv4=
@ -398,8 +398,8 @@ github.com/fluxcd/pkg/masktoken v0.7.0 h1:pitmyOg2pUVdW+nn2Lk/xqm2TaA08uxvOC0ns3
github.com/fluxcd/pkg/masktoken v0.7.0/go.mod h1:Lc1uoDjO1GY6+YdkK+ZqqBIBWquyV58nlSJ5S1N1IYU=
github.com/fluxcd/pkg/oci v0.52.0 h1:rkHMtXYm21MtDrjNcR5KScqOe6C1JHPExoShuVdNm8M=
github.com/fluxcd/pkg/oci v0.52.0/go.mod h1:5J6IhHoDVYCVeBEC+4E3nPeKh7d0kjJ8IEL6NVCiTx4=
github.com/fluxcd/pkg/runtime v0.78.0 h1:xwNZqnazmgURGuLiHDbzST6BI5K9fvZuNS4eMVY35Es=
github.com/fluxcd/pkg/runtime v0.78.0/go.mod h1:iGhdaEq+lMJQTJNAFEPOU4gUJ7kt3yeDcJPZy7O9IUw=
github.com/fluxcd/pkg/runtime v0.79.0 h1:9tv79EiQDx/QJH9mYDd9kZ9WybCVWBUGoiBHij+eKkc=
github.com/fluxcd/pkg/runtime v0.79.0/go.mod h1:iGhdaEq+lMJQTJNAFEPOU4gUJ7kt3yeDcJPZy7O9IUw=
github.com/fluxcd/pkg/sourceignore v0.13.0 h1:ZvkzX2WsmyZK9cjlqOFFW1onHVzhPZIqDbCh96rPqbU=
github.com/fluxcd/pkg/sourceignore v0.13.0/go.mod h1:Z9H1GoBx0ljOhptnzoV0PL6Nd/UzwKcSphP27lqb4xI=
github.com/fluxcd/pkg/ssh v0.20.0 h1:Ak0laIYIc/L8lEfqls/LDWRW8wYPESGaravQsCRGLb8=

View File

@ -31,6 +31,7 @@ import (
authutils "github.com/fluxcd/pkg/auth/utils"
"github.com/fluxcd/pkg/git/github"
"github.com/fluxcd/pkg/runtime/logger"
"github.com/fluxcd/pkg/runtime/secrets"
"github.com/go-git/go-git/v5/plumbing/transport"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -486,7 +487,11 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
var proxyURL *url.URL
if obj.Spec.ProxySecretRef != nil {
var err error
proxyOpts, proxyURL, err = r.getProxyOpts(ctx, obj.Spec.ProxySecretRef.Name, obj.GetNamespace())
secretRef := types.NamespacedName{
Name: obj.Spec.ProxySecretRef.Name,
Namespace: obj.GetNamespace(),
}
proxyURL, err = secrets.ProxyURLFromSecretRef(ctx, r.Client, secretRef)
if err != nil {
e := serror.NewGeneric(
fmt.Errorf("failed to configure proxy options: %w", err),
@ -496,6 +501,7 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
// Return error as the world as observed may change
return sreconcile.ResultEmpty, e
}
proxyOpts = &transport.ProxyOptions{URL: proxyURL.String()}
}
u, err := url.Parse(obj.Spec.URL)
@ -618,52 +624,16 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
return sreconcile.ResultSuccess, nil
}
// getProxyOpts fetches the secret containing the proxy settings, constructs a
// transport.ProxyOptions object using those settings and then returns it.
func (r *GitRepositoryReconciler) getProxyOpts(ctx context.Context, proxySecretName,
proxySecretNamespace string) (*transport.ProxyOptions, *url.URL, error) {
proxyData, err := r.getSecretData(ctx, proxySecretName, proxySecretNamespace)
if err != nil {
return nil, nil, fmt.Errorf("failed to get proxy secret '%s/%s': %w", proxySecretNamespace, proxySecretName, err)
}
b, ok := proxyData["address"]
if !ok {
return nil, nil, fmt.Errorf("invalid proxy secret '%s/%s': key 'address' is missing", proxySecretNamespace, proxySecretName)
}
address := string(b)
username := string(proxyData["username"])
password := string(proxyData["password"])
proxyOpts := &transport.ProxyOptions{
URL: address,
Username: username,
Password: password,
}
proxyURL, err := url.Parse(string(address))
if err != nil {
return nil, nil, fmt.Errorf("invalid address in proxy secret '%s/%s': %w", proxySecretNamespace, proxySecretName, err)
}
switch {
case username != "" && password == "":
proxyURL.User = url.User(username)
case username != "" && password != "":
proxyURL.User = url.UserPassword(username, password)
}
return proxyOpts, proxyURL, nil
}
// getAuthOpts fetches the secret containing the auth options (if specified),
// constructs a git.AuthOptions object using those options along with the provided
// URL and returns it.
func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1.GitRepository,
u url.URL, proxyURL *url.URL) (*git.AuthOptions, error) {
var secret *corev1.Secret
var authData map[string][]byte
if obj.Spec.SecretRef != nil {
var err error
authData, err = r.getSecretData(ctx, obj.Spec.SecretRef.Name, obj.GetNamespace())
secret, err = r.getSecret(ctx, obj.Spec.SecretRef.Name, obj.GetNamespace())
if err != nil {
e := serror.NewGeneric(
fmt.Errorf("failed to get secret '%s/%s': %w", obj.GetNamespace(), obj.Spec.SecretRef.Name, err),
@ -672,6 +642,7 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
return nil, e
}
authData = secret.Data
}
// Configure authentication strategy to access the source
@ -718,24 +689,38 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
return nil, e
}
targetURL := fmt.Sprintf("%s://%s", u.Scheme, u.Host)
authMethods, err := secrets.AuthMethodsFromSecret(ctx, secret, secrets.WithTargetURL(targetURL), secrets.WithTLSSystemCertPool())
if err != nil {
return nil, err
}
if !authMethods.HasGitHubAppData() {
e := serror.NewGeneric(
fmt.Errorf("secretRef with github app data must be specified when provider is set to github"),
sourcev1.InvalidProviderConfigurationReason,
)
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
return nil, e
}
getCreds = func() (*authutils.GitCredentials, error) {
var opts []github.OptFunc
var appOpts []github.OptFunc
if len(authData) > 0 {
opts = append(opts, github.WithAppData(authData))
}
appOpts = append(appOpts, github.WithAppData(authMethods.GitHubAppData))
if proxyURL != nil {
opts = append(opts, github.WithProxyURL(proxyURL))
appOpts = append(appOpts, github.WithProxyURL(proxyURL))
}
if r.TokenCache != nil {
opts = append(opts, github.WithCache(r.TokenCache, sourcev1.GitRepositoryKind,
appOpts = append(appOpts, github.WithCache(r.TokenCache, sourcev1.GitRepositoryKind,
obj.GetName(), obj.GetNamespace(), cache.OperationReconcile))
}
username, password, err := github.GetCredentials(ctx, opts...)
if authMethods.HasTLS() {
appOpts = append(appOpts, github.WithTLSConfig(authMethods.TLS))
}
username, password, err := github.GetCredentials(ctx, appOpts...)
if err != nil {
return nil, err
}
@ -772,16 +757,16 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
return opts, nil
}
func (r *GitRepositoryReconciler) getSecretData(ctx context.Context, name, namespace string) (map[string][]byte, error) {
func (r *GitRepositoryReconciler) getSecret(ctx context.Context, name, namespace string) (*corev1.Secret, error) {
key := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var secret corev1.Secret
if err := r.Client.Get(ctx, key, &secret); err != nil {
return nil, err
secret := &corev1.Secret{}
if err := r.Client.Get(ctx, key, secret); err != nil {
return nil, fmt.Errorf("failed to get secret '%s/%s': %w", namespace, name, err)
}
return secret.Data, nil
return secret, nil
}
// reconcileArtifact archives a new Artifact to the Storage, if the current

View File

@ -18,6 +18,7 @@ package controller
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
@ -33,7 +34,6 @@ import (
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/storage/memory"
. "github.com/onsi/gomega"
sshtestdata "golang.org/x/crypto/ssh/testdata"
@ -349,6 +349,8 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
server options
secret *corev1.Secret
beforeFunc func(obj *sourcev1.GitRepository)
secretFunc func(secret *corev1.Secret, baseURL string)
middlewareFunc gittestserver.HTTPMiddleware
want sreconcile.Result
wantErr bool
assertConditions []metav1.Condition
@ -528,6 +530,85 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "foo"),
},
},
{
name: "mTLS GitHub App without ca.crt makes FetchFailed=True",
protocol: "https",
server: options{
publicKey: tlsPublicKey,
privateKey: tlsPrivateKey,
ca: tlsCA,
},
secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "gh-app-no-ca"},
Data: map[string][]byte{
github.KeyAppID: []byte("123"),
github.KeyAppInstallationID: []byte("456"),
github.KeyAppPrivateKey: sshtestdata.PEMBytes["rsa"],
},
},
beforeFunc: func(obj *sourcev1.GitRepository) {
obj.Spec.Provider = sourcev1.GitProviderGitHub
obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "gh-app-no-ca"}
conditions.MarkReconciling(obj, meta.ProgressingReason, "foo")
conditions.MarkUnknown(obj, meta.ReadyCondition, meta.ProgressingWithRetryReason, "foo")
},
secretFunc: func(secret *corev1.Secret, baseURL string) {
secret.Data[github.KeyAppBaseURL] = []byte(baseURL + "/api/v3")
},
wantErr: true,
assertConditions: []metav1.Condition{
// should record a FetchFailedCondition due to TLS handshake
*conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "x509: "),
*conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"),
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingWithRetryReason, "foo"),
},
},
{
name: "mTLS GitHub App with ca.crt makes Reconciling=True",
protocol: "https",
server: options{
publicKey: tlsPublicKey,
privateKey: tlsPrivateKey,
ca: tlsCA,
username: github.AccessTokenUsername,
password: "some-enterprise-token",
},
secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "gh-app-ca"},
Data: map[string][]byte{
github.KeyAppID: []byte("123"),
github.KeyAppInstallationID: []byte("456"),
github.KeyAppPrivateKey: sshtestdata.PEMBytes["rsa"],
},
},
beforeFunc: func(obj *sourcev1.GitRepository) {
obj.Spec.Provider = sourcev1.GitProviderGitHub
obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "gh-app-ca"}
},
secretFunc: func(secret *corev1.Secret, baseURL string) {
secret.Data[github.KeyAppBaseURL] = []byte(baseURL + "/api/v3")
secret.Data["ca.crt"] = tlsCA
},
middlewareFunc: func(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/v3/app/installations/") {
w.WriteHeader(http.StatusOK)
tok := &github.AppToken{
Token: "some-enterprise-token",
ExpiresAt: time.Now().Add(time.Hour),
}
_ = json.NewEncoder(w).Encode(tok)
}
handler.ServeHTTP(w, r)
})
},
wantErr: false,
want: sreconcile.ResultSuccess,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new upstream revision 'master@sha1:<commit>'"),
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new upstream revision 'master@sha1:<commit>'"),
},
},
// TODO: Add test case for HTTPS with bearer token auth secret. It
// depends on gitkit to have support for bearer token based
// authentication.
@ -674,6 +755,34 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "foo"),
},
},
{
// This test is only for verifying the failure state when using
// provider auth. Protocol http is used for simplicity.
name: "github provider without github app data in secret makes FetchFailed=True",
protocol: "http",
secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "github-basic-auth",
},
Data: map[string][]byte{
"username": []byte("abc"),
"password": []byte("1234"),
},
},
beforeFunc: func(obj *sourcev1.GitRepository) {
obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "github-basic-auth"}
obj.Spec.Provider = sourcev1.GitProviderGitHub
conditions.MarkReconciling(obj, meta.ProgressingReason, "foo")
conditions.MarkUnknown(obj, meta.ReadyCondition, meta.ProgressingReason, "foo")
},
want: sreconcile.ResultEmpty,
wantErr: true,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.InvalidProviderConfigurationReason, "secretRef with github app data must be specified when provider is set to github"),
*conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"),
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "foo"),
},
},
}
for _, tt := range tests {
@ -696,6 +805,10 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
defer os.RemoveAll(server.Root())
server.AutoCreate()
if tt.middlewareFunc != nil {
server.AddHTTPMiddlewares(tt.middlewareFunc)
}
repoPath := "/test.git"
localRepo, err := initGitRepo(server, "testdata/git/repository", git.DefaultBranch, repoPath)
g.Expect(err).NotTo(HaveOccurred())
@ -740,6 +853,10 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
tt.beforeFunc(obj)
}
if tt.secretFunc != nil {
tt.secretFunc(secret, server.HTTPAddress())
}
clientBuilder := fakeclient.NewClientBuilder().
WithScheme(testEnv.GetScheme()).
WithStatusSubresource(&sourcev1.GitRepository{})
@ -850,6 +967,26 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
},
wantErr: "secretRef '/githubAppSecret' has github app data but provider is not set to github",
},
{
name: "github provider with basic auth secret",
url: "https://github.com/org/repo.git",
secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "basic-auth-secret",
},
Data: map[string][]byte{
"username": []byte("abc"),
"password": []byte("1234"),
},
},
beforeFunc: func(obj *sourcev1.GitRepository) {
obj.Spec.Provider = sourcev1.GitProviderGitHub
obj.Spec.SecretRef = &meta.LocalObjectReference{
Name: "basic-auth-secret",
}
},
wantErr: "secretRef with github app data must be specified when provider is set to github",
},
{
name: "generic provider",
url: "https://example.com/org/repo",
@ -2230,85 +2367,6 @@ func TestGitRepositoryReconciler_verifySignature(t *testing.T) {
}
}
func TestGitRepositoryReconciler_getProxyOpts(t *testing.T) {
invalidProxy := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "invalid-proxy",
Namespace: "default",
},
Data: map[string][]byte{
"url": []byte("https://example.com"),
},
}
validProxy := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "valid-proxy",
Namespace: "default",
},
Data: map[string][]byte{
"address": []byte("https://example.com"),
"username": []byte("user"),
"password": []byte("pass"),
},
}
clientBuilder := fakeclient.NewClientBuilder().
WithScheme(testEnv.GetScheme()).
WithObjects(invalidProxy, validProxy)
r := &GitRepositoryReconciler{
Client: clientBuilder.Build(),
}
tests := []struct {
name string
secret string
err string
proxyOpts *transport.ProxyOptions
proxyURL *url.URL
}{
{
name: "non-existent secret",
secret: "non-existent",
err: "failed to get proxy secret 'default/non-existent': ",
},
{
name: "invalid proxy secret",
secret: "invalid-proxy",
err: "invalid proxy secret 'default/invalid-proxy': key 'address' is missing",
},
{
name: "valid proxy secret",
secret: "valid-proxy",
proxyOpts: &transport.ProxyOptions{
URL: "https://example.com",
Username: "user",
Password: "pass",
},
proxyURL: &url.URL{
Scheme: "https",
Host: "example.com",
User: url.UserPassword("user", "pass"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
opts, proxyURL, err := r.getProxyOpts(context.TODO(), tt.secret, "default")
if opts != nil {
g.Expect(err).ToNot(HaveOccurred())
g.Expect(opts).To(Equal(tt.proxyOpts))
g.Expect(proxyURL).To(Equal(tt.proxyURL))
} else {
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring(tt.err))
}
})
}
}
func TestGitRepositoryReconciler_ConditionsUpdate(t *testing.T) {
g := NewWithT(t)