From 2ae6b2e3d8b459411e9df83578d509548df52a1c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:22:35 +0000 Subject: [PATCH] Mark clare@ as existing Workspace user and drop stale state Deploy runs #289 and #290 (2026-10-05) fail in the refresh pass of `make up` (Makefile:23) with: googleworkspace:index:User (gws-user-clare): Error when reading or editing clare@modelcontextprotocol.io: googleapi: Error 400: Request contains an invalid argument. The account is active in the Admin console, so the stored resource is simply no longer refreshable. Follow the repo precedent for Workspace accounts managed outside Pulumi (bcfc49f ajribeiro/ochafik, 63a42f7 nick, ec18773 den): mark the member existingGWSUser so src/google.ts stops declaring gws-user-clare and its gws-pwd-clare RandomPassword, while her GroupMember resources are still created (now without dependsOn). Because the program no longer declares those two resources, they must leave state before `make up` or Pulumi would plan a real users.delete. Add a one-time TEMP block to the deploy workflow, as in e9e9f1b/93edb25 (state delete before `make up`) and 89cb9de (export/jq/import surgery). `pulumi state delete` cannot be used here: clare's GroupMember records depend on the User, so it refuses without --target-dependents, which would also drop the memberships. The block removes both entries, strips their URNs from the remaining resources' dependencies, re-imports, and is unguarded so a failed surgery fails the deploy loudly. Remove it after the next green deploy. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01SyDWqMwnKtkynCQNahMKxf --- .github/workflows/deploy.yml | 37 ++++++++++++++++++++++++++++++++++++ src/config/users.ts | 3 +++ 2 files changed, 40 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 667fee0..c29b730 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -78,4 +78,41 @@ jobs: if [ -n "$CLOUDFLARE_ROLE_MANAGEMENT_TOKEN" ]; then pulumi config set cloudflare:roleManagementToken "$CLOUDFLARE_ROLE_MANAGEMENT_TOKEN" --secret --stack prod fi + # TEMP: one-time state surgery so Pulumi stops managing clare@'s Workspace + # user (existingGWSUser in src/config/users.ts). Deploy runs #289 and #290 + # (2026-10-05) fail in the refresh pass of `make up` because Google returns + # 400 on users.get for the stored gws-user-clare resource although the + # account is active. With the flag set, the program no longer declares + # gws-user-clare or its gws-pwd-clare RandomPassword, so both MUST leave + # state before `make up`, or Pulumi plans a real users.delete. + # `pulumi state delete` is not usable here: clare's GroupMember records list + # the User in their dependencies, so it refuses without --target-dependents + # (which would also drop the memberships from state). Instead: export the + # state, remove both entries, strip their URNs from every remaining + # resource's dependencies, and re-import. Deliberately NOT `|| true`-guarded: + # a failed surgery must fail the deploy loudly rather than let `make up` + # delete the real account. Idempotent: if neither entry is in state, the + # import is skipped. Remove this block after the next green deploy. + STALE_URNS='[ + "urn:pulumi:prod::mcp-access::googleworkspace:index/user:User::gws-user-clare", + "urn:pulumi:prod::mcp-access::random:index/randomPassword:RandomPassword::gws-pwd-clare" + ]' + pulumi stack export --stack prod --file /tmp/state.json + jq --argjson urns "$STALE_URNS" ' + def drop_stale: map(select(. as $d | ($urns | index($d)) | not)); + .deployment.resources |= ( + map(select(.urn as $u | ($urns | index($u)) | not)) + | map( + (if .dependencies then .dependencies |= drop_stale else . end) + | (if .propertyDependencies then .propertyDependencies |= map_values(drop_stale) else . end) + ) + )' /tmp/state.json > /tmp/state-repaired.json + before=$(jq '.deployment.resources | length' /tmp/state.json) + after=$(jq '.deployment.resources | length' /tmp/state-repaired.json) + echo "State surgery: removing $((before - after)) stale gws-user-clare/gws-pwd-clare entries" + if [ "$before" -eq "$after" ]; then + echo "No matching entries in state (already removed); skipping import" + else + pulumi stack import --stack prod --file /tmp/state-repaired.json + fi make up diff --git a/src/config/users.ts b/src/config/users.ts index 4ad071c..9919b59 100644 --- a/src/config/users.ts +++ b/src/config/users.ts @@ -152,6 +152,9 @@ export const MEMBERS: readonly Member[] = [ firstName: 'Clare', lastName: 'Liguori', googleEmailPrefix: 'clare', + // Google returns 400 on refresh of this user since 2026-10-05 (deploy runs + // #289/#290); the account is active and managed outside Pulumi. + existingGWSUser: true, memberOf: [ROLE_IDS.CORE_MAINTAINERS, ROLE_IDS.TRIGGERS_EVENTS_WG], }, {