Personas: who owns what¶
Audience: All
Running GitHub Actions Gateway (GAG) for many teams means more than one role is involved, and the split between them is not a documentation convention. It is the product: the platform owns limits a tenant cannot raise, the tenant composes freely inside them, and neither has to file a ticket with the other for routine work. Single-tenant runner controllers do not need this distinction, which is why they generally do not have a primitive for it.
This page defines each role by what it owns and, more usefully, what it cannot do. A boundary that a role can talk its way past is not a boundary.
One boundary is enforced; the rest are just labels¶
Only one line here is a privilege boundary the system enforces: platform side versus tenant side. A tenant operator cannot raise their own quota or self-grant privilege no matter who they report to, and that is checked by RBAC, admission, and a quota the control plane cannot write.
Everything else is a routing label for finding the right document.
On-call is a mode, not a role. Both sides get paged, for different things: the platform side when the control plane misbehaves, the tenant side when one namespace's CI does. Whoever is carrying the pager already appears below under the side they sit on, so there is no separate on-call persona on this page.
Job titles are not roles, which is why none of them appear here. "SRE" was a tag in this tree until 2026-08-07 and was retired for being ambiguous in the one way a routing tag cannot afford: both the platform and its tenants need SREs, so the tag never told a reader which side of the boundary a page was written for. Retiring it forced every page it covered to declare a side, and three turned out to be tenant-facing pages that had been filed as platform ones. "DevOps" was never a tag and should not become one; it is even less specific, and CI is not an application being operated in production.
A role name here states a scope, a domain, and a responsibility. Read it as one question: which side of the tenancy boundary are you on?
The roles¶
Platform engineer¶
Owns the cluster and everything shared in it, and carries the pager when the control plane itself misbehaves.
Owns: the GMC install and upgrades; the actions-gateway.github.com/tenant
namespace marker; each tenant namespace's ResourceQuota; the
PriorityClassAllowlist;
ClusterRunnerTemplate objects; the Pod Security Admission level and the
privileged-profile: allowed grant; whether the cluster has a node autoscaler.
At 03:00 the same person owns the shipped alerts,
the runbook, backup and restore, and
upgrades.
Cannot, by design: be required in the loop for a tenant's day-to-day runner changes. If adding a runner shape or adjusting concurrency needs a platform ticket, the model has failed.
Needs, specifically: failure modes that surface as a named condition, an Event, and a metric rather than as a log line to grep. The troubleshooting guide is organised by observable symptom for this reason.
Notably does not own: the ResourceQuota through GAG. The GMC holds no
write verb on resourcequotas, so the quota is set on the namespace by the
platform admin and the control plane operates within it. That is what makes the
quota a real cap rather than a suggestion.
Tenant operator¶
Owns one namespace's CI end to end: the runner configuration and the workflow files in the repositories being tested. Usually one person per tenant, sometimes one person across several similar tenants. When that team's CI breaks at 03:00, this is who looks at it, whatever their job title says.
That span is the point. runs-on: in a workflow and the RunnerSet that
answers it are two halves of one job on one desk. It is why a migration that
needs no workflow edit is worth something concrete to this person, and why a
gap that forces one edit per target
(migrating from ARC) is a real cost rather than a
detail. It is also why this role, not the platform engineer, is the one that
has to be able to self-diagnose.
Owns: the ActionsGateway, its RunnerSets and RunnerTemplates, the
GitHub App credential Secret for their own organization, worker pod shape,
concurrency ceilings, their own EgressProxy if they use one, and the
runs-on labels their workflows target.
Cannot, by design: raise their own ResourceQuota; name a PriorityClass
outside the platform's allowlist; author a privileged worker template; or read
another tenant's metrics, logs, or Secrets.
Should be able to: answer "why is my job queued?" without opening a ticket. That is the test the tenant dashboard and the per-tenant metrics exist to pass, and the reason it matters is that the person asking is also the person who has to fix it.
Security / compliance¶
Reads rather than operates, and needs evidence rather than assurances.
Owns: the threat model's operational half, admission policy compatibility, abuse response, and whatever an auditor asks for.
Needs, specifically: artifacts produced unprompted. A control that exists but leaves no record is hard to evidence, which is why per-tenant egress attribution and admission decisions matter as much as the controls themselves. Security operations and admission policies are the entry points.
Budget owner¶
Owns the spend, and usually cannot read the cluster at all.
Needs, specifically: cost per tenant, in currency, from data they can
defend in a planning conversation.
Cost attribution maps tenant namespaces and
app.kubernetes.io/* labels onto OpenCost and Kubecost allocation queries for
exactly this. There is no dashboard for this persona yet; see the
roadmap.
Maintainer¶
Internal to GAG itself: cutting releases, the publish pipeline, supply-chain attestations. See release.md. Listed because the docs index tags it, not because adopters need it.
The role that is not a user¶
An external contributor to a public repository can cause code to run on your cluster without being a user of your platform, and a fork pull request is an arbitrary-code-execution request the CI system is designed to honour. For every other role above, this one is part of the threat model rather than an audience.
That asymmetry is why isolation is a separate concern from access control: the question is not what this person is permitted to do, but what their code can reach if it tries. GAG's stance today is Kata micro-VM workers for trusted CI, with the untrusted-pull-request posture still in progress. The threat model, the layer map, and what is explicitly out of scope are in the secure multi-tenant OSS CI goal.
How personas are recorded¶
A doc's audience is recorded in two places, deliberately:
- the Personas column in the operations index, which drives the filter chips; and
- that doc's own
> **Audience:** …blockquote, which drives the per-doc pill and deep-links back to the filtered index.
They must agree. There is no CI check, so when you retag a doc, update both. Use the tag names already in use verbatim: an unlisted spelling silently creates a new chip that matches one document. "Tenant operator" is the correct name for the namespace-owning role; "Tenant owner" was a drifted variant and has been normalised.
Every tag is a role on this page, with one exception. All means every
persona, and a page carrying it stays visible under any chip. This page and the
glossary use it, which is why the audience line
above names no roles: a page about who the roles are is not addressed to one of
them.
Otherwise, tag with a role name. Do not reintroduce a job title as a tag. A tag exists to route a reader to the right page, so it has to answer "is this for me?", and a title that both sides of the boundary use cannot. If a new tag seems necessary, the question to answer first is what scope, domain, and responsibility it names.