allow to reference via zitadel too
All checks were successful
Build and Publish / build-release (push) Successful in 2m9s

This commit is contained in:
2026-04-30 15:36:20 -05:00
parent c6aff229ae
commit 319acd90de
8 changed files with 185 additions and 77 deletions

View File

@@ -18,6 +18,7 @@ package v1alpha1
import ( import (
"context" "context"
"fmt"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -78,6 +79,12 @@ func (d *APIApp) IsReady() bool {
} }
func (d *APIApp) ConnectionRef(ctx context.Context, refresolver *RefResolver) (*ConnectionRef, error) { func (d *APIApp) ConnectionRef(ctx context.Context, refresolver *RefResolver) (*ConnectionRef, error) {
// Check if using direct Zitadel ID reference
if d.Spec.ProjectRef.ID != "" {
return &d.Spec.ProjectRef.ConnectionRef, nil
}
// Fall back to K8s reference resolution
project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -88,24 +95,29 @@ func (d *APIApp) ConnectionRef(ctx context.Context, refresolver *RefResolver) (*
} }
return &org.Spec.ConnectionRef, nil return &org.Spec.ConnectionRef, nil
} }
func (d *APIApp) Organization(ctx context.Context, refresolver *RefResolver) (*Organization, error) { func (d *APIApp) Organization(ctx context.Context, refresolver *RefResolver) (*ResolvedReference, error) {
project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) // Check if using direct Zitadel ID reference for project
if err != nil { if d.Spec.ProjectRef.ID != "" {
return nil, err // For cross-cluster references, we need to get the organization ID from the project reference
} // Since we don't have the full project object, we'll need to resolve the organization differently
org, err := refresolver.OrganizationRef(ctx, &project.Spec.OrganizationRef, d.Namespace) // For now, return an error as this requires more complex handling
if err != nil { return nil, fmt.Errorf("cross-cluster organization resolution not yet implemented")
return nil, err
}
return org, nil
} }
func (d *APIApp) Project(ctx context.Context, refresolver *RefResolver) (*Project, error) { // Fall back to K8s reference resolution
project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return project, nil orgRef, err := refresolver.ResolveOrganization(ctx, &project.Spec.OrganizationRef, d.Namespace)
if err != nil {
return nil, err
}
return orgRef, nil
}
func (d *APIApp) Project(ctx context.Context, refresolver *RefResolver) (*ResolvedReference, error) {
return refresolver.ResolveProject(ctx, &d.Spec.ProjectRef, d.Namespace)
} }
//+kubebuilder:object:root=true //+kubebuilder:object:root=true

View File

@@ -18,6 +18,7 @@ package v1alpha1
import ( import (
"context" "context"
"fmt"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
@@ -99,6 +100,12 @@ func (d *OIDCApp) IsReady() bool {
} }
func (d *OIDCApp) ConnectionRef(ctx context.Context, refresolver *RefResolver) (*ConnectionRef, error) { func (d *OIDCApp) ConnectionRef(ctx context.Context, refresolver *RefResolver) (*ConnectionRef, error) {
// Check if using direct Zitadel ID reference
if d.Spec.ProjectRef.ID != "" {
return &d.Spec.ProjectRef.ConnectionRef, nil
}
// Fall back to K8s reference resolution
project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -111,24 +118,29 @@ func (d *OIDCApp) ConnectionRef(ctx context.Context, refresolver *RefResolver) (
return &org.Spec.ConnectionRef, nil return &org.Spec.ConnectionRef, nil
} }
func (d *OIDCApp) Organization(ctx context.Context, refresolver *RefResolver) (*Organization, error) { func (d *OIDCApp) Organization(ctx context.Context, refresolver *RefResolver) (*ResolvedReference, error) {
project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) // Check if using direct Zitadel ID reference for project
if err != nil { if d.Spec.ProjectRef.ID != "" {
return nil, err // For cross-cluster references, we need to get the organization ID from the project reference
} // Since we don't have the full project object, we'll need to resolve the organization differently
org, err := refresolver.OrganizationRef(ctx, &project.Spec.OrganizationRef, d.Namespace) // For now, return an error as this requires more complex handling
if err != nil { return nil, fmt.Errorf("cross-cluster organization resolution not yet implemented")
return nil, err
}
return org, nil
} }
func (d *OIDCApp) Project(ctx context.Context, refresolver *RefResolver) (*Project, error) { // Fall back to K8s reference resolution
project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return project, nil orgRef, err := refresolver.ResolveOrganization(ctx, &project.Spec.OrganizationRef, d.Namespace)
if err != nil {
return nil, err
}
return orgRef, nil
}
func (d *OIDCApp) Project(ctx context.Context, refresolver *RefResolver) (*ResolvedReference, error) {
return refresolver.ResolveProject(ctx, &d.Spec.ProjectRef, d.Namespace)
} }
func (d *OIDCApp) ClientSecretName() string { func (d *OIDCApp) ClientSecretName() string {

View File

@@ -96,6 +96,12 @@ func (d *Project) IsReady() bool {
} }
func (d *Project) ConnectionRef(ctx context.Context, refresolver *RefResolver) (*ConnectionRef, error) { func (d *Project) ConnectionRef(ctx context.Context, refresolver *RefResolver) (*ConnectionRef, error) {
// Check if using direct Zitadel ID reference
if d.Spec.OrganizationRef.ID != "" {
return &d.Spec.OrganizationRef.ConnectionRef, nil
}
// Fall back to K8s reference resolution
org, err := refresolver.OrganizationRef(ctx, &d.Spec.OrganizationRef, d.Namespace) org, err := refresolver.OrganizationRef(ctx, &d.Spec.OrganizationRef, d.Namespace)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -5,31 +5,31 @@ import (
) )
type ConnectionRef struct { type ConnectionRef struct {
// ObjectReference is a reference to a object. ObjectReference corev1.ObjectReference `json:",inline"`
// +operator-sdk:csv:customresourcedefinitions:type=spec
corev1.ObjectReference `json:",inline"`
} }
type OIDCAppRef struct { type OIDCAppRef struct {
// ObjectReference is a reference to a object. ObjectReference corev1.ObjectReference `json:",inline"`
// +operator-sdk:csv:customresourcedefinitions:type=spec
corev1.ObjectReference `json:",inline"`
} }
// OrganizationRef can reference an organization via K8s object or direct Zitadel ID
// +kubebuilder:validation:XValidation:rule="has(self.name) == has(self.id)",message="must provide either k8s object reference (name) or zitadel ID reference (id), but not both"
// +kubebuilder:validation:XValidation:rule="!has(self.id) || has(self.connectionRef.name)",message="zitadel ID reference requires connectionRef.name"
type OrganizationRef struct { type OrganizationRef struct {
// ObjectReference is a reference to a object. ObjectReference corev1.ObjectReference `json:",inline"`
// +operator-sdk:csv:customresourcedefinitions:type=spec ID string `json:"id,omitempty"`
corev1.ObjectReference `json:",inline"` ConnectionRef ConnectionRef `json:"connectionRef,omitempty"`
} }
// ProjectRef can reference a project via K8s object or direct Zitadel ID
// +kubebuilder:validation:XValidation:rule="has(self.name) == has(self.id)",message="must provide either k8s object reference (name) or zitadel ID reference (id), but not both"
// +kubebuilder:validation:XValidation:rule="!has(self.id) || has(self.connectionRef.name)",message="zitadel ID reference requires connectionRef.name"
type ProjectRef struct { type ProjectRef struct {
// ObjectReference is a reference to a object. ObjectReference corev1.ObjectReference `json:",inline"`
// +operator-sdk:csv:customresourcedefinitions:type=spec ID string `json:"id,omitempty"`
corev1.ObjectReference `json:",inline"` ConnectionRef ConnectionRef `json:"connectionRef,omitempty"`
} }
type ActionRef struct { type ActionRef struct {
// ObjectReference is a reference to a object. ObjectReference corev1.ObjectReference `json:",inline"`
// +operator-sdk:csv:customresourcedefinitions:type=spec
corev1.ObjectReference `json:",inline"`
} }

View File

@@ -9,6 +9,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
) )
// ResolvedReference is the common abstraction for both reference types
type ResolvedReference struct {
ID string
Namespace string
Name string
}
// +kubebuilder:object:generate=false // +kubebuilder:object:generate=false
type RefResolver struct { type RefResolver struct {
client client.Client client client.Client
@@ -22,16 +29,16 @@ func NewRefResolver(client client.Client) *RefResolver {
func (r *RefResolver) OIDCAppRef(ctx context.Context, ref *OIDCAppRef, func (r *RefResolver) OIDCAppRef(ctx context.Context, ref *OIDCAppRef,
namespace string) (*OIDCApp, error) { namespace string) (*OIDCApp, error) {
if ref.Kind != "" && ref.Kind != "OIDCApp" { if ref.ObjectReference.Kind != "" && ref.ObjectReference.Kind != "OIDCApp" {
return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.ObjectReference.Kind)
} }
key := types.NamespacedName{ key := types.NamespacedName{
Name: ref.Name, Name: ref.ObjectReference.Name,
Namespace: namespace, Namespace: namespace,
} }
if ref.Namespace != "" { if ref.ObjectReference.Namespace != "" {
key.Namespace = ref.Namespace key.Namespace = ref.ObjectReference.Namespace
} }
var zitadel OIDCApp var zitadel OIDCApp
@@ -43,16 +50,16 @@ func (r *RefResolver) OIDCAppRef(ctx context.Context, ref *OIDCAppRef,
func (r *RefResolver) ActionRef(ctx context.Context, ref *ActionRef, func (r *RefResolver) ActionRef(ctx context.Context, ref *ActionRef,
namespace string) (*Action, error) { namespace string) (*Action, error) {
if ref.Kind != "" && ref.Kind != "Action" { if ref.ObjectReference.Kind != "" && ref.ObjectReference.Kind != "Action" {
return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.ObjectReference.Kind)
} }
key := types.NamespacedName{ key := types.NamespacedName{
Name: ref.Name, Name: ref.ObjectReference.Name,
Namespace: namespace, Namespace: namespace,
} }
if ref.Namespace != "" { if ref.ObjectReference.Namespace != "" {
key.Namespace = ref.Namespace key.Namespace = ref.ObjectReference.Namespace
} }
var zitadel Action var zitadel Action
@@ -64,16 +71,16 @@ func (r *RefResolver) ActionRef(ctx context.Context, ref *ActionRef,
func (r *RefResolver) ProjectRef(ctx context.Context, ref *ProjectRef, func (r *RefResolver) ProjectRef(ctx context.Context, ref *ProjectRef,
namespace string) (*Project, error) { namespace string) (*Project, error) {
if ref.Kind != "" && ref.Kind != "Project" { if ref.ObjectReference.Kind != "" && ref.ObjectReference.Kind != "Project" {
return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.ObjectReference.Kind)
} }
key := types.NamespacedName{ key := types.NamespacedName{
Name: ref.Name, Name: ref.ObjectReference.Name,
Namespace: namespace, Namespace: namespace,
} }
if ref.Namespace != "" { if ref.ObjectReference.Namespace != "" {
key.Namespace = ref.Namespace key.Namespace = ref.ObjectReference.Namespace
} }
var zitadel Project var zitadel Project
@@ -85,16 +92,16 @@ func (r *RefResolver) ProjectRef(ctx context.Context, ref *ProjectRef,
func (r *RefResolver) OrganizationRef(ctx context.Context, ref *OrganizationRef, func (r *RefResolver) OrganizationRef(ctx context.Context, ref *OrganizationRef,
namespace string) (*Organization, error) { namespace string) (*Organization, error) {
if ref.Kind != "" && ref.Kind != "Organization" { if ref.ObjectReference.Kind != "" && ref.ObjectReference.Kind != "Organization" {
return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.ObjectReference.Kind)
} }
key := types.NamespacedName{ key := types.NamespacedName{
Name: ref.Name, Name: ref.ObjectReference.Name,
Namespace: namespace, Namespace: namespace,
} }
if ref.Namespace != "" { if ref.ObjectReference.Namespace != "" {
key.Namespace = ref.Namespace key.Namespace = ref.ObjectReference.Namespace
} }
var zitadel Organization var zitadel Organization
@@ -105,15 +112,15 @@ func (r *RefResolver) OrganizationRef(ctx context.Context, ref *OrganizationRef,
} }
func (r *RefResolver) ConnectionRef(ctx context.Context, ref *ConnectionRef, namespace string) (*Connection, error) { func (r *RefResolver) ConnectionRef(ctx context.Context, ref *ConnectionRef, namespace string) (*Connection, error) {
if ref.Kind != "" && ref.Kind != "Connection" { if ref.ObjectReference.Kind != "" && ref.ObjectReference.Kind != "Connection" {
return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.ObjectReference.Kind)
} }
key := types.NamespacedName{ key := types.NamespacedName{
Name: ref.Name, Name: ref.ObjectReference.Name,
Namespace: namespace, Namespace: namespace,
} }
if ref.Namespace != "" { if ref.ObjectReference.Namespace != "" {
key.Namespace = ref.Namespace key.Namespace = ref.ObjectReference.Namespace
} }
var connection Connection var connection Connection
@@ -141,3 +148,79 @@ func (r *RefResolver) SecretKeyRef(ctx context.Context, selector corev1.SecretKe
return string(data), nil return string(data), nil
} }
// ResolveOrganization resolves an organization reference to a common abstraction
func (r *RefResolver) ResolveOrganization(ctx context.Context, ref *OrganizationRef, namespace string) (*ResolvedReference, error) {
// Priority 1: Direct Zitadel ID reference (cross-cluster)
if ref.ID != "" {
return &ResolvedReference{
ID: ref.ID,
}, nil
}
// Priority 2: K8s object reference (same-cluster, backward compatible)
if ref.ObjectReference.Name != "" {
org, err := r.OrganizationRef(ctx, ref, namespace)
if err != nil {
return nil, err
}
if org.Status.OrganizationId == nil {
return nil, fmt.Errorf("organization not ready")
}
return &ResolvedReference{
ID: *org.Status.OrganizationId,
Namespace: org.Namespace,
Name: org.Name,
}, nil
}
return nil, fmt.Errorf("no valid organization reference provided")
}
// ResolveProject resolves a project reference to a common abstraction
func (r *RefResolver) ResolveProject(ctx context.Context, ref *ProjectRef, namespace string) (*ResolvedReference, error) {
// Priority 1: Direct Zitadel ID reference (cross-cluster)
if ref.ID != "" {
return &ResolvedReference{
ID: ref.ID,
}, nil
}
// Priority 2: K8s object reference (same-cluster, backward compatible)
if ref.ObjectReference.Name != "" {
project, err := r.ProjectRef(ctx, ref, namespace)
if err != nil {
return nil, err
}
if project.Status.ProjectId == nil {
return nil, fmt.Errorf("project not ready")
}
return &ResolvedReference{
ID: *project.Status.ProjectId,
Namespace: project.Namespace,
Name: project.Name,
}, nil
}
return nil, fmt.Errorf("no valid project reference provided")
}
// ResolveConnectionForRef resolves connection from either a ConnectionRef or enhanced reference with embedded ConnectionRef
func (r *RefResolver) ResolveConnectionForRef(ctx context.Context, ref interface{}, namespace string) (*Connection, error) {
switch v := ref.(type) {
case *ConnectionRef:
return r.ConnectionRef(ctx, v, namespace)
case *OrganizationRef:
if v.ID != "" {
return r.ConnectionRef(ctx, &v.ConnectionRef, namespace)
}
return nil, fmt.Errorf("organization reference does not contain connection info")
case *ProjectRef:
if v.ID != "" {
return r.ConnectionRef(ctx, &v.ConnectionRef, namespace)
}
return nil, fmt.Errorf("project reference does not contain connection info")
default:
return nil, fmt.Errorf("unsupported reference type for connection resolution")
}
}

View File

@@ -101,11 +101,11 @@ func newWrappedOIDCAppReconciler(client client.Client, refResolver *zitadelv1alp
} }
func (wr *wrappedOIDCAppReconciler) Reconcile(ctx context.Context, ztdClient *clientv2.Client) error { func (wr *wrappedOIDCAppReconciler) Reconcile(ctx context.Context, ztdClient *clientv2.Client) error {
project, err := wr.OIDCApp.Project(ctx, wr.refResolver) projectRef, err := wr.OIDCApp.Project(ctx, wr.refResolver)
if err != nil { if err != nil {
return err return err
} }
if project.Status.ProjectId == nil { if projectRef.ID == "" {
return fmt.Errorf("Project has not been created yet...") return fmt.Errorf("Project has not been created yet...")
} }
responseTypes := []application.OIDCResponseType{} responseTypes := []application.OIDCResponseType{}
@@ -133,7 +133,7 @@ func (wr *wrappedOIDCAppReconciler) Reconcile(ctx context.Context, ztdClient *cl
{ {
Filter: &application.ApplicationSearchFilter_ProjectIdFilter{ Filter: &application.ApplicationSearchFilter_ProjectIdFilter{
ProjectIdFilter: &application.ProjectIDFilter{ ProjectIdFilter: &application.ProjectIDFilter{
ProjectId: *project.Status.ProjectId, ProjectId: projectRef.ID,
}, },
}, },
}, },
@@ -153,7 +153,7 @@ func (wr *wrappedOIDCAppReconciler) Reconcile(ctx context.Context, ztdClient *cl
resp, err := ztdClient.ApplicationServiceV2().CreateApplication(ctx, resp, err := ztdClient.ApplicationServiceV2().CreateApplication(ctx,
&application.CreateApplicationRequest{ &application.CreateApplicationRequest{
Name: wr.OIDCApp.Spec.OIDCAppName, Name: wr.OIDCApp.Spec.OIDCAppName,
ProjectId: *project.Status.ProjectId, ProjectId: projectRef.ID,
ApplicationType: &application.CreateApplicationRequest_OidcConfiguration{ ApplicationType: &application.CreateApplicationRequest_OidcConfiguration{
OidcConfiguration: &application.CreateOIDCApplicationRequest{ OidcConfiguration: &application.CreateOIDCApplicationRequest{
ApplicationType: application.OIDCApplicationType(application.OIDCApplicationType_value[wr.OIDCApp.Spec.AppType]), ApplicationType: application.OIDCApplicationType(application.OIDCApplicationType_value[wr.OIDCApp.Spec.AppType]),
@@ -205,7 +205,7 @@ func (wr *wrappedOIDCAppReconciler) Reconcile(ctx context.Context, ztdClient *cl
_, err := ztdClient.ApplicationServiceV2().UpdateApplication(ctx, _, err := ztdClient.ApplicationServiceV2().UpdateApplication(ctx,
&application.UpdateApplicationRequest{ &application.UpdateApplicationRequest{
Name: wr.OIDCApp.Name, Name: wr.OIDCApp.Name,
ProjectId: *project.Status.ProjectId, ProjectId: projectRef.ID,
ApplicationId: *appid, ApplicationId: *appid,
ApplicationType: &application.UpdateApplicationRequest_OidcConfiguration{ ApplicationType: &application.UpdateApplicationRequest_OidcConfiguration{
OidcConfiguration: &application.UpdateOIDCApplicationConfigurationRequest{ OidcConfiguration: &application.UpdateOIDCApplicationConfigurationRequest{

View File

@@ -58,13 +58,13 @@ func (wr *wrappedOIDCAppFinalizer) ContainsFinalizer() bool {
func (wf *wrappedOIDCAppFinalizer) Reconcile(ctx context.Context, ztdClient *clientv2.Client) error { func (wf *wrappedOIDCAppFinalizer) Reconcile(ctx context.Context, ztdClient *clientv2.Client) error {
if wf.OIDCApp.Status.AppId != nil { if wf.OIDCApp.Status.AppId != nil {
project, err := wf.OIDCApp.Project(ctx, wf.refresolver) projectRef, err := wf.OIDCApp.Project(ctx, wf.refresolver)
if err != nil { if err != nil {
return err return err
} }
_, err = ztdClient.ApplicationServiceV2().DeleteApplication(ctx, &application.DeleteApplicationRequest{ _, err = ztdClient.ApplicationServiceV2().DeleteApplication(ctx, &application.DeleteApplicationRequest{
ApplicationId: *wf.OIDCApp.Status.AppId, ApplicationId: *wf.OIDCApp.Status.AppId,
ProjectId: *project.Status.ProjectId, ProjectId: projectRef.ID,
}) })
if err != nil { if err != nil {
if strings.Contains(err.Error(), "doesn't exist") { if strings.Contains(err.Error(), "doesn't exist") {

View File

@@ -124,13 +124,11 @@ func (wr *wrappedProjectReconciler) Reconcile(ctx context.Context, ztdClient *cl
} }
func (wr *wrappedProjectReconciler) reconcileProject(ctx context.Context, ztdClient *clientv2.Client) error { func (wr *wrappedProjectReconciler) reconcileProject(ctx context.Context, ztdClient *clientv2.Client) error {
org, err := wr.refResolver.OrganizationRef(ctx, &wr.project.Spec.OrganizationRef, wr.project.Namespace) orgRef, err := wr.refResolver.ResolveOrganization(ctx, &wr.project.Spec.OrganizationRef, wr.project.Namespace)
if err != nil { if err != nil {
return err return err
} }
if org.Status.OrganizationId == nil {
return fmt.Errorf("Organization not created yet")
}
var projectId *string var projectId *string
projectList, err := ztdClient.ProjectServiceV2().ListProjects(ctx, &project.ListProjectsRequest{ projectList, err := ztdClient.ProjectServiceV2().ListProjects(ctx, &project.ListProjectsRequest{
Filters: []*project.ProjectSearchFilter{ Filters: []*project.ProjectSearchFilter{
@@ -145,7 +143,7 @@ func (wr *wrappedProjectReconciler) reconcileProject(ctx context.Context, ztdCli
&project.ProjectSearchFilter{ &project.ProjectSearchFilter{
Filter: &project.ProjectSearchFilter_OrganizationIdFilter{ Filter: &project.ProjectSearchFilter_OrganizationIdFilter{
OrganizationIdFilter: &project.ProjectOrganizationIDFilter{ OrganizationIdFilter: &project.ProjectOrganizationIDFilter{
OrganizationId: *org.Status.OrganizationId, OrganizationId: orgRef.ID,
Type: project.ProjectOrganizationIDFilter_OWNED, Type: project.ProjectOrganizationIDFilter_OWNED,
}, },
}, },
@@ -163,7 +161,7 @@ func (wr *wrappedProjectReconciler) reconcileProject(ctx context.Context, ztdCli
resp, err := resp, err :=
ztdClient.ProjectServiceV2().CreateProject(ctx, ztdClient.ProjectServiceV2().CreateProject(ctx,
&project.CreateProjectRequest{ &project.CreateProjectRequest{
OrganizationId: *org.Status.OrganizationId, OrganizationId: orgRef.ID,
Name: wr.project.Spec.ProjectName, Name: wr.project.Spec.ProjectName,
ProjectRoleAssertion: wr.project.Spec.ProjectRoleAssertion, ProjectRoleAssertion: wr.project.Spec.ProjectRoleAssertion,
AuthorizationRequired: wr.project.Spec.ProjectRoleCheck, AuthorizationRequired: wr.project.Spec.ProjectRoleCheck,
@@ -254,16 +252,13 @@ func (wr *wrappedProjectReconciler) reconcileGrants(ctx context.Context, ztdClie
return fmt.Errorf("Error listing project grants: %v", err) return fmt.Errorf("Error listing project grants: %v", err)
} }
for _, grant := range wr.project.DeepCopy().Spec.Grants { for _, grant := range wr.project.DeepCopy().Spec.Grants {
grantedOrg, err := wr.refResolver.OrganizationRef(ctx, &grant.OrganizationRef, wr.project.Namespace) grantedOrgRef, err := wr.refResolver.ResolveOrganization(ctx, &grant.OrganizationRef, wr.project.Namespace)
if err != nil { if err != nil {
return err return err
} }
if grantedOrg.Status.OrganizationId == nil {
continue
}
var existingGrant *project.ProjectGrant var existingGrant *project.ProjectGrant
for _, eGrant := range existingGrants.ProjectGrants { for _, eGrant := range existingGrants.ProjectGrants {
if eGrant.GrantedOrganizationId == *grantedOrg.Status.OrganizationId { if eGrant.GrantedOrganizationId == grantedOrgRef.ID {
existingGrant = eGrant existingGrant = eGrant
break break
} }
@@ -271,7 +266,7 @@ func (wr *wrappedProjectReconciler) reconcileGrants(ctx context.Context, ztdClie
if existingGrant == nil { if existingGrant == nil {
_, err := ztdClient.ProjectServiceV2().CreateProjectGrant(ctx, &project.CreateProjectGrantRequest{ _, err := ztdClient.ProjectServiceV2().CreateProjectGrant(ctx, &project.CreateProjectGrantRequest{
ProjectId: *wr.project.Status.ProjectId, ProjectId: *wr.project.Status.ProjectId,
GrantedOrganizationId: *grantedOrg.Status.OrganizationId, GrantedOrganizationId: grantedOrgRef.ID,
RoleKeys: grant.RoleKeys, RoleKeys: grant.RoleKeys,
}) })
if err != nil { if err != nil {