diff --git a/README.md b/README.md index 297f8de..57a50af 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Infrastructure as Code for managing access to MCP community resources using Pulu - **GitHub Teams**: Automatically syncs team memberships in the MCP GitHub organization - **Google Workspace Groups**: Automatically syncs group memberships for @modelcontextprotocol.io email accounts + - **Email Groups**: Groups with `isEmailGroup: true` accept emails from anyone (including external users) and notify all members. External posts are moderated for security. ## Deployment diff --git a/src/config/groups.ts b/src/config/groups.ts index 694462c..6cf782a 100644 --- a/src/config/groups.ts +++ b/src/config/groups.ts @@ -2,6 +2,9 @@ import { defineGroups } from './utils'; // NOTE: For GitHub teams, only the first memberOf will be used as the parent team. // GitHub only supports one parent team per team. +// +// Email groups (isEmailGroup: true) accept emails from anyone (including external users) +// and notify group members for each email. export const GROUPS = defineGroups([ { name: 'test-parent', @@ -12,4 +15,14 @@ export const GROUPS = defineGroups([ description: 'Registry maintainers', memberOf: ['test-parent'], }, + { + name: 'test-email-group', + description: 'Example email group that accepts external emails', + isEmailGroup: true, + }, + { + name: 'antitrust', + description: 'Antitrust compliance contacts', + isEmailGroup: true, + }, ] as const); \ No newline at end of file diff --git a/src/config/users.ts b/src/config/users.ts index 95e0c66..82b00fa 100644 --- a/src/config/users.ts +++ b/src/config/users.ts @@ -6,4 +6,16 @@ export const MEMBERS: readonly Member[] = [ email: 'adam@modelcontextprotocol.io', memberOf: ['test-child'], }, + { + email: 'davidsp@anthropic.com', + memberOf: ['antitrust'], + }, + { + email: 'mattsamuels@anthropic.com', + memberOf: ['antitrust'], + }, + { + email: 'davideramian@anthropic.com', + memberOf: ['antitrust'], + }, ] as const; \ No newline at end of file diff --git a/src/config/utils.ts b/src/config/utils.ts index 14401a2..9c36942 100644 --- a/src/config/utils.ts +++ b/src/config/utils.ts @@ -9,6 +9,7 @@ export function defineGroups< name: Lowercase; description: string; memberOf?: readonly (T[number]['name'])[]; + isEmailGroup?: boolean; }[] >(groups: T) { for (const group of groups) { @@ -28,10 +29,11 @@ export interface Group { name: GroupKey; description: string; memberOf?: readonly GroupKey[]; + isEmailGroup?: boolean; } export interface Member { github?: string; - email?: `${string}@modelcontextprotocol.io`; + email?: string; memberOf: readonly GroupKey[]; } \ No newline at end of file diff --git a/src/google.ts b/src/google.ts index 25d39b0..69363c6 100644 --- a/src/google.ts +++ b/src/google.ts @@ -17,18 +17,25 @@ GROUPS.forEach((group: Group) => { // Maximise visibility of group. It's visible in GitHub anyway whoCanViewMembership: 'ALL_IN_DOMAIN_CAN_VIEW', - + // This specifies who can add/remove members. We want this to only be via this IaC. whoCanModerateMembers: 'NONE', whoCanLeaveGroup: 'NONE_CAN_LEAVE', whoCanJoin: 'INVITED_CAN_JOIN', - - // We don't intend these groups to be used as mailing lists, so we set posting and viewing messages to the most restrictive settings currently available. - whoCanPostMessage: 'ALL_OWNERS_CAN_POST', - whoCanContactOwner: 'ALL_OWNERS_CAN_CONTACT', - // This is badly named, but actually means 'Permissions to view group messages'. See https://developers.google.com/workspace/admin/groups-settings/v1/reference/groups - whoCanViewGroup: 'ALL_OWNERS_CAN_VIEW', - + + // Email groups allow anyone (including externals) to post + // Non-email groups are not intended as mailing lists, so use the most restrictive settings + // whoCanViewGroup is badly named, but actually means 'Permissions to view group messages'. See https://developers.google.com/workspace/admin/groups-settings/v1/reference/groups + ...(group.isEmailGroup ? { + whoCanPostMessage: 'ANYONE_CAN_POST', + whoCanContactOwner: 'ALL_OWNERS_CAN_CONTACT', + whoCanViewGroup: 'ALL_MEMBERS_CAN_VIEW', + } : { + whoCanPostMessage: 'ALL_OWNERS_CAN_POST', + whoCanContactOwner: 'ALL_OWNERS_CAN_CONTACT', + whoCanViewGroup: 'ALL_OWNERS_CAN_VIEW', + }), + }); group.memberOf?.forEach((parentGroupKey) => {