Skip to content

Fix CVEs in multicloud-integrations - #591

Merged
xiangjingli merged 3 commits into
stolostron:mainfrom
falconizmi:cve-fixes-integrations
Aug 13, 2026
Merged

Fix CVEs in multicloud-integrations#591
xiangjingli merged 3 commits into
stolostron:mainfrom
falconizmi:cve-fixes-integrations

Conversation

@falconizmi

@falconizmi falconizmi commented Aug 12, 2026

Copy link
Copy Markdown
Contributor
  • CVE-2026-72526 (f001) — gate pull-model propagation on namespace PlacementDecision
  • CVE-2026-70398 (f002) — gate cross-namespace argoNamespace on admin Namespace label

Summary by CodeRabbit

  • New Features

    • Added authorization controls for cross-namespace Argo CD secret access. Target namespaces must be explicitly labeled by an administrator.
    • Added validation to ensure applications target clusters selected through placement decisions.
  • Bug Fixes

    • Unauthorized namespace or cluster access is now rejected with an updated status and reconciliation retry.
    • Tenant annotations can no longer bypass namespace authorization checks, while still allowing liveness verification to be skipped.

The ocm-managed-cluster annotation on an Application is tenant-controlled
input, but Reconcile() used it verbatim as the ManifestWork target
namespace with only a bare existence check on the ManagedCluster. A
tenant with namespaced create on applications.argoproj.io could direct
the controller (which holds cluster-wide manifestworks:create) to write a
ManifestWork into any managed-cluster hub namespace, yielding
cluster-admin on an arbitrary spoke via the spoke's openshift-gitops
ArgoCD instance.

This adds isClusterBoundToNamespace(): the controller now requires that a
PlacementDecision in the Application's own namespace selects the target
cluster. PlacementDecisions are written by the OCM placement controller
and a Placement can only select clusters from ManagedClusterSets that an
admin has bound to the namespace via ManagedClusterSetBinding, so a
matching decision proves the namespace is authorized to target the
cluster.

CWEs: CWE-441, CWE-639
Signed-off-by: Ismail Ibrahim Quwarah <iquwarah@redhat.com>
spec.argoServer.argoNamespace is taken verbatim from the namespaced
GitOpsCluster CR and used as the destination for managed-cluster
bearer-token Secrets that the controller copies out of privileged
managed-cluster namespaces. The only existing guard
(VerifyArgocdNamespace, a Service-label probe) was both
tenant-spoofable and bypassable via the tenant-settable
skipArgoNamespaceVerify annotation, so a tenant could redirect spoke
tokens into a namespace they read.

reconcileGitOpsCluster now calls verifyArgoNamespaceAuthorized() before
any other processing: same-namespace writes pass; cross-namespace
writes are permitted only when a cluster admin has labelled the target
Namespace with apps.open-cluster-management.io/gitops-argo-namespace=true.
Namespace labels require cluster-scoped update on namespaces, which a
namespaced tenant does not hold, so the opt-in cannot be self-granted.
The skipArgoNamespaceVerify annotation continues to skip only the
liveness probe and no longer bypasses authorization.

CWEs: CWE-441, CWE-522
Signed-off-by: Ismail Ibrahim Quwarah <iquwarah@redhat.com>
@openshift-ci

openshift-ci Bot commented Aug 12, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: falconizmi

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

The pull request process is described 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

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: stolostron/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: aceb3c19-ecba-487b-8717-3aa172cf0f8e

📥 Commits

Reviewing files that changed from the base of the PR and between 9d153e3 and 933e8f8.

📒 Files selected for processing (1)
  • pkg/controller/gitopscluster/gitopscluster_controller_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/controller/gitopscluster/gitopscluster_controller_test.go

Walkthrough

The PR adds ArgoCD namespace authorization for GitOpsCluster reconciliation and PlacementDecision-based authorization for propagated Applications. It registers the cluster API scheme, adds PlacementDecision RBAC permissions, and extends tests and fixtures.

Changes

Authorization controls

Layer / File(s) Summary
ArgoCD namespace authorization and reconciliation gate
pkg/controller/gitopscluster/gitopscluster_controller.go, pkg/controller/gitopscluster/gitopscluster_controller_test.go
Same-namespace access remains allowed. Cross-namespace access requires an existing Namespace with the authorization label set to true. Reconciliation performs this check before liveness verification and updates status when authorization fails.
PlacementDecision cluster binding
cmd/propagation/main.go, propagation-controller/application/application_controller.go, propagation-controller/application/helper_test.go
The cluster API is registered, PlacementDecision read permissions are added, and Applications proceed only when a PlacementDecision selects the target ManagedCluster.
Authorization test fixtures
pkg/controller/gitopscluster/gitopscluster_controller_test.go
Tests cover same-namespace access, labeled cross-namespace access, rejected namespaces, and labeled ArgoCD fixtures used by placement tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Mergeability Score: ⚪ Minimal · up to 933e8

The pull request applies narrowly scoped CVE-related behavior changes, and no actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant GitOpsClusterReconciler
  participant KubernetesNamespaceAPI
  participant ArgoServerVerification
  GitOpsClusterReconciler->>KubernetesNamespaceAPI: verify target namespace authorization
  KubernetesNamespaceAPI-->>GitOpsClusterReconciler: namespace authorization result
  GitOpsClusterReconciler->>ArgoServerVerification: verify liveness when authorized
Loading
sequenceDiagram
  participant ApplicationReconciler
  participant PlacementDecisionAPI
  participant ManifestWorkAPI
  ApplicationReconciler->>PlacementDecisionAPI: list PlacementDecisions
  PlacementDecisionAPI-->>ApplicationReconciler: cluster selection result
  ApplicationReconciler->>ManifestWorkAPI: reconcile ManifestWork when selected
Loading

Suggested reviewers: xiangjingli, philipwu08

🚥 Pre-merge checks | ✅ 9 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Test Structure And Quality ⚠️ Warning The PR adds require.NoError, assert.Error, and assert.NoError calls without meaningful failure messages in TestVerifyArgoNamespaceAuthorized. Add case-specific messages to the scheme setup and authorization assertions, such as the namespace and expected authorization outcome.
✅ Passed checks (9 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the pull request's primary objective: fixing two CVEs in multicloud-integrations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed The PR diff adds only standard Go Test/t.Run cases with literal table names; it introduces no Ginkgo It, Describe, Context, or When titles with dynamic values.
No-Weak-Crypto ✅ Passed The PR diff adds scheme registration and authorization checks only; it introduces no MD5, SHA1, DES, RC4, Blowfish, ECB, custom crypto, or secret/token comparisons. The existing SHA-1 comment is un...
Container-Privileges ✅ Passed The complete PR diff changes only Go source and tests; it adds no container/Kubernetes privilege settings or manifest entries matching the custom check.
No-Sensitive-Data-In-Logs ✅ Passed The PR adds no logs of passwords, tokens, API keys, PII, or payload data. New logs contain only resource namespace/name, managedCluster, and authorization errors.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
pkg/controller/gitopscluster/gitopscluster_controller.go (1)

656-669: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Migrate to klog/v2 before using structured logging.

Replace the import with k8s.io/klog/v2, then replace both klog.Errorf calls with klog.ErrorS and record namespace, name, and the error as structured fields.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/gitopscluster/gitopscluster_controller.go` around lines 656 -
669, Update the klog import to k8s.io/klog/v2, then convert both klog.Errorf
calls in the GitOpsCluster rejection and status-update error paths to
klog.ErrorS. Preserve their messages while passing namespace, name, and the
relevant error as structured key-value fields.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controller/gitopscluster/gitopscluster_controller_test.go`:
- Around line 103-151: Add meaningful failure messages to the require.NoError
setup assertion and both authorization assertions in
TestVerifyArgoNamespaceAuthorized. Identify the specific namespace authorization
case using the table test name and state whether authorization was expected to
succeed or fail.

In `@pkg/controller/gitopscluster/gitopscluster_controller.go`:
- Around line 668-670: Wrap err2 with operation context before returning from
the Status().Update failure branch in the GitOpsCluster reconciliation flow.
Replace the direct return of err2 with a fmt.Errorf-wrapped error that preserves
err2 using %w, while leaving the existing logging and retry result unchanged.
- Around line 76-83: Update reconcileGitOpsCluster and
verifyArgoNamespaceAuthorized to accept and propagate the reconciliation
context, then replace context.TODO() in the Namespace r.Get lookup with that ctx
so cancellation reaches the Kubernetes API call.
- Around line 650-655: Move the verifyArgoNamespaceAuthorized gate in the
GitOpsCluster reconciliation flow before ensureArgoCDAgentJWTSecret, so
unauthorized configurations cannot create secrets in the tenant-selected
namespace. Add a test covering an unlabelled target with
skipArgoNamespaceVerify=true and assert that no secret is created in that target
namespace.

In `@propagation-controller/application/application_controller.go`:
- Around line 112-115: Update ApplicationReconciler.isClusterBoundToNamespace so
the PlacementDecision List call uses a bounded child context with a local
timeout, ensuring the deadline is released afterward. When the call fails, wrap
the error with the operation and namespace context using fmt.Errorf with %w
before returning it.
- Around line 493-506: Update SetupWithManager to watch PlacementDecision
resources and map each event to Applications in the PlacementDecision’s
namespace, so binding changes enqueue affected Applications for reconciliation.
Add or update tests covering PlacementDecision create/update events and verify
they enqueue Applications in the same namespace while preserving the existing
Application watch.

---

Nitpick comments:
In `@pkg/controller/gitopscluster/gitopscluster_controller.go`:
- Around line 656-669: Update the klog import to k8s.io/klog/v2, then convert
both klog.Errorf calls in the GitOpsCluster rejection and status-update error
paths to klog.ErrorS. Preserve their messages while passing namespace, name, and
the relevant error as structured key-value fields.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: stolostron/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a9fdbfd4-eb33-4729-a4ea-59235fbe3bd1

📥 Commits

Reviewing files that changed from the base of the PR and between 7296973 and 9d153e3.

📒 Files selected for processing (5)
  • cmd/propagation/main.go
  • pkg/controller/gitopscluster/gitopscluster_controller.go
  • pkg/controller/gitopscluster/gitopscluster_controller_test.go
  • propagation-controller/application/application_controller.go
  • propagation-controller/application/helper_test.go

Comment thread pkg/controller/gitopscluster/gitopscluster_controller_test.go
Comment thread pkg/controller/gitopscluster/gitopscluster_controller.go
Comment thread pkg/controller/gitopscluster/gitopscluster_controller.go
Comment thread pkg/controller/gitopscluster/gitopscluster_controller.go
Comment thread propagation-controller/application/application_controller.go
Comment thread propagation-controller/application/application_controller.go
@xiangjingli

Copy link
Copy Markdown
Contributor

/retest

…t test

verifyArgoNamespaceAuthorized requires the target argocd namespace to
exist with LabelKeyAllowedArgoNamespace=true for cross-namespace
configurations. Without it, reconcile is rejected before reaching
the local-cluster-in-Placement check the test targets.

Signed-off-by: Ismail Ibrahim Quwarah <iquwarah@redhat.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
42.5% Coverage on New Code (required ≥ 70%)

See analysis details on SonarQube Cloud

@openshift-ci

openshift-ci Bot commented Aug 13, 2026

Copy link
Copy Markdown

@falconizmi: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/sonarcloud 933e8f8 link true /test sonarcloud

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@xiangjingli
xiangjingli merged commit 6ae9a09 into stolostron:main Aug 13, 2026
15 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants