Skip to content

WIP: feat(namespacesync): add NamespaceSyncController for per-namespace resource management#3581

Draft
jkhelil wants to merge 7 commits into
tektoncd:mainfrom
jkhelil:rfe-7814-namespace-sync-controller
Draft

WIP: feat(namespacesync): add NamespaceSyncController for per-namespace resource management#3581
jkhelil wants to merge 7 commits into
tektoncd:mainfrom
jkhelil:rfe-7814-namespace-sync-controller

Conversation

@jkhelil

@jkhelil jkhelil commented Jun 26, 2026

Copy link
Copy Markdown
Member

Changes

Introduces a new NamespaceSyncController that replaces the
scan-based batch processing in rbac.go with an event-driven,
per-namespace reconciler. Addresses RFE-7814 (flexible service
account binding for Quay Robot credentials).

What this does

  • Adds NamespaceSyncController — a watch-based controller that
    reacts to Namespace, ServiceAccount, Secret, and TektonConfig
    events to ensure per-namespace Tekton resources are present and
    up to date in every user namespace
  • Creates pipeline SA, SCC RoleBinding, edit RoleBinding, and
    CA bundle ConfigMaps in each namespace
  • Manages openshift-pipelines-clusterinterceptors CRB
    incrementally (add/remove only the affected namespace's subject)
  • Supports Quay Robot secret binding via spec.platforms.openshift .namespaceSync.secretBindings (the core RFE-7814 use case)
  • Adds typed spec.platforms.openshift.namespaceSync API field to
    TektonConfig, replacing legacy spec.params entries
  • Removes ~1300 lines of dead per-namespace batch code from rbac.go
  • Registers the controller in the lifecycle container and adds
    LeaderAwareFuncs embedding (required by Knative sharedmain)
  • Adds namespaceSync schema to the TektonConfig CRD

Status

Work in progress — more e2e tests needed before merge:

  • E2E test: Quay Robot secret binding end-to-end
  • E2E test: namespace deletion removes CRB subject
  • E2E test: self-healing when pipeline SA is deleted manually
  • make test lint full pass

Verified on cluster

All per-namespace resources (pipeline SA, SCC RoleBinding, edit
RoleBinding, CA bundles, CRB subject) created correctly in new
namespaces within seconds. Established namespaces unaffected.

Submitter Checklist

Release Notes

Add NamespaceSyncController: event-driven per-namespace provisioning
of pipeline SA, SCC/edit RoleBindings, CA bundles, and Quay Robot
secret binding on OpenShift. Replaces legacy batch scan in rbac.go.
New typed API: spec.platforms.openshift.namespaceSync in TektonConfig.

Made with Cursor

jkhelil and others added 6 commits June 26, 2026 09:25
…source management

Add a new watch-based NamespaceSyncController that replaces the scan-based
per-namespace reconciliation loop in rbac.go. The new controller uses Kubernetes
informers to react to namespace, ServiceAccount, Secret, and TektonConfig events,
eliminating O(N) API server calls on every TektonConfig reconcile.

New typed API in TektonConfig.spec.platforms.openShift.namespaceSync:
- createPipelineSA: manage the pipeline ServiceAccount (replaces createRbacResource)
- createCABundles: manage CA bundle ConfigMaps (replaces createCABundleConfigMaps)
- createEditRoleBinding: manage openshift-pipelines-edit RoleBinding (replaces legacyPipelineRbac)
- createSCCRoleBinding: manage pipelines-scc-rolebinding (defaults true)
- secretBindings: bind registry secrets (by name or label selector) to the pipeline SA

Key behaviors:
- Pipeline SA self-heals on add/update/delete events
- Named secret bindings are removed from the pipeline SA when the secret is deleted
- Label-based bindings re-evaluate on every secret add/delete event
- TektonConfig updates only trigger a full namespace sweep when the NamespaceSync
  config itself changes (reflect.DeepEqual guard prevents thundering herd)
- Legacy spec.params entries are migrated to the typed fields on first reconcile

Design doc: docs/plans/2026-06-26-namespace-sync-controller-design.md

Signed-off-by: Abdeljaouad Khelil <akhelil@redhat.com>
Assisted-by: Claude Sonnet 4.6
Co-authored-by: Cursor <cursoragent@cursor.com>
When TektonConfig.spec.platforms.openShift.namespaceSync is configured
(which is now the default), the NamespaceSyncController owns all per-namespace
resources (pipeline SA, CA bundles, SCC RoleBinding, edit RoleBinding, secret
bindings). The legacy rbac.go createResources loop now skips per-namespace
iteration and only maintains cluster-scoped resources:

- ensurePreRequisites: RBACInstallerSet, pipelines-scc-clusterrole, SCC validation
- removeAndUpdateNSFromCI: ClusterInterceptors ClusterRoleBinding cleanup
- handleClusterRoleBinding: keep openshift-pipelines-clusterinterceptors in sync
  using existing pipeline SAs collected via the new collectExistingPipelineSAs helper

This commit can be reverted independently to restore the legacy scan-based
per-namespace reconciliation without losing the NamespaceSyncController changes.

Signed-off-by: Abdeljaouad Khelil <akhelil@redhat.com>
Assisted-by: Claude Sonnet 4.6
Co-authored-by: Cursor <cursoragent@cursor.com>
…RoleBinding

The openshift-pipelines-clusterinterceptors ClusterRoleBinding grants the
pipeline SA in every user namespace get/list/watch access to
ClusterInterceptors, which EventListeners need to resolve webhook interceptors.

The previous implementation in rbac.go rebuilt the full subject list on every
TektonConfig reconcile (O(N) API calls). NamespaceSyncController now manages
this ClusterRoleBinding with a per-namespace patch:

- Pipeline SA created / namespace reconciled → subject is added (idempotent).
- Pipeline SA deleted → reconcile of that namespace removes the subject.
- RetryOnConflict handles concurrent updates from parallel namespace workers.
- ClusterRole is bootstrapped once; it never changes so no update path needed.

Five new tests cover: creation, no-op when SA absent, idempotency,
multi-namespace accumulation, and subject removal on SA deletion.

Signed-off-by: Abdeljaoued Khelil <abdeljaouedkhelil@example.com>
Assisted-by: Claude Sonnet 4.6
Co-authored-by: Cursor <cursoragent@cursor.com>
Now that NamespaceSyncController handles the openshift-pipelines-clusterinterceptors
ClusterRoleBinding incrementally per namespace, rbac.go no longer needs to:

- Accumulate all pipeline SAs via collectExistingPipelineSAs
- Rebuild the full subject list via handleClusterRoleBinding

The NamespaceSync guard in createResources is simplified: it now only calls
ensurePreRequisites (cluster-scoped SCC ClusterRole + validation) before
returning; all other RBAC and secret binding work is owned by the new controller.

Signed-off-by: Abdeljaoued Khelil <abdeljaouedkhelil@example.com>
Assisted-by: Claude Sonnet 4.6
Co-authored-by: Cursor <cursoragent@cursor.com>
…ped work

Now that NamespaceSyncController owns all per-namespace resources (pipeline SA,
CA bundles, SCC RoleBinding, edit RoleBinding, secret bindings, ClusterInterceptors
subjects) and NamespaceSync is always defaulted to non-nil, the legacy per-namespace
branch of rbac.go is permanently unreachable.

Removed (~1 350 lines):
  - shouldIgnoreNamespace, needsRBAC, needsCABundle, getNamespacesToBeReconciled
  - processRBAC, handleSCCInNamespace, getSCCRoleInNamespace, patchNamespaceLabel
  - ensureSA, createSA, ensureSCCRoleInNamespace
  - ensurePipelinesSCCRoleBinding, createSCCRoleBinding, updateRoleBinding
  - ensureCABundles, ensureCABundlesInNamespace, createCABundleConfigMaps
  - createServiceCABundleConfigMap, patchNamespaceTrustedConfigLabel
  - ensureRoleBindings, createRoleBinding, isLegacyRBACEnabled
  - handleClusterRoleBinding, bulkUpdateClusterRoleBinding, bulkCreateClusterRoleBinding
  - createClusterRole, removeAndUpdateNSFromCI, removeIndex
  - updateOwnerRefs, removeAndUpdate, hasSubject, CompareSubjects, mergeSubjects
  - hasOwnerRefernce, cleanUpRBACNameChange (TODO: remove after v0.55.0 - now done)
  - NamespaceServiceAccount, NamespacesToReconcile types

Kept:
  - createResources → only calls ensurePreRequisites (cluster-scoped)
  - ensurePreRequisites: InstallerSet, SCC validation, pipelines-scc-clusterrole
  - ensurePipelinesSCClusterRole: dynamic ClusterRole for default SCC
  - EnsureRBACInstallerSet, cleanUp, setDefault, removeObsoleteRBACInstallerSet

extension.go: removed rbacInformer field (no longer needed), removed
cleanUpRBACNameChange call, removed unused rbacV1 and rbacInformer imports.

rbac_test.go: replaced 500-line dead-path test with focused tests for
createResources (prerequisites path) and setDefault.

Signed-off-by: Abdeljaoued Khelil <abdeljaouedkhelil@example.com>
Assisted-by: Claude Sonnet 4.6
Co-authored-by: Cursor <cursoragent@cursor.com>
Add the namespacesync controller to the lifecycle container's
-controllers arg so it actually runs on OpenShift. Add the
namespaceSync field schema to the TektonConfig CRD so the
API server accepts it. Embed reconciler.LeaderAwareFuncs in
the Reconciler struct to satisfy Knative sharedmain's
leader-election requirement.

Signed-off-by: Jawed khelil <jkhelil@redhat.com>
Assisted-by: Claude Sonnet 4.6 (via Cursor)
Co-authored-by: Cursor <cursoragent@cursor.com>
@tekton-robot tekton-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Jun 26, 2026
@tekton-robot tekton-robot requested a review from infernus01 June 26, 2026 09:23
@tekton-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To complete the pull request process, please ask for approval from jkhelil after the PR has been reviewed.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@tekton-robot tekton-robot requested a review from pratap0007 June 26, 2026 09:23
@tekton-robot tekton-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jun 26, 2026
The e2e test referenced tconfig.PipelineRoleBinding from the
tektonconfig package, which no longer exists after the rbac.go
cleanup. Export the constant from namespacesync (its new owner)
and update the test import alias accordingly.

Signed-off-by: Jawed khelil <jkhelil@redhat.com>
Assisted-by: Claude Sonnet 4.6 (via Cursor)
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants