Skip to content

Access Reviews and Offboarding at Enterprise Scale

Lesson 8 of 8Advanced14 min readGit at Scale & Enterprise Engineering · Enterprise IdentityVerified: GitHub Enterprise Cloud documentation, September 2026

“Who has access to this repository?” is a question with a longer answer than anybody expects.

Organisation members through base permission. Team members through grants. Individuals granted directly. Outside collaborators. Enterprise members, if it is internal. Apps with installations. Deploy keys. Tokens held by any of the above. A complete answer covers all of them, and most access reviews cover two.

An access review answers who can reach what, and confirms that each is still appropriate.

Six populations to cover: organisation members, team-based grants, direct individual grants, outside collaborators, machine identities, and administrative roles.

Automation covers the first two well. SCIM and team synchronisation make membership derive from the directory, which means reviewing directory groups reviews most GitHub access.

The other four are manual, and they are where stale access accumulates.

Offboarding is the same problem with a deadline. The populations are identical; the difference is that somebody is leaving today.

Before reviewing anything, produce the data. This is an API exercise and it is worth automating once.

Organisation members, with their role and whether they have a linked identity.

Team memberships, and which teams are synchronised from the directory.

Repository permissions, per repository: which teams, which individuals, at what level.

Outside collaborators, per repository, with when they were added.

App installations, with permissions and repository scope.

Deploy keys, per repository, with creation date and whether read-only.

Administrative roles: enterprise owners, organisation owners, custom role assignments.

Base permission per organisation, because it is the floor under everything else and it is easy to overlook when reading a permission list.

Understanding why this is difficult explains why most organisations do not have it.

Access comes from several independent sources, and they compose. A person’s effective access to a repository is the maximum of: the organisation’s base permission, any team grant they inherit, any direct grant, and anything a custom role adds. No single view shows all of it.

Sources have different shapes. Organisation membership is a list. Team grants are a many-to-many relationship. Collaborators are per repository. Apps are per installation with a permission set. There is no natural join.

Some are enumerable and some are not. Repository collaborators can be listed. Personal access tokens belonging to individuals largely cannot be enumerated centrally.

Scale multiplies it. A thousand repositories, each with teams, collaborators and deploy keys, is tens of thousands of relationships, and querying them all is a substantial number of API calls.

Which is why the answer is a collector run on a schedule rather than a query run on demand. Assembling the picture takes long enough that it must be assembled ahead of time, and once it is, everything else — reviews, offboarding, anomaly detection — becomes a filter over it rather than a fresh investigation.

Build it once and everything downstream is cheap. Skip it, and every access question is a research project.

Organisation members. Reviewed by reviewing the directory groups that provision them. Where SCIM is in place, this is largely solved.

Team-based grants. Two questions: is the team’s membership right, and is the team’s repository access right. The first is a directory question; the second is a GitHub one and is reviewed less often.

Direct individual grants. A person granted access on a repository rather than through a team. These survive every team change and every role change. Enumerate them and convert them to team grants wherever possible; the ones that remain need explicit justification.

Outside collaborators. Not covered by SAML, not provisioned by SCIM, not removed by any automated process. This is the highest-risk population and it requires a review with a real owner. Each one needs a justification and an expiry.

Machine identities. Apps, deploy keys, tokens. Reviewed against the inventory, with owners confirming each is still needed. See machine identities.

Administrative roles. Small, powerful, and reliably stale. Enterprise owners and organisation owners should be reviewed most frequently and are usually reviewed least.

How often, and for what, is a resource-allocation decision rather than a policy one.

Not everything on the same schedule. A quarterly review of every grant in the enterprise is a large amount of work that produces mostly approvals. Vary the frequency by risk.

Administrative roles: quarterly, at least. Small lists, high consequence, and they go stale quickly.

Outside collaborators: quarterly. Highest-risk population, and the one with no automated removal.

Machine identities: semi-annually, with an inventory refresh more often. Rotation schedules are the more important control here.

Team-based repository grants: annually. Where team membership is synchronised, the frequent part is handled and the annual question is whether the team should still have this access.

Direct individual grants: whenever found. These should be exceptions, and the right response to finding one is to convert or remove it rather than to schedule a review.

Event-driven beats calendar-driven where possible. A review triggered by a team change, a repository visibility change, or a new admin grant is more useful than one triggered by the calendar — it arrives when the reviewer has the context.

And separate the review from the audit. A quarterly review is an operational control. An annual audit that checks whether the reviews happened is a different exercise with a different audience. Conflating them means doing the audit work four times a year.

Because the output frequently ends up in front of an assessor, it is worth knowing what makes it hold up.

The population is complete and stated. A review of “repository access” that silently omitted outside collaborators is not a review of repository access. State what was covered and what was not.

The reviewer had the information. A reviewer approving a grant they could not evaluate has approved nothing. The record should show what was presented.

The reviewer was the right person. Somebody with knowledge of the role and the repository. A central administrator approving on behalf of forty teams is a documented rubber stamp.

Removals actually happened. A review that identified twelve grants to remove, none of which were removed, is worse than no review — it demonstrates the control was exercised and ignored. Track remediation separately from review completion.

The timing is evidenced. When the review was issued, when it was completed, when removals were executed. Dates matter more than people expect.

Exceptions are approved and dated. A grant retained despite the review needs a reason and a re-review date, not silence.

No configuration produces compliance by itself. These reviews are evidence supporting an access-management control objective. Whether they satisfy SOC 2, ISO 27001, PCI DSS, HIPAA or FedRAMP is an assessment made against your stated control by your auditor — never something a GitHub feature or a completed review grants automatically.

The design problem, because a review nobody completes is worse than no review — it produces a record of approval without the scrutiny.

Review by owner, not centrally. The person who knows whether somebody should still have access to a repository is that repository’s owner. A central team reviewing four hundred repositories is rubber-stamping.

Give them a short list. A team lead asked to review twelve people will do it. Asked to review four hundred grants across sixty repositories, they will approve everything.

Pre-filter what has not changed. If nothing about a grant has changed since the last review and the person is still in the same team, that is a lower-scrutiny item. Highlight what is new, what is unusual, and what is old.

Highlight the anomalies. A direct individual grant, an outside collaborator added eighteen months ago, an admin permission on a production repository. These are what the review is for.

Make removal the easy action. If approving is one click and removing requires a ticket, everything will be approved.

Set a deadline with a default. Reviews that can be ignored are ignored. A stated consequence — escalation, or removal of unreviewed grants — is what produces completion.

Track completion, and report it. Not the outcome, the completion rate. A review with 40% completion is not a control.

The same populations, executed under time pressure, usually by somebody following a checklist.

  1. Directory removal. SCIM suspends or removes membership, and removes mapped team memberships. The automatic part.

  2. Revoke sessions and authorised credentials. SCIM handles membership; credentials need explicit revocation. Do credentials first, then identity, then sessions.

  3. Outside collaborator grants. Search across the estate; not covered by SCIM.

  4. Direct repository grants. Same — a grant made directly to them on a repository.

  5. Machine identities they created or own. Tokens, deploy keys, app private keys they had access to. This is the step that breaks production three weeks later.

  6. Administrative roles. Enterprise owner, organisation owner, custom role assignments.

  7. Repository ownership. Any repository whose owner property names them individually needs reassigning.

  8. CODEOWNERS entries. An entry naming a departed person blocks merges that require their review.

  9. Record what was done. The evidence for the control.

Steps 3 through 8 are where residual access lives, and they are the ones that get skipped when the checklist is long and the day is busy.

Automate the detection even if removal stays manual. A report listing everything associated with a departing person, generated from their username, turns a research task into a checklist. That report is the single highest-value thing you can build for offboarding.

Offboarding on a schedule is one thing. Removing access immediately, for cause, is another, and it should be a rehearsed sequence rather than an improvisation.

The order matters. Revoke authorised credentials first, then the linked identity, then sessions. Doing it in the other order leaves a window in which a live session can create a new credential.

Suspend rather than delete. Under managed users, suspension makes the account inert while preserving the record. Deleting destroys evidence you may need.

Do not stop at the account. Machine identities they created, deploy keys they added, webhooks they configured, apps they installed, workflow files they modified. A person with write access who wanted to retain access could have established several paths, and revoking their account closes none of them.

Check what they did recently. The audit log, filtered by actor, over whatever window is relevant. Look specifically for: new deploy keys, new tokens, new collaborators, changes to workflow files, changes to CODEOWNERS, and pushes to protected branches.

Preserve the evidence before it ages out. GitHub documents 180-day audit log retention with Git events retained for seven days. If Git activity matters to the investigation, seven days is the window — which is another reason to be streaming the log before you need it.

Have the sequence written down, with who has authority to execute it and who must be informed. The people who execute this are usually not the people who decided it, and they will be doing it at short notice.

Rehearse it. On a test account, once. The rehearsal finds the screen nobody could locate and the permission nobody had.

The case every manual process misses. Somebody changes teams and keeps their old access, because nothing triggers a removal.

With team synchronisation this is handled for mapped teams — the directory group changes and the team membership follows.

Everything else persists: direct grants, outside collaborator status, machine identities they own, CODEOWNERS entries, administrative roles.

Run the offboarding detection report on movers too. Same query, different action: instead of removing everything, review each item against their new role.

Over a few years, movers are the larger population. More people change roles than leave, and each unremoved grant accumulates. An engineer of ten years’ standing who has moved four times has access from four roles unless something removed it.

This is an automation problem, and the automation is not large. What follows is the shape of it.

A collector that walks the enterprise through the API and produces a normalised record of every access relationship: subject, object, permission, source, granted date. Run on a schedule, output stored.

Rate limits are the practical constraint. An enterprise with thousands of repositories, queried for permissions, collaborators and deploy keys, will hit them. The collector needs to handle that gracefully and resume rather than restart. See API automation.

A differ that compares consecutive snapshots. New grants, removed grants, changed permissions. The diff is more useful than the snapshot for a reviewer, because it is short and it is where the interesting things are.

A per-owner view that filters the current picture to what a given team owns, which is what gets sent for review.

A per-person view that filters to everything a given username has, which is what offboarding needs.

An anomaly list: direct individual grants, collaborators over a year old, admin permissions, apps installed on all repositories, deploy keys with write access. These are the standing findings, and they should be visible continuously rather than surfaced quarterly.

Store the snapshots. They are small, and they are the only route to the retrospective question.

Do not over-build it. A collector, a store and three views is enough to transform how reviews work. An access-governance platform is a different project with a different budget, and most of the benefit is in the first week’s work.

Reviewing only organisation members. Five other populations exist.

Central review. Rubber-stamping at scale.

Lists too long to review. Everything gets approved.

Approval easier than removal. Determines the outcome.

No deadline or consequence. Reviews are ignored.

Ignoring outside collaborators. The highest-risk population.

Ignoring machine identities. Where the standing access is.

Offboarding leavers but not movers. The larger population over time.

Not keeping point-in-time exports. The retrospective question becomes unanswerable.

Presenting a completed review as compliance. The review is evidence for a control; whether it satisfies a framework is your auditor’s assessment.

The most effective access review programme is the one with the least to review, and that is a design outcome rather than a process one.

Team grants instead of individual grants. One review item covering twelve people, instead of twelve.

Synchronised teams instead of manual ones. The membership question moves to the directory, where it is already reviewed.

Apps instead of user tokens. One reviewable identity with explicit permissions, instead of an unenumerable population of personal credentials.

Base permission set correctly. If everybody legitimately has read access, that is one decision rather than thousands of grants.

Fewer custom roles. Each one is a thing a reviewer must understand before they can evaluate an assignment.

Expiry on everything that supports it. A grant that expires does not need a review to remove it; it removes itself and requires a decision to renew. This is the single most effective structural change available.

Time-bounded collaborator access. Every outside collaborator invitation with a stated end date, tracked, and removed on that date whether or not anybody reviewed it.

Which reframes the whole exercise. A quarterly review of ten thousand grants is a compliance ritual. A quarterly review of forty anomalies, in an estate where everything else expires or derives from the directory, is a control. The work is in getting to the second state, and it is worth more than any improvement to the review process itself.

An access review is only as good as its coverage. Automation solves the membership question and leaves five populations untouched — direct grants, collaborators, machine identities, administrative roles and the repository permissions those teams hold. Reviews succeed when the list is short, the reviewer is the owner, and removal is easier than approval.

  • Six populations need covering: members, team grants, direct grants, outside collaborators, machine identities and administrative roles
  • SCIM and team synchronisation cover the first two; the rest are manual
  • Outside collaborators are outside SAML and SCIM entirely and are the highest-risk population
  • Point-in-time exports answer “who had access on this date”, which current state cannot
  • Reviews should go to repository owners with short, pre-filtered lists highlighting anomalies
  • If approving is easier than removing, everything will be approved
  • The offboarding steps most often skipped are collaborator grants, direct grants, machine identities and CODEOWNERS
  • A departing person’s existing clone is not reachable by any offboarding control
  • Movers are a larger population than leavers over time, and manual processes miss them entirely

Use an organisation you administer.

  1. Produce the six-population picture for one organisation. Predict: which population is largest, and which surprises you?

  2. Count outside collaborators and their ages. How many are over a year old?

  3. Count direct individual repository grants. For three, determine why they are not team grants.

  4. List enterprise and organisation owners. Predict: does everyone still need it?

  5. Pick somebody who changed teams in the last year. Find everything they still have from their previous role.

  6. Time how long it takes to produce the complete access picture for one person. That is your offboarding research cost.

  7. Design the detection report you would generate from a username.

  8. Write the review email a team lead would receive, and count how many items it would contain.

Engineering Team Onboarding SystemA 30-day Git and GitHub programme with standards templates, assessments and governance checklists.