Add Discord role sync with role-centric architecture (#22)
* Add Discord role sync with role-centric architecture This refactors the access management to use a role-centric model where each role explicitly defines which platforms it exists on (GitHub, Discord, Google). Key changes: - Add Discord role sync via Pulumi Dynamic Provider - Replace groups.ts with roleIds.ts + roles.ts for type-safe role definitions - Use ROLE_IDS constants to prevent typos in memberOf references - Each role has platform-specific config (github/discord/google keys) - Discord-only roles (e.g., administrators) and GitHub-only roles (e.g., typescript-sdk-auth) are now explicitly modeled - Add PR preview workflow to show Pulumi changes before merge - Add test-config.ts for config structure validation - Fix typo: docs-maintaners -> docs-maintainers Discord roles will match existing server roles: - administrators, lead maintainers, core maintainers - sdk maintainers, working groups, interest groups - etc. Requires new GitHub secrets: - DISCORD_BOT_TOKEN - DISCORD_GUILD_ID * Fix GitHub team ordering and make Discord integration optional - Add topological sort for GitHub teams to ensure parent teams are created before child teams, fixing the registry-wg parentTeamId issue - Make Discord integration optional by using config.get() instead of config.require(), allowing CI preview to succeed without Discord secrets - Add sortRolesByGitHubDependency() utility function in config/utils.ts Claude-Generated-By: Claude Code (cli/claude-opus-4-5=20%) Claude-Steers: 2 Claude-Permission-Prompts: 1 Claude-Escapes: 0 * Reconcile Discord roles for listed users Replace per-role-membership approach with per-user role sync that: - Adds missing roles users should have - Removes managed roles users shouldn't have - Only touches roles defined in config (won't affect admin roles, etc.) Users not in config remain untouched. Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%) Claude-Steers: 4 Claude-Permission-Prompts: 1 Claude-Escapes: 0 * Fix descriptions to match existing resources * Cache Pulumi plugins and fix GITHUB_TOKEN for pulumi install * Remove accidentally committed state backup * Use github.token for pulumi install * Fix formatting Fix deploy: add pulumi login before config set Fix deploy: set PULUMI_CONFIG_PASSPHRASE_FILE for config commands Import existing docs-maintainers team (remove after deploy) Remove docs-maintainers import workaround Add docs-maintainers cleanup to state cleanup Add pulumi refresh before up to sync state with reality Rename Discord roles to add (synced) suffix Cleanup Makefile and add lead-maintainers GitHub team
This commit is contained in:
parent
f0336a9991
commit
f960494174
1 changed files with 1354 additions and 414 deletions
|
|
@ -1,22 +1,24 @@
|
|||
import * as gworkspace from '@pulumi/googleworkspace';
|
||||
import { GROUPS } from './config/groups';
|
||||
import type { Group } from './config/utils';
|
||||
import { ROLES, type Role, buildRoleLookup } from './config/roles';
|
||||
import { MEMBERS } from './config/users';
|
||||
import type { RoleId } from './config/roleIds';
|
||||
|
||||
const roleLookup = buildRoleLookup();
|
||||
// Groups keyed by Google group name
|
||||
const groups: Record<string, gworkspace.Group> = {};
|
||||
|
||||
GROUPS.forEach((group: Group) => {
|
||||
// Skip groups that don't include google in their platforms
|
||||
if (group.onlyOnPlatforms && !group.onlyOnPlatforms.includes('google')) return;
|
||||
// Create Google groups for roles that have Google config
|
||||
ROLES.forEach((role: Role) => {
|
||||
if (!role.google) return;
|
||||
|
||||
groups[group.name] = new gworkspace.Group(group.name, {
|
||||
email: `${group.name}@modelcontextprotocol.io`,
|
||||
name: group.name,
|
||||
description: group.description + ' \n(Managed by github.com/modelcontextprotocol/access)',
|
||||
groups[role.google.group] = new gworkspace.Group(role.google.group, {
|
||||
email: `${role.google.group}@modelcontextprotocol.io`,
|
||||
name: role.google.group,
|
||||
description: role.description + ' \n(Managed by github.com/modelcontextprotocol/access)',
|
||||
});
|
||||
|
||||
new gworkspace.GroupSettings(group.name, {
|
||||
email: groups[group.name].email,
|
||||
new gworkspace.GroupSettings(role.google.group, {
|
||||
email: groups[role.google.group].email,
|
||||
|
||||
// Maximise visibility of group. It's visible in GitHub anyway
|
||||
whoCanViewMembership: 'ALL_IN_DOMAIN_CAN_VIEW',
|
||||
|
|
@ -29,7 +31,7 @@ GROUPS.forEach((group: Group) => {
|
|||
// 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
|
||||
...(role.google.isEmailGroup
|
||||
? {
|
||||
whoCanPostMessage: 'ANYONE_CAN_POST',
|
||||
whoCanContactOwner: 'ALL_OWNERS_CAN_CONTACT',
|
||||
|
|
@ -41,30 +43,22 @@ GROUPS.forEach((group: Group) => {
|
|||
whoCanViewGroup: 'ALL_OWNERS_CAN_VIEW',
|
||||
}),
|
||||
});
|
||||
|
||||
group.memberOf?.forEach((parentGroupKey) => {
|
||||
// Skip if parent group doesn't exist on Google (e.g., onlyOnPlatforms: ['github'])
|
||||
if (!groups[parentGroupKey]) return;
|
||||
|
||||
new gworkspace.GroupMember(`${group.name}-in-${parentGroupKey}`, {
|
||||
groupId: groups[parentGroupKey].id,
|
||||
email: groups[group.name].email,
|
||||
role: 'MEMBER',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Create group memberships for users
|
||||
MEMBERS.forEach((member) => {
|
||||
if (!member.email) return;
|
||||
|
||||
member.memberOf.forEach((teamKey) => {
|
||||
// Skip if group doesn't exist on Google (e.g., onlyOnPlatforms: ['github'])
|
||||
if (!groups[teamKey]) return;
|
||||
member.memberOf.forEach((roleId: RoleId) => {
|
||||
const role = roleLookup.get(roleId);
|
||||
if (!role?.google) return; // Role doesn't have Google config
|
||||
|
||||
new gworkspace.GroupMember(`${member.email}-${teamKey}`, {
|
||||
groupId: groups[teamKey].id,
|
||||
new gworkspace.GroupMember(`${member.email}-${role.google.group}`, {
|
||||
groupId: groups[role.google.group].id,
|
||||
email: member.email!,
|
||||
role: 'MEMBER',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export { groups as googleGroups };
|
||||
|
|
|
|||
Loading…
Reference in a new issue