diff --git a/README.md b/README.md index e07859b..5375bcc 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,24 @@ 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. +- **Google Workspace User Accounts**: Provisions @modelcontextprotocol.io accounts for members of roles with `provisionUser: true` + +### Opting in to a Google Workspace account (maintainers) + +If you're a maintainer and want an `@modelcontextprotocol.io` account, open a PR adding the following fields to your entry in [`src/config/users.ts`](src/config/users.ts): + +```ts +{ + github: 'your-github-username', + // ... + firstName: 'Your', + lastName: 'Name', + googleEmailPrefix: 'yourname', // -> yourname@modelcontextprotocol.io + memberOf: [ROLE_IDS.MAINTAINERS /* , ... */], +}, +``` + +Once merged, Pulumi provisions the account. An admin will share your initial password (retrievable via `pulumi stack output --show-secrets newGWSUserPasswords`). ## Deployment diff --git a/scripts/test-config.ts b/scripts/test-config.ts index edffdca..108e57e 100644 --- a/scripts/test-config.ts +++ b/scripts/test-config.ts @@ -99,7 +99,7 @@ test('googleEmailPrefix values are unique', () => { return prefixes.length === new Set(prefixes).size; }); -test('ProvisionUser members are explicit: fields present or skip flag set', () => { +test('skipGoogleUserProvisioning is only used in provisionUser roles and without fields', () => { const provisionRoleIds = new Set(ROLES.filter((r) => r.google?.provisionUser).map((r) => r.id)); return MEMBERS.every((member) => { const inProvisionRole = member.memberOf.some((id) => provisionRoleIds.has(id)); @@ -110,7 +110,7 @@ test('ProvisionUser members are explicit: fields present or skip flag set', () = member.lastName && member.googleEmailPrefix ); - return hasProvisioningFields !== !!member.skipGoogleUserProvisioning; + return !(hasProvisioningFields && member.skipGoogleUserProvisioning); }); }); diff --git a/scripts/validate-config.ts b/scripts/validate-config.ts index 4f8c748..168c00f 100644 --- a/scripts/validate-config.ts +++ b/scripts/validate-config.ts @@ -154,13 +154,6 @@ console.log('Validating Google Workspace user provisioning fields...'); ); hasErrors = true; } - - if (inProvisionUserRole && !hasProvisioningFields && !member.skipGoogleUserProvisioning) { - console.error( - `ERROR: Member "${memberId}" is in a provisionUser role but is missing Google user fields. Add fields or set skipGoogleUserProvisioning: true` - ); - hasErrors = true; - } } } diff --git a/src/config/roles.ts b/src/config/roles.ts index 318bb36..8e18b8f 100644 --- a/src/config/roles.ts +++ b/src/config/roles.ts @@ -102,7 +102,9 @@ export const ROLES: readonly Role[] = [ id: ROLE_IDS.MAINTAINERS, description: 'General maintainers', discord: { role: 'maintainers (synced)' }, - // Discord only - general maintainer role + // GWS user accounts are opt-in: maintainers add firstName/lastName/googleEmailPrefix + // to their entry in users.ts via PR to get an @modelcontextprotocol.io account + google: { group: 'maintainers', provisionUser: true }, }, { id: ROLE_IDS.DOCS_MAINTAINERS,