@@ -44,6 +44,7 @@ import (
4444 kstatus "sigs.k8s.io/cli-utils/pkg/kstatus/status"
4545 "sigs.k8s.io/controller-runtime/pkg/client"
4646 "sigs.k8s.io/controller-runtime/pkg/client/fake"
47+ fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
4748 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
4849
4950 "github.com/fluxcd/pkg/apis/meta"
@@ -893,21 +894,11 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) {
893894 chartPath = "testdata/charts/helmchart-0.1.0.tgz"
894895 )
895896
896- // Login to the registry
897- err := testRegistryServer .registryClient .Login (testRegistryServer .registryHost ,
898- helmreg .LoginOptBasicAuth (testRegistryUsername , testRegistryPassword ),
899- helmreg .LoginOptInsecure (true ))
900- g .Expect (err ).NotTo (HaveOccurred ())
901-
902897 // Load a test chart
903898 chartData , err := ioutil .ReadFile (chartPath )
904- g .Expect (err ).NotTo (HaveOccurred ())
905- metadata , err := extractChartMeta (chartData )
906- g .Expect (err ).NotTo (HaveOccurred ())
907899
908900 // Upload the test chart
909- ref := fmt .Sprintf ("%s/testrepo/%s:%s" , testRegistryServer .registryHost , metadata .Name , metadata .Version )
910- _ , err = testRegistryServer .registryClient .Push (chartData , ref )
901+ metadata , err := loadTestChartToOCI (chartData , chartPath , testRegistryServer )
911902 g .Expect (err ).NotTo (HaveOccurred ())
912903
913904 storage , err := NewStorage (tmpDir , "example.com" , retentionTTL , retentionRecords )
@@ -2038,6 +2029,194 @@ func TestHelmChartReconciler_notify(t *testing.T) {
20382029 }
20392030}
20402031
2032+ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy (t * testing.T ) {
2033+ const (
2034+ chartPath = "testdata/charts/helmchart-0.1.0.tgz"
2035+ )
2036+
2037+ type secretOptions struct {
2038+ username string
2039+ password string
2040+ }
2041+
2042+ tests := []struct {
2043+ name string
2044+ url string
2045+ registryOpts registryOptions
2046+ secretOpts secretOptions
2047+ provider string
2048+ providerImg string
2049+ want sreconcile.Result
2050+ wantErr bool
2051+ assertConditions []metav1.Condition
2052+ }{
2053+ {
2054+ name : "HTTP without basic auth" ,
2055+ want : sreconcile .ResultSuccess ,
2056+ assertConditions : []metav1.Condition {
2057+ * conditions .TrueCondition (sourcev1 .ArtifactOutdatedCondition , "NewChart" , "pulled '<helmchart>' chart with version '<version>'" ),
2058+ },
2059+ },
2060+ {
2061+ name : "HTTP with basic auth secret" ,
2062+ want : sreconcile .ResultSuccess ,
2063+ registryOpts : registryOptions {
2064+ withBasicAuth : true ,
2065+ },
2066+ secretOpts : secretOptions {
2067+ username : testRegistryUsername ,
2068+ password : testRegistryPassword ,
2069+ },
2070+ assertConditions : []metav1.Condition {
2071+ * conditions .TrueCondition (sourcev1 .ArtifactOutdatedCondition , "NewChart" , "pulled '<helmchart>' chart with version '<version>'" ),
2072+ },
2073+ },
2074+ {
2075+ name : "HTTP registry - basic auth with invalid secret" ,
2076+ want : sreconcile .ResultEmpty ,
2077+ wantErr : true ,
2078+ registryOpts : registryOptions {
2079+ withBasicAuth : true ,
2080+ },
2081+ secretOpts : secretOptions {
2082+ username : "wrong-pass" ,
2083+ password : "wrong-pass" ,
2084+ },
2085+ assertConditions : []metav1.Condition {
2086+ * conditions .TrueCondition (sourcev1 .FetchFailedCondition , "Unknown" , "unknown build error: failed to login to OCI registry" ),
2087+ },
2088+ },
2089+ {
2090+ name : "with contextual login provider" ,
2091+ wantErr : true ,
2092+ provider : "aws" ,
2093+ providerImg : "oci://123456789000.dkr.ecr.us-east-2.amazonaws.com/test" ,
2094+ assertConditions : []metav1.Condition {
2095+ * conditions .TrueCondition (sourcev1 .FetchFailedCondition , "Unknown" , "unknown build error: failed to get credential from" ),
2096+ },
2097+ },
2098+ {
2099+ name : "with contextual login provider and secretRef" ,
2100+ want : sreconcile .ResultSuccess ,
2101+ registryOpts : registryOptions {
2102+ withBasicAuth : true ,
2103+ },
2104+ secretOpts : secretOptions {
2105+ username : testRegistryUsername ,
2106+ password : testRegistryPassword ,
2107+ },
2108+ provider : "azure" ,
2109+ assertConditions : []metav1.Condition {
2110+ * conditions .TrueCondition (sourcev1 .ArtifactOutdatedCondition , "NewChart" , "pulled '<helmchart>' chart with version '<version>'" ),
2111+ },
2112+ },
2113+ }
2114+
2115+ for _ , tt := range tests {
2116+ t .Run (tt .name , func (t * testing.T ) {
2117+ g := NewWithT (t )
2118+
2119+ builder := fakeclient .NewClientBuilder ().WithScheme (testEnv .GetScheme ())
2120+ workspaceDir := t .TempDir ()
2121+ server , err := setupRegistryServer (ctx , workspaceDir , tt .registryOpts )
2122+
2123+ g .Expect (err ).NotTo (HaveOccurred ())
2124+
2125+ // Load a test chart
2126+ chartData , err := ioutil .ReadFile (chartPath )
2127+
2128+ // Upload the test chart
2129+ metadata , err := loadTestChartToOCI (chartData , chartPath , server )
2130+ g .Expect (err ).NotTo (HaveOccurred ())
2131+ g .Expect (err ).ToNot (HaveOccurred ())
2132+
2133+ repo := & sourcev1.HelmRepository {
2134+ ObjectMeta : metav1.ObjectMeta {
2135+ GenerateName : "auth-strategy-" ,
2136+ },
2137+ Spec : sourcev1.HelmRepositorySpec {
2138+ Interval : metav1.Duration {Duration : interval },
2139+ Timeout : & metav1.Duration {Duration : timeout },
2140+ Type : sourcev1 .HelmRepositoryTypeOCI ,
2141+ Provider : sourcev1 .GenericOCIProvider ,
2142+ URL : fmt .Sprintf ("oci://%s/testrepo" , server .registryHost ),
2143+ },
2144+ }
2145+
2146+ if tt .provider != "" {
2147+ repo .Spec .Provider = tt .provider
2148+ }
2149+ // If a provider specific image is provided, overwrite existing URL
2150+ // set earlier. It'll fail but it's necessary to set them because
2151+ // the login check expects the URLs to be of certain pattern.
2152+ if tt .providerImg != "" {
2153+ repo .Spec .URL = tt .providerImg
2154+ }
2155+
2156+ if tt .secretOpts .username != "" && tt .secretOpts .password != "" {
2157+ secret := & corev1.Secret {
2158+ ObjectMeta : metav1.ObjectMeta {
2159+ Name : "auth-secretref" ,
2160+ },
2161+ Type : corev1 .SecretTypeDockerConfigJson ,
2162+ Data : map [string ][]byte {
2163+ ".dockerconfigjson" : []byte (fmt .Sprintf (`{"auths": {%q: {"username": %q, "password": %q}}}` ,
2164+ server .registryHost , tt .secretOpts .username , tt .secretOpts .password )),
2165+ },
2166+ }
2167+
2168+ repo .Spec .SecretRef = & meta.LocalObjectReference {
2169+ Name : secret .Name ,
2170+ }
2171+ builder .WithObjects (secret , repo )
2172+ } else {
2173+ builder .WithObjects (repo )
2174+ }
2175+
2176+ obj := & sourcev1.HelmChart {
2177+ ObjectMeta : metav1.ObjectMeta {
2178+ GenerateName : "auth-strategy-" ,
2179+ },
2180+ Spec : sourcev1.HelmChartSpec {
2181+ Chart : metadata .Name ,
2182+ Version : metadata .Version ,
2183+ SourceRef : sourcev1.LocalHelmChartSourceReference {
2184+ Kind : sourcev1 .HelmRepositoryKind ,
2185+ Name : repo .Name ,
2186+ },
2187+ Interval : metav1.Duration {Duration : interval },
2188+ },
2189+ }
2190+
2191+ r := & HelmChartReconciler {
2192+ Client : builder .Build (),
2193+ EventRecorder : record .NewFakeRecorder (32 ),
2194+ Getters : testGetters ,
2195+ RegistryClientGenerator : registry .ClientGenerator ,
2196+ }
2197+
2198+ var b chart.Build
2199+ defer func () {
2200+ if _ , err := os .Stat (b .Path ); ! os .IsNotExist (err ) {
2201+ err := os .Remove (b .Path )
2202+ g .Expect (err ).NotTo (HaveOccurred ())
2203+ }
2204+ }()
2205+
2206+ assertConditions := tt .assertConditions
2207+ for k := range assertConditions {
2208+ assertConditions [k ].Message = strings .ReplaceAll (assertConditions [k ].Message , "<helmchart>" , metadata .Name )
2209+ assertConditions [k ].Message = strings .ReplaceAll (assertConditions [k ].Message , "<version>" , metadata .Version )
2210+ }
2211+
2212+ got , err := r .reconcileSource (ctx , obj , & b )
2213+ g .Expect (err != nil ).To (Equal (tt .wantErr ))
2214+ g .Expect (got ).To (Equal (tt .want ))
2215+ g .Expect (obj .Status .Conditions ).To (conditions .MatchConditions (tt .assertConditions ))
2216+ })
2217+ }
2218+ }
2219+
20412220// extractChartMeta is used to extract a chart metadata from a byte array
20422221func extractChartMeta (chartData []byte ) (* hchart.Metadata , error ) {
20432222 ch , err := loader .LoadArchive (bytes .NewReader (chartData ))
@@ -2046,3 +2225,32 @@ func extractChartMeta(chartData []byte) (*hchart.Metadata, error) {
20462225 }
20472226 return ch .Metadata , nil
20482227}
2228+
2229+ func loadTestChartToOCI (chartData []byte , chartPath string , server * registryClientTestServer ) (* hchart.Metadata , error ) {
2230+ // Login to the registry
2231+ err := server .registryClient .Login (server .registryHost ,
2232+ helmreg .LoginOptBasicAuth (testRegistryUsername , testRegistryPassword ),
2233+ helmreg .LoginOptInsecure (true ))
2234+ if err != nil {
2235+ return nil , err
2236+ }
2237+
2238+ // Load a test chart
2239+ chartData , err = ioutil .ReadFile (chartPath )
2240+ if err != nil {
2241+ return nil , err
2242+ }
2243+ metadata , err := extractChartMeta (chartData )
2244+ if err != nil {
2245+ return nil , err
2246+ }
2247+
2248+ // Upload the test chart
2249+ ref := fmt .Sprintf ("%s/testrepo/%s:%s" , server .registryHost , metadata .Name , metadata .Version )
2250+ _ , err = server .registryClient .Push (chartData , ref )
2251+ if err != nil {
2252+ return nil , err
2253+ }
2254+
2255+ return metadata , nil
2256+ }
0 commit comments