60. Cross-org mint authorization via org variables
Date: 2026-06-07
Status
Accepted
Context
The central token mint (ADR 0029) issues short-lived GitHub App installation tokens to OIDC-authenticated workflows. Today the mint scopes tokens to the caller's repository_owner: the App installation lookup and PEM lookup both use the org from the OIDC repository claim.
Some workloads need to act on a different org than the workflow's owner. The e2e test pool (ADR 0040) runs CI from fullsend-ai/fullsend but mutates dedicated pool orgs (halfsend-01, …). Future cross-org agent flows (#672, #1916) have the same shape.
The target org must explicitly authorize which foreign repos or orgs may request tokens for a given role. A mint-operator central allowlist does not scale and does not give target orgs control over their own policy.
Decision
Optional
target_orgon mint requests. When omitted, or when equal to the caller'srepository_owner(case-insensitive), behavior uses the samemintTokenpath with no FOREIGN check. Whenreposis omitted, the mint issues an installation-wide token via org-level installation lookup (same as the cross-org path). Callers are authenticated via WIF/OIDC; only enrolled workflows that pass mint enrollment checks can reach the handler.Cross-org path applies only when
target_orgis set and differs from the caller org:- Resolve the requested role's App installation on
target_orgvia org-level installation lookup. - Read
FULLSEND_FOREIGN_<role>_REPOSon the target org using that role's App installation token (organization_actions_variables: read). - Deny if installation lookup fails, the variable is missing/empty, or the OIDC caller (
repositoryor barerepository_owner) is not on the allowlist. - Mint an installation token for the requested repos on the target org, or installation-wide when
reposis omitted. Thee2erole acting on pool orgs from CI is the first consumer (#2155).
- Resolve the requested role's App installation on
Variable format. Org-level GitHub Actions variable on the target org:
- Name:
FULLSEND_FOREIGN_<ROLE>_REPOS(uppercase role suffix, per ADR 0014) - Value: comma-separated list of
org/repo(exactrepositorymatch) and/or bareorg(repository_ownermatch)
- Name:
Role-agnostic mechanism. Any allowed role may use the cross-org path when the target org has installed that role's App and configured the FOREIGN variable. The
e2erole (#2155) is the first consumer.CLI.
fullsend admin foreign allow|list|revokemanages FOREIGN variables on a target org.
Consequences
- Cross-org mint requests add GitHub API calls. FOREIGN allowlist lookups are cached in-memory per mint instance (key:
target_org/role, TTL 60s). Cache entries include empty/missing allowlists (negative cache) so revoked or unset variables may take up to one TTL window to take effect. Cardinality is bounded by enrolled orgs × roles; no explicit eviction beyond TTL. - Roles used on the cross-org path need
organization_actions_variables: readon their App permissions. - The
e2erole additionally needsactions_variables: writeandorganization_actions_variables: writeso pool tests can set repo/org variables during install flows; these writes are scoped to pool orgs that explicitly authorize CI viaFULLSEND_FOREIGN_E2E_REPOS. - Installation-wide tokens (empty
repos) are permitted on both same-org and cross-org paths. Cross-org requests additionally require FOREIGN authorization on the target org. Same-org elevation relies on WIF/OIDC enrollment: only trusted workflows can call the mint. - Target orgs opt in by installing the role App and setting the FOREIGN allowlist (cross-org).
- Same-org mint for enrolled orgs adds zero FOREIGN API calls; optional
reposomission uses org-level installation lookup when callers need installation-wide scope. - Pool org provisioning must install the e2e App and set
FULLSEND_FOREIGN_E2E_REPOSfor CI callers.
