Checkpoint Lab — Organizations, Teams, Roles, Repository Access, Enterprise Policies, and Delegated Administration
Design and verify a three-repository organization access model through onboarding, temporary elevation, offboarding, and a quarterly access-review runbook.
Learning objectives
- Design engineering, security, and release teams across three repositories.
- Predict and verify onboarding and temporary-elevation effects before applying them.
- Prove offboarding removes every modeled access path, not merely one membership.
- Write a quarterly access-review checklist and break-glass procedure.
- Bridge organization governance into Chapter 29 audit/compliance evidence.
1. Checkpoint scenario and preflight
You are designing synthetic organization atlas-c28 with
repositories app-api, security-policy, and
release-ops. Persistent teams are Engineering,
Security, and Release. The mandatory lab is local and free. Optional
live verification may use a disposable GitHub organization you own.
No real colleague identities, employer organization, custom
enterprise roles, SSO changes, token creation, repository transfer,
or deletion are required.
gh auth status and confirm the exact disposable
organization/repository before every mutation.
2. Design the least-privilege role matrix
| Team | app-api | security-policy | release-ops | Why |
|---|---|---|---|---|
| Engineering | Write | Read | Read | Build application; inspect policy/release context without administering it. |
| Security | Read | Maintain | Read | Review source and own security policy without source/release write. |
| Release | Read | Read | Maintain | Operate release automation while keeping app source write separate. |
Set base permission to none in the fixture. Predict two
changes before running: (P1) onboarding devon into
Engineering should yield Write/Read/Read; (P2) temporary Maintain on
release-ops should raise only that repository, and
removing the exception should fall back to Read.
3. Build the final model and evaluator
Save checkpoint.json with the role matrix. Do not use
nested Engineering in this final matrix yet; nesting is introduced
as a controlled failure later.
{
"base_permission":"none",
"repositories":["app-api","security-policy","release-ops"],
"teams":{
"engineering":{"parent":null,"repos":{"app-api":"write","security-policy":"read","release-ops":"read"}},
"security":{"parent":null,"repos":{"app-api":"read","security-policy":"maintain","release-ops":"read"}},
"release":{"parent":null,"repos":{"app-api":"read","security-policy":"read","release-ops":"maintain"}},
"break-glass-release":{"parent":null,"repos":{"release-ops":"maintain"}}
},
"users":{
"devon":{"active":true,"relationship":"member","teams":["engineering"],"direct":{}},
"sam":{"active":true,"relationship":"member","teams":["security"],"direct":{}},
"riley":{"active":true,"relationship":"member","teams":["release"],"direct":{}}
}
}
#!/usr/bin/env python3
"""c28_access.py — local, synthetic GitHub access evaluator."""
import json, sys
from pathlib import Path
RANK = {"none":0,"read":1,"triage":2,"write":3,"maintain":4,"admin":5}
def max_role(*roles):
return max(roles, key=lambda r: RANK[r])
def ancestors(team, teams):
out=[]; seen=set(); cur=team
while cur and cur not in seen:
seen.add(cur); parent=teams.get(cur,{}).get("parent")
if parent: out.append(parent)
cur=parent
return out
def effective(model, user, repo):
u=model["users"][user]
if not u.get("active", True): return {"role":"none","sources":["identity inactive"]}
sources=[]; roles=[]
if u["relationship"]=="member":
roles.append(model["base_permission"]); sources.append(f"base:{model['base_permission']}")
if repo in u.get("direct",{}):
roles.append(u["direct"][repo]); sources.append(f"direct:{u['direct'][repo]}")
for t in u.get("teams",[]):
for current in [t]+ancestors(t, model["teams"]):
grant=model["teams"].get(current,{}).get("repos",{}).get(repo)
if grant: roles.append(grant); sources.append(f"team:{current}:{grant}")
return {"role":max_role(*(roles or ["none"])),"sources":sources}
m=json.loads(Path(sys.argv[1]).read_text())
for user in m["users"]:
for repo in m["repositories"]:
print(user, repo, json.dumps(effective(m,user,repo)))
python c28_access.py checkpoint.json
Verify P1 from the output before continuing.
4. Simulate time-bound elevation
For incident INC-C28-0042, temporarily add Devon to
break-glass-release. Record a synthetic approval and
expiry in elevation.json:
{
"principal":"devon",
"team":"break-glass-release",
"reason":"INC-C28-0042 release recovery",
"approved_by":"release-duty-manager",
"starts":"2026-08-19T19:00:00Z",
"expires":"2026-08-19T20:00:00Z"
}
Add the team, run the evaluator, and confirm only
release-ops rises to Maintain. Then remove the team and
prove it returns to Engineering's Read. This verifies P2 and
demonstrates that break-glass elevation is a state transition with
evidence and expiry.
5. Inject a nested-team failure and diagnose it
Change security so its parent is
engineering. Predict the effect: Security already has
Read on app-api, but it now inherits Engineering Write,
so Sam unexpectedly gains Write. Run the evaluator and preserve the
failure output.
Repair by restoring security.parent to
null. Rerun and prove Sam returns to Read on
app-api. This is the chapter's policy-failure exercise:
hierarchy placement can expand repository authorization.
6. Offboard Devon completely
Before action, predict that removing only Engineering membership
will remove persistent team access but any forgotten
direct/elevation grant could survive. Perform the complete synthetic
sequence: remove all teams, clear direct grants, mark the identity
inactive, and verify none across all repositories. In a
real environment, also remove/disable the authoritative IdP or
organization identity state, reassign owned automation/release
duties, revoke personal credentials where policy requires, and
review Apps/deploy keys/secrets that were personally controlled.
7. Produce the quarterly access-review checklist
Quarterly GitHub access review — atlas-c28
[ ] Export/inspect current organization members, owners, outside/repository collaborators.
[ ] Confirm every owner is still a continuity/high-impact administrator; keep appropriate redundancy.
[ ] Inventory teams, parent/child relationships, maintainers, and synchronized-IdP ownership.
[ ] For every repository, enumerate team grants + direct grants + base permission + org roles.
[ ] Flag direct grants without business owner, reason, and expiry.
[ ] Reconcile temporary/break-glass grants against expiry records.
[ ] Review custom/predefined organization roles and all-repository permissions where available.
[ ] Review internal-repository visibility assumptions at enterprise scope.
[ ] Confirm departed/transferred users have no residual team/direct/role/credential ownership.
[ ] Sample high-risk repositories and independently prove effective access for representative users.
[ ] Record exceptions, remediation owner, deadline, and evidence link.
[ ] Preserve review date, reviewer, scope, and completion evidence for Chapter 29 audit work.
8. Optional hosted verification
If you own a disposable organization, compare the local model with hosted state. Use only synthetic users/teams you control. Read operations first:
ORG="octo-c28-governance-lab"
gh api --paginate -H "X-GitHub-Api-Version: 2026-03-10" "orgs/$ORG/teams" --jq '.[] | {slug,parent:(.parent.slug // null),privacy}'
gh api --paginate -H "X-GitHub-Api-Version: 2026-03-10" "orgs/$ORG/members" --jq '.[].login'
Do not publish the output if it contains real personal identities. Optional grant/revoke steps from Lesson 2 may be repeated only in the disposable organization. Cleanup removes the grant/team/member created for the lab and verifies absence; it does not delete the organization.
9. Access governance runbook
| Event | Action | Independent verification |
|---|---|---|
| Onboard | Provision identity → add member → add function team(s) → no broad direct grants. | Calculate/inspect effective access on representative repositories. |
| Role change | Add new function team before removing old only if overlap is approved and time-bounded. | Verify final access matches new role, not union of both jobs. |
| Temporary elevation | Use dedicated elevation team/role; record approver/reason/expiry. | After expiry, prove elevated source is absent and effective role fell back. |
| Offboard | Disable authoritative identity; remove org/team/direct/role access; reassign ownership; revoke applicable credentials. | Enumerate all access sources and test representative resources. |
| Quarterly review | Reconcile identity source, organization, teams, direct grants, roles, enterprise policy. | Preserve signed/dated review evidence and exception remediation. |
Knowledge check
During the checkpoint, why did nesting Security under Engineering unexpectedly increase Sam's access?
Child teams inherit parent repository permissions. Engineering had Write on app-api, so Security inherited that stronger grant.
What proves temporary break-glass access was removed?
The elevation team membership/grant is gone and a fresh effective-access calculation shows the principal returned to the ordinary lower role.
Why is a quarterly review based only on the repository People page incomplete?
Effective access can come from teams, parent teams, base permission, organization roles, and enterprise/internal visibility. Reviews must enumerate all relevant sources.
What should happen to organization ownership during normal onboarding?
Usually nothing. New users should receive member/team/repository access matching their job. Owner is reserved for full administrative responsibility and continuity.
What does Chapter 28 add to the production operating model?
A scalable authorization-governance plane: function-based teams, bounded roles, explicit elevation, complete lifecycle/offboarding, and repeatable effective-access reviews.
What evidence does Chapter 29 need from this checkpoint?
Dated access-review scope/results, role and team decisions, exception/elevation records, before/after verification, and remediation ownership—rather than only current-state screenshots.
Summary and bridge to Chapter 29
Chapter 28 adds the access-governance plane to the GitHub operating model. Persistent access follows teams and task-specific roles; broad ownership is exceptional; temporary elevation is explicit and expiring; offboarding proves every access path is gone; and periodic reviews reconcile effective access rather than trusting one grant list. Chapter 29 will turn these controls and their changes into audit logs, compliance evidence, security policy, and enterprise governance records.
Official references
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.