(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:
parent
bd6d090ef0
commit
46522f9815
|
@ -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