Offboard a member
A leaving member hands their work over first, then loses each access they held. Plan the hand-off with them before their last day. Removing members takes owner rights on both GitHub organizations.
LOGIN=octocatHand their work over
List their open work
FILTERS=(--owner a-novel --owner a-novel-kit --state open)
gh search issues --assignee "$LOGIN" "${FILTERS[@]}"
gh search prs --author "$LOGIN" "${FILTERS[@]}"
gh search prs --review-requested "$LOGIN" "${FILTERS[@]}"Give each item a new owner
Agree with them who takes each item. Move each issue and review request to its new owner:
NEW_LOGIN=octocat2
ISSUE=https://github.com/a-novel/infra/issues/1
PR=https://github.com/a-novel/infra/pull/2
gh issue edit "$ISSUE" --remove-assignee "$LOGIN" --add-assignee "$NEW_LOGIN"
gh pr edit "$PR" --remove-reviewer "$LOGIN" --add-reviewer "$NEW_LOGIN"The new owner of a pull request pushes to its branch, or closes it with a note that links its issue.
Cover their roles
List the teams they belong to, with each team's member count:
for ORG in a-novel a-novel-kit; do
gh api graphql -f org="$ORG" -f login="$LOGIN" -f query='
query($org: String!, $login: String!) {
organization(login: $org) {
teams(first: 100, userLogins: [$login]) {
nodes { slug members { totalCount } }
}
}
}' --jq '.data.organization.teams.nodes[] | "\(.slug) \(.members.totalCount)"'
doneA maintainers- or core team at 1 would lose its last member. Promote someone into it first. Give each Discord repository role they hold to another member too, so CI alerts and review requests still reach someone.
Remove their access
Run these on their last day, in this order.
Ops: suspend their Google account
Suspending blocks their sign-in to Google, Google Cloud included. In the Google Admin console, open Directory → Users, then their account, then Suspend user.
Remove them from GitHub
gh auth refresh -h github.com -s admin:org
for ORG in a-novel a-novel-kit; do
gh api -X DELETE "orgs/$ORG/memberships/$LOGIN"
done
gh auth refresh -h github.com --remove-scopes admin:orgThis drops every team and cancels a pending invitation. Their commits and reviews stay. Each organization now answers Not Found:
gh api "orgs/a-novel/members/$LOGIN"
gh api "orgs/a-novel-kit/members/$LOGIN"Remove their Discord roles
Untick every role they hold: developers or ops, their repository roles and the admin role. They keep the community channels, as any visitor does.
Unlink their accounts
Print their GitHub ID:
gh api "users/$LOGIN" --jq .idIn the Bitwarden web app, open Secrets Manager → Projects → github-discord-map and delete the secret with that name.
Core: close their Bitwarden access
- Under Secrets Manager → Machine accounts, open the account behind
repo updateand revoke their access token. - Remove them under Admin Console → Members.
- Rotate every secret of the
a-novelanda-novel-kitprojects, since they could read them all. Replace each value with a new one from its source, then apply the settings with--all, which copies the new values to every repository. Delete each old App key or token only after that run.
Ops: remove their production access
Find every line of a-novel/infra that names their address, from an up-to-date checkout. IAM lists and alert recipients both show up:
EMAIL=octocat@agorastoryverse.com
git -C ~/git-projects/a-novel/app/infra grep -n "$EMAIL" -- '*.tfvars'In one pull request, delete their user: entries from the IAM lists and give each other line, such as an alert recipient, to another member. Then rotate the production secrets they could read, with the infra secrets runbook.
Ops: delete their Google account
Wait for the infra merge to apply, so no binding names a deleted account. Then open their account in Directory → Users and choose Delete user. Google offers to transfer their Drive and Calendar data: give it to the member who took over their work.