* Add Filesystems Working Group role, team, and lead memberships
* Add DanielTemesgen as Filesystems WG lead and michaelcheah as member per updated charter
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012ujLL8MSZA6F1apWiwQQ9b
---------
Co-authored-by: Claude <noreply@anthropic.com>
koic (Koichi Ito, Ruby SDK maintainer) only held ROLE_IDS.RUBY_SDK,
which maps to the ruby-sdk GitHub team with triage on the
modelcontextprotocol spec repo. The SDK_MAINTAINERS -> MAINTAINERS
implication is discordImplies-only and does not add members to the
maintainers GitHub team, so he could not push branches or open PRs
in the spec repo. Add ROLE_IDS.MAINTAINERS directly, matching other
maintainer entries.
Claude-Session: https://claude.ai/code/session_01H4JKj5FVkmj6bRzgh1GPrY
Co-authored-by: Claude <noreply@anthropic.com>
* Grant maintainers team read access to maintainer-docs
Adds a GitHub team for the existing 'maintainers' role (previously
Discord/Google only, with no parent team so it does not inherit
steering-committee repo permissions) and grants it pull access to the
maintainer-docs repository.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LRucdTmghybeWkeaTtVuS1
* Grant maintainers team write access to the spec repo
Complete the maintainers group model: the parentless maintainers GitHub
team (added in this PR alongside its existing Discord role and Google
group) now gets push on modelcontextprotocol/modelcontextprotocol in
addition to pull on maintainer-docs. Branch protection on the spec repo
still requires changes to land via pull requests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V6sAnrWknVzWzfuuzomMXk
---------
Co-authored-by: Claude <noreply@anthropic.com>
Adds tnorimat as a member, creates the conformance-auth GitHub team
(tnorimat + pcarleton), and grants it push on the conformance repo so
the team can be referenced from a CODEOWNERS file there.
Claude-Session: https://claude.ai/code/session_01FDRFtxQbYLnBcpwndGXF7W
Co-authored-by: Claude <noreply@anthropic.com>
Add the enterprise-managed-authorization IG, the two active auth
sub-WGs (tool scopes and fine-grained authorization), an agents WG
Discord role, and auth IG memberships from the charter. Convert
skills-over-mcp from IG to WG and security from WG to IG per their
charters, updating team names and all references. Add ochafik to the
MCP Apps WG and pcarleton to the security IG. Remove the
server-identity-wg and agents-ig roles, whose Discord channels are
archived or gone. Fix the README link to src/config/roles.ts.
Claude-Session: https://claude.ai/code/session_01VRxNJh9HqnkTYdpALP5Vhf
Co-authored-by: Claude <noreply@anthropic.com>
* Add npm/PyPI package publishing access management (config + drift detection)
Declare expected npm org membership, per-package maintainers and trusted
publishers, and PyPI project rosters in src/config/packageAccess.ts, with
npm/pypi identity fields on members in users.ts.
Deliberately outside the Pulumi resource graph: npm governance writes
require an interactive 2FA challenge since August 2026 (read endpoints
still work with a granular access token), and PyPI has no management API
at all. Drift against the live npm registry is detected read-only by
scripts/check-package-drift.ts (weekly via package-drift.yml, no-op when
the NPM_READ_TOKEN secret is absent), which emits a remediation plan of
npm CLI commands for a maintainer to run in one 2FA-approved session.
PyPI procedures are documented as a manual runbook in the README.
* Encode all slashes when escaping package names in registry URLs
Fixes the CodeQL finding: String.replace with a string pattern only
replaces the first occurrence. Use a shared helper with a global regex,
following the npm CLI convention (keep '@' literal, encode every '/').
---------
Co-authored-by: Claude <noreply@anthropic.com>
Restore the googleEmailPrefix dropped in the previous commit and mark the
account existingGWSUser so it is kept but no longer Pulumi-managed, matching
how toby's emeritus account is handled. Before deploying, remove the
gws-user-nick resource from Pulumi state (pulumi state delete, not destroy)
or Pulumi will delete the real account.
No-Verification-Needed: declarative access config, only exercisable via prod deploy
Same approach as pwwpche in #111: keep the member entry, empty memberOf.
The googleEmailPrefix is dropped since no remaining role provisions a
GWS account, so the nick@ account will be deprovisioned on next deploy.
No-Verification-Needed: declarative access config, only exercisable via prod deploy
* Skills Over MCP IG membership housekeeping
Add aditya-scio to the Skills Over MCP Interest Group.
Remove the IG role from BobDickinson; his other roles are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Apply prettier formatting
Bob's memberOf array now fits on one line at printWidth 100.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Adds a 'service-accounts' role that carries no GitHub, Discord, or
Google group config and exists solely to make its members eligible
for GWS user provisioning, plus a member entry that provisions
claude@modelcontextprotocol.io. Claude has no GitHub or Discord
handle, so none of the existing provisionUser roles fit.
Brings the conformance repo under access management. Its only direct
grant today is felixweinberger at maintain (team access comes from
org-level roles), so this entry bumps him to admin.
GWS user accounts were only created for members whose direct roles had
google.provisionUser (lead/core maintainers, moderators, maintainers,
registry-wg). SDK maintainers and working-group members who opted in by
adding firstName/lastName/googleEmailPrefix (e.g. #148, #150, #152)
silently got no account.
- Move provisionUser from GoogleConfig to the Role level, and add it to
the implicit-maintainer containers (sdk-maintainers, working-groups)
plus the standalone maintainer roles (docs, inspector, mcpb,
reference-servers, use-mcp, server-identity-wg, wg/ig facilitators).
- Eligibility now walks github.parent chains (hasProvisionUserRole),
matching GitHub team-nesting semantics, so e.g. python-sdk members
qualify via sdk-maintainers.
- validate-config now errors when a googleEmailPrefix would be a silent
no-op (no eligible role and not an existing GWS user), so opt-in PRs
like #150 fail CI instead of quietly doing nothing.
Newly provisioned on next apply: marcelo@, alexhancock@, liad@.
ochafik is now eligible but already has an account (existingGWSUser).
* Add security-managers org role and assign maxisbey
Model GitHub's pre-defined security_manager organization role in the
IaC: new GitHub-only security-managers team wired to the org role via
ORG_ROLE_ASSIGNMENTS, following the existing all_repo_admin pattern.
Add Max Isbey (maxisbey) as its first member so he can view draft
security advisories for coordinated disclosure work.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147Pp292yN9cQKCQBphVyMy
* Add jenn-newton to security-managers team
Paul Carleton asked for Jenn to join the new security-managers team
alongside Max Isbey. Resolved to Jenn Newton (jenn-newton), already a
member of the security working group in this config.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Dependabot-triggered runs read from the Dependabot secrets store, which
is empty, so the Google Cloud auth step receives an empty credential and
fails. Skip the preview job for Dependabot; CI still validates those PRs.
Also guard the PR comment step so it doesn't post 'Failed to read
preview output' when the preview step never ran.
Co-authored-by: Claude <noreply@anthropic.com>
Dependabot's npm updater fetches manifests directly from git and aborts on
every run because package.json declares
"@pulumi/googleworkspace": "file:sdks/googleworkspace" while sdks/ is
gitignored and only materialized by `pulumi install`.
Keep the generated SDK sources ignored, but commit
sdks/googleworkspace/package.json (name/version/dependencies matching the
existing package-lock.json entry) so the path dependency resolves from the
git tree. `pulumi install` removes and regenerates the whole SDK directory
before npm ci in CI, so CI behavior is unchanged.
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Den Delimarsky <53200638+localden@users.noreply.github.com>
The "Verify GroupMember state healed (TEMP, #133)" step passed on deploy
run 28624873606 (attempt 4), meeting the documented removal criterion for
the one-time state surgery added in #139. Also removes the stale TEMP
pulumi state delete for experimental-ext-tasks (#125), whose
one-successful-deploy condition was met on 6/30.
Co-authored-by: Claude <noreply@anthropic.com>
* Declare allowExternalMembers on managed group settings
Every pulumi up was resetting the Google Workspace per-group setting
ALLOW_EXTERNAL_MEMBERS to false on all managed groups, because the
GroupSettings resources never declared allowExternalMembers and the
provider (SamuZad/googleworkspace 0.11.1) defaults the field to false.
Google then silently purges external-email members from affected groups
roughly 1-2 days after each apply, with no audit events.
Pin the setting to true for all managed groups. External membership
itself remains governed exclusively by config/users.ts entries; this
setting only permits it.
Part of the #133 incident.
* Scope allowExternalMembers per group, derived from membership config
Instead of permitting external members on every managed group, derive
allowExternalMembers per group: true only for groups whose membership
config (config/users.ts) resolves at least one member to a
non-@modelcontextprotocol.io email. Email resolution is factored into
resolveGoogleMemberEmail and shared with GroupMember creation so the
two cannot drift. The field stays declared on every group because the
provider defaults it to false on each apply, after which Google
silently purges external members (#133 incident).
With current config, exactly these groups derive true: maintainers,
registry-wg, antitrust, catch-all. A config test pins this set so
changes to it are always deliberate.
* Make allowExternalMembers an explicit per-role opt-in with config validation
Replace the derived per-group allowExternalMembers (computed from
membership config) with an explicit opt-in: group owners set
allowExternalMembers: true on the role's google config in
src/config/roles.ts, and src/google.ts passes it straight through to
GroupSettings (defaulting to false). The field stays declared on every
group because the provider resets an omitted field to false on each
apply, after which Google silently purges external members (#133).
Roles opting in, matching current membership: maintainers,
registry-maintainers (registry-wg), antitrust, catch-all.
A validate-config check replaces the old pinned-set test: it fails with
an actionable error whenever a group has a member resolving to a
non-@modelcontextprotocol.io email but its role does not opt in, naming
the group, the member email, and the exact config line to add.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Repair corrupted GroupMember state so deploys stop failing (#133)
Every Deploy to Production run since 2026-06-30 aborts about a minute
in with "googleapi: Error 409: Member already exists" and merged
changes (e.g. #134, #137) never apply. Two external-email GroupMember
records in the maintainers group are recorded in state with an empty
member ID ("groups/04f1mdlm38smb30/members/"), so each pulumi up plans
a create-before-delete replace whose create conflicts with the live
membership and fails the whole update. Five other records corrupted at
the same time were already healed by the 2026-07-02 deploy run.
Add a one-time TEMP block to the deploy workflow (same precedent as the
auth-maintainers repair and the experimental-ext-tasks state delete):
drop the two broken records, then re-import each membership by member
email so the provider records the numeric member ID. All commands are
|| true-guarded, and the block must be removed after one successful
deploy.
Fixes#133
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NazA3QKftRn72tdPG5vrpb
* Widen state repair to all seven corrupted GroupMember records (#133)
* Replace per-URN state deletes with export surgery; verify healing post-deploy (#133)
The committed repair used 'pulumi state delete <urn>' per record, but the
failed create-before-delete replaces left duplicate same-URN entries (a
live record plus a pending-delete leftover) for some of the seven
corrupted GroupMember records. 'pulumi state delete' fails on an
ambiguous URN, and the '|| true' guard hid that failure, making the
repair a silent no-op.
- Replace the per-URN deletes with state surgery: export the stack,
drop every entry (including pending-delete duplicates) whose URN is
one of the seven with jq, and re-import. Unguarded, so a surgery
failure is loud; skips the import when nothing matches (idempotent).
- Keep the seven imports-by-email ('|| true' so a not-currently-live
membership falls back to a create instead of blocking the deploy).
- Add a post-deploy verification step that fails if any GroupMember
record still has an empty member ID or a duplicate URN. The pinned
provider (SamuZad/googleworkspace 0.11.1) writes an empty member ID
even on successful creates (fixed upstream in 0.11.2), so a green
'make up' alone does not prove healing; the TEMP block must only be
removed after this verification step passes.
- Correct the root-cause comment: Google-side membership removals ->
refresh dropped the records -> re-create -> provider create bug wrote
empty IDs.
* Bump googleworkspace provider 0.11.1 -> 0.11.2 (#133)
0.11.2 carries upstream commit "handle edge case with group
memberships" (SamuZad/terraform-provider-googleworkspace, 2026-03-12),
which fixes the create-path bug that stores an empty member ID for
external-email group members — the bug that corrupted the seven records
repaired by the TEMP block in deploy.yml and that would re-corrupt any
record restored via the fallback create path. CI regenerates the SDK
from this pin via 'pulumi install' and typechecks against it.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Both Workspace accounts (ajr@ and ochafik@modelcontextprotocol.io) were
created manually in Google Workspace; mark them with existingGWSUser so
Pulumi skips creating the User resources.
Co-authored-by: Claude <noreply@anthropic.com>
Elevates the inspector-maintainers team from push to admin on the
inspector repository, in parity with the SDK teams and the
reference-servers-maintainers team, which hold admin on the repos
they own.
Claude-Session: https://claude.ai/code/session_01W6EqMj921DKTJJtiPpCGNE
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds appeals@modelcontextprotocol.io as an email Google Group so banned
or external users have an out-of-band channel to appeal Code of Conduct
actions even after an org-level GitHub block. Mirrors the existing
antitrust@/catch-all@ email-group setup (isEmailGroup, no new GoogleConfig
fields).
Membership is curated explicitly (like the antitrust@ members) to the
current moderators and active lead maintainers, rather than derived from
the MODERATORS/LEAD_MAINTAINERS roles, since those roles include emeritus
and former members who should not receive appeals.
Co-authored-by: Tadas Antanavicius <tadas@modelcontextprotocol.io>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: David Soria Parra <167242713+dsp-ant@users.noreply.github.com>
The repo was renamed to ext-tasks in #125, but Pulumi state still holds
the old RepositoryCollaborators resource. The first 'pulumi up' (which
runs before refresh) tries to delete it and 404s, blocking all deploys.
Drop it from state explicitly before 'make up'. Idempotent via '|| true';
remove this line after one successful deploy.
* Add evalstate and cliffhall to docs-maintaners team
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(users): add olaservo to interceptors-wg
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Den Delimarsky <53200638+localden@users.noreply.github.com>
- GroupSettings: ignoreChanges on isArchived (upstream
hashicorp/terraform-provider-googleworkspace#398)
- OrgUnit: drop the stale import option; it was only needed for the
initial adopt and now triggers a re-compare on every preview