Delegated administration¶
Out of the box every authenticated portal session may do everything. This guide turns that into delegated administration: named admins, per-marketplace approvers, and read-only auditors — without ever locking yourself out.
The three roles¶
| Role | Scope | May |
|---|---|---|
admin |
global | Everything, including managing grants. |
approver |
one marketplace | Ingest, approve, reject, re-vet, and waive findings for that marketplace only. |
auditor |
global | Read the ledger, its export, the webhook subscriber/delivery/sink listings, and retention candidates. Nothing else. |
Roles compose upward — an admin can do everything an approver or auditor can. Every session, role or not, keeps the browsing surface (marketplaces, the catalog, snapshot contents, provenance, vetting results, waiver lists) and its own access tokens.
Enforcement lives at the REST API, which is what the portal speaks. The git facade is untouched: its authorization is token scopes, a different credential for a different surface.
Step 1 — stage your grants¶
Role enforcement is off by default (skills-gateway.roles.enabled=false):
every check passes and the gateway behaves exactly as before. The grants API
already works in this state, which is how you stage grants before anything is
enforced:
$ curl -X POST localhost:8080/api/roles \
-H 'Content-Type: application/json' \
-d '{"principal": "alice@example.com", "role": "approver", "marketplace": "acme"}'
$ curl -X POST localhost:8080/api/roles \
-H 'Content-Type: application/json' \
-d '{"principal": "carol@example.com", "role": "auditor"}'
An approver grant must name a marketplace that exists; admin and auditor grants must not name one. See the roles API reference for the full contract.
Inert until enabled
While enforcement is disabled, grants are data with no effect — and any session can write them. That is deliberate: flipping the switch is a configuration decision, made by whoever controls deployment, which is strictly more privileged than any API caller.
Step 2 — name at least one bootstrap admin¶
Principals in skills-gateway.roles.admins are admins by configuration:
they need no grant row, they appear on their own /api/me as a synthetic
admin role, and no API call can revoke them. This is the escape hatch that
survives any bad grant edit. Admins granted through the API work exactly as
well — the configuration list is the one you cannot lose.
Step 3 — enable and verify¶
Restart with the configuration above. Then verify from a browser session:
GET /api/menow reports"rolesEnabled": trueand your effective roles.- A session with no role gets 403 from every mutation and from the ledger, while browsing and its own tokens keep working.
- Your approver can approve their marketplace and gets 403 for any other, including through bare snapshot ids.
Every grant and revocation lands on the
audit ledger as role-granted /
role-revoked with the acting identity, the target principal, the role, and
the marketplace.
Grants, or groups?¶
Grants are not the only source of a role. A session's effective roles are the union of three:
| Source | /api/me reports |
Managed by |
|---|---|---|
skills-gateway.roles.admins |
config |
Whoever controls deployment. Unrevocable through the API. |
| A row in the grants API | grant |
Admins, at runtime, audited on the ledger. |
| An identity-provider claim | claim |
Your directory, through skills-gateway.roles.mappings. |
Prefer groups wherever your identity provider already governs membership: the joiner/mover/leaver process you already have then governs gateway access too, and there is no second list to keep in step. Reach for a grant when the person is not in a group that fits, when you want the change audited on the ledger with an acting identity, or when the role must survive the person leaving the group. Keep at least one configuration admin either way — it is the one source that no directory outage and no bad mapping can take away.
Setting the mappings up, including a worked Microsoft Entra ID walkthrough, is in Identity providers.
Locked out anyway?¶
Set skills-gateway.roles.enabled=false and restart: every check passes again,
grants intact. Fix the grants (or the admins list) and re-enable.
What this is not¶
- No portal UI for managing grants or claim mappings yet — the API (and the coming CLI) is the management surface for grants; mappings are configuration.
- No roles on personal access tokens: the facade's authorization is token scopes.
- No per-team catalog scoping yet; approver scope is the marketplace.