Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,22 @@
return nil, errors.NewInternalError(fmt.Errorf("failed to list membership removals: %w", err))
}
if len(existingRemovals.Items) > 0 {
errs = append(errs, field.Invalid(field.NewPath("spec"), cgm.Spec, fmt.Sprintf("cannot create membership as a ContactGroupMembershipRemoval %s already exists", existingRemovals.Items[0].Name)))
}

// Check that cgm namespace is the same as the contact namespace for contacts that are related
// to the resourcemanager.miloapis.com API group
if contact.Spec.SubjectRef != nil {
switch contact.Spec.SubjectRef.APIGroup {
case "resourcemanager.miloapis.com":
if cgm.Namespace != contact.Namespace {
errs = append(errs, field.Invalid(field.NewPath("spec"), cgm.Spec, "namespace must be the same as the contact namespace for contacts that are related to the resourcemanager.miloapis.com API group"))
}
default:
return nil, errors.NewInternalError(fmt.Errorf("server does not handle SubjectRef APIGroup %s", contact.Spec.SubjectRef.APIGroup))

Check warning on line 121 in internal/webhooks/notification/v1alpha1/contactgroupmembership_webhook.go

View check run for this annotation

JoggrBot / Joggr

internal/webhooks/notification/v1alpha1/contactgroupmembership_webhook.go#L109-L121

"docs/api/notification.md" is outdated: ContactGroupMembershipValidator and ContactGroupMembershipRemovalValidator now enforce that, for contacts with SubjectRef APIGroup 'resourcemanager.miloapis.com', the resource namespace must match the contact's namespace, a restriction not described in the documentation.
}
}

if len(errs) > 0 {
return nil, errors.NewInvalid(notificationv1alpha1.SchemeGroupVersion.WithKind("ContactGroupMembership").GroupKind(), cgm.Name, errs)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,45 @@ func TestContactGroupMembershipValidator(t *testing.T) {
expectError: true,
errorContains: "not found",
},
"subjectref same namespace": {
newObj: &notificationv1alpha1.ContactGroupMembership{
ObjectMeta: metav1.ObjectMeta{Name: "m6", Namespace: "default"},
Spec: notificationv1alpha1.ContactGroupMembershipSpec{
ContactRef: notificationv1alpha1.ContactReference{Name: "c-sub", Namespace: "default"},
ContactGroupRef: notificationv1alpha1.ContactGroupReference{Name: "g-sub", Namespace: "default"},
},
},
seedObjects: []client.Object{
&notificationv1alpha1.Contact{
ObjectMeta: metav1.ObjectMeta{Name: "c-sub", Namespace: "default"},
Spec: notificationv1alpha1.ContactSpec{
SubjectRef: &notificationv1alpha1.SubjectReference{APIGroup: "resourcemanager.miloapis.com", Kind: "Project", Name: "proj1"},
},
},
&notificationv1alpha1.ContactGroup{ObjectMeta: metav1.ObjectMeta{Name: "g-sub", Namespace: "default"}},
},
expectError: false,
},
"subjectref namespace mismatch": {
newObj: &notificationv1alpha1.ContactGroupMembership{
ObjectMeta: metav1.ObjectMeta{Name: "m7", Namespace: "other"},
Spec: notificationv1alpha1.ContactGroupMembershipSpec{
ContactRef: notificationv1alpha1.ContactReference{Name: "c-sub", Namespace: "default"},
ContactGroupRef: notificationv1alpha1.ContactGroupReference{Name: "g-sub", Namespace: "other"},
},
},
seedObjects: []client.Object{
&notificationv1alpha1.Contact{
ObjectMeta: metav1.ObjectMeta{Name: "c-sub", Namespace: "default"},
Spec: notificationv1alpha1.ContactSpec{
SubjectRef: &notificationv1alpha1.SubjectReference{APIGroup: "resourcemanager.miloapis.com", Kind: "Project", Name: "proj1"},
},
},
&notificationv1alpha1.ContactGroup{ObjectMeta: metav1.ObjectMeta{Name: "g-sub", Namespace: "other"}},
},
expectError: true,
errorContains: "namespace must be the same",
},
}

for name, tt := range tests {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
var errs field.ErrorList

// Ensure Contact exists
if err := v.Client.Get(ctx, client.ObjectKey{Namespace: removal.Spec.ContactRef.Namespace, Name: removal.Spec.ContactRef.Name}, &notificationv1alpha1.Contact{}); err != nil {
contact := &notificationv1alpha1.Contact{}
if err := v.Client.Get(ctx, client.ObjectKey{Namespace: removal.Spec.ContactRef.Namespace, Name: removal.Spec.ContactRef.Name}, contact); err != nil {
if errors.IsNotFound(err) {
errs = append(errs, field.NotFound(field.NewPath("spec", "contactRef", "name"), removal.Spec.ContactRef.Name))
} else {
Expand All @@ -76,9 +77,22 @@
return nil, errors.NewInternalError(fmt.Errorf("failed to list removals: %w", err))
}
if len(existing.Items) > 0 {
errs = append(errs, field.Duplicate(field.NewPath("spec"), fmt.Sprintf("membership removal already exists in ContactGroupMembershipRemoval %s", existing.Items[0].Name)))
}

// Check that cgmr namespace is the same as the contact namespace for contacts that are related
// to the resourcemanager.miloapis.com API group
if contact.Spec.SubjectRef != nil {
switch contact.Spec.SubjectRef.APIGroup {
case "resourcemanager.miloapis.com":
if removal.Namespace != contact.Namespace {
errs = append(errs, field.Invalid(field.NewPath("spec"), removal.Spec, "namespace must be the same as the contact namespace for contacts that are related to the resourcemanager.miloapis.com API group"))
}
default:
return nil, errors.NewInternalError(fmt.Errorf("server does not handle SubjectRef APIGroup %s", contact.Spec.SubjectRef.APIGroup))

Check warning on line 92 in internal/webhooks/notification/v1alpha1/contactgroupmembershipremoval_webhook.go

View check run for this annotation

JoggrBot / Joggr

internal/webhooks/notification/v1alpha1/contactgroupmembershipremoval_webhook.go#L80-L92

"docs/api/notification.md" is outdated: ContactGroupMembershipRemovalValidator now returns an error if the namespace does not match for contacts with SubjectRef APIGroup 'resourcemanager.miloapis.com', and also rejects unsupported API groups—neither is documented.
}
}

if len(errs) > 0 {
return nil, errors.NewInvalid(notificationv1alpha1.SchemeGroupVersion.WithKind("ContactGroupMembershipRemoval").GroupKind(), removal.Name, errs)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ func TestContactGroupMembershipRemovalValidator(t *testing.T) {
return &notificationv1alpha1.ContactGroup{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "default"}}
}

// makeContactWithSubject creates a Contact that includes a SubjectRef with the given apiGroup and namespace.
makeContactWithSubject := func(name, ns, apiGroup string) *notificationv1alpha1.Contact {
return &notificationv1alpha1.Contact{
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
Spec: notificationv1alpha1.ContactSpec{
SubjectRef: &notificationv1alpha1.SubjectReference{
APIGroup: apiGroup,
Kind: "User",
Name: "demo", // value not relevant for validator logic
Namespace: ns,
},
FamilyName: "Doe",
GivenName: "John",
Email: "[email protected]",
},
}
}

tests := map[string]struct {
newObj *notificationv1alpha1.ContactGroupMembershipRemoval
seedObjects []client.Object
Expand Down Expand Up @@ -81,6 +99,29 @@ func TestContactGroupMembershipRemovalValidator(t *testing.T) {
},
expectError: false,
},
"contact with resourcemanager apiGroup same namespace": {
newObj: makeRemoval("rm7", "c-res", "g1"),
seedObjects: []client.Object{makeContactWithSubject("c-res", "default", "resourcemanager.miloapis.com"), makeGroup("g1")},
expectError: false,
},
"contact with resourcemanager apiGroup different namespace": {
newObj: &notificationv1alpha1.ContactGroupMembershipRemoval{
ObjectMeta: metav1.ObjectMeta{Name: "rm8", Namespace: "other-ns"},
Spec: notificationv1alpha1.ContactGroupMembershipRemovalSpec{
ContactRef: notificationv1alpha1.ContactReference{Name: "c-res", Namespace: "default"},
ContactGroupRef: notificationv1alpha1.ContactGroupReference{Name: "g1", Namespace: "default"},
},
},
seedObjects: []client.Object{makeContactWithSubject("c-res", "default", "resourcemanager.miloapis.com"), makeGroup("g1")},
expectError: true,
errorContains: "namespace must be the same",
},
"contact with unsupported apiGroup": {
newObj: makeRemoval("rm9", "c-oth", "g1"),
seedObjects: []client.Object{makeContactWithSubject("c-oth", "default", "unsupported.group"), makeGroup("g1")},
expectError: true,
errorContains: "server does not handle subjectref apigroup",
},
}

for name, tt := range tests {
Expand Down