Merge pull request #1860 from abhijith-darshan/feat/gh_app_tls
Add support for mTLS to GitHub App transport
This commit is contained in:
commit
cd5eebfb32
|
|
@ -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
6
go.mod
|
|
@ -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
12
go.sum
|
|
@ -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=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue