Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions gh_org_mgr/_gh_org.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,56 @@ def _resolve_gh_username(self, username: str, teamname: str) -> NamedUser | None

return gh_user

def validate_configured_usernames(self) -> None:
"""Resolve all configured usernames and verify they still match, before
any write operation is executed. Abort with an error if any configured
user has been renamed or does not exist anymore, so no write operation
can ever touch the wrong account.
"""
configured_users: set[str] = set()

# Collect configured org owners, if they are a proper list
if isinstance(self.configured_org_owners, list):
configured_users.update(self.configured_org_owners)

# Collect configured team members and maintainers
for team_attrs in self.configured_teams.values():
if not isinstance(team_attrs, dict):
continue
for role in ("member", "maintainer"):
if users := team_attrs.get(role):
configured_users.update(users)

# Resolve each configured user and verify their current login name
invalid_users: list[str] = []
for username in configured_users:
try:
gh_user: NamedUser = self.gh.get_user(username)
except UnknownObjectException:
logging.exception(
"The configured user '%s' does not exist on GitHub.",
username,
)
invalid_users.append(username)
continue

if gh_user.login != username:
logging.error(
"The configured user '%s' has been renamed to '%s'.",
username,
gh_user.login,
)
invalid_users.append(username)

# Any invalid user is a hard error: abort before any write operation
if invalid_users:
logging.critical(
"The following configured usernames do not match their GitHub accounts: %s. "
"For security reasons, please update your configuration. Aborting without making any changes.",
", ".join(sorted(invalid_users)),
)
sys.exit(1)

# --------------------------------------------------------------------------
# Configuration
# --------------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions gh_org_mgr/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ def main() -> None:
# Get current rate limit
org.ratelimit()

# Validate all configured usernames before any write operation, and
# abort if any renamed or vanished user is found
log_progress("Validating configured usernames...")
org.validate_configured_usernames()

# Synchronise organisation owners
log_progress("Synchronising organisation owners...")
org.sync_org_owners(dry=args.dry, force=args.force)
Expand Down