@@ -89,26 +89,37 @@ type KustomizationReconciler struct {
8989 kuberecorder.EventRecorder
9090 runtimeCtrl.Metrics
9191
92- artifactFetchRetries int
93- requeueDependency time.Duration
94-
95- Mapper apimeta.RESTMapper
96- APIReader client.Reader
97- ClusterReader engine.ClusterReaderFactory
98- ControllerName string
99- statusManager string
100- NoCrossNamespaceRefs bool
101- NoRemoteBases bool
92+ // Kubernetes options
93+
94+ APIReader client.Reader
95+ ClusterReader engine.ClusterReaderFactory
96+ ConcurrentSSA int
97+ ControllerName string
98+ KubeConfigOpts runtimeClient.KubeConfigOptions
99+ Mapper apimeta.RESTMapper
100+ StatusManager string
101+
102+ // Multi-tenancy and security options
103+
104+ DefaultServiceAccount string
105+ DisallowedFieldManagers []string
106+ NoCrossNamespaceRefs bool
107+ NoRemoteBases bool
108+ SOPSAgeSecret string
109+ TokenCache * cache.TokenCache
110+
111+ // Retry and requeue options
112+
113+ ArtifactFetchRetries int
114+ DependencyRequeueInterval time.Duration
115+
116+ // Feature gates
117+
118+ AdditiveCELDependencyCheck bool
119+ AllowExternalArtifact bool
102120 FailFast bool
103- DefaultServiceAccount string
104- SOPSAgeSecret string
105- KubeConfigOpts runtimeClient.KubeConfigOptions
106- ConcurrentSSA int
107- DisallowedFieldManagers []string
108- StrictSubstitutions bool
109121 GroupChangeLog bool
110- AdditiveCELDependencyCheck bool
111- TokenCache * cache.TokenCache
122+ StrictSubstitutions bool
112123}
113124
114125func (r * KustomizationReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (result ctrl.Result , retErr error ) {
@@ -207,9 +218,9 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
207218
208219 if acl .IsAccessDenied (err ) {
209220 conditions .MarkFalse (obj , meta .ReadyCondition , apiacl .AccessDeniedReason , "%s" , err )
210- log . Error ( err , "Access denied to cross-namespace source" )
221+ conditions . MarkStalled ( obj , apiacl . AccessDeniedReason , "%s" , err )
211222 r .event (obj , "" , "" , eventv1 .EventSeverityError , err .Error (), nil )
212- return ctrl.Result {RequeueAfter : obj . GetRetryInterval ()}, nil
223+ return ctrl.Result {}, reconcile . TerminalError ( err )
213224 }
214225
215226 // Retry with backoff on transient errors.
@@ -218,10 +229,10 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
218229
219230 // Requeue the reconciliation if the source artifact is not found.
220231 if artifactSource .GetArtifact () == nil {
221- msg := fmt .Sprintf ("Source artifact not found, retrying in %s" , r .requeueDependency .String ())
232+ msg := fmt .Sprintf ("Source artifact not found, retrying in %s" , r .DependencyRequeueInterval .String ())
222233 conditions .MarkFalse (obj , meta .ReadyCondition , meta .ArtifactFailedReason , "%s" , msg )
223234 log .Info (msg )
224- return ctrl.Result {RequeueAfter : r .requeueDependency }, nil
235+ return ctrl.Result {RequeueAfter : r .DependencyRequeueInterval }, nil
225236 }
226237 revision := artifactSource .GetArtifact ().Revision
227238 originRevision := getOriginRevision (artifactSource )
@@ -241,10 +252,10 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
241252
242253 // Retry on transient errors.
243254 conditions .MarkFalse (obj , meta .ReadyCondition , meta .DependencyNotReadyReason , "%s" , err )
244- msg := fmt .Sprintf ("Dependencies do not meet ready condition, retrying in %s" , r .requeueDependency .String ())
255+ msg := fmt .Sprintf ("Dependencies do not meet ready condition, retrying in %s" , r .DependencyRequeueInterval .String ())
245256 log .Info (msg )
246257 r .event (obj , revision , originRevision , eventv1 .EventSeverityInfo , msg , nil )
247- return ctrl.Result {RequeueAfter : r .requeueDependency }, nil
258+ return ctrl.Result {RequeueAfter : r .DependencyRequeueInterval }, nil
248259 }
249260 log .Info ("All dependencies are ready, proceeding with reconciliation" )
250261 }
@@ -254,10 +265,10 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
254265
255266 // Requeue at the specified retry interval if the artifact tarball is not found.
256267 if errors .Is (reconcileErr , fetch .ErrFileNotFound ) {
257- msg := fmt .Sprintf ("Source is not ready, artifact not found, retrying in %s" , r .requeueDependency .String ())
268+ msg := fmt .Sprintf ("Source is not ready, artifact not found, retrying in %s" , r .DependencyRequeueInterval .String ())
258269 conditions .MarkFalse (obj , meta .ReadyCondition , meta .ArtifactFailedReason , "%s" , msg )
259270 log .Info (msg )
260- return ctrl.Result {RequeueAfter : r .requeueDependency }, nil
271+ return ctrl.Result {RequeueAfter : r .DependencyRequeueInterval }, nil
261272 }
262273
263274 // Broadcast the reconciliation failure and requeue at the specified retry interval.
@@ -318,7 +329,7 @@ func (r *KustomizationReconciler) reconcile(
318329 // Download artifact and extract files to the tmp dir.
319330 fetcher := fetch .New (
320331 fetch .WithLogger (ctrl .LoggerFrom (ctx )),
321- fetch .WithRetries (r .artifactFetchRetries ),
332+ fetch .WithRetries (r .ArtifactFetchRetries ),
322333 fetch .WithMaxDownloadSize (tar .UnlimitedUntarSize ),
323334 fetch .WithUntar (tar .WithMaxUntarSize (tar .UnlimitedUntarSize )),
324335 fetch .WithHostnameOverwrite (os .Getenv ("SOURCE_CONTROLLER_LOCALHOST" )),
@@ -625,12 +636,20 @@ func (r *KustomizationReconciler) getSource(ctx context.Context,
625636 Name : obj .Spec .SourceRef .Name ,
626637 }
627638
639+ // Check if cross-namespace references are allowed.
628640 if r .NoCrossNamespaceRefs && sourceNamespace != obj .GetNamespace () {
629641 return src , acl .AccessDeniedError (
630642 fmt .Sprintf ("can't access '%s/%s', cross-namespace references have been blocked" ,
631643 obj .Spec .SourceRef .Kind , namespacedName ))
632644 }
633645
646+ // Check if ExternalArtifact kind is allowed.
647+ if obj .Spec .SourceRef .Kind == sourcev1 .ExternalArtifactKind && ! r .AllowExternalArtifact {
648+ return src , acl .AccessDeniedError (
649+ fmt .Sprintf ("can't access '%s/%s', %s feature gate is disabled" ,
650+ obj .Spec .SourceRef .Kind , namespacedName , sourcev1 .ExternalArtifactKind ))
651+ }
652+
634653 switch obj .Spec .SourceRef .Kind {
635654 case sourcev1 .OCIRepositoryKind :
636655 var repository sourcev1.OCIRepository
@@ -1204,7 +1223,7 @@ func (r *KustomizationReconciler) patch(ctx context.Context,
12041223 patchOpts = append (patchOpts ,
12051224 patch.WithOwnedConditions {Conditions : ownedConditions },
12061225 patch.WithForceOverwriteConditions {},
1207- patch .WithFieldOwner (r .statusManager ),
1226+ patch .WithFieldOwner (r .StatusManager ),
12081227 )
12091228
12101229 // Patch the object status, conditions and finalizers.
0 commit comments