From b4d7fda692520762e1c1af6a129272afbb7742da Mon Sep 17 00:00:00 2001 From: Jose Szychowski Date: Wed, 17 Jun 2026 17:07:38 -0300 Subject: [PATCH 1/2] feat: implement PlatformAccess CRD and associated RBAC roles --- .../iam.miloapis.com_platformaccesses.yaml | 175 +++++++++++++ .../iam/kustomization.yaml | 1 + .../iam/platformaccess.yaml | 18 ++ config/roles/iam-platform-accesses-admin.yaml | 11 + .../roles/iam-platform-accesses-editor.yaml | 16 ++ .../roles/iam-platform-accesses-reader.yaml | 13 + config/roles/kustomization.yaml | 3 + docs/api/iam.md | 244 ++++++++++++++++++ pkg/apis/iam/v1alpha1/platformaccess_types.go | 92 +++++++ pkg/apis/iam/v1alpha1/register.go | 2 + .../iam/v1alpha1/zz_generated.deepcopy.go | 97 +++++++ 11 files changed, 672 insertions(+) create mode 100644 config/crd/bases/iam/iam.miloapis.com_platformaccesses.yaml create mode 100644 config/protected-resources/iam/platformaccess.yaml create mode 100644 config/roles/iam-platform-accesses-admin.yaml create mode 100644 config/roles/iam-platform-accesses-editor.yaml create mode 100644 config/roles/iam-platform-accesses-reader.yaml create mode 100644 pkg/apis/iam/v1alpha1/platformaccess_types.go diff --git a/config/crd/bases/iam/iam.miloapis.com_platformaccesses.yaml b/config/crd/bases/iam/iam.miloapis.com_platformaccesses.yaml new file mode 100644 index 00000000..73cf995c --- /dev/null +++ b/config/crd/bases/iam/iam.miloapis.com_platformaccesses.yaml @@ -0,0 +1,175 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + discovery.miloapis.com/parent-contexts: Platform + name: platformaccesses.iam.miloapis.com +spec: + group: iam.miloapis.com + names: + kind: PlatformAccess + listKind: PlatformAccessList + plural: platformaccesses + singular: platformaccess + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.userRef.name + name: User + type: string + - jsonPath: .spec.state + name: State + type: string + - jsonPath: .spec.reason + name: Reason + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + PlatformAccess is the Schema for the platformaccesses API. + It is the single mutable resource governing whether a user can access the platform, + replacing UserDeactivation, PlatformAccessApproval, and PlatformAccessRejection. + There is at most one PlatformAccess per user; by convention it is named after the user. + The UserController derives User.status.accessState from this resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: PlatformAccessSpec defines the desired access state for a + user on the platform. + properties: + reason: + description: Reason is a human-readable explanation for the current + state. + type: string + state: + default: Pending + description: |- + State is the desired platform access state for the user. + Valid transitions: + Pending → Approved (fraud accepts, or admin approves) + Pending → Rejected (fraud or admin rejects) + Approved → Suspended (fraud deactivates, or admin suspends) + Approved → Rejected (admin disapproves) + Suspended → Approved (admin reactivates) + enum: + - Pending + - Approved + - Rejected + - Suspended + type: string + userRef: + description: |- + UserRef is a reference to the User this resource governs. + User is a cluster-scoped resource. + properties: + name: + description: Name is the name of the User being referenced. + type: string + required: + - name + type: object + required: + - state + - userRef + type: object + status: + description: PlatformAccessStatus defines the observed state of PlatformAccess. + properties: + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for control plane to reconcile + reason: Unknown + status: Unknown + type: Ready + description: Conditions represent the latest available observations + of the resource's current state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + selectableFields: + - jsonPath: .spec.userRef.name + - jsonPath: .spec.state + served: true + storage: true + subresources: + status: {} diff --git a/config/protected-resources/iam/kustomization.yaml b/config/protected-resources/iam/kustomization.yaml index f13d61ea..10025b86 100644 --- a/config/protected-resources/iam/kustomization.yaml +++ b/config/protected-resources/iam/kustomization.yaml @@ -11,6 +11,7 @@ resources: - policybinding.yaml - userpreference.yaml - userdeactivation.yaml + - platformaccess.yaml - platformaccessapproval.yaml - platformaccessrejection.yaml - platforminvitation.yaml diff --git a/config/protected-resources/iam/platformaccess.yaml b/config/protected-resources/iam/platformaccess.yaml new file mode 100644 index 00000000..51ca6b7b --- /dev/null +++ b/config/protected-resources/iam/platformaccess.yaml @@ -0,0 +1,18 @@ +apiVersion: iam.miloapis.com/v1alpha1 +kind: ProtectedResource +metadata: + name: iam.miloapis.com-platformaccess +spec: + serviceRef: + name: "iam.miloapis.com" + kind: PlatformAccess + plural: platformaccesses + singular: platformaccess + permissions: + - list + - get + - create + - update + - delete + - patch + - watch diff --git a/config/roles/iam-platform-accesses-admin.yaml b/config/roles/iam-platform-accesses-admin.yaml new file mode 100644 index 00000000..9fbe503f --- /dev/null +++ b/config/roles/iam-platform-accesses-admin.yaml @@ -0,0 +1,11 @@ +apiVersion: iam.miloapis.com/v1alpha1 +kind: Role +metadata: + name: iam-platform-accesses-admin + annotations: + kubernetes.io/display-name: Platform Access Admin + kubernetes.io/description: Full access to platform accesses +spec: + launchStage: Beta + inheritedRoles: + - name: iam-platform-accesses-editor diff --git a/config/roles/iam-platform-accesses-editor.yaml b/config/roles/iam-platform-accesses-editor.yaml new file mode 100644 index 00000000..adb7298b --- /dev/null +++ b/config/roles/iam-platform-accesses-editor.yaml @@ -0,0 +1,16 @@ +apiVersion: iam.miloapis.com/v1alpha1 +kind: Role +metadata: + name: iam-platform-accesses-editor + annotations: + kubernetes.io/display-name: Platform Access Editor + kubernetes.io/description: Create, update, and delete platform accesses +spec: + launchStage: Beta + inheritedRoles: + - name: iam-platform-accesses-reader + includedPermissions: + - iam.miloapis.com/platformaccesses.create + - iam.miloapis.com/platformaccesses.update + - iam.miloapis.com/platformaccesses.patch + - iam.miloapis.com/platformaccesses.delete diff --git a/config/roles/iam-platform-accesses-reader.yaml b/config/roles/iam-platform-accesses-reader.yaml new file mode 100644 index 00000000..f53dabec --- /dev/null +++ b/config/roles/iam-platform-accesses-reader.yaml @@ -0,0 +1,13 @@ +apiVersion: iam.miloapis.com/v1alpha1 +kind: Role +metadata: + name: iam-platform-accesses-reader + annotations: + kubernetes.io/display-name: Platform Access Viewer + kubernetes.io/description: View platform accesses +spec: + launchStage: Beta + includedPermissions: + - iam.miloapis.com/platformaccesses.get + - iam.miloapis.com/platformaccesses.list + - iam.miloapis.com/platformaccesses.watch diff --git a/config/roles/kustomization.yaml b/config/roles/kustomization.yaml index 5456bf66..469f2bb7 100644 --- a/config/roles/kustomization.yaml +++ b/config/roles/kustomization.yaml @@ -59,6 +59,9 @@ resources: - project-admin.yaml - iam.miloapis.com-getinvitation.yaml - iam.miloapis.com-acceptinvitation.yaml + - iam-platform-accesses-reader.yaml + - iam-platform-accesses-editor.yaml + - iam-platform-accesses-admin.yaml - iam-platform-access-approvals-reader.yaml - iam-platform-access-approvals-editor.yaml - iam-platform-access-approvals-admin.yaml diff --git a/docs/api/iam.md b/docs/api/iam.md index bc478a59..57e7cea6 100644 --- a/docs/api/iam.md +++ b/docs/api/iam.md @@ -14,6 +14,8 @@ Resource Types: - [PlatformAccessApproval](#platformaccessapproval) +- [PlatformAccess](#platformaccess) + - [PlatformAccessRejection](#platformaccessrejection) - [PlatformInvitation](#platforminvitation) @@ -622,6 +624,248 @@ If not specified, the approval was made by the system. +## PlatformAccess +[↩ Parent](#iammiloapiscomv1alpha1 ) + + + + + + +PlatformAccess is the Schema for the platformaccesses API. +It is the single mutable resource governing whether a user can access the platform, +replacing UserDeactivation, PlatformAccessApproval, and PlatformAccessRejection. +There is at most one PlatformAccess per user; by convention it is named after the user. +The UserController derives User.status.accessState from this resource. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
apiVersionstringiam.miloapis.com/v1alpha1true
kindstringPlatformAccesstrue
metadataobjectRefer to the Kubernetes API documentation for the fields of the `metadata` field.true
specobject + PlatformAccessSpec defines the desired access state for a user on the platform.
+
false
statusobject + PlatformAccessStatus defines the observed state of PlatformAccess.
+
false
+ + +### PlatformAccess.spec +[↩ Parent](#platformaccess) + + + +PlatformAccessSpec defines the desired access state for a user on the platform. + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
stateenum + State is the desired platform access state for the user. +Valid transitions: + Pending → Approved (fraud accepts, or admin approves) + Pending → Rejected (fraud or admin rejects) + Approved → Suspended (fraud deactivates, or admin suspends) + Approved → Rejected (admin disapproves) + Suspended → Approved (admin reactivates)
+
+ Enum: Pending, Approved, Rejected, Suspended
+ Default: Pending
+
true
userRefobject + UserRef is a reference to the User this resource governs. +User is a cluster-scoped resource.
+
true
reasonstring + Reason is a human-readable explanation for the current state.
+
false
+ + +### PlatformAccess.spec.userRef +[↩ Parent](#platformaccessspec) + + + +UserRef is a reference to the User this resource governs. +User is a cluster-scoped resource. + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
namestring + Name is the name of the User being referenced.
+
true
+ + +### PlatformAccess.status +[↩ Parent](#platformaccess) + + + +PlatformAccessStatus defines the observed state of PlatformAccess. + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
conditions[]object + Conditions represent the latest available observations of the resource's current state.
+
+ Default: [map[lastTransitionTime:1970-01-01T00:00:00Z message:Waiting for control plane to reconcile reason:Unknown status:Unknown type:Ready]]
+
false
+ + +### PlatformAccess.status.conditions[index] +[↩ Parent](#platformaccessstatus) + + + +Condition contains details for one aspect of the current state of this API Resource. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
lastTransitionTimestring + lastTransitionTime is the last time the condition transitioned from one status to another. +This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
+
+ Format: date-time
+
true
messagestring + message is a human readable message indicating details about the transition. +This may be an empty string.
+
true
reasonstring + reason contains a programmatic identifier indicating the reason for the condition's last transition. +Producers of specific condition types may define expected values and meanings for this field, +and whether the values are considered a guaranteed API. +The value should be a CamelCase string. +This field may not be empty.
+
true
statusenum + status of the condition, one of True, False, Unknown.
+
+ Enum: True, False, Unknown
+
true
typestring + type of condition in CamelCase or in foo.example.com/CamelCase.
+
true
observedGenerationinteger + observedGeneration represents the .metadata.generation that the condition was set based upon. +For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date +with respect to the current state of the instance.
+
+ Format: int64
+ Minimum: 0
+
false
+ ## PlatformAccessRejection [↩ Parent](#iammiloapiscomv1alpha1 ) diff --git a/pkg/apis/iam/v1alpha1/platformaccess_types.go b/pkg/apis/iam/v1alpha1/platformaccess_types.go new file mode 100644 index 00000000..8a1d154a --- /dev/null +++ b/pkg/apis/iam/v1alpha1/platformaccess_types.go @@ -0,0 +1,92 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// PlatformAccessState represents the access lifecycle state of a user on the platform. +// +kubebuilder:validation:Enum=Pending;Approved;Rejected;Suspended +type PlatformAccessState string + +const ( + PlatformAccessStatePending PlatformAccessState = "Pending" + PlatformAccessStateApproved PlatformAccessState = "Approved" + PlatformAccessStateRejected PlatformAccessState = "Rejected" + PlatformAccessStateSuspended PlatformAccessState = "Suspended" +) + +const ( + // PlatformAccessReadyCondition is set to True when the PlatformAccess has been reconciled. + PlatformAccessReadyCondition = "Ready" + // PlatformAccessReconciledReason is the typical reason used when reconciliation succeeds. + PlatformAccessReconciledReason = "Reconciled" +) + +// PlatformAccessSpec defines the desired access state for a user on the platform. +type PlatformAccessSpec struct { + // UserRef is a reference to the User this resource governs. + // User is a cluster-scoped resource. + // +kubebuilder:validation:Required + UserRef UserReference `json:"userRef"` + + // State is the desired platform access state for the user. + // Valid transitions: + // Pending → Approved (fraud accepts, or admin approves) + // Pending → Rejected (fraud or admin rejects) + // Approved → Suspended (fraud deactivates, or admin suspends) + // Approved → Rejected (admin disapproves) + // Suspended → Approved (admin reactivates) + // +kubebuilder:validation:Required + // +kubebuilder:default=Pending + State PlatformAccessState `json:"state"` + + // Reason is a human-readable explanation for the current state. + // +kubebuilder:validation:Optional + Reason string `json:"reason,omitempty"` +} + +// PlatformAccessStatus defines the observed state of PlatformAccess. +type PlatformAccessStatus struct { + // Conditions represent the latest available observations of the resource's current state. + // +kubebuilder:default={{type: "Ready", status: "Unknown", reason: "Unknown", message: "Waiting for control plane to reconcile", lastTransitionTime: "1970-01-01T00:00:00Z"}} + // +kubebuilder:validation:Optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// PlatformAccess is the Schema for the platformaccesses API. +// It is the single mutable resource governing whether a user can access the platform, +// replacing UserDeactivation, PlatformAccessApproval, and PlatformAccessRejection. +// There is at most one PlatformAccess per user; by convention it is named after the user. +// The UserController derives User.status.accessState from this resource. +// +kubebuilder:printcolumn:name="User",type="string",JSONPath=".spec.userRef.name" +// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".spec.state" +// +kubebuilder:printcolumn:name="Reason",type="string",JSONPath=".spec.reason" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +// +kubebuilder:selectablefield:JSONPath=".spec.userRef.name" +// +kubebuilder:selectablefield:JSONPath=".spec.state" +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:metadata:annotations="discovery.miloapis.com/parent-contexts=Platform" +type PlatformAccess struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PlatformAccessSpec `json:"spec,omitempty"` + Status PlatformAccessStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true + +// PlatformAccessList contains a list of PlatformAccess. +type PlatformAccessList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PlatformAccess `json:"items"` +} diff --git a/pkg/apis/iam/v1alpha1/register.go b/pkg/apis/iam/v1alpha1/register.go index b8a4037d..7a005550 100644 --- a/pkg/apis/iam/v1alpha1/register.go +++ b/pkg/apis/iam/v1alpha1/register.go @@ -43,6 +43,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &UserInvitationList{}, &PlatformInvitation{}, &PlatformInvitationList{}, + &PlatformAccess{}, + &PlatformAccessList{}, &PlatformAccessApproval{}, &PlatformAccessApprovalList{}, &PlatformAccessRejection{}, diff --git a/pkg/apis/iam/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/iam/v1alpha1/zz_generated.deepcopy.go index be9292cc..2bccd59c 100644 --- a/pkg/apis/iam/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/iam/v1alpha1/zz_generated.deepcopy.go @@ -217,6 +217,33 @@ func (in *ParentResourceRef) DeepCopy() *ParentResourceRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlatformAccess) DeepCopyInto(out *PlatformAccess) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformAccess. +func (in *PlatformAccess) DeepCopy() *PlatformAccess { + if in == nil { + return nil + } + out := new(PlatformAccess) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PlatformAccess) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PlatformAccessApproval) DeepCopyInto(out *PlatformAccessApproval) { *out = *in @@ -296,6 +323,38 @@ func (in *PlatformAccessApprovalSpec) DeepCopy() *PlatformAccessApprovalSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlatformAccessList) DeepCopyInto(out *PlatformAccessList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PlatformAccess, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformAccessList. +func (in *PlatformAccessList) DeepCopy() *PlatformAccessList { + if in == nil { + return nil + } + out := new(PlatformAccessList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PlatformAccessList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PlatformAccessRejection) DeepCopyInto(out *PlatformAccessRejection) { *out = *in @@ -375,6 +434,44 @@ func (in *PlatformAccessRejectionSpec) DeepCopy() *PlatformAccessRejectionSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlatformAccessSpec) DeepCopyInto(out *PlatformAccessSpec) { + *out = *in + out.UserRef = in.UserRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformAccessSpec. +func (in *PlatformAccessSpec) DeepCopy() *PlatformAccessSpec { + if in == nil { + return nil + } + out := new(PlatformAccessSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlatformAccessStatus) DeepCopyInto(out *PlatformAccessStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformAccessStatus. +func (in *PlatformAccessStatus) DeepCopy() *PlatformAccessStatus { + if in == nil { + return nil + } + out := new(PlatformAccessStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PlatformInvitation) DeepCopyInto(out *PlatformInvitation) { *out = *in From aade1b9c35e3a0ca670797dbb7746193ae41334a Mon Sep 17 00:00:00 2001 From: Jose Szychowski Date: Wed, 17 Jun 2026 17:18:25 -0300 Subject: [PATCH 2/2] feat: add platformaccesses CRD to IAM kustomization --- config/crd/bases/iam/kustomization.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/crd/bases/iam/kustomization.yaml b/config/crd/bases/iam/kustomization.yaml index 8f615aff..ac2c84c5 100644 --- a/config/crd/bases/iam/kustomization.yaml +++ b/config/crd/bases/iam/kustomization.yaml @@ -10,5 +10,6 @@ resources: - iam.miloapis.com_userpreferences.yaml - iam.miloapis.com_userdeactivations.yaml - iam.miloapis.com_platforminvitations.yaml +- iam.miloapis.com_platformaccesses.yaml - iam.miloapis.com_platformaccessapprovals.yaml - iam.miloapis.com_platformaccessrejections.yaml