Skip to content

validate-org: reject a plain member team role for an organisation owner - #75

Merged
dev-milos merged 3 commits into
mainfrom
fix/reject-member-role-for-owner
Aug 14, 2026
Merged

validate-org: reject a plain member team role for an organisation owner#75
dev-milos merged 3 commits into
mainfrom
fix/reject-member-role-for-owner

Conversation

@dev-milos

Copy link
Copy Markdown
Collaborator

Closes G-Research/gr-oss#1434

GitHub reports organisation owners as maintainers of every team they belong to, so a team
membership declaring the member role for an owner never settles:

  1. apply reports success — 1 added, 0 changed, 1 destroyed
  2. GitHub keeps maintainer
  3. the next plan, with no config change at all, proposes 1 to change on that membership
  4. repeats indefinitely

Nothing objected to it. The schema accepts either team role with no relationship to the
person's organisation role, and validation passed cleanly. The importer never generates this
shape — it reads maintainer from GitHub — so it only arises from editing members.yaml by
hand, which is the normal way to manage membership.

Why it is worth a rule rather than a note

The damage is to trust in the plan. A workspace that never reaches "no changes" trains
reviewers to skim past 1 to change, which is precisely the habit that makes a genuine
destroy easy to miss — on the plans that decide who belongs to the organisation.

Both facts live in the same file, so this needs no API call:

- username: someone
  role: owner          # organisation role
  teams:
    - name: platform
      role: member     # cannot hold while the above is owner

The omitted role counts too

members.tf reads a missing team role as member, and the importer omits it for plain
members. Leaving it out therefore produces exactly the same non-convergence as writing it, so
both are rejected — with different messages, since the cause differs:

Config Message
explicit role: member ... cannot use role "member": ...
role omitted ... needs role "maintainer": the role defaults to "member" when omitted, ...

Two existing fixtures had to change

Both encoded an owner with an omitted team role and asserted it was valid:

  • TestMembersConfigValidate / "valid config with team member and maintainer roles"
  • TestValidateOrg_StagedMembersResolveAgainstPromotedTeams

Changing existing tests to make a new rule pass is exactly how a mistake gets hidden, so it is
worth being explicit: the claim is that the fixtures were wrong, not the rule. The same
shape was observed producing a perpetual diff against a real organisation. Both now set the
role explicitly, which also makes them realistic — the importer always writes it.

That it was baked into two fixtures independently is itself a sign the constraint was not
known.

Tests

Three cases added, including one asserting the rule does not over-reach: a plain member may
hold either team role.

Verified against the real configuration that produced the perpetual diff — it now fails at
validate, before the plan:

member "<owner>" is an organisation owner, so team "<team>" cannot use role "member": GitHub
reports owners as maintainers of every team they belong to, so the plan would keep proposing
this change without it ever taking effect

The organisation's current config still validates cleanly, since the importer wrote explicit
roles throughout.

dev-milos and others added 3 commits August 14, 2026 12:55
GitHub reports organisation owners as maintainers of every team they belong to, so
a team membership declaring the member role for an owner never settles. Apply
reports success, GitHub keeps maintainer, and the next plan proposes the same
change again, indefinitely.

Nothing objected to it. The schema accepts either team role with no relationship to
the person's organisation role, and both facts sit in the same file, so this is
catchable without any API call.

The omitted role is covered too: Terraform reads a missing team role as member, and
the importer omits it for plain members, so leaving it out produces exactly the same
non-convergence as writing it.

Two existing fixtures encoded that shape and asserted it was valid. They were
wrong - the same shape was observed producing a perpetual diff against a real
organisation - so both now set the role explicitly.
…Role

The previous commit removed the wrong one. members.go now carries no comment change
relative to main.
@dev-milos
dev-milos marked this pull request as ready for review August 14, 2026 11:04

@bitwisecook bitwisecook left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dev-milos
dev-milos merged commit 86becc1 into main Aug 14, 2026
1 check passed
@dev-milos
dev-milos deleted the fix/reject-member-role-for-owner branch August 14, 2026 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants