Repository navigation
Conversation
Same root cause as trustyai-explainability#908 (deployments, rolebindings): the manager's cached client establishes an informer/watch for any GVK it Lists or Gets, requiring the watch verb in addition to get/list. Two more call sites hit this that weren't covered by trustyai-explainability#908: - migration.go's adoptServices lists Services for in-tree adoption - dependencies.go's checkPrometheus lists Prometheus via the cached client (the InferenceService check uses RESTMapper discovery instead, so it doesn't need watch) Found by proactively auditing every List/Get call site in the package after Steven Tobin reported the Services watch failure, to catch the remaining latent gap before it surfaced separately.
|
Warning Review limit reachedNext included review available in 37 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe operator RBAC declarations now grant ChangesRBAC watch permissions
Estimated code review effort: 1 (Trivial) | ~2 minutes Merge Risk: ⚪ Minimal · up to This enables the operator's cached Service and Prometheus resource access without adding unrelated permissions, leaving no actionable merge-blocking risk. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
ruivieira
left a comment
There was a problem hiding this comment.
Thanks @kpunwatk LGTM.
Is it ok just to add the rego tests, eg (to policy/clusterrole.rego):
deny contains msg if {
input.kind == "ClusterRole"
input.metadata.name == "trustyai-operator-module-manager-role"
rule := input.rules[_]
"" in rule.apiGroups
"services" in rule.resources
not "watch" in rule.verbs
msg := "RBAC VIOLATION: TrustyAI module services permission must include watch."
}
deny contains msg if {
input.kind == "ClusterRole"
input.metadata.name == "trustyai-operator-module-manager-role"
rule := input.rules[_]
"monitoring.coreos.com" in rule.apiGroups
"prometheuses" in rule.resources
not "watch" in rule.verbs
msg := "RBAC VIOLATION: TrustyAI module prometheuses permission must include watch."
}
and to (policy/clusterrole_test.rego)
test_module_services_watch_required if {
count(deny) > 0 with input as {
"kind": "ClusterRole",
"metadata": {"name": "trustyai-operator-module-manager-role"},
"rules": [{
"apiGroups": [""],
"resources": ["services"],
"verbs": ["get", "list", "patch"],
}],
}
}
test_module_prometheuses_watch_required if {
count(deny) > 0 with input as {
"kind": "ClusterRole",
"metadata": {"name": "trustyai-operator-module-manager-role"},
"rules": [{
"apiGroups": ["monitoring.coreos.com"],
"resources": ["prometheuses"],
"verbs": ["get", "list"],
}],
}
}
Per Rui Vieira's review on trustyai-explainability#913: add deny rules to policy/clusterrole.rego that fail if the trustyai-operator-module-manager-role ClusterRole ever loses the watch verb on services or prometheuses, plus unit tests covering both the violation and the passing case. Also adds monitoring.coreos.com/prometheuses to the Layer 1 allowlist, which was missing despite the module already having get/list on it. Note: trustyai-operator-module isn't yet one of the kustomize entry points make policy-check renders (only the in-tree config/overlays/* paths are), so these rules currently only run via the unit tests in clusterrole_test.rego, not against the module's real rendered manifests. Wiring the module into the live policy-check workflow is a separate, larger change.
|
Done @ruivieira addressed in 64b0da1 |
|
/test images |
1 similar comment
|
/test images |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: ruivieira, sheltoncyril The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
…(services/prometheuses watch) trustyai-explainability/trustyai-service-operator#913 merged and has propagated through both red-hat-data-services sync hops (main, then rhoai-3.6-ea.2). Bumped the rhoai ref and verified locally: services and prometheuses RBAC rules now include watch. The odh pin is not bumped yet -- opendatahub-io/trustyai-service-operator#195 (the pull[bot] sync PR) already has the right content but hasn't merged.
…y condition aggregation (#915) * fix(module): add missing RBAC for serviceaccounts Same root cause as #908/#913: the module's generic deploy pipeline looks up the pre-existing in-tree trustyai-service-operator ServiceAccount before applying the workload manifests, but the ClusterRole never granted any permission on serviceaccounts at all. Found via a live cluster test: after fixing the /opt/manifests permission issue and confirming it resolved, the reconciler progressed further and hit this as the next blocker: serviceaccounts "trustyai-service-operator" is forbidden: User "system:serviceaccount:opendatahub:trustyai-operator-module-controller-manager" cannot get resource "serviceaccounts" in API group "" in the namespace "opendatahub" * fix(module): add create verb for services, serviceaccounts, deployments, rolebindings Found via the same live test: after fixing the missing serviceaccounts RBAC entirely, the next error was "cannot create resource serviceaccounts" rather than "cannot get". Kubernetes' Server-Side Apply requires the create verb (not just patch) when the target object does not already exist yet -- true for these four resource types on a fresh deploy (new namespace, nothing pre-adopted from an in-tree controller). patch alone was only sufficient in scenarios where the object already existed (e.g. adopting from a prior in-tree install), which is why this wasn't caught until testing a genuinely fresh deployment. * fix(module): exempt Degraded condition from happy-condition aggregation The shared odh-platform-utilities conditions.Manager treats any dependent condition with Status=False (or Unknown) as "unhappy" and overwrites the Ready condition's values with it, unless the dependent carries Severity=Info. Degraded is an inverted-polarity condition (False means healthy), so every healthy-case MarkFalse(Degraded, "FullyFunctional") call was clobbering the correct MarkTrue(Ready, "AllServicesHealthy") set moments earlier in the same reconcile. Mark all Degraded transitions with WithSeverity(ConditionSeverityInfo) to exempt it from aggregation, matching the existing precondition.WithSeverity(Info) pattern already used for the optional KServe dependency check. Found via live-cluster testing on tai-kpunwatk while replicating Steven's opendatahub-operator PR #4051 test flow. * fix(module): wire spec.enabledServices into --enable-services on the deployed operator spec.EnabledServices was only ever read to decide which per-service Deployments to health-check; nothing wrote it into the deployed trustyai-service-operator workload's actual startup configuration. The static manifests-template Deployment has no --enable-services arg or ENABLED_SERVICES env var at all, so the underlying operator pod always crash-looped with "please specify at least one service", regardless of what the module CR requested. Add injectEnabledServices, called in reconcileComponent after rendering the Kustomize overlay and before SSA-applying it, which sets --enable-services=<comma-separated names> on the manager container of the trustyai-service-operator Deployment. When no services are explicitly enabled (the current always-empty state, since opendatahub-operator's BuildModuleCR does not yet project per-service toggles onto this CR), default to enabling all five services, matching the pre-modular in-tree operator's own default deployment args. Found via live-cluster testing on tai-kpunwatk: with enabledServices left at its zero value, updateHealthStatus ran zero health checkers and trivially reported Ready=True while the core operator pod was crash-looping the entire time.
…operator on fresh installs (#918) * fix(module): add missing RBAC for serviceaccounts Same root cause as #908/#913: the module's generic deploy pipeline looks up the pre-existing in-tree trustyai-service-operator ServiceAccount before applying the workload manifests, but the ClusterRole never granted any permission on serviceaccounts at all. Found via a live cluster test: after fixing the /opt/manifests permission issue and confirming it resolved, the reconciler progressed further and hit this as the next blocker: serviceaccounts "trustyai-service-operator" is forbidden: User "system:serviceaccount:opendatahub:trustyai-operator-module-controller-manager" cannot get resource "serviceaccounts" in API group "" in the namespace "opendatahub" * fix(module): add create verb for services, serviceaccounts, deployments, rolebindings Found via the same live test: after fixing the missing serviceaccounts RBAC entirely, the next error was "cannot create resource serviceaccounts" rather than "cannot get". Kubernetes' Server-Side Apply requires the create verb (not just patch) when the target object does not already exist yet -- true for these four resource types on a fresh deploy (new namespace, nothing pre-adopted from an in-tree controller). patch alone was only sufficient in scenarios where the object already existed (e.g. adopting from a prior in-tree install), which is why this wasn't caught until testing a genuinely fresh deployment. * fix(module): exempt Degraded condition from happy-condition aggregation The shared odh-platform-utilities conditions.Manager treats any dependent condition with Status=False (or Unknown) as "unhappy" and overwrites the Ready condition's values with it, unless the dependent carries Severity=Info. Degraded is an inverted-polarity condition (False means healthy), so every healthy-case MarkFalse(Degraded, "FullyFunctional") call was clobbering the correct MarkTrue(Ready, "AllServicesHealthy") set moments earlier in the same reconcile. Mark all Degraded transitions with WithSeverity(ConditionSeverityInfo) to exempt it from aggregation, matching the existing precondition.WithSeverity(Info) pattern already used for the optional KServe dependency check. Found via live-cluster testing on tai-kpunwatk while replicating Steven's opendatahub-operator PR #4051 test flow. * fix(module): wire spec.enabledServices into --enable-services on the deployed operator spec.EnabledServices was only ever read to decide which per-service Deployments to health-check; nothing wrote it into the deployed trustyai-service-operator workload's actual startup configuration. The static manifests-template Deployment has no --enable-services arg or ENABLED_SERVICES env var at all, so the underlying operator pod always crash-looped with "please specify at least one service", regardless of what the module CR requested. Add injectEnabledServices, called in reconcileComponent after rendering the Kustomize overlay and before SSA-applying it, which sets --enable-services=<comma-separated names> on the manager container of the trustyai-service-operator Deployment. When no services are explicitly enabled (the current always-empty state, since opendatahub-operator's BuildModuleCR does not yet project per-service toggles onto this CR), default to enabling all five services, matching the pre-modular in-tree operator's own default deployment args. Found via live-cluster testing on tai-kpunwatk: with enabledServices left at its zero value, updateHealthStatus ran zero health checkers and trivially reported Ready=True while the core operator pod was crash-looping the entire time. * fix(module): create ClusterRole/ClusterRoleBinding for the deployed operator's RBAC config/manifests-template only ever had a Deployment and ServiceAccount; hack/get_trustyai_manifests.sh explicitly flags this as a placeholder pending "download of the real operator manifests bundle". Because migration.go's adoptRBACResources only adopts pre-existing, labeled RoleBindings (never ClusterRole/ClusterRoleBinding, and never creates anything from scratch), the deployed trustyai-service-operator workload gets zero RBAC on any cluster that never had the old CSV/OLM-based install to adopt from. Confirmed live: the pod crash-loops on "apiservers.config.openshift.io ... is forbidden" before it can even read its TLS profile. Precedent: spark-operator-module (further along in this migration) already creates its full RBAC surface fresh via SSA and declares Owns(&rbacv1.ClusterRole{}) / Owns(&rbacv1.ClusterRoleBinding{}) in SetupWithManager, because its CR is cluster-scoped. TrustyAI's CR is namespace-scoped, so it cannot use owner-reference-based ownership for cluster-scoped resources (Kubernetes rejects a namespace-scoped owner on a cluster-scoped object) -- these are excluded from ownership via deploy.WithExcludeFromOwnership and cleaned up explicitly in handleDeletion instead. Adds: - config/manifests-template/base/rbac/: the tls-profile-reader ClusterRole (apiservers read, fixes the observed crash) plus each service's manager-role ClusterRole, ported from config/components/<service>/rbac/manager-rbac.yaml, each with a fresh ClusterRoleBinding to the trustyai-service-operator ServiceAccount (module's base has no namePrefix, so these intentionally use unprefixed names distinct from the classic CSV-installed ones). - cluster_rbac.go: deleteClusterScopedRBAC, called from handleDeletion. - Owns() for ServiceAccount/Service/Deployment/RoleBinding in SetupWithManager, matching spark-operator-module's pattern. - RBAC markers + regenerated config/rbac/role.yaml for the module's own clusterroles/clusterrolebindings management. * fix(module): grant the module its own workload RBAC to satisfy escalation checks Kubernetes' RBAC escalation-prevention check rejects a create/update on a ClusterRole/ClusterRoleBinding if the requesting principal doesn't already hold every permission being granted. Confirmed live: the module's SA was denied creating evalhub-manager-role with "attempting to grant RBAC permissions not currently held". Add workload_rbac.go, mirroring the exact rule sets from config/manifests-template/base/rbac/*_clusterrole.yaml as kubebuilder markers, so the module's own manager-role ClusterRole becomes a superset of everything it grants to the deployed operator's ServiceAccount. Also drops a dead "bind" rule on evalhub-manager-role that referenced classic CSV-prefixed ClusterRole names (trustyai-service-operator-evalhub-*) which this deployment path never creates. * fix(module): provision webhook TLS certs for the deployed operator trustyai-service-operator registers CRD conversion webhooks (EvalHub, TrustyAIService) whenever TAS or EVALHUB is enabled, which requires TLS certs at /tmp/k8s-webhook-server/serving-certs. config/manifests-template had no webhook Service and no cert volume mount, so the deployed pod crash-looped with "open .../tls.crt: no such file or directory" -- confirmed live, immediately after the RBAC fix got the pod past its previous crash. Ports config/components/webhook/webhook-service.yaml (a Service with the OpenShift service-CA operator's serving-cert-secret-name annotation, which auto-populates a webhook-server-cert Secret) and the volume/mount from config/components/evalhub/patches/manager_webhook_config.yaml onto the module's Deployment. * fix(module): use default services for health checks --------- Co-authored-by: Rui Vieira <ruidevieira@googlemail.com>
Per Rui Vieira's review on trustyai-explainability#913: add deny rules to policy/clusterrole.rego that fail if the trustyai-operator-module-manager-role ClusterRole ever loses the watch verb on services or prometheuses, plus unit tests covering both the violation and the passing case. Also adds monitoring.coreos.com/prometheuses to the Layer 1 allowlist, which was missing despite the module already having get/list on it. Note: trustyai-operator-module isn't yet one of the kustomize entry points make policy-check renders (only the in-tree config/overlays/* paths are), so these rules currently only run via the unit tests in clusterrole_test.rego, not against the module's real rendered manifests. Wiring the module into the live policy-check workflow is a separate, larger change.
…y condition aggregation (trustyai-explainability#915) * fix(module): add missing RBAC for serviceaccounts Same root cause as trustyai-explainability#908/trustyai-explainability#913: the module's generic deploy pipeline looks up the pre-existing in-tree trustyai-service-operator ServiceAccount before applying the workload manifests, but the ClusterRole never granted any permission on serviceaccounts at all. Found via a live cluster test: after fixing the /opt/manifests permission issue and confirming it resolved, the reconciler progressed further and hit this as the next blocker: serviceaccounts "trustyai-service-operator" is forbidden: User "system:serviceaccount:opendatahub:trustyai-operator-module-controller-manager" cannot get resource "serviceaccounts" in API group "" in the namespace "opendatahub" * fix(module): add create verb for services, serviceaccounts, deployments, rolebindings Found via the same live test: after fixing the missing serviceaccounts RBAC entirely, the next error was "cannot create resource serviceaccounts" rather than "cannot get". Kubernetes' Server-Side Apply requires the create verb (not just patch) when the target object does not already exist yet -- true for these four resource types on a fresh deploy (new namespace, nothing pre-adopted from an in-tree controller). patch alone was only sufficient in scenarios where the object already existed (e.g. adopting from a prior in-tree install), which is why this wasn't caught until testing a genuinely fresh deployment. * fix(module): exempt Degraded condition from happy-condition aggregation The shared odh-platform-utilities conditions.Manager treats any dependent condition with Status=False (or Unknown) as "unhappy" and overwrites the Ready condition's values with it, unless the dependent carries Severity=Info. Degraded is an inverted-polarity condition (False means healthy), so every healthy-case MarkFalse(Degraded, "FullyFunctional") call was clobbering the correct MarkTrue(Ready, "AllServicesHealthy") set moments earlier in the same reconcile. Mark all Degraded transitions with WithSeverity(ConditionSeverityInfo) to exempt it from aggregation, matching the existing precondition.WithSeverity(Info) pattern already used for the optional KServe dependency check. Found via live-cluster testing on tai-kpunwatk while replicating Steven's opendatahub-operator PR #4051 test flow. * fix(module): wire spec.enabledServices into --enable-services on the deployed operator spec.EnabledServices was only ever read to decide which per-service Deployments to health-check; nothing wrote it into the deployed trustyai-service-operator workload's actual startup configuration. The static manifests-template Deployment has no --enable-services arg or ENABLED_SERVICES env var at all, so the underlying operator pod always crash-looped with "please specify at least one service", regardless of what the module CR requested. Add injectEnabledServices, called in reconcileComponent after rendering the Kustomize overlay and before SSA-applying it, which sets --enable-services=<comma-separated names> on the manager container of the trustyai-service-operator Deployment. When no services are explicitly enabled (the current always-empty state, since opendatahub-operator's BuildModuleCR does not yet project per-service toggles onto this CR), default to enabling all five services, matching the pre-modular in-tree operator's own default deployment args. Found via live-cluster testing on tai-kpunwatk: with enabledServices left at its zero value, updateHealthStatus ran zero health checkers and trivially reported Ready=True while the core operator pod was crash-looping the entire time.
…operator on fresh installs (trustyai-explainability#918) * fix(module): add missing RBAC for serviceaccounts Same root cause as trustyai-explainability#908/trustyai-explainability#913: the module's generic deploy pipeline looks up the pre-existing in-tree trustyai-service-operator ServiceAccount before applying the workload manifests, but the ClusterRole never granted any permission on serviceaccounts at all. Found via a live cluster test: after fixing the /opt/manifests permission issue and confirming it resolved, the reconciler progressed further and hit this as the next blocker: serviceaccounts "trustyai-service-operator" is forbidden: User "system:serviceaccount:opendatahub:trustyai-operator-module-controller-manager" cannot get resource "serviceaccounts" in API group "" in the namespace "opendatahub" * fix(module): add create verb for services, serviceaccounts, deployments, rolebindings Found via the same live test: after fixing the missing serviceaccounts RBAC entirely, the next error was "cannot create resource serviceaccounts" rather than "cannot get". Kubernetes' Server-Side Apply requires the create verb (not just patch) when the target object does not already exist yet -- true for these four resource types on a fresh deploy (new namespace, nothing pre-adopted from an in-tree controller). patch alone was only sufficient in scenarios where the object already existed (e.g. adopting from a prior in-tree install), which is why this wasn't caught until testing a genuinely fresh deployment. * fix(module): exempt Degraded condition from happy-condition aggregation The shared odh-platform-utilities conditions.Manager treats any dependent condition with Status=False (or Unknown) as "unhappy" and overwrites the Ready condition's values with it, unless the dependent carries Severity=Info. Degraded is an inverted-polarity condition (False means healthy), so every healthy-case MarkFalse(Degraded, "FullyFunctional") call was clobbering the correct MarkTrue(Ready, "AllServicesHealthy") set moments earlier in the same reconcile. Mark all Degraded transitions with WithSeverity(ConditionSeverityInfo) to exempt it from aggregation, matching the existing precondition.WithSeverity(Info) pattern already used for the optional KServe dependency check. Found via live-cluster testing on tai-kpunwatk while replicating Steven's opendatahub-operator PR #4051 test flow. * fix(module): wire spec.enabledServices into --enable-services on the deployed operator spec.EnabledServices was only ever read to decide which per-service Deployments to health-check; nothing wrote it into the deployed trustyai-service-operator workload's actual startup configuration. The static manifests-template Deployment has no --enable-services arg or ENABLED_SERVICES env var at all, so the underlying operator pod always crash-looped with "please specify at least one service", regardless of what the module CR requested. Add injectEnabledServices, called in reconcileComponent after rendering the Kustomize overlay and before SSA-applying it, which sets --enable-services=<comma-separated names> on the manager container of the trustyai-service-operator Deployment. When no services are explicitly enabled (the current always-empty state, since opendatahub-operator's BuildModuleCR does not yet project per-service toggles onto this CR), default to enabling all five services, matching the pre-modular in-tree operator's own default deployment args. Found via live-cluster testing on tai-kpunwatk: with enabledServices left at its zero value, updateHealthStatus ran zero health checkers and trivially reported Ready=True while the core operator pod was crash-looping the entire time. * fix(module): create ClusterRole/ClusterRoleBinding for the deployed operator's RBAC config/manifests-template only ever had a Deployment and ServiceAccount; hack/get_trustyai_manifests.sh explicitly flags this as a placeholder pending "download of the real operator manifests bundle". Because migration.go's adoptRBACResources only adopts pre-existing, labeled RoleBindings (never ClusterRole/ClusterRoleBinding, and never creates anything from scratch), the deployed trustyai-service-operator workload gets zero RBAC on any cluster that never had the old CSV/OLM-based install to adopt from. Confirmed live: the pod crash-loops on "apiservers.config.openshift.io ... is forbidden" before it can even read its TLS profile. Precedent: spark-operator-module (further along in this migration) already creates its full RBAC surface fresh via SSA and declares Owns(&rbacv1.ClusterRole{}) / Owns(&rbacv1.ClusterRoleBinding{}) in SetupWithManager, because its CR is cluster-scoped. TrustyAI's CR is namespace-scoped, so it cannot use owner-reference-based ownership for cluster-scoped resources (Kubernetes rejects a namespace-scoped owner on a cluster-scoped object) -- these are excluded from ownership via deploy.WithExcludeFromOwnership and cleaned up explicitly in handleDeletion instead. Adds: - config/manifests-template/base/rbac/: the tls-profile-reader ClusterRole (apiservers read, fixes the observed crash) plus each service's manager-role ClusterRole, ported from config/components/<service>/rbac/manager-rbac.yaml, each with a fresh ClusterRoleBinding to the trustyai-service-operator ServiceAccount (module's base has no namePrefix, so these intentionally use unprefixed names distinct from the classic CSV-installed ones). - cluster_rbac.go: deleteClusterScopedRBAC, called from handleDeletion. - Owns() for ServiceAccount/Service/Deployment/RoleBinding in SetupWithManager, matching spark-operator-module's pattern. - RBAC markers + regenerated config/rbac/role.yaml for the module's own clusterroles/clusterrolebindings management. * fix(module): grant the module its own workload RBAC to satisfy escalation checks Kubernetes' RBAC escalation-prevention check rejects a create/update on a ClusterRole/ClusterRoleBinding if the requesting principal doesn't already hold every permission being granted. Confirmed live: the module's SA was denied creating evalhub-manager-role with "attempting to grant RBAC permissions not currently held". Add workload_rbac.go, mirroring the exact rule sets from config/manifests-template/base/rbac/*_clusterrole.yaml as kubebuilder markers, so the module's own manager-role ClusterRole becomes a superset of everything it grants to the deployed operator's ServiceAccount. Also drops a dead "bind" rule on evalhub-manager-role that referenced classic CSV-prefixed ClusterRole names (trustyai-service-operator-evalhub-*) which this deployment path never creates. * fix(module): provision webhook TLS certs for the deployed operator trustyai-service-operator registers CRD conversion webhooks (EvalHub, TrustyAIService) whenever TAS or EVALHUB is enabled, which requires TLS certs at /tmp/k8s-webhook-server/serving-certs. config/manifests-template had no webhook Service and no cert volume mount, so the deployed pod crash-looped with "open .../tls.crt: no such file or directory" -- confirmed live, immediately after the RBAC fix got the pod past its previous crash. Ports config/components/webhook/webhook-service.yaml (a Service with the OpenShift service-CA operator's serving-cert-secret-name annotation, which auto-populates a webhook-server-cert Secret) and the volume/mount from config/components/evalhub/patches/manager_webhook_config.yaml onto the module's Deployment. * fix(module): use default services for health checks --------- Co-authored-by: Rui Vieira <ruidevieira@googlemail.com>
* feat: migrate TrustyAI from component to module Rewrites the TrustyAI module handler against the current ModuleHandler interface (PopulatePlatformModule/IsEnabled/BuildModuleCR signatures and ModuleConfig fields changed significantly since the previous attempt in PR #3643, which predates the DAG-orchestration and common action-framework refactors). Follows sparkoperator's handler as the template, since both are out-of-tree kustomize-based modules with their own dedicated operator image. - Add internal/controller/modules/trustyai/handler.go + handler_test.go - Add PlatformModules.TrustyAI field (DSC mode only for now; Platform/xKS mode deferred pending API updates, matching the original migration's scope decision) - Register TrustyAI in existingModules/moduleRunlevels (RL(32), after KServe's RL(31), since TrustyAI depends on KServe CRDs) - Remove TrustyAI from existingComponents/componentRunlevels and delete the legacy in-tree component controller and its monitoring resources - CRName uses componentApi.TrustyAIInstanceName ("default-trustyai"), now aligned with the trustyai-operator-module CRD's own singleton validation (see companion fix in trustyai-service-operator) * fix(trustyai): use current image var name, add RHOAI build-config exception RELATED_IMAGE_ODH_TRUSTYAI_SERVICE_IMAGE was renamed to RELATED_IMAGE_ODH_TRUSTYAI_SERVICE_PY_IMAGE (#4011) before this migration branch was rebased; the RelatedImages list still had the stale name. Also adds an RHOAI-Build-Config exception for the new RELATED_IMAGE_ODH_TRUSTYAI_MODULE_OPERATOR_IMAGE, matching the trainer/sparkoperator module operator images (RHOAIENG-80231, delivering in RHOAI 3.6 EA2). Confirmed via `make validate-related-images` locally: 2 errors -> 0. * docs: regenerate api-overview for TrustyAI module field make generate manifests-all api-docs picked up the new PlatformModules.TrustyAI field added in the previous commit. * fix(trustyai): register manifests-config entry, fix ManifestDir/ContextDir mismatch Two bugs causing "must build at directory: not a valid directory: evalsymlink failure on '/opt/manifests/trustyai-module-operator/default'" at deploy time: - manifests-config.yaml had no entry for the module at all, so `make get-manifests` never fetched it. Added trustyai-module-operator, reusing the exact same repo/ref pins as the existing trustyai (component) entry, since both mirrors already have trustyai-operator-module/ at those SHAs -- confirmed via the GitHub API before adding. - handler.go's ManifestDir was missing ContextDir: "default". Every other kustomize-based module (e.g. trainer) points sourcePath at the whole `config` directory and lets ContextDir select the `default` overlay at render time; PlatformModules.String() joins Path+ContextDir, so without it the platform looked for manifests directly under ManifestDir instead of ManifestDir/default -- the exact directory missing in the reported error. Verified end to end: `make get-manifests` now fetches trustyai-operator-module/config/{crd,rbac,manager,default} correctly, and `kustomize build opt/manifests/trustyai-module-operator/default` renders successfully. * fix(trustyai): align RBAC markers and e2e tests with module architecture RBAC markers for the trustyais CR belonged in internal/controller/modules (module-managed), not datasciencecluster; moved them accordingly with no change to generated output. Updated dag_ordering_test.go and resilience_test.go to treat TrustyAI as a module like the other already-migrated components (Trainer, Workbenches, Dashboard, AIHub), matching gaps found by comparing against PR #4000. * fix(trustyai): reuse existing trustyai manifests-config entry instead of a duplicate The old trustyai entry (sourcePath: config) pointed at the removed in-tree component manifests and had no remaining code consumer, so keeping a separate trustyai-module-operator entry alongside it was redundant. Repointed the existing entry's sourcePath at the module manifests and dropped the duplicate. * fix(trustyai): explicitly map permit fields instead of blind struct conversion BuildModuleCR converted the whole DSC-facing TrustyAICommonSpec into the module CR's spec via runtime.DefaultUnstructuredConverter. The DSC-facing API declares permitCodeExecution/permitOnline as a string enum ("allow"/"deny") while the module CRD declares them as bool, so the wholesale conversion projected a string into a field the module's typed client expects to be bool, breaking its watch/list reflector on existing CRs. Map the two permit fields explicitly with the string-to-bool conversion instead. Reported-by: Steven Tobin * fix(trustyai): bump rhoai manifest pin to pick up CR-naming fix The rhoai-3.6-ea.2 pin predated commit 5ed6709 (fix(module): align TrustyAI singleton CR name with sibling modules), so the deployed module CRD still required metadata.name == 'default' while BuildModuleCR creates 'default-trustyai', causing every apply to be rejected by the CRD's own CEL validation. Bumped to the branch's current tip, which already includes the fix (verified via GitHub compare API and by re-downloading manifests locally). The odh pin (opendatahub-io/trustyai-service-operator@incubation) still needs the same fix; that branch hasn't been re-synced from main since before the fix landed, so it's left unchanged pending that sync. Reported-by: Steven Tobin * fix(trustyai): switch odh manifest pin from incubation to main The incubation branch (opendatahub-io/trustyai-service-operator) is synced from that repo's own main via a separate, infrequent process (last sync 2026-08-05), and hasn't picked up the CR-naming CEL fix (commit 5ed6709, landed 2026-09-01) that the rhoai pin already has. Waiting on that sync is unbounded, and this file already has precedent for pinning odh directly at main (see the modelregistry entry), so switch to main@<sha> instead. Verified the pinned commit contains the fix by fetching the CRD directly and confirming the CEL rule reads 'default-trustyai', and by re-running `make get-manifests` + `kustomize build` locally. Reported-by: Steven Tobin * fix(trustyai): bump odh/rhoai manifest pins to pick up module operator fixes trustyai-service-operator#908 (RBAC watch verbs, /opt write permission, platform version handshake) has now propagated through both downstream sync chains: - odh: opendatahub-io/trustyai-service-operator#194 merged - rhoai: red-hat-data-services/trustyai-service-operator#1932 (into main) and #1934 (main into rhoai-3.6-ea.2) both merged Bumped both pins to the post-merge tips and verified locally: the "watch" verb is present on deployments/rolebindings in both ODH and RHOAI mode, kustomize build succeeds, and go build/test pass. Reported-by: Steven Tobin * fix(trustyai): remove redundant CRD-generating types now owned by the module TrustyAI's Go type still had +kubebuilder:object:root=true on TrustyAI/ TrustyAIList, plus the PlatformObject interface implementation and scheme registration. Since the CRD is now installed by trustyai-operator-module (from its own manifests), this caused opendatahub-operator to generate a second, competing CRD definition for the same GVK from a Go type that isn't kept in sync with the module's actual schema (already missing mcpGuardrailsMode and the default-trustyai singleton validation independently added on each side). Removed the top-level TrustyAI/TrustyAIList struct, scheme registration, and PlatformObject methods, keeping only the nested spec/status types and DSCTrustyAI/DSCTrustyAIStatus, matching the pattern already used by sibling modules (see sparkoperator_types.go). Updated tests/e2e/trustyai_test.go to use NewModuleTestCtx (GVK + instance name) instead of NewComponentTestCtx (which required a typed struct) -- this is the existing mechanism other module e2e tests (kserve_test.go, aigateway_test.go) already use for exactly this case. Verified via a full config/crd/bases wipe + make manifests that no components.platform.opendatahub.io_trustyais.yaml is generated anymore. * fix(trustyai): bump rhoai manifest pin to pick up #913 (services/prometheuses watch) trustyai-explainability/trustyai-service-operator#913 merged and has propagated through both red-hat-data-services sync hops (main, then rhoai-3.6-ea.2). Bumped the rhoai ref and verified locally: services and prometheuses RBAC rules now include watch. The odh pin is not bumped yet -- opendatahub-io/trustyai-service-operator#195 (the pull[bot] sync PR) already has the right content but hasn't merged. * fix(trustyai): temporarily point odh pin at canonical upstream repo opendatahub-io/trustyai-service-operator#195 (the pull[bot] sync PR bringing in #913's services/prometheuses watch fix) already has the right content as its head commit, but is stuck on the OWNERS approval gate while the approver is on PTO. Rather than wait, point the odh pin directly at trustyai-explainability/trustyai-service-operator (the canonical upstream #195 pulls from) at that same commit. Verified locally: make get-manifests resolves cleanly, RBAC role.yaml has watch on services/prometheuses, CRD CEL rule reads 'default-trustyai', kustomize build succeeds, go build/test pass. Switch back to the opendatahub-io mirror once #195 merges. * switch ODH manifest pin back to opendatahub-io mirror * bump(trustyai): rhoai manifest pin to pick up rhoai PR #1943 Picks up the same fixes that were merged into the ODH upstream repo. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * bump(trustyai): manifest pins for #920/#921/#925 sync Pick up post-sync mirror SHAs: ODH main @0b428d2 (#197) and rhoai-3.6-ea.2 @5f278d7 (#1949), including the emptyDir/clearDir fix. Co-authored-by: Cursor <cursoragent@cursor.com> * bump(trustyai): update module operator image digest to latest build * sync manager image overrides and regenerate api docs * chore: resolve image digests after trustyai manifest sync * bump(trustyai): service operator image only; revert broad digest resolve Update RELATED_IMAGE_ODH_TRUSTYAI_SERVICE_OPERATOR_IMAGE to fix --metrics-cert-path crash. Reverts platform-wide resolve-image-digests from 4e0700d; module operator stays at e5cd204a (#925). * fix(trustyai): TrustyAI-only image pins at latest validated digests * fix(trustyai): drop unrelated data-registry rhoai digest from PR Keep manifests-config image pin changes TrustyAI-only; remove MOD_ARCH_DATA_REGISTRY rhoai block not in scope for #4051. Co-authored-by: Cursor <cursoragent@cursor.com> * Revert "fix(trustyai): drop unrelated data-registry rhoai digest from PR" Restore MOD_ARCH_DATA_REGISTRY rhoai mapping from upstream #4073 merge. * test(e2e): drop TrustyAI from platform-owned CRD validation TrustyAI is now an out-of-tree module; its CRD is installed by the module operator when enabled, not by the platform operator at startup. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(manifests): bump trustyai rhoai ref after #1955 sync Pick up #926 module operator fixes on rhoai-3.6-ea.2 (RELATED_IMAGE mapping, manifest staging, memory limits). * chore(manifests): bump trustyai odh ref to pick up #926 fixes Sync opendatahub-io/trustyai-service-operator main to #202 merge (9c0ffa8). * chore(manifests): bump trustyai pins for #928 readiness fix - ODH main@feb5b94 (opendatahub-io #204) - RHOAI rhoai-3.6-ea.2@75a4af5 (#1956 / #928 on rhoai) - Module-operator image digest d2df18f5 (Konflux build for feb5b94) * chore(manifests): align TrustyAI module-operator image with build configs - ODH: quay.io/opendatahub/odh-trustyai-module-operator@b3cef1149 - RHOAI: quay.io/rhoai/odh-trustyai-module-operator-rhel9@51384d9610 - Remove stale rhoai_exceptions entry (RHOAIENG-80231 onboarded) Co-authored-by: Cursor <cursoragent@cursor.com> * feat(trustyai): propagate MCP Guardrails mode Signed-off-by: Rui Vieira <ruidevieira@googlemail.com> (cherry picked from commit 8a76d74) * chore(docs): regenerate api-overview after Ray/TrustyAI module migration Drop Ray and TrustyAI from the platform-owned Resource Types index so make api-docs matches CI (Ensure generated files are included). Co-authored-by: Cursor <cursoragent@cursor.com> * fix(trustyai): bump module refs to include mcpGuardrailsMode in CRD schema ODH: main@7838ba58fffca619610c6b260c4ec87c031d0a27 (was feb5b944...) RHOAI: rhoai-3.6-ea.2@9a3b7b9f4f936419451c833b70ba180fe03a3e61 (was 75a4af5b...) The previous refs lacked mcpGuardrailsMode in the TrustyAI CRD schema, causing deployment failures when trying to apply the field: "field not declared in schema". Newer upstream commits include this field. Fixes e2e test failure: "unable to patch components.platform.opendatahub.io/v1alpha1, Kind=TrustyAI default-trustyai: failed to create typed patch object: .spec.mcpGuardrailsMode: field not declared in schema" * fix(trustyai): bump module operator image digests to latest builds Update both ODH and RHOAI image digests to the latest trustyai-module-operator builds that include the MCP guardrails fix: - ODH: sha256:65cba5211000f9b13b87b2bd9f1fb052ea814e1826e53f498edd84209d877b6e (midstream incubation→stable sync by Rui, synced to ODH) - RHOAI: sha256:e6a0be61ecbedf259b80fc2a63ae8ee975aa18a6a6743538554b21bab9f7bd4c Previous digests were stale and not available in the registry, causing e2e test deployment failures with missing CRD fields. * test(trustyai): override ValidateOperandsOwnerReferences for modular architecture TrustyAI is now a module operator that deploys operands with different labels. Override the parent test implementation to use the correct TrustyAI-specific label 'app.kubernetes.io/part-of: trustyai' instead of the generic component label, and verify operands are owned by the TrustyAI CR by kind and name. * style(test): fix import order in trustyai_test.go * align the trusty tests to the module architecture * Align RHOAI TrustyAI Module operator with RHOAI manifests * Fix Missing Components CRD Handling test --------- Signed-off-by: Rui Vieira <ruidevieira@googlemail.com> Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Rui Vieira <ruidevieira@googlemail.com> Co-authored-by: Steven Tobin <stobin@redhat.com> Co-authored-by: Marián Macik <mmacik@redhat.com>
* feat: migrate TrustyAI from component to module Rewrites the TrustyAI module handler against the current ModuleHandler interface (PopulatePlatformModule/IsEnabled/BuildModuleCR signatures and ModuleConfig fields changed significantly since the previous attempt in PR #3643, which predates the DAG-orchestration and common action-framework refactors). Follows sparkoperator's handler as the template, since both are out-of-tree kustomize-based modules with their own dedicated operator image. - Add internal/controller/modules/trustyai/handler.go + handler_test.go - Add PlatformModules.TrustyAI field (DSC mode only for now; Platform/xKS mode deferred pending API updates, matching the original migration's scope decision) - Register TrustyAI in existingModules/moduleRunlevels (RL(32), after KServe's RL(31), since TrustyAI depends on KServe CRDs) - Remove TrustyAI from existingComponents/componentRunlevels and delete the legacy in-tree component controller and its monitoring resources - CRName uses componentApi.TrustyAIInstanceName ("default-trustyai"), now aligned with the trustyai-operator-module CRD's own singleton validation (see companion fix in trustyai-service-operator) * fix(trustyai): use current image var name, add RHOAI build-config exception RELATED_IMAGE_ODH_TRUSTYAI_SERVICE_IMAGE was renamed to RELATED_IMAGE_ODH_TRUSTYAI_SERVICE_PY_IMAGE (#4011) before this migration branch was rebased; the RelatedImages list still had the stale name. Also adds an RHOAI-Build-Config exception for the new RELATED_IMAGE_ODH_TRUSTYAI_MODULE_OPERATOR_IMAGE, matching the trainer/sparkoperator module operator images (RHOAIENG-80231, delivering in RHOAI 3.6 EA2). Confirmed via `make validate-related-images` locally: 2 errors -> 0. * docs: regenerate api-overview for TrustyAI module field make generate manifests-all api-docs picked up the new PlatformModules.TrustyAI field added in the previous commit. * fix(trustyai): register manifests-config entry, fix ManifestDir/ContextDir mismatch Two bugs causing "must build at directory: not a valid directory: evalsymlink failure on '/opt/manifests/trustyai-module-operator/default'" at deploy time: - manifests-config.yaml had no entry for the module at all, so `make get-manifests` never fetched it. Added trustyai-module-operator, reusing the exact same repo/ref pins as the existing trustyai (component) entry, since both mirrors already have trustyai-operator-module/ at those SHAs -- confirmed via the GitHub API before adding. - handler.go's ManifestDir was missing ContextDir: "default". Every other kustomize-based module (e.g. trainer) points sourcePath at the whole `config` directory and lets ContextDir select the `default` overlay at render time; PlatformModules.String() joins Path+ContextDir, so without it the platform looked for manifests directly under ManifestDir instead of ManifestDir/default -- the exact directory missing in the reported error. Verified end to end: `make get-manifests` now fetches trustyai-operator-module/config/{crd,rbac,manager,default} correctly, and `kustomize build opt/manifests/trustyai-module-operator/default` renders successfully. * fix(trustyai): align RBAC markers and e2e tests with module architecture RBAC markers for the trustyais CR belonged in internal/controller/modules (module-managed), not datasciencecluster; moved them accordingly with no change to generated output. Updated dag_ordering_test.go and resilience_test.go to treat TrustyAI as a module like the other already-migrated components (Trainer, Workbenches, Dashboard, AIHub), matching gaps found by comparing against PR #4000. * fix(trustyai): reuse existing trustyai manifests-config entry instead of a duplicate The old trustyai entry (sourcePath: config) pointed at the removed in-tree component manifests and had no remaining code consumer, so keeping a separate trustyai-module-operator entry alongside it was redundant. Repointed the existing entry's sourcePath at the module manifests and dropped the duplicate. * fix(trustyai): explicitly map permit fields instead of blind struct conversion BuildModuleCR converted the whole DSC-facing TrustyAICommonSpec into the module CR's spec via runtime.DefaultUnstructuredConverter. The DSC-facing API declares permitCodeExecution/permitOnline as a string enum ("allow"/"deny") while the module CRD declares them as bool, so the wholesale conversion projected a string into a field the module's typed client expects to be bool, breaking its watch/list reflector on existing CRs. Map the two permit fields explicitly with the string-to-bool conversion instead. Reported-by: Steven Tobin * fix(trustyai): bump rhoai manifest pin to pick up CR-naming fix The rhoai-3.6-ea.2 pin predated commit 5ed6709 (fix(module): align TrustyAI singleton CR name with sibling modules), so the deployed module CRD still required metadata.name == 'default' while BuildModuleCR creates 'default-trustyai', causing every apply to be rejected by the CRD's own CEL validation. Bumped to the branch's current tip, which already includes the fix (verified via GitHub compare API and by re-downloading manifests locally). The odh pin (opendatahub-io/trustyai-service-operator@incubation) still needs the same fix; that branch hasn't been re-synced from main since before the fix landed, so it's left unchanged pending that sync. Reported-by: Steven Tobin * fix(trustyai): switch odh manifest pin from incubation to main The incubation branch (opendatahub-io/trustyai-service-operator) is synced from that repo's own main via a separate, infrequent process (last sync 2026-08-05), and hasn't picked up the CR-naming CEL fix (commit 5ed6709, landed 2026-09-01) that the rhoai pin already has. Waiting on that sync is unbounded, and this file already has precedent for pinning odh directly at main (see the modelregistry entry), so switch to main@<sha> instead. Verified the pinned commit contains the fix by fetching the CRD directly and confirming the CEL rule reads 'default-trustyai', and by re-running `make get-manifests` + `kustomize build` locally. Reported-by: Steven Tobin * fix(trustyai): bump odh/rhoai manifest pins to pick up module operator fixes trustyai-service-operator#908 (RBAC watch verbs, /opt write permission, platform version handshake) has now propagated through both downstream sync chains: - odh: opendatahub-io/trustyai-service-operator#194 merged - rhoai: red-hat-data-services/trustyai-service-operator#1932 (into main) and #1934 (main into rhoai-3.6-ea.2) both merged Bumped both pins to the post-merge tips and verified locally: the "watch" verb is present on deployments/rolebindings in both ODH and RHOAI mode, kustomize build succeeds, and go build/test pass. Reported-by: Steven Tobin * fix(trustyai): remove redundant CRD-generating types now owned by the module TrustyAI's Go type still had +kubebuilder:object:root=true on TrustyAI/ TrustyAIList, plus the PlatformObject interface implementation and scheme registration. Since the CRD is now installed by trustyai-operator-module (from its own manifests), this caused opendatahub-operator to generate a second, competing CRD definition for the same GVK from a Go type that isn't kept in sync with the module's actual schema (already missing mcpGuardrailsMode and the default-trustyai singleton validation independently added on each side). Removed the top-level TrustyAI/TrustyAIList struct, scheme registration, and PlatformObject methods, keeping only the nested spec/status types and DSCTrustyAI/DSCTrustyAIStatus, matching the pattern already used by sibling modules (see sparkoperator_types.go). Updated tests/e2e/trustyai_test.go to use NewModuleTestCtx (GVK + instance name) instead of NewComponentTestCtx (which required a typed struct) -- this is the existing mechanism other module e2e tests (kserve_test.go, aigateway_test.go) already use for exactly this case. Verified via a full config/crd/bases wipe + make manifests that no components.platform.opendatahub.io_trustyais.yaml is generated anymore. * fix(trustyai): bump rhoai manifest pin to pick up #913 (services/prometheuses watch) trustyai-explainability/trustyai-service-operator#913 merged and has propagated through both red-hat-data-services sync hops (main, then rhoai-3.6-ea.2). Bumped the rhoai ref and verified locally: services and prometheuses RBAC rules now include watch. The odh pin is not bumped yet -- opendatahub-io/trustyai-service-operator#195 (the pull[bot] sync PR) already has the right content but hasn't merged. * fix(trustyai): temporarily point odh pin at canonical upstream repo opendatahub-io/trustyai-service-operator#195 (the pull[bot] sync PR bringing in #913's services/prometheuses watch fix) already has the right content as its head commit, but is stuck on the OWNERS approval gate while the approver is on PTO. Rather than wait, point the odh pin directly at trustyai-explainability/trustyai-service-operator (the canonical upstream #195 pulls from) at that same commit. Verified locally: make get-manifests resolves cleanly, RBAC role.yaml has watch on services/prometheuses, CRD CEL rule reads 'default-trustyai', kustomize build succeeds, go build/test pass. Switch back to the opendatahub-io mirror once #195 merges. * switch ODH manifest pin back to opendatahub-io mirror * bump(trustyai): rhoai manifest pin to pick up rhoai PR #1943 Picks up the same fixes that were merged into the ODH upstream repo. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * bump(trustyai): manifest pins for #920/#921/#925 sync Pick up post-sync mirror SHAs: ODH main @0b428d2 (#197) and rhoai-3.6-ea.2 @5f278d7 (#1949), including the emptyDir/clearDir fix. Co-authored-by: Cursor <cursoragent@cursor.com> * bump(trustyai): update module operator image digest to latest build * sync manager image overrides and regenerate api docs * chore: resolve image digests after trustyai manifest sync * bump(trustyai): service operator image only; revert broad digest resolve Update RELATED_IMAGE_ODH_TRUSTYAI_SERVICE_OPERATOR_IMAGE to fix --metrics-cert-path crash. Reverts platform-wide resolve-image-digests from 4e0700d; module operator stays at e5cd204a (#925). * fix(trustyai): TrustyAI-only image pins at latest validated digests * fix(trustyai): drop unrelated data-registry rhoai digest from PR Keep manifests-config image pin changes TrustyAI-only; remove MOD_ARCH_DATA_REGISTRY rhoai block not in scope for #4051. Co-authored-by: Cursor <cursoragent@cursor.com> * Revert "fix(trustyai): drop unrelated data-registry rhoai digest from PR" Restore MOD_ARCH_DATA_REGISTRY rhoai mapping from upstream #4073 merge. * test(e2e): drop TrustyAI from platform-owned CRD validation TrustyAI is now an out-of-tree module; its CRD is installed by the module operator when enabled, not by the platform operator at startup. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(manifests): bump trustyai rhoai ref after #1955 sync Pick up #926 module operator fixes on rhoai-3.6-ea.2 (RELATED_IMAGE mapping, manifest staging, memory limits). * chore(manifests): bump trustyai odh ref to pick up #926 fixes Sync opendatahub-io/trustyai-service-operator main to #202 merge (9c0ffa8). * chore(manifests): bump trustyai pins for #928 readiness fix - ODH main@feb5b94 (opendatahub-io #204) - RHOAI rhoai-3.6-ea.2@75a4af5 (#1956 / #928 on rhoai) - Module-operator image digest d2df18f5 (Konflux build for feb5b94) * chore(manifests): align TrustyAI module-operator image with build configs - ODH: quay.io/opendatahub/odh-trustyai-module-operator@b3cef1149 - RHOAI: quay.io/rhoai/odh-trustyai-module-operator-rhel9@51384d9610 - Remove stale rhoai_exceptions entry (RHOAIENG-80231 onboarded) Co-authored-by: Cursor <cursoragent@cursor.com> * feat(trustyai): propagate MCP Guardrails mode Signed-off-by: Rui Vieira <ruidevieira@googlemail.com> (cherry picked from commit 8a76d74) * chore(docs): regenerate api-overview after Ray/TrustyAI module migration Drop Ray and TrustyAI from the platform-owned Resource Types index so make api-docs matches CI (Ensure generated files are included). Co-authored-by: Cursor <cursoragent@cursor.com> * fix(trustyai): bump module refs to include mcpGuardrailsMode in CRD schema ODH: main@7838ba58fffca619610c6b260c4ec87c031d0a27 (was feb5b944...) RHOAI: rhoai-3.6-ea.2@9a3b7b9f4f936419451c833b70ba180fe03a3e61 (was 75a4af5b...) The previous refs lacked mcpGuardrailsMode in the TrustyAI CRD schema, causing deployment failures when trying to apply the field: "field not declared in schema". Newer upstream commits include this field. Fixes e2e test failure: "unable to patch components.platform.opendatahub.io/v1alpha1, Kind=TrustyAI default-trustyai: failed to create typed patch object: .spec.mcpGuardrailsMode: field not declared in schema" * fix(trustyai): bump module operator image digests to latest builds Update both ODH and RHOAI image digests to the latest trustyai-module-operator builds that include the MCP guardrails fix: - ODH: sha256:65cba5211000f9b13b87b2bd9f1fb052ea814e1826e53f498edd84209d877b6e (midstream incubation→stable sync by Rui, synced to ODH) - RHOAI: sha256:e6a0be61ecbedf259b80fc2a63ae8ee975aa18a6a6743538554b21bab9f7bd4c Previous digests were stale and not available in the registry, causing e2e test deployment failures with missing CRD fields. * test(trustyai): override ValidateOperandsOwnerReferences for modular architecture TrustyAI is now a module operator that deploys operands with different labels. Override the parent test implementation to use the correct TrustyAI-specific label 'app.kubernetes.io/part-of: trustyai' instead of the generic component label, and verify operands are owned by the TrustyAI CR by kind and name. * style(test): fix import order in trustyai_test.go * align the trusty tests to the module architecture * Align RHOAI TrustyAI Module operator with RHOAI manifests * Fix Missing Components CRD Handling test --------- Signed-off-by: Rui Vieira <ruidevieira@googlemail.com> Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Rui Vieira <ruidevieira@googlemail.com> Co-authored-by: Steven Tobin <stobin@redhat.com> Co-authored-by: Marián Macik <mmacik@redhat.com>
Same root cause as #908 (deployments, rolebindings): the manager's cached client establishes an informer/watch for any GVK it Lists or Gets, requiring the watch verb in addition to get/list. Two more call sites hit this that weren't covered by #908:
Found by proactively auditing every List/Get call site in the package after Steven Tobin reported the Services watch failure, to catch the remaining latent gap before it surfaced separately.
Related to opendatahub-io/opendatahub-operator#4051 — Steven is testing
the TrustyAI module end-to-end via that PR, and this fixes one of the
errors he's hit there.
Summary by CodeRabbit