Skip to content

fix(team_members): key the members set on the lowercased username - #3669

Closed
goakshit wants to merge 1 commit into
integrations:mainfrom
goakshit:fix/team-members-username-case
Closed

goakshit wants to merge 1 commit into
integrations:mainfrom
goakshit:fix/team-members-username-case

Conversation

@goakshit

@goakshit goakshit commented Oct 8, 2026 •

Copy link
Copy Markdown

Resolves #3533
Refs #1968 (the same bug seen from the other side, closed as stale) and #3539 (earlier attempt; as currently pushed it adds a duplicate check and lowercases the remove path but does not change the set key, so the diff still appears).


Before the change?

  • members.username has a case-insensitive DiffSuppressFunc, but members is a TypeSet and the default hash includes the raw username. A configured login whose case differs from what getTeamMembers returns lands on a different set key, so the suppress function never runs and every plan shows the member removed and re-added.
  • Pre-6.13.0 this bit when github_membership.username was created with non-canonical casing and referenced from github_team_members ([BUG]: Discrepency between github_membership and github_team_members casing #1968). Since 6.13.0 reads lowercase every login, it bites every mixed-case username ([BUG]: v6.13.0 lower cases all team members #3533).
  • The apply is a remove then an add. We hit the real-world consequence: an apply interrupted between the two calls left a user removed from all their teams, twice in three weeks.

After the change?

  • members gets a Set function that hashes the lowercased username plus role, so the configured and the read block share a key and the existing DiffSuppressFunc applies. No state migration: the state content is unchanged, only the set keys are derived differently.
  • Unit test Test_hashTeamMember covers the hash.
  • Acceptance test TestAccGithubTeamMembers/members_are_case_insensitive applies with testOrgUser1, then runs a PlanOnly step with the case flipped and expects an empty plan.

Testing

  • make test passes, golangci-lint run --new-from-merge-base main is clean.

  • I have not run the acceptance tests locally, I do not have a test org set up. If a maintainer can trigger them, or if you prefer I set one up first, say so.

  • Manual test against a real organisation with dev_overrides, planning two github_team_members resources that hold three mixed-case logins (names replaced below). Unpatched main:

    # github_team_members.example will be updated in-place
        - username = "octocat" -> null
        - username = "monalisa" -> null
        - username = "hubot" -> null
        + username = "OctoCat"
        + username = "MonaLisa"
        + username = "Hubot"
    # github_team_members.example_two will be updated in-place
        (same for two of the three)
    Plan: 0 to add, 2 to change, 0 to destroy.
    

    This branch: No changes. Your infrastructure matches the configuration.

Pull request checklist

  • Schema migrations have been created if needed (none needed, see above)
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been reviewed and added / updated if needed (no user-facing behaviour change)

Does this introduce a breaking change?

  • Yes
  • No

Disclosure per CONTRIBUTING: the change was written with AI assistance (Claude Code). I have read it, the unit and lint runs above are mine, and the manual before/after plan was run against a real organisation.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

👋 Hi, and thank you for this contribution!

This repo is maintained by GitHub and community members on a best-effort basis. We'll get to this as soon as we can.

You can help us prioritize by joining the discussion on open issues and PRs, sharing details on the changes you need, and reviewing other contributions.


🤖 This is an automated message.

@github-actions github-actions Bot added the Type: Bug Something isn't working as documented label Oct 8, 2026
GitHub logins are case-insensitive and the API returns the canonical
casing. When the configured username differs only in case from what the
provider reads back, the two members blocks land on different set keys,
so the username DiffSuppressFunc never gets a chance to run and every
plan removes and re-adds the member. An apply that is interrupted
between the two calls leaves the user removed from the team.

Hash the members set on the lowercased username (and role) so both
blocks share a key and the existing case-insensitive diff suppression
applies.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@goakshit
goakshit force-pushed the fix/team-members-username-case branch from c69b0bb to 7464223 Compare October 8, 2026 09:03
@goakshit
goakshit marked this pull request as ready for review October 8, 2026 09:05
@deiga deiga closed this Oct 9, 2026
@deiga

deiga commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

Duplicate of #3539

Please add to the discussion there instead of creating a new one

@deiga deiga marked this as a duplicate of #3539 Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Bug Something isn't working as documented

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: v6.13.0 lower cases all team members

2 participants