Skip to content

Commit f0c9752

Browse files
committed
Merge branch 'main' of ssh://github.com/linuxfoundation/lfx-v2-mailing-list-service into andrest50/settings
2 parents 060722c + 2f96a40 commit f0c9752

File tree

2 files changed

+50
-16
lines changed

2 files changed

+50
-16
lines changed

internal/service/grpsio_member_writer.go

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ import (
1919
"github.com/linuxfoundation/lfx-v2-mailing-list-service/pkg/utils"
2020
)
2121

22+
// groupsioMailingListMemberStub represents the minimal data needed for member access control
23+
type groupsioMailingListMemberStub struct {
24+
// UID is the mailing list member ID.
25+
UID string `json:"uid"`
26+
// Username is the username (i.e. LFID) of the member. This is the identity of the user object in FGA.
27+
Username string `json:"username"`
28+
// MailingListUID is the mailing list ID for the mailing list the member belongs to.
29+
MailingListUID string `json:"mailing_list_uid"`
30+
}
31+
2232
// ensureMemberIdempotent checks if member already exists by Groups.io member ID or email
2333
// Returns existing entity if found, nil if not found, error on failure
2434
// Pattern mirrors ensureMailingListIdempotent
@@ -415,8 +425,8 @@ func (o *grpsIOWriterOrchestrator) DeleteGrpsIOMember(ctx context.Context, uid s
415425
)
416426

417427
// Publish delete messages (indexer and access control)
418-
if o.publisher != nil {
419-
if err := o.publishMemberDeleteMessages(ctx, uid); err != nil {
428+
if o.publisher != nil && member != nil {
429+
if err := o.publishMemberDeleteMessages(ctx, uid, *member); err != nil {
420430
slog.ErrorContext(ctx, "failed to publish member delete messages", "error", err)
421431
// Don't fail the operation on message failure, delete succeeded
422432
}
@@ -461,16 +471,24 @@ func (o *grpsIOWriterOrchestrator) publishMemberMessages(ctx context.Context, me
461471
return fmt.Errorf("failed to build %s indexer message: %w", action, err)
462472
}
463473

464-
// TODO: LFXV2-459 - Review and implement member access control logic for OpenFGA integration
465-
// Access control message building and publishing will be implemented after research is complete
466-
467-
// Publish messages concurrently (only indexer for now)
474+
// Prepare messages to publish
468475
messages := []func() error{
469476
func() error {
470477
return o.publisher.Indexer(ctx, constants.IndexGroupsIOMemberSubject, indexerMessage)
471478
},
472479
}
473480

481+
// Only publish access control message if member has a username (required for FGA identity)
482+
if member.Username != "" {
483+
accessMessage := o.buildMemberAccessMessage(member)
484+
messages = append(messages, func() error {
485+
return o.publisher.Access(ctx, constants.PutMemberGroupsIOMailingListSubject, accessMessage)
486+
})
487+
} else {
488+
slog.DebugContext(ctx, "skipping access control message - member has no username",
489+
"member_uid", member.UID)
490+
}
491+
474492
// Execute all messages concurrently
475493
errPublishingMessage := concurrent.NewWorkerPool(len(messages)).Run(ctx, messages...)
476494
if errPublishingMessage != nil {
@@ -489,15 +507,13 @@ func (o *grpsIOWriterOrchestrator) publishMemberMessages(ctx context.Context, me
489507
return nil
490508
}
491509

492-
// publishMemberDeleteMessages publishes member delete messages concurrently (for future use)
493-
// nolint:unused // Reserved for future member deletion functionality
494-
func (o *grpsIOWriterOrchestrator) publishMemberDeleteMessages(ctx context.Context, uid string) error {
510+
// publishMemberDeleteMessages publishes member delete messages concurrently
511+
func (o *grpsIOWriterOrchestrator) publishMemberDeleteMessages(ctx context.Context, uid string, member model.GrpsIOMember) error {
495512
if o.publisher == nil {
496513
slog.WarnContext(ctx, "publisher not available, skipping member delete message publishing")
497514
return nil
498515
}
499516

500-
// For delete messages, we just need the UID
501517
indexerMessage := &model.IndexerMessage{
502518
Action: model.ActionDeleted,
503519
Tags: []string{},
@@ -509,16 +525,22 @@ func (o *grpsIOWriterOrchestrator) publishMemberDeleteMessages(ctx context.Conte
509525
return fmt.Errorf("failed to build member delete indexer message: %w", err)
510526
}
511527

512-
// Publish delete messages concurrently
528+
// Prepare messages to publish
513529
messages := []func() error{
514530
func() error {
515531
return o.publisher.Indexer(ctx, constants.IndexGroupsIOMemberSubject, builtMessage)
516532
},
517-
// TODO: LFXV2-459 Implement proper member removal from mailing list relations
518-
// Currently commented out to avoid deleting entire mailing list from OpenFGA
519-
// func() error {
520-
// return o.publisher.Access(ctx, constants.DeleteAllAccessGroupsIOMemberSubject, uid)
521-
// },
533+
}
534+
535+
// Only publish access control message if member has a username (required for FGA identity)
536+
if member.Username != "" {
537+
accessMessage := o.buildMemberAccessMessage(&member)
538+
messages = append(messages, func() error {
539+
return o.publisher.Access(ctx, constants.RemoveMemberGroupsIOMailingListSubject, accessMessage)
540+
})
541+
} else {
542+
slog.DebugContext(ctx, "skipping access control delete message - member has no username",
543+
"member_uid", uid)
522544
}
523545

524546
// Execute all messages concurrently
@@ -546,6 +568,15 @@ func (o *grpsIOWriterOrchestrator) buildMemberIndexerMessage(ctx context.Context
546568
return indexerMessage.Build(ctx, member)
547569
}
548570

571+
// buildMemberAccessMessage creates the access control message stub for OpenFGA integration
572+
func (o *grpsIOWriterOrchestrator) buildMemberAccessMessage(member *model.GrpsIOMember) *groupsioMailingListMemberStub {
573+
return &groupsioMailingListMemberStub{
574+
UID: member.UID,
575+
Username: member.Username,
576+
MailingListUID: member.MailingListUID,
577+
}
578+
}
579+
549580
// mergeMemberData merges existing member data with updated fields, preserving immutable fields
550581
func (o *grpsIOWriterOrchestrator) mergeMemberData(ctx context.Context, existing *model.GrpsIOMember, updated *model.GrpsIOMember) {
551582
// Preserve immutable fields

pkg/constants/subjects.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ const (
1919
UpdateAccessGroupsIOMailingListSubject = "lfx.update_access.groupsio_mailing_list"
2020
DeleteAllAccessGroupsIOMailingListSubject = "lfx.delete_all_access.groupsio_mailing_list"
2121

22+
PutMemberGroupsIOMailingListSubject = "lfx.put_member.groupsio_mailing_list"
23+
RemoveMemberGroupsIOMailingListSubject = "lfx.remove_member.groupsio_mailing_list"
24+
2225
// Committee event subjects from committee-api
2326
CommitteeMemberCreatedSubject = "lfx.committee-api.committee_member.created"
2427
CommitteeMemberDeletedSubject = "lfx.committee-api.committee_member.deleted"

0 commit comments

Comments
 (0)